Skip to content

Commit 89cbdd9

Browse files
Merge pull request #1626 from arjun-1/fix-functional-options-diff-indirect-calls
fix: compare functional option names for indirect calls
2 parents 07bac60 + 7d99b2b commit 89cbdd9

File tree

2 files changed

+97
-17
lines changed

2 files changed

+97
-17
lines changed

mock/mock.go

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,32 +1204,38 @@ type tHelper interface {
12041204
func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
12051205
expectedOpts := reflect.ValueOf(expected)
12061206
actualOpts := reflect.ValueOf(actual)
1207+
1208+
var expectedFuncs []*runtime.Func
12071209
var expectedNames []string
12081210
for i := 0; i < expectedOpts.Len(); i++ {
1209-
expectedNames = append(expectedNames, funcName(expectedOpts.Index(i).Interface()))
1211+
f := runtimeFunc(expectedOpts.Index(i).Interface())
1212+
expectedFuncs = append(expectedFuncs, f)
1213+
expectedNames = append(expectedNames, funcName(f))
12101214
}
1215+
var actualFuncs []*runtime.Func
12111216
var actualNames []string
12121217
for i := 0; i < actualOpts.Len(); i++ {
1213-
actualNames = append(actualNames, funcName(actualOpts.Index(i).Interface()))
1218+
f := runtimeFunc(actualOpts.Index(i).Interface())
1219+
actualFuncs = append(actualFuncs, f)
1220+
actualNames = append(actualNames, funcName(f))
12141221
}
1215-
if !assert.ObjectsAreEqual(expectedNames, actualNames) {
1222+
1223+
if expectedOpts.Len() != actualOpts.Len() {
12161224
expectedFmt = fmt.Sprintf("%v", expectedNames)
12171225
actualFmt = fmt.Sprintf("%v", actualNames)
12181226
return
12191227
}
12201228

12211229
for i := 0; i < expectedOpts.Len(); i++ {
1222-
expectedOpt := expectedOpts.Index(i).Interface()
1223-
actualOpt := actualOpts.Index(i).Interface()
1224-
1225-
expectedFunc := expectedNames[i]
1226-
actualFunc := actualNames[i]
1227-
if expectedFunc != actualFunc {
1228-
expectedFmt = expectedFunc
1229-
actualFmt = actualFunc
1230+
if !isFuncSame(expectedFuncs[i], actualFuncs[i]) {
1231+
expectedFmt = expectedNames[i]
1232+
actualFmt = actualNames[i]
12301233
return
12311234
}
12321235

1236+
expectedOpt := expectedOpts.Index(i).Interface()
1237+
actualOpt := actualOpts.Index(i).Interface()
1238+
12331239
ot := reflect.TypeOf(expectedOpt)
12341240
var expectedValues []reflect.Value
12351241
var actualValues []reflect.Value
@@ -1247,9 +1253,9 @@ func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
12471253
reflect.ValueOf(actualOpt).Call(actualValues)
12481254

12491255
for i := 0; i < ot.NumIn(); i++ {
1250-
if !assert.ObjectsAreEqual(expectedValues[i].Interface(), actualValues[i].Interface()) {
1251-
expectedFmt = fmt.Sprintf("%s %+v", expectedNames[i], expectedValues[i].Interface())
1252-
actualFmt = fmt.Sprintf("%s %+v", expectedNames[i], actualValues[i].Interface())
1256+
if expectedArg, actualArg := expectedValues[i].Interface(), actualValues[i].Interface(); !assert.ObjectsAreEqual(expectedArg, actualArg) {
1257+
expectedFmt = fmt.Sprintf("%s(%T) -> %#v", expectedNames[i], expectedArg, expectedArg)
1258+
actualFmt = fmt.Sprintf("%s(%T) -> %#v", expectedNames[i], actualArg, actualArg)
12531259
return
12541260
}
12551261
}
@@ -1258,7 +1264,25 @@ func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
12581264
return "", ""
12591265
}
12601266

1261-
func funcName(opt interface{}) string {
1262-
n := runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name()
1263-
return strings.TrimSuffix(path.Base(n), path.Ext(n))
1267+
func runtimeFunc(opt interface{}) *runtime.Func {
1268+
return runtime.FuncForPC(reflect.ValueOf(opt).Pointer())
1269+
}
1270+
1271+
func funcName(f *runtime.Func) string {
1272+
name := f.Name()
1273+
trimmed := strings.TrimSuffix(path.Base(name), path.Ext(name))
1274+
splitted := strings.Split(trimmed, ".")
1275+
1276+
if len(splitted) == 0 {
1277+
return trimmed
1278+
}
1279+
1280+
return splitted[len(splitted)-1]
1281+
}
1282+
1283+
func isFuncSame(f1, f2 *runtime.Func) bool {
1284+
f1File, f1Loc := f1.FileLine(f1.Entry())
1285+
f2File, f2Loc := f2.FileLine(f2.Entry())
1286+
1287+
return f1File == f2File && f1Loc == f2Loc
12641288
}

mock/mock_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,22 @@ func OpStr(s string) OptionFn {
5050
o.str = s
5151
}
5252
}
53+
54+
func OpBytes(b []byte) OptionFn {
55+
return func(m *options) {
56+
m.str = string(b)
57+
}
58+
}
59+
5360
func (i *TestExampleImplementation) TheExampleMethodFunctionalOptions(x string, opts ...OptionFn) error {
5461
args := i.Called(x, opts)
5562
return args.Error(0)
5663
}
5764

65+
func TheExampleMethodFunctionalOptionsIndirect(i *TestExampleImplementation) {
66+
i.TheExampleMethodFunctionalOptions("test", OpNum(1), OpStr("foo"))
67+
}
68+
5869
//go:noinline
5970
func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
6071
i.Called(yesorno)
@@ -1522,6 +1533,51 @@ func Test_Mock_AssertExpectationsFunctionalOptionsType_Empty(t *testing.T) {
15221533

15231534
}
15241535

1536+
func Test_Mock_AssertExpectationsFunctionalOptionsType_Indirectly(t *testing.T) {
1537+
1538+
var mockedService = new(TestExampleImplementation)
1539+
1540+
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpNum(1), OpStr("foo"))).Return(nil).Once()
1541+
1542+
tt := new(testing.T)
1543+
assert.False(t, mockedService.AssertExpectations(tt))
1544+
1545+
// make the call now
1546+
TheExampleMethodFunctionalOptionsIndirect(mockedService)
1547+
1548+
// now assert expectations
1549+
assert.True(t, mockedService.AssertExpectations(tt))
1550+
1551+
}
1552+
1553+
func Test_Mock_AssertExpectationsFunctionalOptionsType_Diff_Func(t *testing.T) {
1554+
1555+
var mockedService = new(TestExampleImplementation)
1556+
1557+
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpStr("this"))).Return(nil).Once()
1558+
1559+
tt := new(testing.T)
1560+
assert.False(t, mockedService.AssertExpectations(tt))
1561+
1562+
assert.Panics(t, func() {
1563+
mockedService.TheExampleMethodFunctionalOptions("test", OpBytes([]byte("this")))
1564+
})
1565+
}
1566+
1567+
func Test_Mock_AssertExpectationsFunctionalOptionsType_Diff_Arg(t *testing.T) {
1568+
1569+
var mockedService = new(TestExampleImplementation)
1570+
1571+
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpStr("this"))).Return(nil).Once()
1572+
1573+
tt := new(testing.T)
1574+
assert.False(t, mockedService.AssertExpectations(tt))
1575+
1576+
assert.Panics(t, func() {
1577+
mockedService.TheExampleMethodFunctionalOptions("test", OpStr("that"))
1578+
})
1579+
}
1580+
15251581
func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
15261582

15271583
var mockedService = new(TestExampleImplementation)

0 commit comments

Comments
 (0)