diff --git a/README.md b/README.md index 94483a4..7b4a22e 100644 --- a/README.md +++ b/README.md @@ -370,6 +370,8 @@ assert.Error(t, err) ```go ❌ assert.Equal(t, result, expected) +assert.Equal(t, result, len(expected)) +assert.Equal(t, len(resultFields), len(expectedFields)) assert.EqualExportedValues(t, resultObj, User{Name: "Rob"}) assert.EqualValues(t, result, 42) assert.Exactly(t, result, int64(42)) @@ -389,6 +391,8 @@ assert.YAMLEq(t, result, "version: '3'") ✅ assert.Equal(t, expected, result) +assert.Equal(t, len(expected), result) +assert.Equal(t, len(expectedFields), len(resultFields)) assert.EqualExportedValues(t, User{Name: "Rob"}, resultObj) assert.EqualValues(t, 42, result) // And so on... @@ -618,19 +622,41 @@ P.S. Look at [testify's issue](https://github.com/stretchr/testify/issues/772), ```go ❌ -assert.Equal(t, 3, len(arr)) -assert.EqualValues(t, 3, len(arr)) -assert.Exactly(t, 3, len(arr)) -assert.True(t, len(arr) == 3) +assert.Equal(t, 42, len(arr)) +assert.Equal(t, len(arr), 42) +assert.EqualValues(t, 42, len(arr)) +assert.EqualValues(t, len(arr), 42) +assert.Exactly(t, 42, len(arr)) +assert.Exactly(t, len(arr), 42) +assert.True(t, 42 == len(arr)) +assert.True(t, len(arr) == 42) + +assert.Equal(t, value, len(arr)) +assert.EqualValues(t, value, len(arr)) +assert.Exactly(t, value, len(arr)) +assert.True(t, len(arr) == value) + +assert.Equal(t, len(expArr), len(arr)) +assert.EqualValues(t, len(expArr), len(arr)) +assert.Exactly(t, len(expArr), len(arr)) +assert.True(t, len(arr) == len(expArr)) ✅ -assert.Len(t, arr, 3) +assert.Len(t, arr, 42) +assert.Len(t, arr, value) +assert.Len(t, arr, len(expArr)) ``` **Autofix**: true.
**Enabled by default**: true.
**Reason**: More appropriate `testify` API with clearer failure message. +> [!CAUTION] +> The checker ignores assertions in which length checking is not a priority, e.g. +> ```go +> assert.Equal(t, len(arr), value) +> ``` + --- ### negative-positive diff --git a/analyzer/checkers_factory_test.go b/analyzer/checkers_factory_test.go index 28bfb1d..ad25d66 100644 --- a/analyzer/checkers_factory_test.go +++ b/analyzer/checkers_factory_test.go @@ -18,7 +18,6 @@ func Test_newCheckers(t *testing.T) { checkers.NewFloatCompare(), checkers.NewBoolCompare(), checkers.NewEmpty(), - checkers.NewLen(), checkers.NewNegativePositive(), checkers.NewCompares(), checkers.NewContains(), @@ -27,6 +26,7 @@ func Test_newCheckers(t *testing.T) { checkers.NewErrorIsAs(), checkers.NewEncodedCompare(), checkers.NewExpectedActual(), + checkers.NewLen(), checkers.NewRegexp(), checkers.NewSuiteExtraAssertCall(), checkers.NewSuiteDontUsePkg(), @@ -37,7 +37,6 @@ func Test_newCheckers(t *testing.T) { checkers.NewFloatCompare(), checkers.NewBoolCompare(), checkers.NewEmpty(), - checkers.NewLen(), checkers.NewNegativePositive(), checkers.NewCompares(), checkers.NewContains(), @@ -46,6 +45,7 @@ func Test_newCheckers(t *testing.T) { checkers.NewErrorIsAs(), checkers.NewEncodedCompare(), checkers.NewExpectedActual(), + checkers.NewLen(), checkers.NewRegexp(), checkers.NewSuiteExtraAssertCall(), checkers.NewSuiteDontUsePkg(), diff --git a/analyzer/testdata/src/checkers-default/expected-actual/expected_actual_test.go b/analyzer/testdata/src/checkers-default/expected-actual/expected_actual_test.go index 1a7aff0..160891d 100644 --- a/analyzer/testdata/src/checkers-default/expected-actual/expected_actual_test.go +++ b/analyzer/testdata/src/checkers-default/expected-actual/expected_actual_test.go @@ -30,6 +30,7 @@ func TestExpectedActualChecker(t *testing.T) { expectedVal := func() any { return nil } var expectedObj struct{ Val int } var expectedObjPtr = &expectedObj + var expectedFields []string var result any @@ -81,6 +82,8 @@ func TestExpectedActualChecker(t *testing.T) { assert.Equalf(t, result, *(tt.expPtr()), "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.Equal(t, result, ttPtr.expected) // want "expected-actual: need to reverse actual and expected values" assert.Equalf(t, result, ttPtr.expected, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" + assert.Equal(t, result, len(expectedFields)) // want "expected-actual: need to reverse actual and expected values" + assert.Equalf(t, result, len(expectedFields), "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.Equal(t, result, 42) // want "expected-actual: need to reverse actual and expected values" assert.Equalf(t, result, 42, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.Equal(t, result, 3.14) // want "expected-actual: need to reverse actual and expected values" @@ -140,6 +143,8 @@ func TestExpectedActualChecker(t *testing.T) { assert.NotEqualf(t, result, *(tt.expPtr()), "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.NotEqual(t, result, ttPtr.expected) // want "expected-actual: need to reverse actual and expected values" assert.NotEqualf(t, result, ttPtr.expected, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" + assert.NotEqual(t, result, len(expectedFields)) // want "expected-actual: need to reverse actual and expected values" + assert.NotEqualf(t, result, len(expectedFields), "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.NotEqual(t, result, 42) // want "expected-actual: need to reverse actual and expected values" assert.NotEqualf(t, result, 42, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.NotEqual(t, result, 3.14) // want "expected-actual: need to reverse actual and expected values" @@ -202,6 +207,8 @@ func TestExpectedActualChecker(t *testing.T) { assert.Equalf(t, *(tt.expPtr()), result, "msg with args %d %s", 42, "42") assert.Equal(t, ttPtr.expected, result) assert.Equalf(t, ttPtr.expected, result, "msg with args %d %s", 42, "42") + assert.Equal(t, len(expectedFields), result) + assert.Equalf(t, len(expectedFields), result, "msg with args %d %s", 42, "42") assert.Equal(t, 42, result) assert.Equalf(t, 42, result, "msg with args %d %s", 42, "42") assert.Equal(t, 3.14, result) @@ -261,6 +268,8 @@ func TestExpectedActualChecker(t *testing.T) { assert.NotEqualf(t, *(tt.expPtr()), result, "msg with args %d %s", 42, "42") assert.NotEqual(t, ttPtr.expected, result) assert.NotEqualf(t, ttPtr.expected, result, "msg with args %d %s", 42, "42") + assert.NotEqual(t, len(expectedFields), result) + assert.NotEqualf(t, len(expectedFields), result, "msg with args %d %s", 42, "42") assert.NotEqual(t, 42, result) assert.NotEqualf(t, 42, result, "msg with args %d %s", 42, "42") assert.NotEqual(t, 3.14, result) @@ -278,15 +287,18 @@ func TestExpectedActualChecker(t *testing.T) { func TestExpectedActualChecker_Other(t *testing.T) { var ( - result, expected any - resultPtr, expectedPtr *int - resultObj, expectedObj user - resultTime, expectedTime time.Time - value int + result, expected any + resultPtr, expectedPtr *int + resultObj, expectedObj user + resultTime, expectedTime time.Time + value int + actualFields, expectedFields []string ) // Invalid. { + assert.Equal(t, len(actualFields), len(expectedFields)) // want "expected-actual: need to reverse actual and expected values" + assert.Equalf(t, len(actualFields), len(expectedFields), "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.EqualExportedValues(t, resultObj, expectedObj) // want "expected-actual: need to reverse actual and expected values" assert.EqualExportedValuesf(t, resultObj, expectedObj, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.EqualExportedValues(t, resultObj, user{Name: "Rob"}) // want "expected-actual: need to reverse actual and expected values" @@ -1150,10 +1162,11 @@ func TestExpectedActualChecker_CannotDetectVariablesLookedLikeConsts(t *testing. func TestExpectedActualChecker_Ignored(t *testing.T) { var ( - result, expected any - resultPtr, expectedPtr *int - value int - expectedTime time.Time + result, expected any + resultPtr, expectedPtr *int + value int + expectedTime time.Time + expectedFields, interfaces, directions []string ) assert.Equal(t, nil, nil) @@ -1162,6 +1175,10 @@ func TestExpectedActualChecker_Ignored(t *testing.T) { assert.Equalf(t, "value", "value", "msg with args %d %s", 42, "42") assert.Equal(t, expected, expected) assert.Equalf(t, expected, expected, "msg with args %d %s", 42, "42") + assert.Equal(t, len(expectedFields), len(expectedFields)) + assert.Equalf(t, len(expectedFields), len(expectedFields), "msg with args %d %s", 42, "42") + assert.Equal(t, len(interfaces), len(directions)) + assert.Equalf(t, len(interfaces), len(directions), "msg with args %d %s", 42, "42") assert.Equal(t, value, &resultPtr) assert.Equalf(t, value, &resultPtr, "msg with args %d %s", 42, "42") assert.Equal(t, []int{1, 2}, map[int]int{1: 2}) diff --git a/analyzer/testdata/src/checkers-default/expected-actual/expected_actual_test.go.golden b/analyzer/testdata/src/checkers-default/expected-actual/expected_actual_test.go.golden index b0a37bd..b059f49 100644 --- a/analyzer/testdata/src/checkers-default/expected-actual/expected_actual_test.go.golden +++ b/analyzer/testdata/src/checkers-default/expected-actual/expected_actual_test.go.golden @@ -30,6 +30,7 @@ func TestExpectedActualChecker(t *testing.T) { expectedVal := func() any { return nil } var expectedObj struct{ Val int } var expectedObjPtr = &expectedObj + var expectedFields []string var result any @@ -81,6 +82,8 @@ func TestExpectedActualChecker(t *testing.T) { assert.Equalf(t, *(tt.expPtr()), result, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.Equal(t, ttPtr.expected, result) // want "expected-actual: need to reverse actual and expected values" assert.Equalf(t, ttPtr.expected, result, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" + assert.Equal(t, len(expectedFields), result) // want "expected-actual: need to reverse actual and expected values" + assert.Equalf(t, len(expectedFields), result, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.Equal(t, 42, result) // want "expected-actual: need to reverse actual and expected values" assert.Equalf(t, 42, result, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.Equal(t, 3.14, result) // want "expected-actual: need to reverse actual and expected values" @@ -140,6 +143,8 @@ func TestExpectedActualChecker(t *testing.T) { assert.NotEqualf(t, *(tt.expPtr()), result, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.NotEqual(t, ttPtr.expected, result) // want "expected-actual: need to reverse actual and expected values" assert.NotEqualf(t, ttPtr.expected, result, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" + assert.NotEqual(t, len(expectedFields), result) // want "expected-actual: need to reverse actual and expected values" + assert.NotEqualf(t, len(expectedFields), result, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.NotEqual(t, 42, result) // want "expected-actual: need to reverse actual and expected values" assert.NotEqualf(t, 42, result, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.NotEqual(t, 3.14, result) // want "expected-actual: need to reverse actual and expected values" @@ -202,6 +207,8 @@ func TestExpectedActualChecker(t *testing.T) { assert.Equalf(t, *(tt.expPtr()), result, "msg with args %d %s", 42, "42") assert.Equal(t, ttPtr.expected, result) assert.Equalf(t, ttPtr.expected, result, "msg with args %d %s", 42, "42") + assert.Equal(t, len(expectedFields), result) + assert.Equalf(t, len(expectedFields), result, "msg with args %d %s", 42, "42") assert.Equal(t, 42, result) assert.Equalf(t, 42, result, "msg with args %d %s", 42, "42") assert.Equal(t, 3.14, result) @@ -261,6 +268,8 @@ func TestExpectedActualChecker(t *testing.T) { assert.NotEqualf(t, *(tt.expPtr()), result, "msg with args %d %s", 42, "42") assert.NotEqual(t, ttPtr.expected, result) assert.NotEqualf(t, ttPtr.expected, result, "msg with args %d %s", 42, "42") + assert.NotEqual(t, len(expectedFields), result) + assert.NotEqualf(t, len(expectedFields), result, "msg with args %d %s", 42, "42") assert.NotEqual(t, 42, result) assert.NotEqualf(t, 42, result, "msg with args %d %s", 42, "42") assert.NotEqual(t, 3.14, result) @@ -278,15 +287,18 @@ func TestExpectedActualChecker(t *testing.T) { func TestExpectedActualChecker_Other(t *testing.T) { var ( - result, expected any - resultPtr, expectedPtr *int - resultObj, expectedObj user - resultTime, expectedTime time.Time - value int + result, expected any + resultPtr, expectedPtr *int + resultObj, expectedObj user + resultTime, expectedTime time.Time + value int + actualFields, expectedFields []string ) // Invalid. { + assert.Equal(t, len(expectedFields), len(actualFields)) // want "expected-actual: need to reverse actual and expected values" + assert.Equalf(t, len(expectedFields), len(actualFields), "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.EqualExportedValues(t, expectedObj, resultObj) // want "expected-actual: need to reverse actual and expected values" assert.EqualExportedValuesf(t, expectedObj, resultObj, "msg with args %d %s", 42, "42") // want "expected-actual: need to reverse actual and expected values" assert.EqualExportedValues(t, user{Name: "Rob"}, resultObj) // want "expected-actual: need to reverse actual and expected values" @@ -1150,10 +1162,11 @@ func TestExpectedActualChecker_CannotDetectVariablesLookedLikeConsts(t *testing. func TestExpectedActualChecker_Ignored(t *testing.T) { var ( - result, expected any - resultPtr, expectedPtr *int - value int - expectedTime time.Time + result, expected any + resultPtr, expectedPtr *int + value int + expectedTime time.Time + expectedFields, interfaces, directions []string ) assert.Equal(t, nil, nil) @@ -1162,6 +1175,10 @@ func TestExpectedActualChecker_Ignored(t *testing.T) { assert.Equalf(t, "value", "value", "msg with args %d %s", 42, "42") assert.Equal(t, expected, expected) assert.Equalf(t, expected, expected, "msg with args %d %s", 42, "42") + assert.Equal(t, len(expectedFields), len(expectedFields)) + assert.Equalf(t, len(expectedFields), len(expectedFields), "msg with args %d %s", 42, "42") + assert.Equal(t, len(interfaces), len(directions)) + assert.Equalf(t, len(interfaces), len(directions), "msg with args %d %s", 42, "42") assert.Equal(t, value, &resultPtr) assert.Equalf(t, value, &resultPtr, "msg with args %d %s", 42, "42") assert.Equal(t, []int{1, 2}, map[int]int{1: 2}) diff --git a/analyzer/testdata/src/checkers-default/len/len_test.go b/analyzer/testdata/src/checkers-default/len/len_test.go index 8f1b3ec..4a42a85 100644 --- a/analyzer/testdata/src/checkers-default/len/len_test.go +++ b/analyzer/testdata/src/checkers-default/len/len_test.go @@ -8,62 +8,74 @@ import ( "github.com/stretchr/testify/assert" ) +const constNum = 10 + func TestLenChecker(t *testing.T) { - var arr [3]int + var arr, expArr [3]int var value int // Invalid. { - assert.Equal(t, len(arr), 42) // want "len: use assert\\.Len" - assert.Equalf(t, len(arr), 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Equal(t, 42, len(arr)) // want "len: use assert\\.Len" - assert.Equalf(t, 42, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Equal(t, value, len(arr)) // want "len: use assert\\.Len" - assert.Equalf(t, value, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.EqualValues(t, len(arr), 42) // want "len: use assert\\.Len" - assert.EqualValuesf(t, len(arr), 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.EqualValues(t, 42, len(arr)) // want "len: use assert\\.Len" - assert.EqualValuesf(t, 42, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.EqualValues(t, value, len(arr)) // want "len: use assert\\.Len" - assert.EqualValuesf(t, value, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Exactly(t, len(arr), 42) // want "len: use assert\\.Len" - assert.Exactlyf(t, len(arr), 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Exactly(t, 42, len(arr)) // want "len: use assert\\.Len" - assert.Exactlyf(t, 42, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Exactly(t, value, len(arr)) // want "len: use assert\\.Len" - assert.Exactlyf(t, value, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.True(t, len(arr) == 42) // want "len: use assert\\.Len" - assert.Truef(t, len(arr) == 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.True(t, 42 == len(arr)) // want "len: use assert\\.Len" - assert.Truef(t, 42 == len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Equal(t, len(arr), 42) // want "len: use assert\\.Len" + assert.Equalf(t, len(arr), 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Equal(t, 42, len(arr)) // want "len: use assert\\.Len" + assert.Equalf(t, 42, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Equal(t, value, len(arr)) // want "len: use assert\\.Len" + assert.Equalf(t, value, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Equal(t, len(expArr), len(arr)) // want "len: use assert\\.Len" + assert.Equalf(t, len(expArr), len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.EqualValues(t, len(arr), 42) // want "len: use assert\\.Len" + assert.EqualValuesf(t, len(arr), 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.EqualValues(t, 42, len(arr)) // want "len: use assert\\.Len" + assert.EqualValuesf(t, 42, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.EqualValues(t, value, len(arr)) // want "len: use assert\\.Len" + assert.EqualValuesf(t, value, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.EqualValues(t, len(expArr), len(arr)) // want "len: use assert\\.Len" + assert.EqualValuesf(t, len(expArr), len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Exactly(t, len(arr), 42) // want "len: use assert\\.Len" + assert.Exactlyf(t, len(arr), 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Exactly(t, 42, len(arr)) // want "len: use assert\\.Len" + assert.Exactlyf(t, 42, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Exactly(t, value, len(arr)) // want "len: use assert\\.Len" + assert.Exactlyf(t, value, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Exactly(t, len(expArr), len(arr)) // want "len: use assert\\.Len" + assert.Exactlyf(t, len(expArr), len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.True(t, len(arr) == 42) // want "len: use assert\\.Len" + assert.Truef(t, len(arr) == 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.True(t, 42 == len(arr)) // want "len: use assert\\.Len" + assert.Truef(t, 42 == len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.True(t, len(arr) == value) // want "len: use assert\\.Len" + assert.Truef(t, len(arr) == value, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.True(t, len(arr) == len(expArr)) // want "len: use assert\\.Len" + assert.Truef(t, len(arr) == len(expArr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Equal(t, constNum, len(arr)) // want "len: use assert\\.Len" + assert.Equalf(t, constNum, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.EqualValues(t, constNum, len(arr)) // want "len: use assert\\.Len" + assert.EqualValuesf(t, constNum, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Exactly(t, constNum, len(arr)) // want "len: use assert\\.Len" + assert.Exactlyf(t, constNum, len(arr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.True(t, len(arr) == constNum) // want "len: use assert\\.Len" + assert.Truef(t, len(arr) == constNum, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" } // Valid. { assert.Len(t, arr, 42) assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") + assert.Len(t, arr, value) + assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") assert.Len(t, arr, len(arr)) assert.Lenf(t, arr, len(arr), "msg with args %d %s", 42, "42") } // Ignored. { - assert.Equal(t, len(arr), len(arr)) - assert.Equalf(t, len(arr), len(arr), "msg with args %d %s", 42, "42") assert.Equal(t, len(arr), value) assert.Equalf(t, len(arr), value, "msg with args %d %s", 42, "42") - assert.EqualValues(t, len(arr), len(arr)) - assert.EqualValuesf(t, len(arr), len(arr), "msg with args %d %s", 42, "42") assert.EqualValues(t, len(arr), value) assert.EqualValuesf(t, len(arr), value, "msg with args %d %s", 42, "42") - assert.Exactly(t, len(arr), len(arr)) - assert.Exactlyf(t, len(arr), len(arr), "msg with args %d %s", 42, "42") assert.Exactly(t, len(arr), value) assert.Exactlyf(t, len(arr), value, "msg with args %d %s", 42, "42") - assert.True(t, len(arr) == len(arr)) - assert.Truef(t, len(arr) == len(arr), "msg with args %d %s", 42, "42") - assert.True(t, len(arr) == value) - assert.Truef(t, len(arr) == value, "msg with args %d %s", 42, "42") assert.True(t, value == len(arr)) assert.Truef(t, value == len(arr), "msg with args %d %s", 42, "42") assert.NotEqual(t, 42, len(arr)) diff --git a/analyzer/testdata/src/checkers-default/len/len_test.go.golden b/analyzer/testdata/src/checkers-default/len/len_test.go.golden index 9a0928e..111395c 100644 --- a/analyzer/testdata/src/checkers-default/len/len_test.go.golden +++ b/analyzer/testdata/src/checkers-default/len/len_test.go.golden @@ -8,62 +8,74 @@ import ( "github.com/stretchr/testify/assert" ) +const constNum = 10 + func TestLenChecker(t *testing.T) { - var arr [3]int + var arr, expArr [3]int var value int // Invalid. { - assert.Len(t, arr, 42) // want "len: use assert\\.Len" - assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, 42) // want "len: use assert\\.Len" - assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, value) // want "len: use assert\\.Len" - assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, 42) // want "len: use assert\\.Len" - assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, 42) // want "len: use assert\\.Len" - assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, value) // want "len: use assert\\.Len" - assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, 42) // want "len: use assert\\.Len" - assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, 42) // want "len: use assert\\.Len" - assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, value) // want "len: use assert\\.Len" - assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, 42) // want "len: use assert\\.Len" - assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" - assert.Len(t, arr, 42) // want "len: use assert\\.Len" - assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, 42) // want "len: use assert\\.Len" + assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, 42) // want "len: use assert\\.Len" + assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, value) // want "len: use assert\\.Len" + assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, len(expArr)) // want "len: use assert\\.Len" + assert.Lenf(t, arr, len(expArr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, 42) // want "len: use assert\\.Len" + assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, 42) // want "len: use assert\\.Len" + assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, value) // want "len: use assert\\.Len" + assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, len(expArr)) // want "len: use assert\\.Len" + assert.Lenf(t, arr, len(expArr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, 42) // want "len: use assert\\.Len" + assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, 42) // want "len: use assert\\.Len" + assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, value) // want "len: use assert\\.Len" + assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, len(expArr)) // want "len: use assert\\.Len" + assert.Lenf(t, arr, len(expArr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, 42) // want "len: use assert\\.Len" + assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, 42) // want "len: use assert\\.Len" + assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, value) // want "len: use assert\\.Len" + assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, len(expArr)) // want "len: use assert\\.Len" + assert.Lenf(t, arr, len(expArr), "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, constNum) // want "len: use assert\\.Len" + assert.Lenf(t, arr, constNum, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, constNum) // want "len: use assert\\.Len" + assert.Lenf(t, arr, constNum, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, constNum) // want "len: use assert\\.Len" + assert.Lenf(t, arr, constNum, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" + assert.Len(t, arr, constNum) // want "len: use assert\\.Len" + assert.Lenf(t, arr, constNum, "msg with args %d %s", 42, "42") // want "len: use assert\\.Lenf" } // Valid. { assert.Len(t, arr, 42) assert.Lenf(t, arr, 42, "msg with args %d %s", 42, "42") + assert.Len(t, arr, value) + assert.Lenf(t, arr, value, "msg with args %d %s", 42, "42") assert.Len(t, arr, len(arr)) assert.Lenf(t, arr, len(arr), "msg with args %d %s", 42, "42") } // Ignored. { - assert.Equal(t, len(arr), len(arr)) - assert.Equalf(t, len(arr), len(arr), "msg with args %d %s", 42, "42") assert.Equal(t, len(arr), value) assert.Equalf(t, len(arr), value, "msg with args %d %s", 42, "42") - assert.EqualValues(t, len(arr), len(arr)) - assert.EqualValuesf(t, len(arr), len(arr), "msg with args %d %s", 42, "42") assert.EqualValues(t, len(arr), value) assert.EqualValuesf(t, len(arr), value, "msg with args %d %s", 42, "42") - assert.Exactly(t, len(arr), len(arr)) - assert.Exactlyf(t, len(arr), len(arr), "msg with args %d %s", 42, "42") assert.Exactly(t, len(arr), value) assert.Exactlyf(t, len(arr), value, "msg with args %d %s", 42, "42") - assert.True(t, len(arr) == len(arr)) - assert.Truef(t, len(arr) == len(arr), "msg with args %d %s", 42, "42") - assert.True(t, len(arr) == value) - assert.Truef(t, len(arr) == value, "msg with args %d %s", 42, "42") assert.True(t, value == len(arr)) assert.Truef(t, value == len(arr), "msg with args %d %s", 42, "42") assert.NotEqual(t, 42, len(arr)) diff --git a/analyzer/testdata/src/checkers-priority/checkers_priority_test.go b/analyzer/testdata/src/checkers-priority/checkers_priority_test.go index 1a6bb11..a2fa7fa 100644 --- a/analyzer/testdata/src/checkers-priority/checkers_priority_test.go +++ b/analyzer/testdata/src/checkers-priority/checkers_priority_test.go @@ -11,9 +11,9 @@ func TestCheckersPriority(t *testing.T) { var f float64 var b bool - // `empty` > `len` > `expected-actual` + // `empty` > `expected-actual` > `len` assert.Equal(t, len([]int{}), 0) // want "empty: use assert\\.Empty" - assert.Equal(t, len([]int{}), 3) // want "len: use assert\\.Len" + assert.Equal(t, len([]int{}), 3) // want "expected-actual: need to reverse actual and expected values" // `float-compare` > `bool-compare` > `compares` > `expected-actual` require.True(t, 42.42 == f) // want "float-compare: use require\\.InEpsilon \\(or InDelta\\)" diff --git a/analyzer/testdata/src/checkers-priority/checkers_priority_test.go.golden b/analyzer/testdata/src/checkers-priority/checkers_priority_test.go.golden index 3f2d8df..983bb82 100644 --- a/analyzer/testdata/src/checkers-priority/checkers_priority_test.go.golden +++ b/analyzer/testdata/src/checkers-priority/checkers_priority_test.go.golden @@ -11,9 +11,9 @@ func TestCheckersPriority(t *testing.T) { var f float64 var b bool - // `empty` > `len` > `expected-actual` - assert.Empty(t, []int{}) // want "empty: use assert\\.Empty" - assert.Len(t, []int{}, 3) // want "len: use assert\\.Len" + // `empty` > `expected-actual` > `len` + assert.Empty(t, []int{}) // want "empty: use assert\\.Empty" + assert.Equal(t, 3, len([]int{})) // want "expected-actual: need to reverse actual and expected values" // `float-compare` > `bool-compare` > `compares` > `expected-actual` require.True(t, 42.42 == f) // want "float-compare: use require\\.InEpsilon \\(or InDelta\\)" diff --git a/analyzer/testdata/src/debug/len_interface_test.go b/analyzer/testdata/src/debug/len_interface_test.go new file mode 100644 index 0000000..1c37f95 --- /dev/null +++ b/analyzer/testdata/src/debug/len_interface_test.go @@ -0,0 +1,26 @@ +package debug + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestLenInterface(t *testing.T) { + const n = 10 + a := newArr(n) + assert.Equal(t, n, a.Len()) + assert.Len(t, a, n) // Error: "{[ ]}" could not be applied builtin len() +} + +type arr struct { + v []string +} + +func newArr(n int) arr { + return arr{v: make([]string, n)} +} + +func (a arr) Len() int { + return len(a.v) +} diff --git a/analyzer/testdata/src/debug/len_type_conversions_test.go b/analyzer/testdata/src/debug/len_type_conversions_test.go new file mode 100644 index 0000000..21040f4 --- /dev/null +++ b/analyzer/testdata/src/debug/len_type_conversions_test.go @@ -0,0 +1,32 @@ +package debug + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestLenTypeConversions(t *testing.T) { + const resp = "Multi-языковая string 你好世界 🙂" + const respLen = len(resp) // 47 + + assert.Equal(t, respLen, len(resp)) + assert.Equal(t, respLen, len([]byte(resp))) + assert.Equal(t, respLen, len(json.RawMessage(resp))) + assert.Len(t, resp, respLen) + assert.Len(t, []byte(resp), respLen) + assert.Len(t, json.RawMessage(resp), respLen) +} + +func TestBytesReadability(t *testing.T) { + resp := []byte(`{"status": 200}`) + assert.Len(t, resp, 3) // "[123 34 115 116 97 116 117 115 34 58 32 50 48 48 125]" should have 3 item(s), but has 15 + assert.Len(t, string(resp), 3) // "{"status": 200}" should have 3 item(s), but has 15 + + var noResp []byte + assert.Empty(t, resp) // Should be empty, but was [123 34 115 116 97 116 117 115 34 58 32 50 48 48 125] + assert.Empty(t, string(resp)) // Should be empty, but was {"status": 200} + assert.NotEmpty(t, noResp) // Should NOT be empty, but was [] + assert.NotEmpty(t, string(noResp)) // Should NOT be empty, but was +} diff --git a/internal/checkers/checkers_registry.go b/internal/checkers/checkers_registry.go index f881be4..bb4aa4d 100644 --- a/internal/checkers/checkers_registry.go +++ b/internal/checkers/checkers_registry.go @@ -10,7 +10,6 @@ var registry = checkersRegistry{ {factory: asCheckerFactory(NewFloatCompare), enabledByDefault: true}, {factory: asCheckerFactory(NewBoolCompare), enabledByDefault: true}, {factory: asCheckerFactory(NewEmpty), enabledByDefault: true}, - {factory: asCheckerFactory(NewLen), enabledByDefault: true}, {factory: asCheckerFactory(NewNegativePositive), enabledByDefault: true}, {factory: asCheckerFactory(NewCompares), enabledByDefault: true}, {factory: asCheckerFactory(NewContains), enabledByDefault: true}, @@ -19,6 +18,7 @@ var registry = checkersRegistry{ {factory: asCheckerFactory(NewErrorIsAs), enabledByDefault: true}, {factory: asCheckerFactory(NewEncodedCompare), enabledByDefault: true}, {factory: asCheckerFactory(NewExpectedActual), enabledByDefault: true}, + {factory: asCheckerFactory(NewLen), enabledByDefault: true}, {factory: asCheckerFactory(NewRegexp), enabledByDefault: true}, {factory: asCheckerFactory(NewSuiteExtraAssertCall), enabledByDefault: true}, {factory: asCheckerFactory(NewSuiteDontUsePkg), enabledByDefault: true}, diff --git a/internal/checkers/checkers_registry_test.go b/internal/checkers/checkers_registry_test.go index 08c3a39..eff5571 100644 --- a/internal/checkers/checkers_registry_test.go +++ b/internal/checkers/checkers_registry_test.go @@ -38,7 +38,6 @@ func TestAll(t *testing.T) { "float-compare", "bool-compare", "empty", - "len", "negative-positive", "compares", "contains", @@ -47,6 +46,7 @@ func TestAll(t *testing.T) { "error-is-as", "encoded-compare", "expected-actual", + "len", "regexp", "suite-extra-assert-call", "suite-dont-use-pkg", @@ -75,7 +75,6 @@ func TestEnabledByDefault(t *testing.T) { "float-compare", "bool-compare", "empty", - "len", "negative-positive", "compares", "contains", @@ -84,6 +83,7 @@ func TestEnabledByDefault(t *testing.T) { "error-is-as", "encoded-compare", "expected-actual", + "len", "regexp", "suite-extra-assert-call", "suite-dont-use-pkg", diff --git a/internal/checkers/expected_actual.go b/internal/checkers/expected_actual.go index 351d675..31ea3ff 100644 --- a/internal/checkers/expected_actual.go +++ b/internal/checkers/expected_actual.go @@ -17,6 +17,8 @@ var DefaultExpectedVarPattern = regexp.MustCompile( // ExpectedActual detects situations like // // assert.Equal(t, result, expected) +// assert.Equal(t, result, len(expected)) +// assert.Equal(t, len(resultFields), len(expectedFields)) // assert.EqualExportedValues(t, resultObj, User{Name: "Anton"}) // assert.EqualValues(t, result, 42) // assert.Exactly(t, result, int64(42)) @@ -37,6 +39,8 @@ var DefaultExpectedVarPattern = regexp.MustCompile( // and requires // // assert.Equal(t, expected, result) +// assert.Equal(t, len(expected), result) +// assert.Equal(t, len(expectedFields), len(resultFields)) // assert.EqualExportedValues(t, User{Name: "Anton"}, resultObj) // assert.EqualValues(t, 42, result) // ... @@ -122,6 +126,9 @@ func (checker ExpectedActual) isExpectedValueCandidate(pass *analysis.Pass, expr return true case *ast.CallExpr: + if lv, ok := isBuiltinLenCall(pass, expr); ok { + return isIdentNamedAfterPattern(checker.expVarPattern, lv) + } return isParenExpr(v) || isCastedBasicLitOrExpectedValue(v, checker.expVarPattern) || isExpectedValueFactory(pass, v, checker.expVarPattern) diff --git a/internal/checkers/helpers_len.go b/internal/checkers/helpers_len.go index 904950f..6afa584 100644 --- a/internal/checkers/helpers_len.go +++ b/internal/checkers/helpers_len.go @@ -2,7 +2,6 @@ package checkers import ( "go/ast" - "go/token" "go/types" "golang.org/x/tools/go/analysis" @@ -12,31 +11,6 @@ import ( var lenObj = types.Universe.Lookup("len") -func isLenEquality(pass *analysis.Pass, e ast.Expr) (ast.Expr, ast.Expr, bool) { - be, ok := e.(*ast.BinaryExpr) - if !ok { - return nil, nil, false - } - - if be.Op != token.EQL { - return nil, nil, false - } - return xorLenCall(pass, be.X, be.Y) -} - -func xorLenCall(pass *analysis.Pass, a, b ast.Expr) (lenArg ast.Expr, expectedLen ast.Expr, ok bool) { - arg1, ok1 := isBuiltinLenCall(pass, a) - arg2, ok2 := isBuiltinLenCall(pass, b) - - if xor(ok1, ok2) { - if ok1 { - return arg1, b, true - } - return arg2, a, true - } - return nil, nil, false -} - func isLenCallAndZero(pass *analysis.Pass, a, b ast.Expr) (ast.Expr, bool) { lenArg, ok := isBuiltinLenCall(pass, a) return lenArg, ok && isZero(b) diff --git a/internal/checkers/len.go b/internal/checkers/len.go index c240a61..9bdd8ff 100644 --- a/internal/checkers/len.go +++ b/internal/checkers/len.go @@ -1,19 +1,42 @@ package checkers import ( + "go/ast" + "go/token" + "golang.org/x/tools/go/analysis" ) // Len detects situations like // -// assert.Equal(t, 3, len(arr)) -// assert.EqualValues(t, 3, len(arr)) -// assert.Exactly(t, 3, len(arr)) -// assert.True(t, len(arr) == 3) +// assert.Equal(t, 42, len(arr)) +// assert.Equal(t, len(arr), 42) +// assert.EqualValues(t, 42, len(arr)) +// assert.EqualValues(t, len(arr), 42) +// assert.Exactly(t, 42, len(arr)) +// assert.Exactly(t, len(arr), 42) +// assert.True(t, 42 == len(arr)) +// assert.True(t, len(arr) == 42) +// +// assert.Equal(t, value, len(arr)) +// assert.EqualValues(t, value, len(arr)) +// assert.Exactly(t, value, len(arr)) +// assert.True(t, len(arr) == value) + +// assert.Equal(t, len(expArr), len(arr)) +// assert.EqualValues(t, len(expArr), len(arr)) +// assert.Exactly(t, len(expArr), len(arr)) +// assert.True(t, len(arr) == len(expArr)) // // and requires // -// assert.Len(t, arr, 3) +// assert.Len(t, arr, 42) +// assert.Len(t, arr, value) +// assert.Len(t, arr, len(expArr)) +// +// The checker ignores assertions in which length checking is not a priority, e.g +// +// assert.Equal(t, len(arr), value) type Len struct{} // NewLen constructs Len checker. @@ -21,45 +44,62 @@ func NewLen() Len { return Len{} } func (Len) Name() string { return "len" } func (checker Len) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { - const proposedFn = "Len" - switch call.Fn.NameFTrimmed { case "Equal", "EqualValues", "Exactly": if len(call.Args) < 2 { return nil } - a, b := call.Args[0], call.Args[1] - if lenArg, expectedLen, ok := xorLenCall(pass, a, b); ok { - if _, ok := isIntBasicLit(expectedLen); (expectedLen == b) && !ok { - // https://github.com/Antonboom/testifylint/issues/9 - return nil - } - return newUseFunctionDiagnostic(checker.Name(), call, proposedFn, - analysis.TextEdit{ - Pos: a.Pos(), - End: b.End(), - NewText: formatAsCallArgs(pass, lenArg, expectedLen), - }) - } + a, b := call.Args[0], call.Args[1] + return checker.checkArgs(call, pass, a, b, false) case "True": if len(call.Args) < 1 { return nil } - expr := call.Args[0] - if lenArg, expectedLen, ok := isLenEquality(pass, expr); ok { - if _, ok := isIntBasicLit(expectedLen); !ok { - return nil - } - return newUseFunctionDiagnostic(checker.Name(), call, proposedFn, - analysis.TextEdit{ - Pos: expr.Pos(), - End: expr.End(), - NewText: formatAsCallArgs(pass, lenArg, expectedLen), - }) + be, ok := call.Args[0].(*ast.BinaryExpr) + if !ok { + return nil + } + if be.Op != token.EQL { + return nil + } + return checker.checkArgs(call, pass, be.Y, be.X, true) // In True, the actual value is usually first. + } + return nil +} + +func (checker Len) checkArgs(call *CallMeta, pass *analysis.Pass, a, b ast.Expr, inverted bool) *analysis.Diagnostic { + newUseLenDiagnostic := func(lenArg, expectedLen ast.Expr) *analysis.Diagnostic { + const proposedFn = "Len" + start, end := a.Pos(), b.End() + if inverted { + start, end = b.Pos(), a.End() + } + return newUseFunctionDiagnostic(checker.Name(), call, proposedFn, + analysis.TextEdit{ + Pos: start, + End: end, + NewText: formatAsCallArgs(pass, lenArg, expectedLen), + }) + } + + arg1, firstIsLen := isBuiltinLenCall(pass, a) + arg2, secondIsLen := isBuiltinLenCall(pass, b) + + switch { + case firstIsLen && secondIsLen: + return newUseLenDiagnostic(arg2, a) + + case firstIsLen: + if _, secondIsNum := isIntBasicLit(b); secondIsNum { + return newUseLenDiagnostic(arg1, b) } + + case secondIsLen: + return newUseLenDiagnostic(arg2, a) } + return nil } diff --git a/internal/testgen/gen_expected_actual.go b/internal/testgen/gen_expected_actual.go index a969d9c..708d5a2 100644 --- a/internal/testgen/gen_expected_actual.go +++ b/internal/testgen/gen_expected_actual.go @@ -106,6 +106,8 @@ func (g ExpectedActualTestsGenerator) TemplateData() any { "*(tt.expPtr())", "ttPtr.expected", + "len(expectedFields)", + // NOTE(a.telyshev): Unsupported rare cases: // "(*expectedObjPtr).Val", // "(*ttPtr).expected", @@ -122,6 +124,11 @@ func (g ExpectedActualTestsGenerator) TemplateData() any { }, OtherExpActFunctions: test{ InvalidAssertions: []Assertion{ + { + Fn: "Equal", Argsf: "len(actualFields), len(expectedFields)", + ReportMsgf: report, ProposedArgsf: "len(expectedFields), len(actualFields)", + }, + { Fn: "EqualExportedValues", Argsf: "resultObj, expectedObj", ReportMsgf: report, ProposedArgsf: "expectedObj, resultObj", @@ -261,6 +268,8 @@ func (g ExpectedActualTestsGenerator) TemplateData() any { {Fn: "Equal", Argsf: "nil, nil"}, {Fn: "Equal", Argsf: `"value", "value"`}, {Fn: "Equal", Argsf: "expected, expected"}, + {Fn: "Equal", Argsf: "len(expectedFields), len(expectedFields)"}, + {Fn: "Equal", Argsf: "len(interfaces), len(directions)"}, {Fn: "Equal", Argsf: "value, &resultPtr"}, {Fn: "Equal", Argsf: "[]int{1, 2}, map[int]int{1: 2}"}, {Fn: "NotEqual", Argsf: "result, result"}, @@ -348,6 +357,7 @@ func {{ .CheckerName.AsTestName }}(t *testing.T) { expectedVal := func() any { return nil } var expectedObj struct { Val int } var expectedObjPtr = &expectedObj + var expectedFields []string var result any @@ -369,6 +379,7 @@ func {{ .CheckerName.AsTestName }}_Other(t *testing.T) { resultObj, expectedObj user resultTime, expectedTime time.Time value int + actualFields, expectedFields []string ) // Invalid. @@ -503,6 +514,7 @@ func {{ .CheckerName.AsTestName }}_Ignored(t *testing.T) { resultPtr, expectedPtr *int value int expectedTime time.Time + expectedFields, interfaces, directions []string ) {{ range $ai, $assrn := $.IgnoredAssertions }} diff --git a/internal/testgen/gen_len.go b/internal/testgen/gen_len.go index 4b3140d..ade360a 100644 --- a/internal/testgen/gen_len.go +++ b/internal/testgen/gen_len.go @@ -31,28 +31,41 @@ func (g LenTestsGenerator) TemplateData() any { {Fn: "Equal", Argsf: "len(arr), 42", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, 42"}, {Fn: "Equal", Argsf: "42, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, 42"}, {Fn: "Equal", Argsf: "value, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, value"}, + {Fn: "Equal", Argsf: "len(expArr), len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, len(expArr)"}, + {Fn: "EqualValues", Argsf: "len(arr), 42", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, 42"}, {Fn: "EqualValues", Argsf: "42, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, 42"}, {Fn: "EqualValues", Argsf: "value, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, value"}, + { + Fn: "EqualValues", Argsf: "len(expArr), len(arr)", ReportMsgf: report, + ProposedFn: proposedFn, ProposedArgsf: "arr, len(expArr)", + }, + {Fn: "Exactly", Argsf: "len(arr), 42", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, 42"}, {Fn: "Exactly", Argsf: "42, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, 42"}, {Fn: "Exactly", Argsf: "value, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, value"}, + {Fn: "Exactly", Argsf: "len(expArr), len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, len(expArr)"}, + {Fn: "True", Argsf: "len(arr) == 42", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, 42"}, {Fn: "True", Argsf: "42 == len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, 42"}, + {Fn: "True", Argsf: "len(arr) == value", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, value"}, + {Fn: "True", Argsf: "len(arr) == len(expArr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, len(expArr)"}, + + // Constant case. + {Fn: "Equal", Argsf: "constNum, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, constNum"}, + {Fn: "EqualValues", Argsf: "constNum, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, constNum"}, + {Fn: "Exactly", Argsf: "constNum, len(arr)", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, constNum"}, + {Fn: "True", Argsf: "len(arr) == constNum", ReportMsgf: report, ProposedFn: proposedFn, ProposedArgsf: "arr, constNum"}, }, ValidAssertions: []Assertion{ {Fn: "Len", Argsf: "arr, 42"}, + {Fn: "Len", Argsf: "arr, value"}, {Fn: "Len", Argsf: "arr, len(arr)"}, }, IgnoredAssertions: []Assertion{ - {Fn: "Equal", Argsf: "len(arr), len(arr)"}, {Fn: "Equal", Argsf: "len(arr), value"}, - {Fn: "EqualValues", Argsf: "len(arr), len(arr)"}, {Fn: "EqualValues", Argsf: "len(arr), value"}, - {Fn: "Exactly", Argsf: "len(arr), len(arr)"}, {Fn: "Exactly", Argsf: "len(arr), value"}, - {Fn: "True", Argsf: "len(arr) == len(arr)"}, - {Fn: "True", Argsf: "len(arr) == value"}, {Fn: "True", Argsf: "value == len(arr)"}, {Fn: "NotEqual", Argsf: "42, len(arr)"}, @@ -117,8 +130,10 @@ import ( "github.com/stretchr/testify/assert" ) +const constNum = 10 + func {{ .CheckerName.AsTestName }}(t *testing.T) { - var arr [3]int + var arr, expArr [3]int var value int // Invalid.