@@ -220,6 +220,90 @@ func TestBool(t *testing.T) {
220220}` ,
221221 expected : "assert.TrueT(t, true)\n \t assert.FalseT(t, false)" ,
222222 },
223+ {
224+ name : "elementsmatch slice upgrade" ,
225+ input : `package p
226+ import (
227+ "testing"
228+ "github.com/go-openapi/testify/v2/assert"
229+ )
230+ func TestElementsMatch(t *testing.T) {
231+ assert.ElementsMatch(t, []int{1, 2, 3}, []int{3, 2, 1})
232+ }` ,
233+ expected : `assert.ElementsMatchT(t, []int{1, 2, 3}, []int{3, 2, 1})` ,
234+ },
235+ {
236+ name : "notelementsmatch slice upgrade" ,
237+ input : `package p
238+ import (
239+ "testing"
240+ "github.com/go-openapi/testify/v2/assert"
241+ )
242+ func TestNotElementsMatch(t *testing.T) {
243+ assert.NotElementsMatch(t, []int{1, 2, 3}, []int{1, 2, 4})
244+ }` ,
245+ expected : `assert.NotElementsMatchT(t, []int{1, 2, 3}, []int{1, 2, 4})` ,
246+ },
247+ {
248+ name : "notelementsmatchf slice format variant" ,
249+ input : `package p
250+ import (
251+ "testing"
252+ "github.com/go-openapi/testify/v2/assert"
253+ )
254+ func TestNotElementsMatchf(t *testing.T) {
255+ assert.NotElementsMatchf(t, []int{1, 2, 3}, []int{1, 2, 4}, "should differ")
256+ }` ,
257+ expected : `assert.NotElementsMatchTf(t, []int{1, 2, 3}, []int{1, 2, 4}, "should differ")` ,
258+ },
259+ {
260+ name : "subset slice upgrade" ,
261+ input : `package p
262+ import (
263+ "testing"
264+ "github.com/go-openapi/testify/v2/assert"
265+ )
266+ func TestSubset(t *testing.T) {
267+ assert.Subset(t, []int{1, 2, 3}, []int{1, 2})
268+ }` ,
269+ expected : `assert.SliceSubsetT(t, []int{1, 2, 3}, []int{1, 2})` ,
270+ },
271+ {
272+ name : "notsubset slice upgrade" ,
273+ input : `package p
274+ import (
275+ "testing"
276+ "github.com/go-openapi/testify/v2/assert"
277+ )
278+ func TestNotSubset(t *testing.T) {
279+ assert.NotSubset(t, []int{1, 2, 3}, []int{4, 5})
280+ }` ,
281+ expected : `assert.SliceNotSubsetT(t, []int{1, 2, 3}, []int{4, 5})` ,
282+ },
283+ {
284+ name : "notsubsetf slice format variant" ,
285+ input : `package p
286+ import (
287+ "testing"
288+ "github.com/go-openapi/testify/v2/assert"
289+ )
290+ func TestNotSubsetf(t *testing.T) {
291+ assert.NotSubsetf(t, []int{1, 2, 3}, []int{4, 5}, "should not contain")
292+ }` ,
293+ expected : `assert.SliceNotSubsetTf(t, []int{1, 2, 3}, []int{4, 5}, "should not contain")` ,
294+ },
295+ {
296+ name : "skip notsubset map (not a slice)" ,
297+ input : `package p
298+ import (
299+ "testing"
300+ "github.com/go-openapi/testify/v2/assert"
301+ )
302+ func TestNotSubsetMap(t *testing.T) {
303+ assert.NotSubset(t, map[string]int{"a": 1}, map[string]int{"b": 2})
304+ }` ,
305+ expected : `assert.NotSubset(t, map[string]int{"a": 1}, map[string]int{"b": 2})` ,
306+ },
223307 })
224308}
225309
@@ -402,6 +486,88 @@ func TestSkipDifferent(t *testing.T) {
402486 }
403487}
404488
489+ func TestGenericUpgradeManualReview (t * testing.T ) {
490+ t .Parallel ()
491+
492+ // IsType and IsNotType both change argument count when upgraded to the
493+ // generic form (IsOfTypeT / IsNotOfTypeT take the expected type as a
494+ // type parameter). The tool must not rewrite the call; it must emit a
495+ // manual-review warning.
496+ cases := []struct {
497+ name string
498+ source string
499+ wantTarget string
500+ }{
501+ {
502+ name : "IsType" ,
503+ source : `package p
504+ import (
505+ "testing"
506+ "github.com/go-openapi/testify/v2/assert"
507+ )
508+ type MyType struct{}
509+ func TestIsType(t *testing.T) {
510+ assert.IsType(t, &MyType{}, &MyType{})
511+ }` ,
512+ wantTarget : "IsOfTypeT" ,
513+ },
514+ {
515+ name : "IsNotType" ,
516+ source : `package p
517+ import (
518+ "testing"
519+ "github.com/go-openapi/testify/v2/assert"
520+ )
521+ type MyType struct{}
522+ func TestIsNotType(t *testing.T) {
523+ assert.IsNotType(t, &MyType{}, 42)
524+ }` ,
525+ wantTarget : "IsNotOfTypeT" ,
526+ },
527+ }
528+
529+ for _ , tc := range cases {
530+ t .Run (tc .name , func (t * testing.T ) {
531+ t .Parallel ()
532+
533+ fset := token .NewFileSet ()
534+ f , err := parser .ParseFile (fset , "test.go" , tc .source , parser .ParseComments )
535+ if err != nil {
536+ t .Fatalf ("parse: %v" , err )
537+ }
538+
539+ info := typeCheckWithMockAssert (t , fset , f )
540+ if info == nil {
541+ t .Fatal ("type-check failed" )
542+ }
543+
544+ pkg := & packages.Package {
545+ TypesInfo : info ,
546+ Syntax : []* ast.File {f },
547+ GoFiles : []string {"test.go" },
548+ }
549+
550+ rpt := & report {}
551+ changes := upgradeFile (f , pkg , fset , rpt , "test.go" , false )
552+
553+ if changes != 0 {
554+ t .Errorf ("expected 0 changes (manual review), got %d" , changes )
555+ }
556+
557+ found := false
558+ for _ , d := range rpt .diagnostics {
559+ if d .kind == "warning" && strings .Contains (d .message , tc .wantTarget ) && strings .Contains (d .message , "manual review" ) {
560+ found = true
561+ break
562+ }
563+ }
564+ if ! found {
565+ t .Errorf ("expected manual-review warning mentioning %s, got diagnostics: %v" , tc .wantTarget , rpt .diagnostics )
566+ }
567+ })
568+ }
569+ }
570+
405571// typeCheckWithMockAssert creates a mock "assert" package that has a few functions
406572// taking (testing.T, any...) and type-checks the file against it.
407573func typeCheckWithMockAssert (t * testing.T , fset * token.FileSet , f * ast.File ) * types.Info {
@@ -472,6 +638,20 @@ func typeCheckWithMockAssert(t *testing.T, fset *token.FileSet, f *ast.File) *ty
472638 makeAssertFunc ("TrueT" , anyParam ("value" ))
473639 makeAssertFunc ("False" , anyParam ("value" ))
474640 makeAssertFunc ("FalseT" , anyParam ("value" ))
641+ makeAssertFunc ("ElementsMatch" , anyParam ("listA" ), anyParam ("listB" ))
642+ makeAssertFunc ("ElementsMatchT" , anyParam ("listA" ), anyParam ("listB" ))
643+ makeAssertFunc ("NotElementsMatch" , anyParam ("listA" ), anyParam ("listB" ))
644+ makeAssertFunc ("NotElementsMatchT" , anyParam ("listA" ), anyParam ("listB" ))
645+ makeAssertFunc ("NotElementsMatchf" , anyParam ("listA" ), anyParam ("listB" ))
646+ makeAssertFunc ("NotElementsMatchTf" , anyParam ("listA" ), anyParam ("listB" ))
647+ makeAssertFunc ("Subset" , anyParam ("list" ), anyParam ("subset" ))
648+ makeAssertFunc ("SliceSubsetT" , anyParam ("list" ), anyParam ("subset" ))
649+ makeAssertFunc ("NotSubset" , anyParam ("list" ), anyParam ("subset" ))
650+ makeAssertFunc ("NotSubsetf" , anyParam ("list" ), anyParam ("subset" ))
651+ makeAssertFunc ("SliceNotSubsetT" , anyParam ("list" ), anyParam ("subset" ))
652+ makeAssertFunc ("SliceNotSubsetTf" , anyParam ("list" ), anyParam ("subset" ))
653+ makeAssertFunc ("IsType" , anyParam ("expectedType" ), anyParam ("object" ))
654+ makeAssertFunc ("IsNotType" , anyParam ("theType" ), anyParam ("object" ))
475655
476656 assertPkg .MarkComplete ()
477657
0 commit comments