github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/diff/apply_patch_test.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2016 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  package diff
    23  
    24  import (
    25  	"context"
    26  	"testing"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  
    31  	"github.com/dolthub/dolt/go/store/chunks"
    32  	"github.com/dolthub/dolt/go/store/d"
    33  	"github.com/dolthub/dolt/go/store/marshal"
    34  	"github.com/dolthub/dolt/go/store/types"
    35  )
    36  
    37  func mustValue(v types.Value, err error) types.Value {
    38  	d.PanicIfError(err)
    39  	return v
    40  }
    41  
    42  func mustGetValue(v types.Value, found bool, err error) types.Value {
    43  	d.PanicIfError(err)
    44  	d.PanicIfFalse(found)
    45  	return v
    46  }
    47  
    48  func TestCommonPrefixCount(t *testing.T) {
    49  	assert := assert.New(t)
    50  
    51  	testCases := [][]interface{}{
    52  		{".value[#94a2oa20oka0jdv5lha03vuvvumul1vb].sizes[#316j9oc39b09fbc2qf3klenm6p1o1d7h]", 0},
    53  		{".value[#94a2oa20oka0jdv5lha03vuvvumul1vb].sizes[#77eavttned7llu1pkvhaei9a9qgcagir]", 3},
    54  		{".value[#94a2oa20oka0jdv5lha03vuvvumul1vb].sizes[#hboaq9581drq4g9jf62d3s06al3us49s]", 3},
    55  		{".value[#94a2oa20oka0jdv5lha03vuvvumul1vb].sizes[#l0hpa7sbr7qutrcfn5173kar4j2847m1]", 3},
    56  		{".value[#9vj5m3049mav94bttcujhgfdfqcavsbn].sizes[#33f6tb4h8agh57s2bqlmi9vbhlkbtmct]", 1},
    57  		{".value[#9vj5m3049mav94bttcujhgfdfqcavsbn].sizes[#a43ne9a8kotcqph4up5pqqdmr1e1qcsl]", 3},
    58  		{".value[#9vj5m3049mav94bttcujhgfdfqcavsbn].sizes[#ppqg6pem2sb64h2i2ptnh8ckj8gogj9h]", 3},
    59  		{".value[#9vj5m3049mav94bttcujhgfdfqcavsbn].sizes[#s7r2vpnqlk20sd72mg8ijerg9cmauaqo]", 3},
    60  		{".value[#bpspmmlc41pk0r144a7682oah0tmge1e].sizes[#9vuc1gg3c3eude5v3j5deqopjsobe3no]", 1},
    61  		{".value[#bpspmmlc41pk0r144a7682oah0tmge1e].sizes[#qo3gfdsf14v3dh0oer82vn1bg4o8nlsc]", 3},
    62  		{".value[#bpspmmlc41pk0r144a7682oah0tmge1e].sizes[#rlidki5ipbjdofsm2rq3a66v908m5fpl]", 3},
    63  		{".value[#bpspmmlc41pk0r144a7682oah0tmge1e].sizes[#st1n96rh89c2vgo090dt9lknd5ip4kck]", 3},
    64  		{".value[#hjh5hpn55591k0gjvgckc14erli968ao].sizes[#267889uv3mtih6fij3fhio2jiqtl6nho]", 1},
    65  		{".value[#hjh5hpn55591k0gjvgckc14erli968ao].sizes[#7ncb7guoip9e400bm2lcvr0dda29o9jn]", 3},
    66  		{".value[#hjh5hpn55591k0gjvgckc14erli968ao].sizes[#afscb0on7rt8bq6eutup8juusmid7i96]", 3},
    67  		{".value[#hjh5hpn55591k0gjvgckc14erli968ao].sizes[#drqe4lr0vdfdtmvejsjun1l3mfv6ums5]", 3},
    68  	}
    69  
    70  	var lastPath types.Path
    71  
    72  	for i, tc := range testCases {
    73  		path, expected := tc[0].(string), tc[1].(int)
    74  		p, err := types.ParsePath(path)
    75  		require.NoError(t, err)
    76  		assert.Equal(expected, commonPrefixCount(lastPath, p), "failed for paths[%d]: %s", i, path)
    77  		lastPath = p
    78  	}
    79  }
    80  
    81  type testFunc func(parent types.Value) types.Value
    82  type testKey struct {
    83  	X, Y int
    84  }
    85  
    86  var (
    87  	vm map[string]types.Value
    88  )
    89  
    90  func vfk(keys ...string) []types.Value {
    91  	var values []types.Value
    92  	for _, k := range keys {
    93  		values = append(values, vm[k])
    94  	}
    95  	return values
    96  }
    97  
    98  func testValues(vrw types.ValueReadWriter) map[string]types.Value {
    99  	if vm == nil {
   100  		vm = map[string]types.Value{
   101  			"k1":      types.String("k1"),
   102  			"k2":      types.String("k2"),
   103  			"k3":      types.String("k3"),
   104  			"s1":      types.String("string1"),
   105  			"s2":      types.String("string2"),
   106  			"s3":      types.String("string3"),
   107  			"s4":      types.String("string4"),
   108  			"n1":      types.Float(1),
   109  			"n2":      types.Float(2),
   110  			"n3":      types.Float(3.3),
   111  			"n4":      types.Float(4.4),
   112  			"b1":      mustMarshal(true),
   113  			"b2":      mustMarshal(false),
   114  			"l1":      mustMarshal([]string{}),
   115  			"l2":      mustMarshal([]string{"one", "two", "three", "four"}),
   116  			"l3":      mustMarshal([]string{"two", "three", "four", "five"}),
   117  			"l4":      mustMarshal([]string{"two", "three", "four"}),
   118  			"l5":      mustMarshal([]string{"one", "two", "three", "four", "five"}),
   119  			"l6":      mustMarshal([]string{"one", "four"}),
   120  			"struct1": mustValue(types.NewStruct(vrw.Format(), "test1", types.StructData{"f1": types.Float(1), "f2": types.Float(2)})),
   121  			"struct2": mustValue(types.NewStruct(vrw.Format(), "test1", types.StructData{"f1": types.Float(11111), "f2": types.Float(2)})),
   122  			"struct3": mustValue(types.NewStruct(vrw.Format(), "test1", types.StructData{"f1": types.Float(1), "f2": types.Float(2), "f3": types.Float(3)})),
   123  			"struct4": mustValue(types.NewStruct(vrw.Format(), "test1", types.StructData{"f2": types.Float(2)})),
   124  			"m1":      mustMarshal(map[string]int{}),
   125  			"m2":      mustMarshal(map[string]int{"k1": 1, "k2": 2, "k3": 3}),
   126  			"m3":      mustMarshal(map[string]int{"k2": 2, "k3": 3, "k4": 4}),
   127  			"m4":      mustMarshal(map[string]int{"k1": 1, "k3": 3}),
   128  			"m5":      mustMarshal(map[string]int{"k1": 1, "k2": 2222, "k3": 3}),
   129  			"ms1":     mustMarshal(map[testKey]int{{1, 1}: 1, {2, 2}: 2, {3, 3}: 3}),
   130  			"ms2":     mustMarshal(map[testKey]int{{1, 1}: 1, {4, 4}: 4, {5, 5}: 5}),
   131  		}
   132  
   133  		vm["mh1"] = mustValue(types.NewMap(context.Background(), vrw, vfk("k1", "struct1", "k2", "l1")...))
   134  		vm["mh2"] = mustValue(types.NewMap(context.Background(), vrw, vfk("k1", "n1", "k2", "l2", "k3", "l3")...))
   135  		vm["set1"] = mustValue(types.NewSet(context.Background(), vrw))
   136  		vm["set2"] = mustValue(types.NewSet(context.Background(), vrw, vfk("s1", "s2")...))
   137  		vm["set3"] = mustValue(types.NewSet(context.Background(), vrw, vfk("s1", "s2", "s3")...))
   138  		vm["set1"] = mustValue(types.NewSet(context.Background(), vrw, vfk("s2")...))
   139  		vm["seth1"] = mustValue(types.NewSet(context.Background(), vrw, vfk("struct1", "struct2", "struct3")...))
   140  		vm["seth2"] = mustValue(types.NewSet(context.Background(), vrw, vfk("struct2", "struct3")...))
   141  		vm["setj3"] = mustValue(types.NewSet(context.Background(), vrw, vfk("struct1")...))
   142  		vm["mk1"] = mustValue(types.NewMap(context.Background(), vrw, vfk("struct1", "s1", "struct2", "s2")...))
   143  		vm["mk2"] = mustValue(types.NewMap(context.Background(), vrw, vfk("struct1", "s3", "struct4", "s4")...))
   144  	}
   145  	return vm
   146  }
   147  
   148  func newTestValueStore() *types.ValueStore {
   149  	st := &chunks.TestStorage{}
   150  	return types.NewValueStore(st.NewViewWithDefaultFormat())
   151  }
   152  
   153  func getPatch(g1, g2 types.Value) (Patch, error) {
   154  	var derr error
   155  	dChan := make(chan Difference)
   156  	go func() {
   157  		defer close(dChan)
   158  		derr = Diff(context.Background(), g1, g2, dChan, true, nil)
   159  	}()
   160  
   161  	patch := Patch{}
   162  	for dif := range dChan {
   163  		patch = append(patch, dif)
   164  	}
   165  
   166  	return patch, derr
   167  }
   168  
   169  func checkApplyPatch(assert *assert.Assertions, vrw types.ValueReadWriter, g1, expectedG2 types.Value, k1, k2 string) {
   170  	patch, err := getPatch(g1, expectedG2)
   171  	assert.NoError(err)
   172  	g2, err := Apply(context.Background(), vrw, g1, patch)
   173  	assert.NoError(err)
   174  	assert.True(expectedG2.Equals(g2), "failed to apply diffs for k1: %s and k2: %s", k1, k2)
   175  }
   176  
   177  func TestPatches(t *testing.T) {
   178  	assert := assert.New(t)
   179  
   180  	vs := newTestValueStore()
   181  	defer vs.Close()
   182  
   183  	cnt := 0
   184  	for k1, g1 := range testValues(vs) {
   185  		for k2, expectedG2 := range testValues(vs) {
   186  			if k1 != k2 {
   187  				cnt++
   188  				checkApplyPatch(assert, vs, g1, expectedG2, k1, k2)
   189  			}
   190  		}
   191  	}
   192  }
   193  
   194  func TestNestedLists(t *testing.T) {
   195  	assert := assert.New(t)
   196  
   197  	vs := newTestValueStore()
   198  	defer vs.Close()
   199  
   200  	ol1 := mustMarshal([]string{"one", "two", "three", "four"})
   201  	nl1 := mustMarshal([]string{"two", "three"})
   202  	ol2 := mustMarshal([]int{2, 3})
   203  	nl2 := mustMarshal([]int{1, 2, 3, 4})
   204  	nl3 := mustMarshal([]bool{true, false, true})
   205  	g1 := mustValue(types.NewList(context.Background(), vs, ol1, ol2))
   206  	g2 := mustValue(types.NewList(context.Background(), vs, nl1, nl2, nl3))
   207  	checkApplyPatch(assert, vs, g1, g2, "g1", "g2")
   208  }
   209  
   210  func TestUpdateNode(t *testing.T) {
   211  	assert := assert.New(t)
   212  
   213  	vs := newTestValueStore()
   214  	defer vs.Close()
   215  
   216  	doTest := func(pp types.PathPart, parent, ov, nv, exp types.Value, f testFunc) {
   217  		stack := &patchStack{}
   218  		se := &stackElem{path: []types.PathPart{pp}, pathPart: pp, changeType: types.DiffChangeModified, oldValue: ov, newValue: nv}
   219  		updated, err := stack.updateNode(context.Background(), se, parent)
   220  		require.NoError(t, err)
   221  		testVal := f(updated)
   222  		assert.True(exp.Equals(testVal), "%s != %s", nv, testVal)
   223  	}
   224  
   225  	var pp types.PathPart
   226  	oldVal := types.String("Yo")
   227  	newVal := types.String("YooHoo")
   228  
   229  	s1, err := types.NewStruct(vs.Format(), "TestStruct", types.StructData{"f1": types.Float(1), "f2": oldVal})
   230  	require.NoError(t, err)
   231  	pp = types.FieldPath{Name: "f2"}
   232  	doTest(pp, s1, oldVal, newVal, newVal, func(parent types.Value) types.Value {
   233  		return mustGetValue(parent.(types.Struct).MaybeGet("f2"))
   234  	})
   235  
   236  	l1, err := types.NewList(context.Background(), vs, types.String("one"), oldVal, types.String("three"))
   237  	require.NoError(t, err)
   238  	pp = types.IndexPath{Index: types.Float(1)}
   239  	doTest(pp, l1, oldVal, newVal, newVal, func(parent types.Value) types.Value {
   240  		return mustValue(parent.(types.List).Get(context.Background(), 1))
   241  	})
   242  
   243  	m1, err := types.NewMap(context.Background(), vs, types.String("k1"), types.Float(1), types.String("k2"), oldVal)
   244  	require.NoError(t, err)
   245  	pp = types.IndexPath{Index: types.String("k2")}
   246  	doTest(pp, m1, oldVal, newVal, newVal, func(parent types.Value) types.Value {
   247  		return mustGetValue(parent.(types.Map).MaybeGet(context.Background(), types.String("k2")))
   248  	})
   249  
   250  	k1, err := types.NewStruct(vs.Format(), "Sizes", types.StructData{"height": types.Float(200), "width": types.Float(300)})
   251  	require.NoError(t, err)
   252  	_, err = vs.WriteValue(context.Background(), k1)
   253  	require.NoError(t, err)
   254  	m1, err = types.NewMap(context.Background(), vs, k1, oldVal)
   255  	require.NoError(t, err)
   256  	h, err := k1.Hash(vs.Format())
   257  	require.NoError(t, err)
   258  	pp = types.HashIndexPath{Hash: h}
   259  	doTest(pp, m1, oldVal, newVal, newVal, func(parent types.Value) types.Value {
   260  		return mustGetValue(parent.(types.Map).MaybeGet(context.Background(), k1))
   261  	})
   262  
   263  	set1, err := types.NewSet(context.Background(), vs, oldVal, k1)
   264  	require.NoError(t, err)
   265  	pp = types.IndexPath{Index: oldVal}
   266  	exp, err := types.NewSet(context.Background(), vs, newVal, k1)
   267  	require.NoError(t, err)
   268  	doTest(pp, set1, oldVal, newVal, exp, func(parent types.Value) types.Value {
   269  		return parent
   270  	})
   271  
   272  	k2, err := types.NewStruct(vs.Format(), "Sizes", types.StructData{"height": types.Float(300), "width": types.Float(500)})
   273  	require.NoError(t, err)
   274  	set1, err = types.NewSet(context.Background(), vs, oldVal, k1)
   275  	require.NoError(t, err)
   276  	h, err = k1.Hash(vs.Format())
   277  	require.NoError(t, err)
   278  	pp = types.HashIndexPath{Hash: h}
   279  	exp, err = types.NewSet(context.Background(), vs, oldVal, k2)
   280  	require.NoError(t, err)
   281  	doTest(pp, set1, k1, k2, exp, func(parent types.Value) types.Value {
   282  		return parent
   283  	})
   284  }
   285  
   286  func checkApplyDiffs(a *assert.Assertions, vrw types.ValueReadWriter, n1, n2 types.Value, leftRight bool) {
   287  	var derr error
   288  	dChan := make(chan Difference)
   289  	go func() {
   290  		defer close(dChan)
   291  		derr = Diff(context.Background(), n1, n2, dChan, leftRight, nil)
   292  	}()
   293  
   294  	difs := Patch{}
   295  	for dif := range dChan {
   296  		difs = append(difs, dif)
   297  	}
   298  
   299  	a.NoError(derr)
   300  
   301  	res, err := Apply(context.Background(), vrw, n1, difs)
   302  	a.NoError(err)
   303  	a.True(n2.Equals(res))
   304  }
   305  
   306  func tryApplyDiff(a *assert.Assertions, vrw types.ValueReadWriter, a1, a2 interface{}) {
   307  	n1 := mustMarshal(a1)
   308  	n2 := mustMarshal(a2)
   309  
   310  	checkApplyDiffs(a, vrw, n1, n2, true)
   311  	checkApplyDiffs(a, vrw, n1, n2, false)
   312  	checkApplyDiffs(a, vrw, n2, n1, true)
   313  	checkApplyDiffs(a, vrw, n2, n1, false)
   314  }
   315  
   316  func TestUpdateList(t *testing.T) {
   317  	a := assert.New(t)
   318  	vs := newTestValueStore()
   319  	defer vs.Close()
   320  
   321  	// insert at beginning
   322  	a1 := []interface{}{"five", "ten", "fifteen"}
   323  	a2 := []interface{}{"one", "two", "three", "five", "ten", "fifteen"}
   324  	tryApplyDiff(a, vs, a1, a2)
   325  
   326  	// append at end
   327  	a1 = []interface{}{"five", "ten", "fifteen"}
   328  	a2 = []interface{}{"five", "ten", "fifteen", "twenty", "twenty-five"}
   329  	tryApplyDiff(a, vs, a1, a2)
   330  
   331  	// insert interleaved
   332  	a1 = []interface{}{"one", "three", "five", "seven"}
   333  	a2 = []interface{}{"one", "two", "three", "four", "five", "six", "seven"}
   334  	tryApplyDiff(a, vs, a1, a2)
   335  
   336  	// delete from beginning and append to end
   337  	a1 = []interface{}{"one", "two", "three", "four", "five"}
   338  	a2 = []interface{}{"four", "five", "six", "seven"}
   339  	tryApplyDiff(a, vs, a1, a2)
   340  
   341  	// replace entries at beginning
   342  	a1 = []interface{}{"one", "two", "three", "four", "five"}
   343  	a2 = []interface{}{"3.5", "four", "five"}
   344  	tryApplyDiff(a, vs, a1, a2)
   345  
   346  	// replace entries at end
   347  	a1 = []interface{}{"one", "two", "three"}
   348  	a2 = []interface{}{"one", "four"}
   349  	tryApplyDiff(a, vs, a1, a2)
   350  
   351  	// insert at beginning, replace at end
   352  	a1 = []interface{}{"five", "ten", "fifteen"}
   353  	a2 = []interface{}{"one", "two", "five", "eight", "eleven", "sixteen", "twenty"}
   354  	tryApplyDiff(a, vs, a1, a2)
   355  
   356  	// remove everything
   357  	a1 = []interface{}{"five", "ten", "fifteen"}
   358  	a2 = []interface{}{}
   359  	tryApplyDiff(a, vs, a1, a2)
   360  }
   361  
   362  func TestUpdateMap(t *testing.T) {
   363  	a := assert.New(t)
   364  	vs := newTestValueStore()
   365  	defer vs.Close()
   366  
   367  	// insertions, deletions, and replacements
   368  	a1 := map[string]int{"five": 5, "ten": 10, "fifteen": 15, "twenty": 20}
   369  	a2 := map[string]int{"one": 1, "two": 2, "three": 3, "five": 5, "ten": 10, "fifteen": 15, "twenty": 2020}
   370  	tryApplyDiff(a, vs, a1, a2)
   371  
   372  	// delete everything
   373  	a1 = map[string]int{"five": 5, "ten": 10, "fifteen": 15, "twenty": 20}
   374  	a2 = map[string]int{}
   375  	tryApplyDiff(a, vs, a1, a2)
   376  }
   377  
   378  func TestUpdateStruct(t *testing.T) {
   379  	a := assert.New(t)
   380  	vs := newTestValueStore()
   381  	defer vs.Close()
   382  
   383  	a1 := mustValue(types.NewStruct(vs.Format(), "tStruct", types.StructData{
   384  		"f1": types.Float(1),
   385  		"f2": types.String("two"),
   386  		"f3": mustMarshal([]string{"one", "two", "three"}),
   387  	}))
   388  	a2 := mustValue(types.NewStruct(vs.Format(), "tStruct", types.StructData{
   389  		"f1": types.Float(2),
   390  		"f2": types.String("twotwo"),
   391  		"f3": mustMarshal([]interface{}{0, "one", 1, "two", 2, "three", 3}),
   392  	}))
   393  	checkApplyDiffs(a, vs, a1, a2, true)
   394  	checkApplyDiffs(a, vs, a1, a2, false)
   395  
   396  	a2 = mustValue(types.NewStruct(vs.Format(), "tStruct", types.StructData{
   397  		"f1": types.Float(2),
   398  		"f2": types.String("two"),
   399  		"f3": mustMarshal([]interface{}{0, "one", 1, "two", 2, "three", 3}),
   400  		"f4": types.Bool(true),
   401  	}))
   402  	checkApplyDiffs(a, vs, a1, a2, true)
   403  	checkApplyDiffs(a, vs, a1, a2, false)
   404  }
   405  
   406  func TestUpdateSet(t *testing.T) {
   407  	a := assert.New(t)
   408  
   409  	vs := newTestValueStore()
   410  	defer vs.Close()
   411  
   412  	a1 := mustValue(types.NewSet(context.Background(), vs, types.Float(1), types.String("two"), mustMarshal([]string{"one", "two", "three"})))
   413  	a2 := mustValue(types.NewSet(context.Background(), vs, types.Float(3), types.String("three"), mustMarshal([]string{"one", "two", "three", "four"})))
   414  
   415  	checkApplyDiffs(a, vs, a1, a2, true)
   416  	checkApplyDiffs(a, vs, a1, a2, false)
   417  	checkApplyDiffs(a, vs, a2, a1, true)
   418  	checkApplyDiffs(a, vs, a2, a1, false)
   419  }
   420  
   421  func mustMarshal(v interface{}) types.Value {
   422  	vs := newTestValueStore()
   423  	defer vs.Close()
   424  
   425  	v1, err := marshal.Marshal(context.Background(), vs, v)
   426  	d.Chk.NoError(err)
   427  	return v1
   428  }