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  }