@@ -63,19 +63,27 @@ func SmokeTestAllMethods(
6363 continue
6464 }
6565
66- result .Total ++
6766 methodName := method .Name
6867 methodValue := v .Method (i )
6968 methodType := methodValue .Type ()
7069
70+ if hasUnmockableArgs (methodType ) {
71+ t .Run (methodName , func (t * testing.T ) {
72+ t .Skipf ("method %s skipped (has unmockable interface args)" , methodName )
73+ })
74+ continue
75+ }
76+
77+ result .Total ++
78+
7179 t .Run (methodName , func (t * testing.T ) {
7280 args := buildZeroArgs (methodType )
7381
7482 outcome := callWithRecover (methodValue , args )
7583 switch outcome {
7684 case outcomePanicked :
7785 result .Panicked ++
78- t .Logf ("method %s panicked (nil interface arg) " , methodName )
86+ t .Errorf ("method %s panicked unexpectedly " , methodName )
7987 case outcomeFailed :
8088 result .Failed ++
8189 t .Logf ("method %s returned an error" , methodName )
@@ -141,6 +149,55 @@ var (
141149 iBinderType = reflect .TypeOf ((* binder .IBinder )(nil )).Elem ()
142150)
143151
152+ // hasUnmockableArgs returns true if the method has arguments containing
153+ // interface types that buildZeroArgs cannot provide a non-nil value for.
154+ // This includes direct interface arguments and struct fields that are
155+ // interfaces (e.g., union types with binder interface fields).
156+ func hasUnmockableArgs (methodType reflect.Type ) bool {
157+ for i := 0 ; i < methodType .NumIn (); i ++ {
158+ if typeContainsUnmockableInterface (methodType .In (i )) {
159+ return true
160+ }
161+ }
162+ return false
163+ }
164+
165+ // typeContainsUnmockableInterface checks whether a type is or contains
166+ // an interface that buildZeroArgs cannot mock. The visited map prevents
167+ // infinite recursion on self-referencing struct types.
168+ func typeContainsUnmockableInterface (t reflect.Type ) bool {
169+ return typeContainsUnmockableInterfaceVisited (t , map [reflect.Type ]bool {})
170+ }
171+
172+ func typeContainsUnmockableInterfaceVisited (t reflect.Type , visited map [reflect.Type ]bool ) bool {
173+ if visited [t ] {
174+ return false
175+ }
176+ visited [t ] = true
177+
178+ switch t .Kind () {
179+ case reflect .Interface :
180+ if t .Implements (contextType ) {
181+ return false
182+ }
183+ if t .Implements (iBinderType ) || t == iBinderType {
184+ return false
185+ }
186+ return true
187+ case reflect .Struct :
188+ for i := 0 ; i < t .NumField (); i ++ {
189+ if typeContainsUnmockableInterfaceVisited (t .Field (i ).Type , visited ) {
190+ return true
191+ }
192+ }
193+ case reflect .Ptr :
194+ return typeContainsUnmockableInterfaceVisited (t .Elem (), visited )
195+ case reflect .Slice , reflect .Array :
196+ return typeContainsUnmockableInterfaceVisited (t .Elem (), visited )
197+ }
198+ return false
199+ }
200+
144201// buildZeroArgs builds zero-value arguments for a method.
145202// context.Context parameters get context.Background().
146203// binder.IBinder parameters get a MockBinder.
0 commit comments