Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions assert/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ func ObjectsAreEqual(expected, actual interface{}) bool {
// copyExportedFields iterates downward through nested data structures and creates a copy
// that only contains the exported struct fields.
func copyExportedFields(expected interface{}) interface{} {
return copyExportedFieldsWithVisited(expected, make(map[uintptr]bool))
}

func copyExportedFieldsWithVisited(expected interface{}, visited map[uintptr]bool) interface{} {
if isNil(expected) {
return expected
}
Expand All @@ -102,15 +106,20 @@ func copyExportedFields(expected interface{}) interface{} {
if isNil(fieldValue) || isNil(fieldValue.Interface()) {
continue
}
newValue := copyExportedFields(fieldValue.Interface())
newValue := copyExportedFieldsWithVisited(fieldValue.Interface(), visited)
result.Field(i).Set(reflect.ValueOf(newValue))
}
}
return result.Interface()

case reflect.Ptr:
ptr := expectedValue.Pointer()
if visited[ptr] {
return reflect.Zero(expectedType).Interface()
}
visited[ptr] = true
result := reflect.New(expectedType.Elem())
unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface())
unexportedRemoved := copyExportedFieldsWithVisited(expectedValue.Elem().Interface(), visited)
result.Elem().Set(reflect.ValueOf(unexportedRemoved))
return result.Interface()

Expand All @@ -126,7 +135,7 @@ func copyExportedFields(expected interface{}) interface{} {
if isNil(index) {
continue
}
unexportedRemoved := copyExportedFields(index.Interface())
unexportedRemoved := copyExportedFieldsWithVisited(index.Interface(), visited)
result.Index(i).Set(reflect.ValueOf(unexportedRemoved))
}
return result.Interface()
Expand All @@ -135,7 +144,7 @@ func copyExportedFields(expected interface{}) interface{} {
result := reflect.MakeMap(expectedType)
for _, k := range expectedValue.MapKeys() {
index := expectedValue.MapIndex(k)
unexportedRemoved := copyExportedFields(index.Interface())
unexportedRemoved := copyExportedFieldsWithVisited(index.Interface(), visited)
result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved))
}
return result.Interface()
Expand Down
16 changes: 16 additions & 0 deletions assert/assertions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3012,6 +3012,22 @@ Diff:
- B: (int) 10
+ B: (int) 15
}

func TestEqualExportedValuesRecursiveStruct(t *testing.T) {
type Node struct {
Self *Node
}
a := &Node{}
a.Self = a
b := &Node{}
b.Self = b

mockT := new(testing.T)
if !EqualExportedValues(mockT, a, b) {
t.Error("EqualExportedValues should handle recursive structures without stack overflow")
}
}

`

actual = diff(
Expand Down
Loading