github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/diff/diff_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 "bytes" 26 "context" 27 "fmt" 28 "strings" 29 "testing" 30 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 34 "github.com/dolthub/dolt/go/store/d" 35 "github.com/dolthub/dolt/go/store/types" 36 "github.com/dolthub/dolt/go/store/util/test" 37 "github.com/dolthub/dolt/go/store/util/writers" 38 ) 39 40 var ( 41 aa1 = createMap("a1", "a-one", "a2", "a-two", "a3", "a-three", "a4", "a-four") 42 aa1x = createMap("a1", "a-one-diff", "a2", "a-two", "a3", "a-three", "a4", "a-four") 43 44 mm1 = createMap("k1", "k-one", "k2", "k-two", "k3", "k-three", "k4", aa1) 45 mm2 = createMap("l1", "l-one", "l2", "l-two", "l3", "l-three", "l4", aa1) 46 mm3 = createMap("m1", "m-one", "v2", "m-two", "m3", "m-three", "m4", aa1) 47 mm3x = createMap("m1", "m-one", "v2", "m-two", "m3", "m-three-diff", "m4", aa1x) 48 mm4 = createMap("n1", "n-one", "n2", "n-two", "n3", "n-three", "n4", aa1) 49 ) 50 51 func valToTypesValue(v interface{}) types.Value { 52 var v1 types.Value 53 switch t := v.(type) { 54 case string: 55 v1 = types.String(t) 56 case int: 57 v1 = types.Float(t) 58 case types.Value: 59 v1 = t 60 } 61 return v1 62 } 63 64 func valsToTypesValues(kv ...interface{}) []types.Value { 65 keyValues := []types.Value{} 66 for _, e := range kv { 67 v := valToTypesValue(e) 68 keyValues = append(keyValues, v) 69 } 70 return keyValues 71 } 72 73 func createMap(kv ...interface{}) types.Map { 74 vs := newTestValueStore() 75 defer vs.Close() 76 keyValues := valsToTypesValues(kv...) 77 m, err := types.NewMap(context.Background(), vs, keyValues...) 78 d.PanicIfError(err) 79 return m 80 } 81 82 func createSet(kv ...interface{}) types.Set { 83 vs := newTestValueStore() 84 defer vs.Close() 85 keyValues := valsToTypesValues(kv...) 86 s, err := types.NewSet(context.Background(), vs, keyValues...) 87 d.PanicIfError(err) 88 return s 89 } 90 91 func createList(kv ...interface{}) types.List { 92 vs := newTestValueStore() 93 defer vs.Close() 94 keyValues := valsToTypesValues(kv...) 95 l, err := types.NewList(context.Background(), vs, keyValues...) 96 d.PanicIfError(err) 97 return l 98 } 99 100 func createStruct(name string, kv ...interface{}) types.Struct { 101 fields := types.StructData{} 102 for i := 0; i < len(kv); i += 2 { 103 fields[kv[i].(string)] = valToTypesValue(kv[i+1]) 104 } 105 st, err := types.NewStruct(types.Format_7_18, name, fields) 106 d.PanicIfError(err) 107 return st 108 } 109 110 func pathsFromDiff(v1, v2 types.Value, leftRight bool) ([]string, error) { 111 var derr error 112 dChan := make(chan Difference) 113 go func() { 114 defer close(dChan) 115 derr = Diff(context.Background(), v1, v2, dChan, leftRight, nil) 116 }() 117 118 var paths []string 119 for d := range dChan { 120 paths = append(paths, d.Path.String()) 121 } 122 123 return paths, derr 124 } 125 126 func mustParsePath(assert *assert.Assertions, s string) types.Path { 127 if s == "" { 128 return nil 129 } 130 p, err := types.ParsePath(s) 131 assert.NoError(err) 132 return p 133 } 134 135 func TestNomsDiffPrintMap(t *testing.T) { 136 assert := assert.New(t) 137 expected := `["map-3"] { 138 - "m3": "m-three" 139 + "m3": "m-three-diff" 140 } 141 ["map-3"]["m4"] { 142 - "a1": "a-one" 143 + "a1": "a-one-diff" 144 } 145 ` 146 expectedPaths := []string{ 147 `["map-3"]["m3"]`, 148 `["map-3"]["m4"]["a1"]`, 149 } 150 151 tf := func(leftRight bool) { 152 m1 := createMap("map-1", mm1, "map-2", mm2, "map-3", mm3, "map-4", mm4) 153 m2 := createMap("map-1", mm1, "map-2", mm2, "map-3", mm3x, "map-4", mm4) 154 buf := &bytes.Buffer{} 155 PrintDiff(context.Background(), buf, m1, m2, leftRight) 156 assert.Equal(expected, buf.String()) 157 158 paths, err := pathsFromDiff(m1, m2, leftRight) 159 require.NoError(t, err) 160 assert.Equal(expectedPaths, paths) 161 } 162 163 tf(true) 164 tf(false) 165 } 166 167 func TestNomsDiffPrintSet(t *testing.T) { 168 assert := assert.New(t) 169 170 expected1 := `(root) { 171 - "five" 172 + "five-diff" 173 } 174 ` 175 expectedPaths1 := []string{ 176 `["five"]`, 177 `["five-diff"]`, 178 } 179 180 expected2 := `(root) { 181 - map { // 4 items 182 - "m1": "m-one", 183 - "m3": "m-three", 184 - "m4": map { // 4 items 185 - "a1": "a-one", 186 - "a2": "a-two", 187 - "a3": "a-three", 188 - "a4": "a-four", 189 - }, 190 - "v2": "m-two", 191 - } 192 + map { // 4 items 193 + "m1": "m-one", 194 + "m3": "m-three-diff", 195 + "m4": map { // 4 items 196 + "a1": "a-one-diff", 197 + "a2": "a-two", 198 + "a3": "a-three", 199 + "a4": "a-four", 200 + }, 201 + "v2": "m-two", 202 + } 203 } 204 ` 205 h3, err := mm3.Hash(types.Format_7_18) 206 require.NoError(t, err) 207 h3x, err := mm3x.Hash(types.Format_7_18) 208 require.NoError(t, err) 209 expectedPaths2 := []string{ 210 fmt.Sprintf("[#%s]", h3), 211 fmt.Sprintf("[#%s]", h3x), 212 } 213 214 s1 := createSet("one", "three", "five", "seven", "nine") 215 s2 := createSet("one", "three", "five-diff", "seven", "nine") 216 s3 := createSet(mm1, mm2, mm3, mm4) 217 s4 := createSet(mm1, mm2, mm3x, mm4) 218 219 tf := func(leftRight bool) { 220 buf := &bytes.Buffer{} 221 PrintDiff(context.Background(), buf, s1, s2, leftRight) 222 assert.Equal(expected1, buf.String()) 223 224 paths, err := pathsFromDiff(s1, s2, leftRight) 225 require.NoError(t, err) 226 assert.Equal(expectedPaths1, paths) 227 228 buf = &bytes.Buffer{} 229 err = PrintDiff(context.Background(), buf, s3, s4, leftRight) 230 require.NoError(t, err) 231 assert.Equal(expected2, buf.String()) 232 233 paths, err = pathsFromDiff(s3, s4, leftRight) 234 require.NoError(t, err) 235 assert.Equal(expectedPaths2, paths) 236 } 237 238 tf(true) 239 tf(false) 240 } 241 242 // This function tests stop functionality in PrintDiff and Diff. 243 func TestNomsDiffPrintStop(t *testing.T) { 244 assert := assert.New(t) 245 246 expected1 := `(root) { 247 - "five" 248 ` 249 250 expected2 := `(root) { 251 - map { // 4 items 252 ` 253 254 s1 := createSet("one", "three", "five", "seven", "nine") 255 s2 := createSet("one", "three", "five-diff", "seven", "nine") 256 s3 := createSet(mm1, mm2, mm3, mm4) 257 s4 := createSet(mm1, mm2, mm3x, mm4) 258 259 tf := func(leftRight bool) { 260 buf := &bytes.Buffer{} 261 mlw := &writers.MaxLineWriter{Dest: buf, MaxLines: 2} 262 PrintDiff(context.Background(), mlw, s1, s2, leftRight) 263 assert.Equal(expected1, buf.String()) 264 265 buf = &bytes.Buffer{} 266 mlw = &writers.MaxLineWriter{Dest: buf, MaxLines: 2} 267 PrintDiff(context.Background(), mlw, s3, s4, leftRight) 268 assert.Equal(expected2, buf.String()) 269 } 270 271 tf(true) 272 tf(false) 273 } 274 275 func TestNomsDiffPrintStruct(t *testing.T) { 276 assert := assert.New(t) 277 278 expected1 := `(root) { 279 - "four": "four" 280 + "four": "four-diff" 281 } 282 ["three"] { 283 - field1: "field1-data" 284 - field3: "field3-data" 285 + field3: "field3-data-diff" 286 + field4: "field4-data" 287 } 288 ` 289 expectedPaths1 := []string{ 290 `["four"]`, 291 `["three"].field1`, 292 `["three"].field3`, 293 `["three"].field4`, 294 } 295 296 expected2 := `(root) { 297 - four: "four" 298 + four: "four-diff" 299 } 300 .three { 301 - field1: "field1-data" 302 - field3: "field3-data" 303 + field3: "field3-data-diff" 304 + field4: "field4-data" 305 } 306 ` 307 expectedPaths2 := []string{ 308 `.four`, 309 `.three.field1`, 310 `.three.field3`, 311 `.three.field4`, 312 } 313 314 s1 := createStruct("TestData", 315 "field1", "field1-data", 316 "field2", "field2-data", 317 "field3", "field3-data", 318 ) 319 s2 := createStruct("TestData", 320 "field2", "field2-data", 321 "field3", "field3-data-diff", 322 "field4", "field4-data", 323 ) 324 325 m1 := createMap("one", 1, "two", 2, "three", s1, "four", "four") 326 m2 := createMap("one", 1, "two", 2, "three", s2, "four", "four-diff") 327 328 s3 := createStruct("", "one", 1, "two", 2, "three", s1, "four", "four") 329 s4 := createStruct("", "one", 1, "two", 2, "three", s2, "four", "four-diff") 330 331 tf := func(leftRight bool) { 332 buf := &bytes.Buffer{} 333 PrintDiff(context.Background(), buf, m1, m2, leftRight) 334 assert.Equal(expected1, buf.String()) 335 336 paths, err := pathsFromDiff(m1, m2, leftRight) 337 require.NoError(t, err) 338 assert.Equal(expectedPaths1, paths) 339 340 buf = &bytes.Buffer{} 341 err = PrintDiff(context.Background(), buf, s3, s4, leftRight) 342 require.NoError(t, err) 343 assert.Equal(expected2, buf.String()) 344 345 paths, err = pathsFromDiff(s3, s4, leftRight) 346 require.NoError(t, err) 347 assert.Equal(expectedPaths2, paths) 348 } 349 350 tf(true) 351 tf(false) 352 } 353 354 func TestNomsDiffPrintMapWithStructKeys(t *testing.T) { 355 a := assert.New(t) 356 357 vs := newTestValueStore() 358 defer vs.Close() 359 360 k1 := createStruct("TestKey", "name", "n1", "label", "l1") 361 362 expected1 := `(root) { 363 - struct TestKey { 364 - label: "l1", 365 - name: "n1", 366 - }: true 367 + struct TestKey { 368 + label: "l1", 369 + name: "n1", 370 + }: false 371 } 372 ` 373 374 m1, err := types.NewMap(context.Background(), vs, k1, types.Bool(true)) 375 require.NoError(t, err) 376 m2, err := types.NewMap(context.Background(), vs, k1, types.Bool(false)) 377 require.NoError(t, err) 378 tf := func(leftRight bool) { 379 buf := &bytes.Buffer{} 380 PrintDiff(context.Background(), buf, m1, m2, leftRight) 381 a.Equal(expected1, buf.String()) 382 } 383 tf(true) 384 tf(false) 385 } 386 387 func TestNomsDiffPrintList(t *testing.T) { 388 assert := assert.New(t) 389 390 expected1 := `(root) { 391 - 2 392 + 22 393 - 44 394 } 395 ` 396 expectedPaths1 := []string{ 397 `[1]`, 398 `[4]`, 399 } 400 401 l1 := createList(1, 2, 3, 4, 44, 5, 6) 402 l2 := createList(1, 22, 3, 4, 5, 6) 403 404 expected2 := `(root) { 405 + "seven" 406 } 407 ` 408 expectedPaths2 := []string{ 409 `[6]`, 410 } 411 412 l3 := createList("one", "two", "three", "four", "five", "six") 413 l4 := createList("one", "two", "three", "four", "five", "six", "seven") 414 415 expected3 := `[2] { 416 - "m3": "m-three" 417 + "m3": "m-three-diff" 418 } 419 [2]["m4"] { 420 - "a1": "a-one" 421 + "a1": "a-one-diff" 422 } 423 ` 424 expectedPaths3 := []string{ 425 `[2]["m3"]`, 426 `[2]["m4"]["a1"]`, 427 } 428 429 l5 := createList(mm1, mm2, mm3, mm4) 430 l6 := createList(mm1, mm2, mm3x, mm4) 431 432 tf := func(leftRight bool) { 433 buf := &bytes.Buffer{} 434 err := PrintDiff(context.Background(), buf, l1, l2, leftRight) 435 require.NoError(t, err) 436 assert.Equal(expected1, buf.String()) 437 438 paths, err := pathsFromDiff(l1, l2, leftRight) 439 require.NoError(t, err) 440 assert.Equal(expectedPaths1, paths) 441 442 buf = &bytes.Buffer{} 443 err = PrintDiff(context.Background(), buf, l3, l4, leftRight) 444 require.NoError(t, err) 445 assert.Equal(expected2, buf.String()) 446 447 paths, err = pathsFromDiff(l3, l4, leftRight) 448 require.NoError(t, err) 449 assert.Equal(expectedPaths2, paths) 450 451 buf = &bytes.Buffer{} 452 err = PrintDiff(context.Background(), buf, l5, l6, leftRight) 453 require.NoError(t, err) 454 assert.Equal(expected3, buf.String()) 455 456 paths, err = pathsFromDiff(l5, l6, leftRight) 457 require.NoError(t, err) 458 assert.Equal(expectedPaths3, paths) 459 } 460 461 tf(true) 462 tf(false) 463 } 464 465 func TestNomsDiffPrintBlob(t *testing.T) { 466 assert := assert.New(t) 467 468 vs := newTestValueStore() 469 defer vs.Close() 470 471 expected := "- Blob (2.0 kB)\n+ Blob (11 B)\n" 472 expectedPaths1 := []string{``} 473 b1, err := types.NewBlob(context.Background(), vs, strings.NewReader(strings.Repeat("x", 2*1024))) 474 require.NoError(t, err) 475 b2, err := types.NewBlob(context.Background(), vs, strings.NewReader("Hello World")) 476 require.NoError(t, err) 477 478 tf := func(leftRight bool) { 479 buf := &bytes.Buffer{} 480 err = PrintDiff(context.Background(), buf, b1, b2, leftRight) 481 require.NoError(t, err) 482 assert.Equal(expected, buf.String()) 483 484 paths, err := pathsFromDiff(b1, b2, leftRight) 485 require.NoError(t, err) 486 assert.Equal(expectedPaths1, paths) 487 } 488 489 tf(true) 490 tf(false) 491 } 492 493 func TestNomsDiffPrintType(t *testing.T) { 494 assert := assert.New(t) 495 496 expected1 := "- List<Float>\n+ List<String>\n" 497 expectedPaths1 := []string{""} 498 t1, err := types.MakeListType(types.PrimitiveTypeMap[types.FloatKind]) 499 require.NoError(t, err) 500 t2, err := types.MakeListType(types.PrimitiveTypeMap[types.StringKind]) 501 require.NoError(t, err) 502 503 expected2 := "- List<Float>\n+ Set<String>\n" 504 expectedPaths2 := []string{``} 505 t3, err := types.MakeListType(types.PrimitiveTypeMap[types.FloatKind]) 506 require.NoError(t, err) 507 t4, err := types.MakeSetType(types.PrimitiveTypeMap[types.StringKind]) 508 require.NoError(t, err) 509 510 tf := func(leftRight bool) { 511 buf := &bytes.Buffer{} 512 err = PrintDiff(context.Background(), buf, t1, t2, leftRight) 513 require.NoError(t, err) 514 assert.Equal(expected1, buf.String()) 515 516 paths, err := pathsFromDiff(t1, t2, leftRight) 517 require.NoError(t, err) 518 assert.Equal(expectedPaths1, paths) 519 520 buf = &bytes.Buffer{} 521 err = PrintDiff(context.Background(), buf, t3, t4, leftRight) 522 require.NoError(t, err) 523 assert.Equal(expected2, buf.String()) 524 525 paths, err = pathsFromDiff(t3, t4, leftRight) 526 require.NoError(t, err) 527 assert.Equal(expectedPaths2, paths) 528 } 529 530 tf(true) 531 tf(false) 532 } 533 534 func TestNomsDiffPrintRef(t *testing.T) { 535 assert := assert.New(t) 536 537 expected := "- #fckcbt7nk5jl4arco2dk7r9nj7abb6ci\n+ #i7d3u5gekm48ot419t2cot6cnl7ltcah\n" 538 expectedPaths1 := []string{``} 539 l1 := createList(1) 540 l2 := createList(2) 541 r1, err := types.NewRef(l1, types.Format_7_18) 542 require.NoError(t, err) 543 r2, err := types.NewRef(l2, types.Format_7_18) 544 require.NoError(t, err) 545 546 tf := func(leftRight bool) { 547 buf := &bytes.Buffer{} 548 err := PrintDiff(context.Background(), buf, r1, r2, leftRight) 549 require.NoError(t, err) 550 test.EqualsIgnoreHashes(t, expected, buf.String()) 551 552 paths, err := pathsFromDiff(r1, r2, leftRight) 553 require.NoError(t, err) 554 assert.Equal(expectedPaths1, paths) 555 } 556 557 tf(true) 558 tf(false) 559 }