blob: e1fe222afc84aaeeea93ca9376015d9c9a50e0a2 [file] [log] [blame]
vinokumaf7605fc2023-06-02 18:08:01 +05301// Copyright 2010 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package gomock
16
17import (
18 "fmt"
19 "reflect"
20 "strconv"
21 "strings"
22)
23
24// Call represents an expected call to a mock.
25type Call struct {
26 t TestHelper // for triggering test failures on invalid call setup
27
bseenivadd66c362026-02-12 19:13:26 +053028 receiver any // the receiver of the method call
vinokumaf7605fc2023-06-02 18:08:01 +053029 method string // the name of the method
30 methodType reflect.Type // the type of the method
31 args []Matcher // the args
32 origin string // file and line number of call setup
33
34 preReqs []*Call // prerequisite calls
35
36 // Expectations
37 minCalls, maxCalls int
38
39 numCalls int // actual number made
40
41 // actions are called when this Call is called. Each action gets the args and
42 // can set the return values by returning a non-nil slice. Actions run in the
43 // order they are created.
bseenivadd66c362026-02-12 19:13:26 +053044 actions []func([]any) []any
vinokumaf7605fc2023-06-02 18:08:01 +053045}
46
47// newCall creates a *Call. It requires the method type in order to support
48// unexported methods.
bseenivadd66c362026-02-12 19:13:26 +053049func newCall(t TestHelper, receiver any, method string, methodType reflect.Type, args ...any) *Call {
vinokumaf7605fc2023-06-02 18:08:01 +053050 t.Helper()
51
52 // TODO: check arity, types.
Abhay Kumarfe505f22025-11-10 14:16:31 +000053 mArgs := make([]Matcher, len(args))
vinokumaf7605fc2023-06-02 18:08:01 +053054 for i, arg := range args {
55 if m, ok := arg.(Matcher); ok {
Abhay Kumarfe505f22025-11-10 14:16:31 +000056 mArgs[i] = m
vinokumaf7605fc2023-06-02 18:08:01 +053057 } else if arg == nil {
58 // Handle nil specially so that passing a nil interface value
59 // will match the typed nils of concrete args.
Abhay Kumarfe505f22025-11-10 14:16:31 +000060 mArgs[i] = Nil()
vinokumaf7605fc2023-06-02 18:08:01 +053061 } else {
Abhay Kumarfe505f22025-11-10 14:16:31 +000062 mArgs[i] = Eq(arg)
vinokumaf7605fc2023-06-02 18:08:01 +053063 }
64 }
65
Abhay Kumarfe505f22025-11-10 14:16:31 +000066 // callerInfo's skip should be updated if the number of calls between the user's test
67 // and this line changes, i.e. this code is wrapped in another anonymous function.
68 // 0 is us, 1 is RecordCallWithMethodType(), 2 is the generated recorder, and 3 is the user's test.
vinokumaf7605fc2023-06-02 18:08:01 +053069 origin := callerInfo(3)
bseenivadd66c362026-02-12 19:13:26 +053070 actions := []func([]any) []any{func([]any) []any {
vinokumaf7605fc2023-06-02 18:08:01 +053071 // Synthesize the zero value for each of the return args' types.
bseenivadd66c362026-02-12 19:13:26 +053072 rets := make([]any, methodType.NumOut())
vinokumaf7605fc2023-06-02 18:08:01 +053073 for i := 0; i < methodType.NumOut(); i++ {
74 rets[i] = reflect.Zero(methodType.Out(i)).Interface()
75 }
76 return rets
77 }}
bseenivadd66c362026-02-12 19:13:26 +053078 return &Call{
79 t: t, receiver: receiver, method: method, methodType: methodType,
80 args: mArgs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions,
81 }
vinokumaf7605fc2023-06-02 18:08:01 +053082}
83
84// AnyTimes allows the expectation to be called 0 or more times
85func (c *Call) AnyTimes() *Call {
86 c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity
87 return c
88}
89
90// MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called or if MaxTimes
91// was previously called with 1, MinTimes also sets the maximum number of calls to infinity.
92func (c *Call) MinTimes(n int) *Call {
93 c.minCalls = n
94 if c.maxCalls == 1 {
95 c.maxCalls = 1e8
96 }
97 return c
98}
99
100// MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called or if MinTimes was
101// previously called with 1, MaxTimes also sets the minimum number of calls to 0.
102func (c *Call) MaxTimes(n int) *Call {
103 c.maxCalls = n
104 if c.minCalls == 1 {
105 c.minCalls = 0
106 }
107 return c
108}
109
110// DoAndReturn declares the action to run when the call is matched.
111// The return values from this function are returned by the mocked function.
bseenivadd66c362026-02-12 19:13:26 +0530112// It takes an any argument to support n-arity functions.
113// The anonymous function must match the function signature mocked method.
114func (c *Call) DoAndReturn(f any) *Call {
vinokumaf7605fc2023-06-02 18:08:01 +0530115 // TODO: Check arity and types here, rather than dying badly elsewhere.
116 v := reflect.ValueOf(f)
117
bseenivadd66c362026-02-12 19:13:26 +0530118 c.addAction(func(args []any) []any {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000119 c.t.Helper()
vinokumaf7605fc2023-06-02 18:08:01 +0530120 ft := v.Type()
Abhay Kumarfe505f22025-11-10 14:16:31 +0000121 if c.methodType.NumIn() != ft.NumIn() {
bseenivadd66c362026-02-12 19:13:26 +0530122 if ft.IsVariadic() {
123 c.t.Fatalf("wrong number of arguments in DoAndReturn func for %T.%v The function signature must match the mocked method, a variadic function cannot be used.",
124 c.receiver, c.method)
125 } else {
126 c.t.Fatalf("wrong number of arguments in DoAndReturn func for %T.%v: got %d, want %d [%s]",
127 c.receiver, c.method, ft.NumIn(), c.methodType.NumIn(), c.origin)
128 }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000129 return nil
130 }
bseenivadd66c362026-02-12 19:13:26 +0530131 vArgs := make([]reflect.Value, len(args))
vinokumaf7605fc2023-06-02 18:08:01 +0530132 for i := 0; i < len(args); i++ {
133 if args[i] != nil {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000134 vArgs[i] = reflect.ValueOf(args[i])
vinokumaf7605fc2023-06-02 18:08:01 +0530135 } else {
136 // Use the zero value for the arg.
Abhay Kumarfe505f22025-11-10 14:16:31 +0000137 vArgs[i] = reflect.Zero(ft.In(i))
vinokumaf7605fc2023-06-02 18:08:01 +0530138 }
139 }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000140 vRets := v.Call(vArgs)
bseenivadd66c362026-02-12 19:13:26 +0530141 rets := make([]any, len(vRets))
Abhay Kumarfe505f22025-11-10 14:16:31 +0000142 for i, ret := range vRets {
vinokumaf7605fc2023-06-02 18:08:01 +0530143 rets[i] = ret.Interface()
144 }
145 return rets
146 })
147 return c
148}
149
150// Do declares the action to run when the call is matched. The function's
151// return values are ignored to retain backward compatibility. To use the
152// return values call DoAndReturn.
bseenivadd66c362026-02-12 19:13:26 +0530153// It takes an any argument to support n-arity functions.
154// The anonymous function must match the function signature mocked method.
155func (c *Call) Do(f any) *Call {
vinokumaf7605fc2023-06-02 18:08:01 +0530156 // TODO: Check arity and types here, rather than dying badly elsewhere.
157 v := reflect.ValueOf(f)
158
bseenivadd66c362026-02-12 19:13:26 +0530159 c.addAction(func(args []any) []any {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000160 c.t.Helper()
bseenivadd66c362026-02-12 19:13:26 +0530161 ft := v.Type()
162 if c.methodType.NumIn() != ft.NumIn() {
163 if ft.IsVariadic() {
164 c.t.Fatalf("wrong number of arguments in Do func for %T.%v The function signature must match the mocked method, a variadic function cannot be used.",
165 c.receiver, c.method)
166 } else {
167 c.t.Fatalf("wrong number of arguments in Do func for %T.%v: got %d, want %d [%s]",
168 c.receiver, c.method, ft.NumIn(), c.methodType.NumIn(), c.origin)
169 }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000170 return nil
171 }
172 vArgs := make([]reflect.Value, len(args))
vinokumaf7605fc2023-06-02 18:08:01 +0530173 for i := 0; i < len(args); i++ {
174 if args[i] != nil {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000175 vArgs[i] = reflect.ValueOf(args[i])
vinokumaf7605fc2023-06-02 18:08:01 +0530176 } else {
177 // Use the zero value for the arg.
Abhay Kumarfe505f22025-11-10 14:16:31 +0000178 vArgs[i] = reflect.Zero(ft.In(i))
vinokumaf7605fc2023-06-02 18:08:01 +0530179 }
180 }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000181 v.Call(vArgs)
vinokumaf7605fc2023-06-02 18:08:01 +0530182 return nil
183 })
184 return c
185}
186
187// Return declares the values to be returned by the mocked function call.
bseenivadd66c362026-02-12 19:13:26 +0530188func (c *Call) Return(rets ...any) *Call {
vinokumaf7605fc2023-06-02 18:08:01 +0530189 c.t.Helper()
190
191 mt := c.methodType
192 if len(rets) != mt.NumOut() {
193 c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]",
194 c.receiver, c.method, len(rets), mt.NumOut(), c.origin)
195 }
196 for i, ret := range rets {
197 if got, want := reflect.TypeOf(ret), mt.Out(i); got == want {
198 // Identical types; nothing to do.
199 } else if got == nil {
200 // Nil needs special handling.
201 switch want.Kind() {
202 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
203 // ok
204 default:
205 c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]",
206 i, c.receiver, c.method, want, c.origin)
207 }
208 } else if got.AssignableTo(want) {
209 // Assignable type relation. Make the assignment now so that the generated code
210 // can return the values with a type assertion.
211 v := reflect.New(want).Elem()
212 v.Set(reflect.ValueOf(ret))
213 rets[i] = v.Interface()
214 } else {
215 c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]",
216 i, c.receiver, c.method, got, want, c.origin)
217 }
218 }
219
bseenivadd66c362026-02-12 19:13:26 +0530220 c.addAction(func([]any) []any {
vinokumaf7605fc2023-06-02 18:08:01 +0530221 return rets
222 })
223
224 return c
225}
226
227// Times declares the exact number of times a function call is expected to be executed.
228func (c *Call) Times(n int) *Call {
229 c.minCalls, c.maxCalls = n, n
230 return c
231}
232
233// SetArg declares an action that will set the nth argument's value,
bseenivadd66c362026-02-12 19:13:26 +0530234// indirected through a pointer. Or, in the case of a slice and map, SetArg
235// will copy value's elements/key-value pairs into the nth argument.
236func (c *Call) SetArg(n int, value any) *Call {
vinokumaf7605fc2023-06-02 18:08:01 +0530237 c.t.Helper()
238
239 mt := c.methodType
240 // TODO: This will break on variadic methods.
241 // We will need to check those at invocation time.
242 if n < 0 || n >= mt.NumIn() {
243 c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]",
244 n, mt.NumIn(), c.origin)
245 }
246 // Permit setting argument through an interface.
247 // In the interface case, we don't (nay, can't) check the type here.
248 at := mt.In(n)
249 switch at.Kind() {
250 case reflect.Ptr:
251 dt := at.Elem()
252 if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) {
253 c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]",
254 n, vt, dt, c.origin)
255 }
bseenivadd66c362026-02-12 19:13:26 +0530256 case reflect.Interface, reflect.Slice, reflect.Map:
vinokumaf7605fc2023-06-02 18:08:01 +0530257 // nothing to do
258 default:
bseenivadd66c362026-02-12 19:13:26 +0530259 c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice non-map type %v [%s]",
vinokumaf7605fc2023-06-02 18:08:01 +0530260 n, at, c.origin)
261 }
262
bseenivadd66c362026-02-12 19:13:26 +0530263 c.addAction(func(args []any) []any {
vinokumaf7605fc2023-06-02 18:08:01 +0530264 v := reflect.ValueOf(value)
265 switch reflect.TypeOf(args[n]).Kind() {
266 case reflect.Slice:
267 setSlice(args[n], v)
bseenivadd66c362026-02-12 19:13:26 +0530268 case reflect.Map:
269 setMap(args[n], v)
vinokumaf7605fc2023-06-02 18:08:01 +0530270 default:
271 reflect.ValueOf(args[n]).Elem().Set(v)
272 }
273 return nil
274 })
275 return c
276}
277
278// isPreReq returns true if other is a direct or indirect prerequisite to c.
279func (c *Call) isPreReq(other *Call) bool {
280 for _, preReq := range c.preReqs {
281 if other == preReq || preReq.isPreReq(other) {
282 return true
283 }
284 }
285 return false
286}
287
288// After declares that the call may only match after preReq has been exhausted.
289func (c *Call) After(preReq *Call) *Call {
290 c.t.Helper()
291
292 if c == preReq {
293 c.t.Fatalf("A call isn't allowed to be its own prerequisite")
294 }
295 if preReq.isPreReq(c) {
296 c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq)
297 }
298
299 c.preReqs = append(c.preReqs, preReq)
300 return c
301}
302
303// Returns true if the minimum number of calls have been made.
304func (c *Call) satisfied() bool {
305 return c.numCalls >= c.minCalls
306}
307
308// Returns true if the maximum number of calls have been made.
309func (c *Call) exhausted() bool {
310 return c.numCalls >= c.maxCalls
311}
312
313func (c *Call) String() string {
314 args := make([]string, len(c.args))
315 for i, arg := range c.args {
316 args[i] = arg.String()
317 }
318 arguments := strings.Join(args, ", ")
319 return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin)
320}
321
322// Tests if the given call matches the expected call.
323// If yes, returns nil. If no, returns error with message explaining why it does not match.
bseenivadd66c362026-02-12 19:13:26 +0530324func (c *Call) matches(args []any) error {
vinokumaf7605fc2023-06-02 18:08:01 +0530325 if !c.methodType.IsVariadic() {
326 if len(args) != len(c.args) {
327 return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: %d",
328 c.origin, len(args), len(c.args))
329 }
330
331 for i, m := range c.args {
332 if !m.Matches(args[i]) {
vinokumaf7605fc2023-06-02 18:08:01 +0530333 return fmt.Errorf(
334 "expected call at %s doesn't match the argument at index %d.\nGot: %v\nWant: %v",
Abhay Kumarfe505f22025-11-10 14:16:31 +0000335 c.origin, i, formatGottenArg(m, args[i]), m,
vinokumaf7605fc2023-06-02 18:08:01 +0530336 )
337 }
338 }
339 } else {
340 if len(c.args) < c.methodType.NumIn()-1 {
341 return fmt.Errorf("expected call at %s has the wrong number of matchers. Got: %d, want: %d",
342 c.origin, len(c.args), c.methodType.NumIn()-1)
343 }
344 if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) {
345 return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: %d",
346 c.origin, len(args), len(c.args))
347 }
348 if len(args) < len(c.args)-1 {
349 return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d",
350 c.origin, len(args), len(c.args)-1)
351 }
352
353 for i, m := range c.args {
354 if i < c.methodType.NumIn()-1 {
355 // Non-variadic args
356 if !m.Matches(args[i]) {
357 return fmt.Errorf("expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
Abhay Kumarfe505f22025-11-10 14:16:31 +0000358 c.origin, strconv.Itoa(i), formatGottenArg(m, args[i]), m)
vinokumaf7605fc2023-06-02 18:08:01 +0530359 }
360 continue
361 }
362 // The last arg has a possibility of a variadic argument, so let it branch
363
364 // sample: Foo(a int, b int, c ...int)
365 if i < len(c.args) && i < len(args) {
366 if m.Matches(args[i]) {
367 // Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any())
368 // Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher)
369 // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC)
370 // Got Foo(a, b) want Foo(matcherA, matcherB)
371 // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD)
372 continue
373 }
374 }
375
376 // The number of actual args don't match the number of matchers,
377 // or the last matcher is a slice and the last arg is not.
378 // If this function still matches it is because the last matcher
379 // matches all the remaining arguments or the lack of any.
380 // Convert the remaining arguments, if any, into a slice of the
381 // expected type.
Abhay Kumarfe505f22025-11-10 14:16:31 +0000382 vArgsType := c.methodType.In(c.methodType.NumIn() - 1)
383 vArgs := reflect.MakeSlice(vArgsType, 0, len(args)-i)
vinokumaf7605fc2023-06-02 18:08:01 +0530384 for _, arg := range args[i:] {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000385 vArgs = reflect.Append(vArgs, reflect.ValueOf(arg))
vinokumaf7605fc2023-06-02 18:08:01 +0530386 }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000387 if m.Matches(vArgs.Interface()) {
vinokumaf7605fc2023-06-02 18:08:01 +0530388 // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any())
389 // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher)
390 // Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any())
391 // Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher)
392 break
393 }
394 // Wrong number of matchers or not match. Fail.
395 // Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD)
396 // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD)
397 // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE)
398 // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD)
399 // Got Foo(a, b, c) want Foo(matcherA, matcherB)
vinokumaf7605fc2023-06-02 18:08:01 +0530400
Abhay Kumarfe505f22025-11-10 14:16:31 +0000401 return fmt.Errorf("expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
402 c.origin, strconv.Itoa(i), formatGottenArg(m, args[i:]), c.args[i])
vinokumaf7605fc2023-06-02 18:08:01 +0530403 }
404 }
405
406 // Check that all prerequisite calls have been satisfied.
407 for _, preReqCall := range c.preReqs {
408 if !preReqCall.satisfied() {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000409 return fmt.Errorf("expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v",
vinokumaf7605fc2023-06-02 18:08:01 +0530410 c.origin, preReqCall, c)
411 }
412 }
413
414 // Check that the call is not exhausted.
415 if c.exhausted() {
416 return fmt.Errorf("expected call at %s has already been called the max number of times", c.origin)
417 }
418
419 return nil
420}
421
422// dropPrereqs tells the expected Call to not re-check prerequisite calls any
423// longer, and to return its current set.
424func (c *Call) dropPrereqs() (preReqs []*Call) {
425 preReqs = c.preReqs
426 c.preReqs = nil
427 return
428}
429
bseenivadd66c362026-02-12 19:13:26 +0530430func (c *Call) call() []func([]any) []any {
vinokumaf7605fc2023-06-02 18:08:01 +0530431 c.numCalls++
432 return c.actions
433}
434
435// InOrder declares that the given calls should occur in order.
bseenivadd66c362026-02-12 19:13:26 +0530436// It panics if the type of any of the arguments isn't *Call or a generated
437// mock with an embedded *Call.
438func InOrder(args ...any) {
439 calls := make([]*Call, 0, len(args))
440 for i := 0; i < len(args); i++ {
441 if call := getCall(args[i]); call != nil {
442 calls = append(calls, call)
443 continue
444 }
445 panic(fmt.Sprintf(
446 "invalid argument at position %d of type %T, InOrder expects *gomock.Call or generated mock types with an embedded *gomock.Call",
447 i,
448 args[i],
449 ))
450 }
vinokumaf7605fc2023-06-02 18:08:01 +0530451 for i := 1; i < len(calls); i++ {
452 calls[i].After(calls[i-1])
453 }
454}
455
bseenivadd66c362026-02-12 19:13:26 +0530456// getCall checks if the parameter is a *Call or a generated struct
457// that wraps a *Call and returns the *Call pointer - if neither, it returns nil.
458func getCall(arg any) *Call {
459 if call, ok := arg.(*Call); ok {
460 return call
461 }
462 t := reflect.ValueOf(arg)
463 if t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface {
464 return nil
465 }
466 t = t.Elem()
467 for i := 0; i < t.NumField(); i++ {
468 f := t.Field(i)
469 if !f.CanInterface() {
470 continue
471 }
472 if call, ok := f.Interface().(*Call); ok {
473 return call
474 }
475 }
476 return nil
477}
478
479func setSlice(arg any, v reflect.Value) {
vinokumaf7605fc2023-06-02 18:08:01 +0530480 va := reflect.ValueOf(arg)
481 for i := 0; i < v.Len(); i++ {
482 va.Index(i).Set(v.Index(i))
483 }
484}
485
bseenivadd66c362026-02-12 19:13:26 +0530486func setMap(arg any, v reflect.Value) {
487 va := reflect.ValueOf(arg)
488 for _, e := range va.MapKeys() {
489 va.SetMapIndex(e, reflect.Value{})
490 }
491 for _, e := range v.MapKeys() {
492 va.SetMapIndex(e, v.MapIndex(e))
493 }
494}
495
496func (c *Call) addAction(action func([]any) []any) {
vinokumaf7605fc2023-06-02 18:08:01 +0530497 c.actions = append(c.actions, action)
498}
Abhay Kumarfe505f22025-11-10 14:16:31 +0000499
bseenivadd66c362026-02-12 19:13:26 +0530500func formatGottenArg(m Matcher, arg any) string {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000501 got := fmt.Sprintf("%v (%T)", arg, arg)
502 if gs, ok := m.(GotFormatter); ok {
503 got = gs.Got(arg)
504 }
505 return got
506}