github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/go/merge/three_way_keyval_test.go (about) 1 // Copyright 2016 Attic Labs, Inc. All rights reserved. 2 // Licensed under the Apache License, version 2.0: 3 // http://www.apache.org/licenses/LICENSE-2.0 4 5 package merge 6 7 import ( 8 "testing" 9 10 "github.com/attic-labs/noms/go/types" 11 "github.com/stretchr/testify/suite" 12 ) 13 14 func TestThreeWayMapMerge(t *testing.T) { 15 suite.Run(t, &ThreeWayMapMergeSuite{}) 16 } 17 18 func TestThreeWayStructMerge(t *testing.T) { 19 suite.Run(t, &ThreeWayStructMergeSuite{}) 20 } 21 22 type kvs []interface{} 23 24 func (kv kvs) items() []interface{} { 25 return kv 26 } 27 28 func (kv kvs) remove(k interface{}) kvs { 29 out := make(kvs, 0, len(kv)) 30 for i := 0; i < len(kv); i += 2 { 31 if kv[i] != k { 32 out = append(out, kv[i], kv[i+1]) 33 } 34 } 35 return out 36 } 37 38 func (kv kvs) set(k, v interface{}) kvs { 39 out := make(kvs, len(kv)) 40 for i := 0; i < len(kv); i += 2 { 41 out[i], out[i+1] = kv[i], kv[i+1] 42 if kv[i] == k { 43 out[i+1] = v 44 } 45 } 46 return out 47 } 48 49 var ( 50 aa1 = kvs{"a1", "a-one", "a2", "a-two", "a3", "a-three", "a4", "a-four"} 51 aa1a = kvs{"a1", "a-one", "a2", "a-two", "a3", "a-three-diff", "a4", "a-four", "a6", "a-six"} 52 aa1b = kvs{"a1", "a-one", "a3", "a-three-diff", "a4", "a-four", "a5", "a-five"} 53 aaMerged = kvs{"a1", "a-one", "a3", "a-three-diff", "a4", "a-four", "a5", "a-five", "a6", "a-six"} 54 55 mm1 = kvs{} 56 mm1a = kvs{"k1", kvs{"a", 0}} 57 mm1b = kvs{"k1", kvs{"b", 1}} 58 mm1Merged = kvs{"k1", kvs{"a", 0, "b", 1}} 59 60 mm2 = kvs{"k2", aa1, "k3", "k-three"} 61 mm2a = kvs{"k1", kvs{"a", 0}, "k2", aa1a, "k3", "k-three", "k4", "k-four"} 62 mm2b = kvs{"k1", kvs{"b", 1}, "k2", aa1b} 63 mm2Merged = kvs{"k1", kvs{"a", 0, "b", 1}, "k2", aaMerged, "k4", "k-four"} 64 ) 65 66 type ThreeWayKeyValMergeSuite struct { 67 ThreeWayMergeSuite 68 } 69 70 type ThreeWayMapMergeSuite struct { 71 ThreeWayKeyValMergeSuite 72 } 73 74 func (s *ThreeWayMapMergeSuite) SetupSuite() { 75 s.create = func(seq seq) (val types.Value) { 76 if seq != nil { 77 keyValues := valsToTypesValues(s.create, seq.items()...) 78 val = types.NewMap(s.vs, keyValues...) 79 } 80 return 81 } 82 s.typeStr = "Map" 83 } 84 85 type ThreeWayStructMergeSuite struct { 86 ThreeWayKeyValMergeSuite 87 } 88 89 func (s *ThreeWayStructMergeSuite) SetupSuite() { 90 s.create = func(seq seq) (val types.Value) { 91 if seq != nil { 92 kv := seq.items() 93 fields := types.StructData{} 94 for i := 0; i < len(kv); i += 2 { 95 fields[kv[i].(string)] = valToTypesValue(s.create, kv[i+1]) 96 } 97 val = types.NewStruct("TestStruct", fields) 98 } 99 return 100 } 101 s.typeStr = "Struct" 102 } 103 104 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_DoNothing() { 105 s.tryThreeWayMerge(nil, nil, aa1, aa1) 106 } 107 108 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_NoRecursion() { 109 s.tryThreeWayMerge(aa1a, aa1b, aa1, aaMerged) 110 s.tryThreeWayMerge(aa1b, aa1a, aa1, aaMerged) 111 } 112 113 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_RecursiveCreate() { 114 s.tryThreeWayMerge(mm1a, mm1b, mm1, mm1Merged) 115 s.tryThreeWayMerge(mm1b, mm1a, mm1, mm1Merged) 116 } 117 118 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_RecursiveCreateNil() { 119 s.tryThreeWayMerge(mm1a, mm1b, nil, mm1Merged) 120 s.tryThreeWayMerge(mm1b, mm1a, nil, mm1Merged) 121 } 122 123 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_RecursiveMerge() { 124 s.tryThreeWayMerge(mm2a, mm2b, mm2, mm2Merged) 125 s.tryThreeWayMerge(mm2b, mm2a, mm2, mm2Merged) 126 } 127 128 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_RefMerge() { 129 strRef := s.vs.WriteValue(types.NewStruct("Foo", types.StructData{"life": types.Number(42)})) 130 131 m := kvs{"r2", s.vs.WriteValue(s.create(aa1))} 132 ma := kvs{"r1", strRef, "r2", s.vs.WriteValue(s.create(aa1a))} 133 mb := kvs{"r1", strRef, "r2", s.vs.WriteValue(s.create(aa1b))} 134 mMerged := kvs{"r1", strRef, "r2", s.vs.WriteValue(s.create(aaMerged))} 135 136 s.tryThreeWayMerge(ma, mb, m, mMerged) 137 s.tryThreeWayMerge(mb, ma, m, mMerged) 138 } 139 140 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_RecursiveMultiLevelMerge() { 141 m := kvs{"mm1", mm1, "mm2", s.vs.WriteValue(s.create(mm2))} 142 ma := kvs{"mm1", mm1a, "mm2", s.vs.WriteValue(s.create(mm2a))} 143 mb := kvs{"mm1", mm1b, "mm2", s.vs.WriteValue(s.create(mm2b))} 144 mMerged := kvs{"mm1", mm1Merged, "mm2", s.vs.WriteValue(s.create(mm2Merged))} 145 146 s.tryThreeWayMerge(ma, mb, m, mMerged) 147 s.tryThreeWayMerge(mb, ma, m, mMerged) 148 } 149 150 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_CustomMerge() { 151 p := kvs{"k1", "k-one", "k2", "k-two", "mm1", mm1, "s1", "s-one"} 152 a := kvs{"k1", "k-won", "k2", "k-too", "mm1", mm1, "s1", "s-one", "n1", kvs{"a", "1"}} 153 b := kvs{"k2", "k-two", "mm1", "mm-one", "s1", "s-one", "n1", kvs{"a", "2"}} 154 exp := kvs{"k2", "k-too", "mm1", "mm-one", "s1", "s-one", "n1", kvs{"a", "1"}} 155 156 expectedConflictPaths := [][]string{{"k1"}, {"n1", "a"}} 157 conflictPaths := []types.Path{} 158 resolve := func(aChange, bChange types.DiffChangeType, aVal, bVal types.Value, p types.Path) (change types.DiffChangeType, merged types.Value, ok bool) { 159 conflictPaths = append(conflictPaths, p) 160 if _, ok := aVal.(types.Map); ok || bChange == types.DiffChangeRemoved { 161 return bChange, bVal, true 162 } 163 return aChange, aVal, true 164 } 165 166 merged, err := ThreeWay(s.create(a), s.create(b), s.create(p), s.vs, resolve, nil) 167 if s.NoError(err) { 168 expected := s.create(exp) 169 s.True(expected.Equals(merged), "%s != %s", types.EncodedValue(expected), types.EncodedValue(merged)) 170 } 171 if s.Len(conflictPaths, len(expectedConflictPaths), "Wrong number of conflicts!") { 172 for i := 0; i < len(conflictPaths); i++ { 173 for j, c := range conflictPaths[i] { 174 s.Contains(c.String(), expectedConflictPaths[i][j]) 175 } 176 } 177 } 178 } 179 180 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_MergeOurs() { 181 p := kvs{"k1", "k-one"} 182 a := kvs{"k1", "k-won"} 183 b := kvs{"k1", "k-too", "k2", "k-two"} 184 exp := kvs{"k1", "k-won", "k2", "k-two"} 185 186 merged, err := ThreeWay(s.create(a), s.create(b), s.create(p), s.vs, Ours, nil) 187 if s.NoError(err) { 188 expected := s.create(exp) 189 s.True(expected.Equals(merged), "%s != %s", types.EncodedValue(expected), types.EncodedValue(merged)) 190 } 191 } 192 193 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_MergeTheirs() { 194 p := kvs{"k1", "k-one"} 195 a := kvs{"k1", "k-won"} 196 b := kvs{"k1", "k-too", "k2", "k-two"} 197 exp := kvs{"k1", "k-too", "k2", "k-two"} 198 199 merged, err := ThreeWay(s.create(a), s.create(b), s.create(p), s.vs, Theirs, nil) 200 if s.NoError(err) { 201 expected := s.create(exp) 202 s.True(expected.Equals(merged), "%s != %s", types.EncodedValue(expected), types.EncodedValue(merged)) 203 } 204 } 205 206 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_NilConflict() { 207 s.tryThreeWayConflict(nil, s.create(mm2b), s.create(mm2), "Cannot merge nil Value with") 208 s.tryThreeWayConflict(s.create(mm2a), nil, s.create(mm2), "with nil Value.") 209 } 210 211 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_ImmediateConflict() { 212 s.tryThreeWayConflict(types.NewSet(s.vs), s.create(mm2b), s.create(mm2), "Cannot merge Set<> with "+s.typeStr) 213 s.tryThreeWayConflict(s.create(mm2b), types.NewSet(s.vs), s.create(mm2), "Cannot merge "+s.typeStr) 214 } 215 216 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_RefConflict() { 217 strRef := s.vs.WriteValue(types.NewStruct("Foo", types.StructData{"life": types.Number(42)})) 218 numRef := s.vs.WriteValue(types.Number(7)) 219 220 m := kvs{"r2", strRef} 221 ma := kvs{"r1", strRef, "r2", strRef} 222 mb := kvs{"r1", numRef, "r2", strRef} 223 224 s.tryThreeWayConflict(s.create(ma), s.create(mb), s.create(m), "Cannot merge Struct Foo") 225 s.tryThreeWayConflict(s.create(mb), s.create(ma), s.create(m), "Cannot merge Number and Struct Foo") 226 } 227 228 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_NestedConflict() { 229 a := mm2a.set("k2", types.NewSet(s.vs)) 230 s.tryThreeWayConflict(s.create(a), s.create(mm2b), s.create(mm2), types.EncodedValue(types.NewSet(s.vs))) 231 s.tryThreeWayConflict(s.create(a), s.create(mm2b), s.create(mm2), types.EncodedValue(s.create(aa1b))) 232 } 233 234 func (s *ThreeWayKeyValMergeSuite) TestThreeWayMerge_NestedConflictingOperation() { 235 a := mm2a.remove("k2") 236 s.tryThreeWayConflict(s.create(a), s.create(mm2b), s.create(mm2), `removed "k2"`) 237 s.tryThreeWayConflict(s.create(a), s.create(mm2b), s.create(mm2), `modded "k2"`) 238 }