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.