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  }