diff --git a/diff/diff.go b/diff/diff.go index 293e382..4b5d37c 100644 --- a/diff/diff.go +++ b/diff/diff.go @@ -18,10 +18,11 @@ package diff import ( "fmt" + "sort" + "github.com/google/go-cmp/cmp" "github.com/rkosegi/yaml-toolkit/dom" "github.com/rkosegi/yaml-toolkit/utils" - "sort" ) type ModificationType string @@ -153,3 +154,25 @@ func Diff(left, right dom.Container) *[]Modification { sortMods(mods) return &mods } + +// OverlayDocs computes semantic difference between 2 Overlay documents +func OverlayDocs(left, right dom.OverlayDocument) map[string]*[]Modification { + res := make(map[string]*[]Modification) + lmap := left.Layers() + rmap := right.Layers() + for ln, ll := range lmap { + if rl, ok := rmap[ln]; ok { + res[ln] = Diff(ll, rl) + } else { + res[ln] = Diff(ll, dom.Builder().Container()) + } + } + for rn, rl := range rmap { + if ll, ok := lmap[rn]; ok { + res[rn] = Diff(ll, rl) + } else { + res[rn] = Diff(dom.Builder().Container(), rl) + } + } + return res +} diff --git a/diff/diff_test.go b/diff/diff_test.go index 3f54292..a4f4813 100644 --- a/diff/diff_test.go +++ b/diff/diff_test.go @@ -18,12 +18,13 @@ package diff import ( "bytes" + "strings" + "testing" + "github.com/google/go-cmp/cmp" "github.com/rkosegi/yaml-toolkit/dom" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" - "strings" - "testing" ) func leavesEqual(l1, l2 interface{}) bool { @@ -277,3 +278,60 @@ root: - item1`) assert.Equal(t, 0, len(*res)) } + +func TestDiffOverlayDocuments(t *testing.T) { + var ( + cb dom.ContainerBuilder + ) + left := dom.NewOverlayDocument() + cb = dom.Builder().Container() + cb.AddValueAt("a.b.c", dom.LeafNode(1)) + left.Add("layer1", cb) + cb = dom.Builder().Container() + cb.AddValueAt("a.b.d", dom.LeafNode("xyz")) + left.Add("layer2", cb) + cb = dom.Builder().Container() + cb.AddValue("something", dom.LeafNode("A")) + left.Add("layer3", cb) + + right := dom.NewOverlayDocument() + cb = dom.Builder().Container() + cb.AddValueAt("a.b.c", dom.LeafNode(2)) + right.Add("layer1", cb) + cb = dom.Builder().Container() + cb.AddValue("hello", dom.LeafNode("Hi!")) + right.Add("layer2", cb) + cb = dom.Builder().Container() + cb.AddValue("hello", dom.LeafNode("Aloha!")) + right.Add("layer4", cb) + + res := OverlayDocs(left, right) + for k, v := range res { + t.Logf("%s: %v", k, v) + } + + assert.Equal(t, 4, len(res)) + assertHasChange(t, Modification{ + Type: ModChange, + Path: "a.b.c", + OldValue: 1, + Value: 2, + }, res["layer1"]) + + assertHasChange(t, Modification{ + Type: ModAdd, + Path: "a.b.d", + Value: "xyz", + }, res["layer2"]) + + assertHasChange(t, Modification{ + Type: ModDelete, + Path: "hello", + }, res["layer2"]) + + assertHasChange(t, Modification{ + Type: ModAdd, + Path: "something", + Value: "A", + }, res["layer3"]) +}