@@ -3,6 +3,7 @@ package mock
3
3
import (
4
4
"errors"
5
5
"fmt"
6
+ "path"
6
7
"reflect"
7
8
"regexp"
8
9
"runtime"
@@ -13,6 +14,7 @@ import (
13
14
"github.com/davecgh/go-spew/spew"
14
15
"github.com/pmezard/go-difflib/difflib"
15
16
"github.com/stretchr/objx"
17
+
16
18
"github.com/stretchr/testify/assert"
17
19
)
18
20
@@ -424,6 +426,10 @@ func callString(method string, arguments Arguments, includeArgumentValues bool)
424
426
if includeArgumentValues {
425
427
var argVals []string
426
428
for argIndex , arg := range arguments {
429
+ if _ , ok := arg .(* FunctionalOptionsArgument ); ok {
430
+ argVals = append (argVals , fmt .Sprintf ("%d: %s" , argIndex , arg ))
431
+ continue
432
+ }
427
433
argVals = append (argVals , fmt .Sprintf ("%d: %#v" , argIndex , arg ))
428
434
}
429
435
argValsString = fmt .Sprintf ("\n \t \t %s" , strings .Join (argVals , "\n \t \t " ))
@@ -780,6 +786,34 @@ func IsType(t interface{}) *IsTypeArgument {
780
786
return & IsTypeArgument {t : t }
781
787
}
782
788
789
+ // FunctionalOptionsArgument is a struct that contains the type and value of an functional option argument
790
+ // for use when type checking.
791
+ type FunctionalOptionsArgument struct {
792
+ value interface {}
793
+ }
794
+
795
+ // String returns the string representation of FunctionalOptionsArgument
796
+ func (f * FunctionalOptionsArgument ) String () string {
797
+ var name string
798
+ tValue := reflect .ValueOf (f .value )
799
+ if tValue .Len () > 0 {
800
+ name = "[]" + reflect .TypeOf (tValue .Index (0 ).Interface ()).String ()
801
+ }
802
+
803
+ return strings .Replace (fmt .Sprintf ("%#v" , f .value ), "[]interface {}" , name , 1 )
804
+ }
805
+
806
+ // FunctionalOptions returns an FunctionalOptionsArgument object containing the functional option type
807
+ // and the values to check of
808
+ //
809
+ // For example:
810
+ // Assert(t, FunctionalOptions("[]foo.FunctionalOption", foo.Opt1(), foo.Opt2()))
811
+ func FunctionalOptions (value ... interface {}) * FunctionalOptionsArgument {
812
+ return & FunctionalOptionsArgument {
813
+ value : value ,
814
+ }
815
+ }
816
+
783
817
// argumentMatcher performs custom argument matching, returning whether or
784
818
// not the argument is matched by the expectation fixture function.
785
819
type argumentMatcher struct {
@@ -926,6 +960,29 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
926
960
differences ++
927
961
output = fmt .Sprintf ("%s\t %d: FAIL: type %s != type %s - %s\n " , output , i , reflect .TypeOf (t ).Name (), reflect .TypeOf (actual ).Name (), actualFmt )
928
962
}
963
+ } else if reflect .TypeOf (expected ) == reflect .TypeOf ((* FunctionalOptionsArgument )(nil )) {
964
+ t := expected .(* FunctionalOptionsArgument ).value
965
+
966
+ var name string
967
+ tValue := reflect .ValueOf (t )
968
+ if tValue .Len () > 0 {
969
+ name = "[]" + reflect .TypeOf (tValue .Index (0 ).Interface ()).String ()
970
+ }
971
+
972
+ tName := reflect .TypeOf (t ).Name ()
973
+ if name != reflect .TypeOf (actual ).String () && tValue .Len () != 0 {
974
+ differences ++
975
+ output = fmt .Sprintf ("%s\t %d: FAIL: type %s != type %s - %s\n " , output , i , tName , reflect .TypeOf (actual ).Name (), actualFmt )
976
+ } else {
977
+ if ef , af := assertOpts (t , actual ); ef == "" && af == "" {
978
+ // match
979
+ output = fmt .Sprintf ("%s\t %d: PASS: %s == %s\n " , output , i , tName , tName )
980
+ } else {
981
+ // not match
982
+ differences ++
983
+ output = fmt .Sprintf ("%s\t %d: FAIL: %s != %s\n " , output , i , af , ef )
984
+ }
985
+ }
929
986
} else {
930
987
// normal checking
931
988
@@ -1102,3 +1159,65 @@ var spewConfig = spew.ConfigState{
1102
1159
type tHelper interface {
1103
1160
Helper ()
1104
1161
}
1162
+
1163
+ func assertOpts (expected , actual interface {}) (expectedFmt , actualFmt string ) {
1164
+ expectedOpts := reflect .ValueOf (expected )
1165
+ actualOpts := reflect .ValueOf (actual )
1166
+ var expectedNames []string
1167
+ for i := 0 ; i < expectedOpts .Len (); i ++ {
1168
+ expectedNames = append (expectedNames , funcName (expectedOpts .Index (i ).Interface ()))
1169
+ }
1170
+ var actualNames []string
1171
+ for i := 0 ; i < actualOpts .Len (); i ++ {
1172
+ actualNames = append (actualNames , funcName (actualOpts .Index (i ).Interface ()))
1173
+ }
1174
+ if ! assert .ObjectsAreEqual (expectedNames , actualNames ) {
1175
+ expectedFmt = fmt .Sprintf ("%v" , expectedNames )
1176
+ actualFmt = fmt .Sprintf ("%v" , actualNames )
1177
+ return
1178
+ }
1179
+
1180
+ for i := 0 ; i < expectedOpts .Len (); i ++ {
1181
+ expectedOpt := expectedOpts .Index (i ).Interface ()
1182
+ actualOpt := actualOpts .Index (i ).Interface ()
1183
+
1184
+ expectedFunc := expectedNames [i ]
1185
+ actualFunc := actualNames [i ]
1186
+ if expectedFunc != actualFunc {
1187
+ expectedFmt = expectedFunc
1188
+ actualFmt = actualFunc
1189
+ return
1190
+ }
1191
+
1192
+ ot := reflect .TypeOf (expectedOpt )
1193
+ var expectedValues []reflect.Value
1194
+ var actualValues []reflect.Value
1195
+ if ot .NumIn () == 0 {
1196
+ return
1197
+ }
1198
+
1199
+ for i := 0 ; i < ot .NumIn (); i ++ {
1200
+ vt := ot .In (i ).Elem ()
1201
+ expectedValues = append (expectedValues , reflect .New (vt ))
1202
+ actualValues = append (actualValues , reflect .New (vt ))
1203
+ }
1204
+
1205
+ reflect .ValueOf (expectedOpt ).Call (expectedValues )
1206
+ reflect .ValueOf (actualOpt ).Call (actualValues )
1207
+
1208
+ for i := 0 ; i < ot .NumIn (); i ++ {
1209
+ if ! assert .ObjectsAreEqual (expectedValues [i ].Interface (), actualValues [i ].Interface ()) {
1210
+ expectedFmt = fmt .Sprintf ("%s %+v" , expectedNames [i ], expectedValues [i ].Interface ())
1211
+ actualFmt = fmt .Sprintf ("%s %+v" , expectedNames [i ], actualValues [i ].Interface ())
1212
+ return
1213
+ }
1214
+ }
1215
+ }
1216
+
1217
+ return "" , ""
1218
+ }
1219
+
1220
+ func funcName (opt interface {}) string {
1221
+ n := runtime .FuncForPC (reflect .ValueOf (opt ).Pointer ()).Name ()
1222
+ return strings .TrimSuffix (path .Base (n ), path .Ext (n ))
1223
+ }
0 commit comments