NotSame should fail if args are not pointers #1661 (#1664)

## Summary
Reduces the confusion assosciated with NotSame that previously would
check nothing if any of the values is not a pointer. The changes made
were tested using TestSame, TestNotSame, and Test_samePointers tests,
and the changes did clear the tests.

## Changes
1. Modified samePointers to return another bool value(ok) that would
determine if the 2 values are of pointer type or not, while the returned
"same" bool value would determine if the 2 pointers are same.
2. Modified assert.NotSame to call Fail() if the 2 values are either
i)pointers pointing to the same address or ii)either/both of the values
are not pointers.
3. Modified assert.Same to call Fail() if the 2 values are either
i)pointers not pointing to the same address or ii)either/both of the
values are not pointers.
4. Modified Test_samePointers to handle the new behavior of samePointers
by checking both if the inputs are pointers (ok) and if they point to
the same object (same).

## Motivation
Ensure NotSame accurately verifies pointer sameness by handling
non-pointer inputs explicitly, improving clarity and reducing potential
misuse.

## Related issues
Closes #1661

---------

Co-authored-by: Bracken <abdawson@gmail.com>
This commit is contained in:
Hisham Akmal 2024-10-28 16:38:04 +05:30 committed by GitHub
parent a1b9c9efe3
commit 118fb83466
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 61 additions and 27 deletions

View File

@ -502,7 +502,13 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
h.Helper() h.Helper()
} }
if !samePointers(expected, actual) { same, ok := samePointers(expected, actual)
if !ok {
return Fail(t, "Both arguments must be pointers", msgAndArgs...)
}
if !same {
// both are pointers but not the same type & pointing to the same address
return Fail(t, fmt.Sprintf("Not same: \n"+ return Fail(t, fmt.Sprintf("Not same: \n"+
"expected: %p %#v\n"+ "expected: %p %#v\n"+
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...) "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
@ -522,7 +528,13 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
h.Helper() h.Helper()
} }
if samePointers(expected, actual) { same, ok := samePointers(expected, actual)
if !ok {
//fails when the arguments are not pointers
return !(Fail(t, "Both arguments must be pointers", msgAndArgs...))
}
if same {
return Fail(t, fmt.Sprintf( return Fail(t, fmt.Sprintf(
"Expected and actual point to the same object: %p %#v", "Expected and actual point to the same object: %p %#v",
expected, expected), msgAndArgs...) expected, expected), msgAndArgs...)
@ -530,21 +542,23 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
return true return true
} }
// samePointers compares two generic interface objects and returns whether // samePointers checks if two generic interface objects are pointers of the same
// they point to the same object // type pointing to the same object. It returns two values: same indicating if
func samePointers(first, second interface{}) bool { // they are the same type and point to the same object, and ok indicating that
// both inputs are pointers.
func samePointers(first, second interface{}) (same bool, ok bool) {
firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr { if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
return false return false, false //not both are pointers
} }
firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second) firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
if firstType != secondType { if firstType != secondType {
return false return false, true // both are pointers, but of different types
} }
// compare pointer addresses // compare pointer addresses
return first == second return first == second, true
} }
// formatUnequalValues takes two values of arbitrary types and returns string // formatUnequalValues takes two values of arbitrary types and returns string

View File

@ -657,37 +657,57 @@ func Test_samePointers(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
assertion BoolAssertionFunc same BoolAssertionFunc
ok BoolAssertionFunc
}{ }{
{ {
name: "1 != 2", name: "1 != 2",
args: args{first: 1, second: 2}, args: args{first: 1, second: 2},
assertion: False, same: False,
ok: False,
}, },
{ {
name: "1 != 1 (not same ptr)", name: "1 != 1 (not same ptr)",
args: args{first: 1, second: 1}, args: args{first: 1, second: 1},
assertion: False, same: False,
ok: False,
}, },
{ {
name: "ptr(1) == ptr(1)", name: "ptr(1) == ptr(1)",
args: args{first: p, second: p}, args: args{first: p, second: p},
assertion: True, same: True,
ok: True,
}, },
{ {
name: "int(1) != float32(1)", name: "int(1) != float32(1)",
args: args{first: int(1), second: float32(1)}, args: args{first: int(1), second: float32(1)},
assertion: False, same: False,
ok: False,
}, },
{ {
name: "array != slice", name: "array != slice",
args: args{first: [2]int{1, 2}, second: []int{1, 2}}, args: args{first: [2]int{1, 2}, second: []int{1, 2}},
assertion: False, same: False,
ok: False,
},
{
name: "non-pointer vs pointer (1 != ptr(2))",
args: args{first: 1, second: p},
same: False,
ok: False,
},
{
name: "pointer vs non-pointer (ptr(2) != 1)",
args: args{first: p, second: 1},
same: False,
ok: False,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, samePointers(tt.args.first, tt.args.second)) same, ok := samePointers(tt.args.first, tt.args.second)
tt.same(t, same)
tt.ok(t, ok)
}) })
} }
} }