diff --git a/diff/diff.go b/diff/diff.go index cd7c50d..2ff2591 100644 --- a/diff/diff.go +++ b/diff/diff.go @@ -190,7 +190,7 @@ func (v *visited) add(lhs, rhs reflect.Value) error { } v.lhs = append(v.lhs, lhs.Pointer()) } - if canAddr(rhs) && !isEmptyMapOrSlice(lhs) { + if canAddr(rhs) && !isEmptyMapOrSlice(rhs) { if inPointers(v.rhs, rhs) { return ErrCyclic } diff --git a/diff/diff_test.go b/diff/diff_test.go index 0d47625..ebb4159 100644 --- a/diff/diff_test.go +++ b/diff/diff_test.go @@ -616,6 +616,9 @@ func TestCircular(t *testing.T) { 0: "foo", }, }, + 1: []interface{}{ + "bar", "baz", + }, } emptySlice := map[int]interface{}{ 0: []interface{}{}, @@ -634,6 +637,11 @@ func TestCircular(t *testing.T) { 1: map[int]interface{}{}, } + repeatingNotCyclic := map[int]interface{}{ + 0: []interface{}{"foo", "bar"}, + } + repeatingNotCyclic[1] = repeatingNotCyclic[0] + for _, test := range []struct { lhs interface{} rhs interface{} @@ -641,14 +649,20 @@ func TestCircular(t *testing.T) { }{ {lhs: first, rhs: first, wantError: true}, {lhs: first, rhs: second, wantError: true}, - {lhs: first, rhs: second, wantError: true}, {lhs: first, rhs: notCyclic, wantError: true}, {lhs: notCyclic, rhs: first, wantError: true}, + {lhs: notCyclic, rhs: emptySlice}, + {lhs: notCyclic, rhs: emptyMap}, {lhs: notCyclic, rhs: notCyclic}, {lhs: emptySlice, rhs: emptySliceNotRepeating}, {lhs: emptySliceNotRepeating, rhs: emptySlice}, {lhs: emptyMap, rhs: emptyMapNotRepeating}, {lhs: emptyMapNotRepeating, rhs: emptyMap}, + + // Known limitation: our circular reference detection can + // give false-positive when an addressable value is repeated + // in a non-circular pattern. + {lhs: notCyclic, rhs: repeatingNotCyclic, wantError: true}, } { d, err := Diff(test.lhs, test.rhs)