Skip to content

Commit

Permalink
fix: difference deadloop
Browse files Browse the repository at this point in the history
  • Loading branch information
sirkon committed Jun 10, 2023
1 parent 7344f22 commit 19717a2
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 7 deletions.
25 changes: 20 additions & 5 deletions difference.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import (
)

// Builds a difference between left and right values.
func difference(l, r reflect.Value, isProto bool) diff.Diff {
func difference(l, r reflect.Value, isProto bool, stack walkSet) diff.Diff {
if !stack.use(l) {
return nil
}

if !l.IsValid() {
panic(fmt.Errorf("left is %s", l.String()))
}
Expand Down Expand Up @@ -69,7 +73,7 @@ func difference(l, r reflect.Value, isProto bool) diff.Diff {
continue
}

if v := difference(l.MapIndex(key), rv, isProto); v != nil {
if v := difference(l.MapIndex(key), rv, isProto, stack); v != nil {
res.Left[key.Interface()] = v
}
}
Expand All @@ -81,7 +85,7 @@ func difference(l, r reflect.Value, isProto bool) diff.Diff {
continue
}

if v := difference(lv, r.MapIndex(key), isProto); v != nil {
if v := difference(lv, r.MapIndex(key), isProto, stack); v != nil {
res.Right[key.Interface()] = v
}
}
Expand All @@ -101,7 +105,7 @@ func difference(l, r reflect.Value, isProto bool) diff.Diff {
fl := getField(l, i)
fr := getField(r, i)

if v := difference(fl, fr, isProto); v != nil {
if v := difference(fl, fr, isProto, stack); v != nil {
res.Fields[l.Type().Field(i).Name] = v
}
}
Expand All @@ -113,7 +117,7 @@ func difference(l, r reflect.Value, isProto bool) diff.Diff {
}

_, isProto = l.Interface().(proto.Message)
return difference(l.Elem(), r.Elem(), isProto)
return difference(l.Elem(), r.Elem(), isProto, stack)

default:
panic(fmt.Errorf("cannot diff values of %T", l.Interface()))
Expand Down Expand Up @@ -162,3 +166,14 @@ func findUncommon(src, known reflect.Value) map[int]diff.Diff {

return info
}

type walkSet map[reflect.Value]struct{}

// use adds a new value into the set. Returns false
// if this value existed before the call and true
// otherwise.
func (s walkSet) use(v reflect.Value) bool {
_, ok := s[v]
s[v] = struct{}{}
return !ok
}
2 changes: 1 addition & 1 deletion difference_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ func TestDifference(t *testing.T) {
t.Error("panic was expected")
}()
}
got := difference(reflect.ValueOf(ttt.a), reflect.ValueOf(ttt.b), false)
got := difference(reflect.ValueOf(ttt.a), reflect.ValueOf(ttt.b), false, walkSet{})
if !reflect.DeepEqual(got, ttt.want) {
t.Error("want\n", spew.Sdump(ttt.want), "\ngot\n", spew.Sdump(got))
}
Expand Down
2 changes: 1 addition & 1 deletion sidebyside.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func linePrefix() string {
}

func printDiff(p TestPrinter, l, r reflect.Value) {
diff := difference(l, r, false)
diff := difference(l, r, false, walkSet{})

lp := newPrinter(true)
lp.printValue("", l, diff, false, true, map[uintptr]struct{}{})
Expand Down

0 comments on commit 19717a2

Please sign in to comment.