github.com/bytedance/mockey@v1.2.10/utils_test.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package mockey 18 19 import ( 20 "bytes" 21 "crypto/sha256" 22 "fmt" 23 "io" 24 "reflect" 25 "testing" 26 27 "github.com/smartystreets/goconvey/convey" 28 ) 29 30 func TestGetNestedMethod(t *testing.T) { 31 convey.Convey("TestGetNestedMethod", t, func() { 32 convey.Convey("basic cases", func() { 33 convey.Convey("case nil", func() { 34 convey.So(func() { GetNestedMethod(nil, "unknown") }, convey.ShouldPanicWith, "can't reflect instance method :unknown") 35 }) 36 37 convey.Convey("case testA", func() { 38 instance := testA{} 39 convey.So(func() { GetNestedMethod(instance, "FooB") }, convey.ShouldPanicWith, "can't reflect instance method :FooB") 40 convey.So(func() { GetNestedMethod(instance, "FooA") }, convey.ShouldNotPanic) 41 convey.So(func() { GetNestedMethod(instance, "BarA") }, convey.ShouldNotPanic) 42 convey.So(func() { GetNestedMethod(instance, "FooC") }, convey.ShouldNotPanic) 43 convey.So(func() { GetNestedMethod(instance, "BarC") }, convey.ShouldNotPanic) 44 convey.So(func() { instance.FooC() }, convey.ShouldPanicWith, "shouldn't here") 45 convey.So(func() { 46 reflect.ValueOf(GetNestedMethod(instance, "FooC")).Call([]reflect.Value{reflect.ValueOf(instance.testC)}) 47 }, convey.ShouldNotPanic) 48 convey.So(func() { instance.BarC() }, convey.ShouldPanicWith, "shouldn't here") 49 convey.So(func() { 50 reflect.ValueOf(GetNestedMethod(instance, "BarC")).Call([]reflect.Value{reflect.ValueOf(&instance.testC)}) 51 }, convey.ShouldNotPanic) 52 }) 53 54 convey.Convey("case testB", func() { 55 instance := testB{} 56 convey.So(func() { GetNestedMethod(instance, "FooA") }, convey.ShouldPanicWith, "can't reflect instance method :FooA") 57 convey.So(func() { GetNestedMethod(instance, "FooB") }, convey.ShouldNotPanic) 58 convey.So(func() { GetNestedMethod(instance, "BarB") }, convey.ShouldNotPanic) 59 convey.So(func() { GetNestedMethod(instance, "FooC") }, convey.ShouldNotPanic) 60 convey.So(func() { GetNestedMethod(instance, "BarC") }, convey.ShouldNotPanic) 61 }) 62 63 convey.Convey("case testD", func() { 64 instance := testD{} 65 convey.So(func() { GetNestedMethod(instance, "FooA") }, convey.ShouldPanicWith, "can't reflect instance method :FooA") 66 convey.So(func() { GetNestedMethod(instance, "FooD") }, convey.ShouldNotPanic) 67 convey.So(func() { GetNestedMethod(instance, "BarD") }, convey.ShouldNotPanic) 68 convey.So(func() { GetNestedMethod(instance, "FooB") }, convey.ShouldNotPanic) 69 convey.So(func() { GetNestedMethod(instance, "BarB") }, convey.ShouldNotPanic) 70 convey.So(func() { GetNestedMethod(instance, "FooC") }, convey.ShouldNotPanic) 71 convey.So(func() { GetNestedMethod(instance, "BarC") }, convey.ShouldNotPanic) 72 }) 73 }) 74 75 PatchConvey("patch cases", func() { 76 PatchConvey("case testA", func() { 77 instance := testA{} 78 Mock(GetNestedMethod(instance, "FooC")).To(func() { panic("should here") }).Build() 79 Mock(GetNestedMethod(instance, "BarC")).To(func() { panic("should here") }).Build() 80 convey.So(func() { instance.FooC() }, convey.ShouldPanicWith, "shouldn't here") // no effect, didn't call testC.FooC() 81 convey.So(func() { instance.BarC() }, convey.ShouldPanicWith, "shouldn't here") // no effect, didn't call testC.BarC() 82 }) 83 84 PatchConvey("case testB", func() { 85 instance := testB{testC: &testC{}} 86 Mock(GetNestedMethod(instance, "FooC")).To(func() { panic("should here") }).Build() 87 Mock(GetNestedMethod(instance, "BarC")).To(func() { panic("should here") }).Build() 88 convey.So(func() { instance.FooC() }, convey.ShouldPanicWith, "should here") 89 convey.So(func() { instance.BarC() }, convey.ShouldPanicWith, "should here") 90 }) 91 92 PatchConvey("case testD", func() { 93 instance := testD{testB: &testB{testC: &testC{}}} 94 Mock(GetNestedMethod(instance, "FooC")).To(func() { panic("should here") }).Build() 95 Mock(GetNestedMethod(instance, "BarC")).To(func() { panic("should here") }).Build() 96 convey.So(func() { instance.FooC() }, convey.ShouldPanicWith, "should here") 97 convey.So(func() { instance.BarC() }, convey.ShouldPanicWith, "should here") 98 }) 99 }) 100 }) 101 } 102 103 type testA struct { 104 testC 105 } 106 107 func (a testA) FooA() {} 108 109 func (a *testA) BarA() {} 110 111 func (a testA) FooC() { 112 panic("shouldn't here") 113 } 114 115 func (a *testA) BarC() { 116 panic("shouldn't here") 117 } 118 119 type testB struct { 120 *testC 121 } 122 123 func (b testB) FooB() {} 124 125 func (b *testB) BarB() {} 126 127 type testC struct{} 128 129 func (s testC) FooC() { 130 fmt.Print("") 131 } 132 133 func (s *testC) BarC() { 134 fmt.Print("") 135 } 136 137 type testD struct { 138 *testB 139 } 140 141 func (s testD) FooD() {} 142 143 func (s *testD) BarD() {} 144 145 type Fn func() 146 147 type testFuncField struct { 148 Public Fn 149 private Fn 150 } 151 152 func NewTestFuncField() *testFuncField { 153 return &testFuncField{ 154 Public: func() { panic("shouldn't here") }, 155 private: func() { panic("shouldn't here") }, 156 } 157 } 158 159 func TestGetMethod(t *testing.T) { 160 convey.Convey("TestGetMethod", t, func() { 161 convey.Convey("basic cases", func() { 162 convey.Convey("case nil", func() { 163 convey.So(func() { GetMethod(nil, "unknown") }, convey.ShouldPanicWith, "can't reflect instance method :unknown") 164 }) 165 166 convey.Convey("case testA", func() { 167 instance := testA{} 168 convey.So(func() { GetMethod(instance, "FooB") }, convey.ShouldPanicWith, "can't reflect instance method :FooB") 169 convey.So(func() { GetMethod(instance, "FooA") }, convey.ShouldNotPanic) 170 convey.So(func() { GetMethod(instance, "BarA") }, convey.ShouldNotPanic) 171 convey.So(func() { GetMethod(instance, "FooC") }, convey.ShouldNotPanic) 172 convey.So(func() { GetMethod(instance, "BarC") }, convey.ShouldNotPanic) 173 convey.So(func() { instance.FooC() }, convey.ShouldPanicWith, "shouldn't here") 174 convey.So(func() { 175 reflect.ValueOf(GetMethod(instance, "FooC")).Call([]reflect.Value{reflect.ValueOf(instance.testC)}) 176 }, convey.ShouldNotPanic) 177 convey.So(func() { instance.BarC() }, convey.ShouldPanicWith, "shouldn't here") 178 convey.So(func() { 179 reflect.ValueOf(GetMethod(instance, "BarC")).Call([]reflect.Value{reflect.ValueOf(&instance.testC)}) 180 }, convey.ShouldNotPanic) 181 }) 182 183 convey.Convey("case testB", func() { 184 instance := testB{} 185 convey.So(func() { GetMethod(instance, "FooA") }, convey.ShouldPanicWith, "can't reflect instance method :FooA") 186 convey.So(func() { GetMethod(instance, "FooB") }, convey.ShouldNotPanic) 187 convey.So(func() { GetMethod(instance, "BarB") }, convey.ShouldNotPanic) 188 convey.So(func() { GetMethod(instance, "FooC") }, convey.ShouldNotPanic) 189 convey.So(func() { GetMethod(instance, "BarC") }, convey.ShouldNotPanic) 190 }) 191 192 convey.Convey("case testD", func() { 193 instance := testD{} 194 convey.So(func() { GetMethod(instance, "FooA") }, convey.ShouldPanicWith, "can't reflect instance method :FooA") 195 convey.So(func() { GetMethod(instance, "FooD") }, convey.ShouldNotPanic) 196 convey.So(func() { GetMethod(instance, "BarD") }, convey.ShouldNotPanic) 197 convey.So(func() { GetMethod(instance, "FooB") }, convey.ShouldNotPanic) 198 convey.So(func() { GetMethod(instance, "BarB") }, convey.ShouldNotPanic) 199 convey.So(func() { GetMethod(instance, "FooC") }, convey.ShouldNotPanic) 200 convey.So(func() { GetMethod(instance, "BarC") }, convey.ShouldNotPanic) 201 }) 202 203 convey.Convey("case testFuncField", func() { 204 var instance interface{} = NewTestFuncField() 205 convey.So(func() { GetMethod(instance, "Public") }, convey.ShouldNotPanic) 206 convey.So(func() { GetMethod(instance, "private") }, convey.ShouldNotPanic) 207 convey.So(func() { GetMethod(instance, "notExist") }, convey.ShouldPanicWith, "can't reflect instance method :notExist") 208 convey.So(func() { 209 reflect.ValueOf(GetMethod(instance, "Public")).Call([]reflect.Value{}) 210 }, convey.ShouldPanicWith, "shouldn't here") 211 convey.So(func() { 212 reflect.ValueOf(GetMethod(instance, "private")).Call([]reflect.Value{}) 213 }, convey.ShouldPanicWith, "shouldn't here") 214 }) 215 }) 216 217 PatchConvey("patch cases", func() { 218 PatchConvey("case testA", func() { 219 instance := testA{} 220 Mock(GetMethod(instance, "FooC")).To(func() { panic("should here") }).Build() 221 Mock(GetMethod(instance, "BarC")).To(func() { panic("should here") }).Build() 222 convey.So(func() { instance.FooC() }, convey.ShouldPanicWith, "shouldn't here") // no effect, didn't call testC.FooC() 223 convey.So(func() { instance.BarC() }, convey.ShouldPanicWith, "shouldn't here") // no effect, didn't call testC.BarC() 224 }) 225 226 PatchConvey("case testB", func() { 227 instance := testB{testC: &testC{}} 228 Mock(GetMethod(instance, "FooC")).To(func() { panic("should here") }).Build() 229 Mock(GetMethod(instance, "BarC")).To(func() { panic("should here") }).Build() 230 convey.So(func() { instance.FooC() }, convey.ShouldPanicWith, "should here") 231 convey.So(func() { instance.BarC() }, convey.ShouldPanicWith, "should here") 232 }) 233 234 PatchConvey("case testD", func() { 235 instance := testD{testB: &testB{testC: &testC{}}} 236 Mock(GetMethod(instance, "FooC")).To(func() { panic("should here") }).Build() 237 Mock(GetMethod(instance, "BarC")).To(func() { panic("should here") }).Build() 238 convey.So(func() { instance.FooC() }, convey.ShouldPanicWith, "should here") 239 convey.So(func() { instance.BarC() }, convey.ShouldPanicWith, "should here") 240 }) 241 242 PatchConvey("case testFuncField", func() { 243 instance := NewTestFuncField() 244 caller := NewTestFuncField() 245 Mock(GetMethod(instance, "Public")).To(func() { panic("should here") }).Build() 246 Mock(GetMethod(instance, "private")).To(func() { panic("should here") }).Build() 247 convey.So(func() { instance.Public() }, convey.ShouldPanicWith, "should here") 248 convey.So(func() { caller.Public() }, convey.ShouldPanicWith, "should here") 249 convey.So(func() { instance.private() }, convey.ShouldPanicWith, "should here") 250 convey.So(func() { caller.private() }, convey.ShouldPanicWith, "should here") 251 }) 252 }) 253 }) 254 } 255 256 type testNested interface { 257 FooNested() 258 } 259 type testOuter struct { 260 testNested 261 } 262 263 type testInner struct { 264 _ int 265 } 266 267 func (testInner) FooNested() { 268 panic("not here") 269 } 270 271 type testInnerP struct { 272 _ string 273 } 274 275 func (*testInnerP) FooNested() { 276 panic("not here p") 277 } 278 279 func TestGetNested(t *testing.T) { 280 PatchConvey("TestGetNested", t, func() { 281 PatchConvey("instance implement", func() { 282 var obj testNested 283 PatchConvey("pointer container", func() { 284 obj = &testOuter{testNested: testInner{}} 285 convey.So(func() { 286 Mock(GetMethod(obj, "FooNested")).Return().Build() 287 }, convey.ShouldNotPanic) 288 convey.So(func() { 289 obj.FooNested() 290 }, convey.ShouldNotPanic) 291 }) 292 PatchConvey("struct container", func() { 293 obj = testOuter{testNested: testInner{}} 294 convey.So(func() { 295 Mock(GetMethod(obj, "FooNested")).Return().Build() 296 }, convey.ShouldNotPanic) 297 convey.So(func() { 298 obj.FooNested() 299 }, convey.ShouldNotPanic) 300 }) 301 PatchConvey("nested container", func() { 302 obj = &testOuter{ 303 testNested: testOuter{ 304 testNested: &testOuter{ 305 testNested: testOuter{ 306 testNested: testInner{}, 307 }, 308 }, 309 }, 310 } 311 convey.So(func() { 312 Mock(GetMethod(obj, "FooNested")).Return().Build() 313 }, convey.ShouldNotPanic) 314 convey.So(func() { 315 obj.FooNested() 316 }, convey.ShouldNotPanic) 317 }) 318 }) 319 PatchConvey("instance implement(but pointer field)", func() { 320 var obj testNested 321 PatchConvey("pointer container", func() { 322 obj = &testOuter{testNested: &testInner{}} 323 convey.So(func() { 324 Mock(GetMethod(obj, "FooNested")).Return().Build() 325 }, convey.ShouldNotPanic) 326 convey.So(func() { 327 obj.FooNested() 328 }, convey.ShouldNotPanic) 329 }) 330 PatchConvey("struct container", func() { 331 obj = testOuter{testNested: &testInner{}} 332 convey.So(func() { 333 Mock(GetMethod(obj, "FooNested")).Return().Build() 334 }, convey.ShouldNotPanic) 335 convey.So(func() { 336 obj.FooNested() 337 }, convey.ShouldNotPanic) 338 }) 339 PatchConvey("nested container", func() { 340 obj = &testOuter{ 341 testNested: testOuter{ 342 testNested: &testOuter{ 343 testNested: testOuter{ 344 testNested: &testInner{}, 345 }, 346 }, 347 }, 348 } 349 convey.So(func() { 350 Mock(GetMethod(obj, "FooNested")).Return().Build() 351 }, convey.ShouldNotPanic) 352 convey.So(func() { 353 obj.FooNested() 354 }, convey.ShouldNotPanic) 355 }) 356 }) 357 PatchConvey("pointer implement", func() { 358 var obj testNested 359 PatchConvey("pointer container", func() { 360 obj = &testOuter{testNested: &testInnerP{}} 361 convey.So(func() { 362 Mock(GetMethod(obj, "FooNested")).Return().Build() 363 }, convey.ShouldNotPanic) 364 convey.So(func() { 365 obj.FooNested() 366 }, convey.ShouldNotPanic) 367 }) 368 PatchConvey("struct container", func() { 369 obj = testOuter{testNested: &testInnerP{}} 370 convey.So(func() { 371 Mock(GetMethod(obj, "FooNested")).Return().Build() 372 }, convey.ShouldNotPanic) 373 convey.So(func() { 374 obj.FooNested() 375 }, convey.ShouldNotPanic) 376 }) 377 PatchConvey("nested container", func() { 378 obj = &testOuter{ 379 testNested: testOuter{ 380 testNested: &testOuter{ 381 testNested: testOuter{ 382 testNested: &testInnerP{}, 383 }, 384 }, 385 }, 386 } 387 convey.So(func() { 388 Mock(GetMethod(obj, "FooNested")).Return().Build() 389 }, convey.ShouldNotPanic) 390 convey.So(func() { 391 obj.FooNested() 392 }, convey.ShouldNotPanic) 393 }) 394 }) 395 }) 396 } 397 398 func TestPrivateMethod(t *testing.T) { 399 PatchConvey("PrivateMethod", t, func() { 400 PatchConvey("unsafeMethodByName", func() { 401 PatchConvey("struct method", func() { 402 fn := unsafeMethodByName(&bytes.Buffer{}, "empty") 403 targetType := reflect.TypeOf(func(*bytes.Buffer) bool { return false }) 404 405 convey.So(reflect.TypeOf(fn), convey.ShouldEqual, targetType) 406 407 buf := bytes.NewBuffer([]byte{1, 2, 3, 4}) 408 b, err := buf.ReadByte() 409 convey.So(b, convey.ShouldEqual, 1) 410 convey.So(err, convey.ShouldBeNil) 411 412 mocker := Mock(fn).Return(true).Build() 413 _, err = buf.ReadByte() 414 convey.So(err, convey.ShouldEqual, io.EOF) 415 convey.So(mocker.MockTimes(), convey.ShouldEqual, 1) 416 }) 417 PatchConvey("struct method mock", func() { 418 buf := bytes.NewBuffer([]byte{1, 2, 3, 4}) 419 b, err := buf.ReadByte() 420 convey.So(b, convey.ShouldEqual, 1) 421 convey.So(err, convey.ShouldBeNil) 422 423 mocker := Mock(GetMethod(bytes.NewBuffer(nil), "empty")).Return(true).Build() 424 _, err = buf.ReadByte() 425 convey.So(err, convey.ShouldEqual, io.EOF) 426 convey.So(mocker.MockTimes(), convey.ShouldEqual, 1) 427 }) 428 429 PatchConvey("interface method mock", func() { 430 mocker := Mock(GetMethod(sha256.New(), "checkSum")).Return([sha256.Size]byte{}).Build() 431 convey.So(sha256.New().Sum([]byte{}), convey.ShouldResemble, make([]byte, 32)) 432 convey.So(mocker.MockTimes(), convey.ShouldEqual, 1) 433 }) 434 PatchConvey("interface method", func() { 435 targetType := reflect.FuncOf([]reflect.Type{reflect.TypeOf(sha256.New())}, []reflect.Type{reflect.TypeOf([sha256.Size]byte{})}, false) 436 fn := unsafeMethodByName(sha256.New(), "checkSum") 437 convey.So(reflect.TypeOf(fn), convey.ShouldEqual, targetType) 438 439 convey.So(sha256.New().Sum([]byte{}), convey.ShouldResemble, []byte{227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85}) 440 mocker := Mock(fn).To(func() [sha256.Size]byte { 441 return [sha256.Size]byte{} 442 }).Build() 443 convey.So(sha256.New().Sum([]byte{}), convey.ShouldResemble, make([]byte, 32)) 444 convey.So(mocker.MockTimes(), convey.ShouldEqual, 1) 445 }) 446 }) 447 }) 448 }