Hi!
The using of ObjectsAreEqual
-based functions with untyped nil
doesn't make sense for any non-interface types, because of expected
and actual
are interfaces:
func ObjectsAreEqual(expected, actual interface{}) bool { if expected == nil || actual == nil { return expected == actual // You cannot do this, because // expected and actual are interfaces }
As a consequence, Equal
, EqualValues
and Exactly
will always fail:
fmt.Println(assert.Equal(t, nil, nilChan)) // false fmt.Println(assert.Equal(t, nil, nilFunc)) // false, cannot take func type as argument fmt.Println(assert.Equal(t, nil, nilInterface)) // true ! fmt.Println(assert.Equal(t, nil, nilMap)) // false fmt.Println(assert.Equal(t, nil, nilPointer)) // false fmt.Println(assert.Equal(t, nil, nilSlice)) // false fmt.Println(assert.Equal(t, nil, nilUnsafePointer)) // false fmt.Println(assert.EqualValues(t, nil, nilChan)) // false fmt.Println(assert.EqualValues(t, nil, nilFunc)) // false fmt.Println(assert.EqualValues(t, nil, nilInterface)) // true ! fmt.Println(assert.EqualValues(t, nil, nilMap)) // false fmt.Println(assert.EqualValues(t, nil, nilPointer)) // false fmt.Println(assert.EqualValues(t, nil, nilSlice)) // false fmt.Println(assert.EqualValues(t, nil, nilUnsafePointer)) // false fmt.Println(assert.Exactly(t, nil, nilChan)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilFunc)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilInterface)) // true ! fmt.Println(assert.Exactly(t, nil, nilMap)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilPointer)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilSlice)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilUnsafePointer)) // false, Types expected to match exactly
And NotEqual
and NotEqualValues
will always pass:
fmt.Println(assert.NotEqual(t, nil, nilChan)) // true fmt.Println(assert.NotEqual(t, nil, nilFunc)) // false, cannot take func type as argument fmt.Println(assert.NotEqual(t, nil, nilInterface)) // false ! fmt.Println(assert.NotEqual(t, nil, nilMap)) // true fmt.Println(assert.NotEqual(t, nil, nilPointer)) // true fmt.Println(assert.NotEqual(t, nil, nilSlice)) // true fmt.Println(assert.NotEqual(t, nil, nilUnsafePointer)) // true fmt.Println(assert.NotEqualValues(t, nil, nilChan)) // true fmt.Println(assert.NotEqualValues(t, nil, nilFunc)) // true fmt.Println(assert.NotEqualValues(t, nil, nilInterface)) // false ! fmt.Println(assert.NotEqualValues(t, nil, nilMap)) // true fmt.Println(assert.NotEqualValues(t, nil, nilPointer)) // true fmt.Println(assert.NotEqualValues(t, nil, nilSlice)) // true fmt.Println(assert.NotEqualValues(t, nil, nilUnsafePointer)) // true
The right way is to use typed nil
:
fmt.Println(assert.Equal(t, (chan struct{})(nil), nilChan)) // true fmt.Println(assert.Equal(t, (func())(nil), nilFunc)) // false, cannot take func type as argument fmt.Println(assert.Equal(t, (map[int]int)(nil), nilMap)) // true fmt.Println(assert.Equal(t, (*int)(nil), nilPointer)) // true fmt.Println(assert.Equal(t, []int(nil), nilSlice)) // true fmt.Println(assert.Equal(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // true fmt.Println(assert.EqualValues(t, (chan struct{})(nil), nilChan)) // true fmt.Println(assert.EqualValues(t, (func())(nil), nilFunc)) // true fmt.Println(assert.EqualValues(t, (map[int]int)(nil), nilMap)) // true fmt.Println(assert.EqualValues(t, (*int)(nil), nilPointer)) // true fmt.Println(assert.EqualValues(t, []int(nil), nilSlice)) // true fmt.Println(assert.EqualValues(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // true fmt.Println(assert.Exactly(t, (chan struct{})(nil), nilChan)) // true fmt.Println(assert.Exactly(t, (func())(nil), nilFunc)) // false, cannot take func type as argument fmt.Println(assert.Exactly(t, (map[int]int)(nil), nilMap)) // true fmt.Println(assert.Exactly(t, (*int)(nil), nilPointer)) // true fmt.Println(assert.Exactly(t, []int(nil), nilSlice)) // true fmt.Println(assert.Exactly(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // true fmt.Println(assert.NotEqual(t, (chan struct{})(nil), nilChan)) // false fmt.Println(assert.NotEqual(t, (func())(nil), nilFunc)) // false, cannot take func type as argument fmt.Println(assert.NotEqual(t, (map[int]int)(nil), nilMap)) // false fmt.Println(assert.NotEqual(t, (*int)(nil), nilPointer)) // false fmt.Println(assert.NotEqual(t, []int(nil), nilSlice)) // false fmt.Println(assert.NotEqual(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // false fmt.Println(assert.NotEqualValues(t, (chan struct{})(nil), nilChan)) // false fmt.Println(assert.NotEqualValues(t, (func())(nil), nilFunc)) // false fmt.Println(assert.NotEqualValues(t, (map[int]int)(nil), nilMap)) // false fmt.Println(assert.NotEqualValues(t, (*int)(nil), nilPointer)) // false fmt.Println(assert.NotEqualValues(t, []int(nil), nilSlice)) // false fmt.Println(assert.NotEqualValues(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // false
But this is verbose and we also see inconsistency of functions when working with nilFunc
.
Better to just use Nil
/NotNil
:
fmt.Println(nilChan == nil) // true fmt.Println(nilFunc == nil) // true fmt.Println(nilInterface == nil) // true fmt.Println(nilMap == nil) // true fmt.Println(nilPointer == nil) // true fmt.Println(nilSlice == nil) // true fmt.Println(nilUnsafePointer == nil) // true fmt.Println(assert.Nil(t, nilChan)) // true fmt.Println(assert.Nil(t, nilFunc)) // true fmt.Println(assert.Nil(t, nilInterface)) // true fmt.Println(assert.Nil(t, nilMap)) // true fmt.Println(assert.Nil(t, nilPointer)) // true fmt.Println(assert.Nil(t, nilSlice)) // true fmt.Println(assert.Nil(t, nilUnsafePointer)) // true fmt.Println(assert.NotNil(t, nilChan)) // false fmt.Println(assert.NotNil(t, nilFunc)) // false fmt.Println(assert.NotNil(t, nilInterface)) // false fmt.Println(assert.NotNil(t, nilMap)) // false fmt.Println(assert.NotNil(t, nilPointer)) // false fmt.Println(assert.NotNil(t, nilSlice)) // false fmt.Println(assert.NotNil(t, nilUnsafePointer)) // false
Full snippet:
https://go.dev/play/p/ClGstUJWkYB
package main import ( "fmt" "testing" "unsafe" "github.com/stretchr/testify/assert" ) func Test(t *testing.T) { var ( nilChan chan struct{} nilFunc func() nilInterface any nilMap map[int]int nilPointer *int nilSlice []int nilUnsafePointer unsafe.Pointer ) fmt.Println("\nEqual") fmt.Println(assert.Equal(t, nil, nilChan)) // false fmt.Println(assert.Equal(t, nil, nilFunc)) // false, cannot take func type as argument fmt.Println(assert.Equal(t, nil, nilInterface)) // true ! fmt.Println(assert.Equal(t, nil, nilMap)) // false fmt.Println(assert.Equal(t, nil, nilPointer)) // false fmt.Println(assert.Equal(t, nil, nilSlice)) // false fmt.Println(assert.Equal(t, nil, nilUnsafePointer)) // false fmt.Println("\nEqualValues") fmt.Println(assert.EqualValues(t, nil, nilChan)) // false fmt.Println(assert.EqualValues(t, nil, nilFunc)) // false fmt.Println(assert.EqualValues(t, nil, nilInterface)) // true ! fmt.Println(assert.EqualValues(t, nil, nilMap)) // false fmt.Println(assert.EqualValues(t, nil, nilPointer)) // false fmt.Println(assert.EqualValues(t, nil, nilSlice)) // false fmt.Println(assert.EqualValues(t, nil, nilUnsafePointer)) // false fmt.Println("\nExactly") fmt.Println(assert.Exactly(t, nil, nilChan)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilFunc)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilInterface)) // true ! fmt.Println(assert.Exactly(t, nil, nilMap)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilPointer)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilSlice)) // false, Types expected to match exactly fmt.Println(assert.Exactly(t, nil, nilUnsafePointer)) // false, Types expected to match exactly fmt.Println("\nNotEqual") fmt.Println(assert.NotEqual(t, nil, nilChan)) // true fmt.Println(assert.NotEqual(t, nil, nilFunc)) // false, cannot take func type as argument fmt.Println(assert.NotEqual(t, nil, nilInterface)) // false ! fmt.Println(assert.NotEqual(t, nil, nilMap)) // true fmt.Println(assert.NotEqual(t, nil, nilPointer)) // true fmt.Println(assert.NotEqual(t, nil, nilSlice)) // true fmt.Println(assert.NotEqual(t, nil, nilUnsafePointer)) // true fmt.Println("\nNotEqualValues") fmt.Println(assert.NotEqualValues(t, nil, nilChan)) // true fmt.Println(assert.NotEqualValues(t, nil, nilFunc)) // true fmt.Println(assert.NotEqualValues(t, nil, nilInterface)) // false ! fmt.Println(assert.NotEqualValues(t, nil, nilMap)) // true fmt.Println(assert.NotEqualValues(t, nil, nilPointer)) // true fmt.Println(assert.NotEqualValues(t, nil, nilSlice)) // true fmt.Println(assert.NotEqualValues(t, nil, nilUnsafePointer)) // true // ------------------------------------------------------------------------------------------ fmt.Println("\nEqual with typed nil") fmt.Println(assert.Equal(t, (chan struct{})(nil), nilChan)) // true fmt.Println(assert.Equal(t, (func())(nil), nilFunc)) // false, cannot take func type as argument fmt.Println(assert.Equal(t, (map[int]int)(nil), nilMap)) // true fmt.Println(assert.Equal(t, (*int)(nil), nilPointer)) // true fmt.Println(assert.Equal(t, []int(nil), nilSlice)) // true fmt.Println(assert.Equal(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // true fmt.Println("\nEqualValues with typed nil") fmt.Println(assert.EqualValues(t, (chan struct{})(nil), nilChan)) // true fmt.Println(assert.EqualValues(t, (func())(nil), nilFunc)) // true fmt.Println(assert.EqualValues(t, (map[int]int)(nil), nilMap)) // true fmt.Println(assert.EqualValues(t, (*int)(nil), nilPointer)) // true fmt.Println(assert.EqualValues(t, []int(nil), nilSlice)) // true fmt.Println(assert.EqualValues(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // true fmt.Println("\nExactly with typed nil") fmt.Println(assert.Exactly(t, (chan struct{})(nil), nilChan)) // true fmt.Println(assert.Exactly(t, (func())(nil), nilFunc)) // false, cannot take func type as argument fmt.Println(assert.Exactly(t, (map[int]int)(nil), nilMap)) // true fmt.Println(assert.Exactly(t, (*int)(nil), nilPointer)) // true fmt.Println(assert.Exactly(t, []int(nil), nilSlice)) // true fmt.Println(assert.Exactly(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // true fmt.Println("\nNotEqual with typed nil") fmt.Println(assert.NotEqual(t, (chan struct{})(nil), nilChan)) // false fmt.Println(assert.NotEqual(t, (func())(nil), nilFunc)) // false, cannot take func type as argument fmt.Println(assert.NotEqual(t, (map[int]int)(nil), nilMap)) // false fmt.Println(assert.NotEqual(t, (*int)(nil), nilPointer)) // false fmt.Println(assert.NotEqual(t, []int(nil), nilSlice)) // false fmt.Println(assert.NotEqual(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // false fmt.Println("\nNotEqualValues with typed nil") fmt.Println(assert.NotEqualValues(t, (chan struct{})(nil), nilChan)) // false fmt.Println(assert.NotEqualValues(t, (func())(nil), nilFunc)) // false fmt.Println(assert.NotEqualValues(t, (map[int]int)(nil), nilMap)) // false fmt.Println(assert.NotEqualValues(t, (*int)(nil), nilPointer)) // false fmt.Println(assert.NotEqualValues(t, []int(nil), nilSlice)) // false fmt.Println(assert.NotEqualValues(t, (unsafe.Pointer)(nil), nilUnsafePointer)) // false // ------------------------------------------------------------------------------------------ fmt.Println("\nGO ==") fmt.Println(nilChan == nil) // true fmt.Println(nilFunc == nil) // true fmt.Println(nilInterface == nil) // true fmt.Println(nilMap == nil) // true fmt.Println(nilPointer == nil) // true fmt.Println(nilSlice == nil) // true fmt.Println(nilUnsafePointer == nil) // true fmt.Println("\nNil") fmt.Println(assert.Nil(t, nilChan)) // true fmt.Println(assert.Nil(t, nilFunc)) // true fmt.Println(assert.Nil(t, nilInterface)) // true fmt.Println(assert.Nil(t, nilMap)) // true fmt.Println(assert.Nil(t, nilPointer)) // true fmt.Println(assert.Nil(t, nilSlice)) // true fmt.Println(assert.Nil(t, nilUnsafePointer)) // true fmt.Println("\nNotNil") fmt.Println(assert.NotNil(t, nilChan)) // false fmt.Println(assert.NotNil(t, nilFunc)) // false fmt.Println(assert.NotNil(t, nilInterface)) // false fmt.Println(assert.NotNil(t, nilMap)) // false fmt.Println(assert.NotNil(t, nilPointer)) // false fmt.Println(assert.NotNil(t, nilSlice)) // false fmt.Println(assert.NotNil(t, nilUnsafePointer)) // false }
Example of bug/typo in testify:
(call.WaitFor
is (<-chan time.Time)(nil)
).
Covered by testifylint#nil-compare.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4