github.com/tomwright/dasel@v1.27.3/node_test.go (about) 1 package dasel_test 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "github.com/tomwright/dasel/storage" 9 "reflect" 10 "strings" 11 "testing" 12 13 "github.com/tomwright/dasel" 14 ) 15 16 // ExampleNode_ReadmeExample tests the code from the readme explanation. 17 func ExampleNode_ReadmeExample() { 18 printNodeValue := func(nodes ...*dasel.Node) { 19 for _, n := range nodes { 20 fmt.Println(n.InterfaceValue()) 21 } 22 } 23 24 var data interface{} 25 _ = json.Unmarshal([]byte(`[{"name": "Tom"}, {"name": "Jim"}]`), &data) 26 27 rootNode := dasel.New(data) 28 29 result, _ := rootNode.Query(".[0].name") 30 printNodeValue(result) // Tom 31 32 results, _ := rootNode.QueryMultiple(".[*].name") 33 printNodeValue(results...) // Tom \n Jim 34 35 _ = rootNode.Put(".[0].name", "Frank") 36 printNodeValue(rootNode) // [ map[name:Frank] map[name:Jim] ] 37 38 _ = rootNode.PutMultiple(".[*].name", "Joe") 39 printNodeValue(rootNode) // [ map[name:Joe] map[name:Joe] ] 40 41 outputBytes, _ := json.Marshal(rootNode.InterfaceValue()) 42 fmt.Println(string(outputBytes)) // [{"name": "Joe"}, {"name": "Joe"}] 43 44 // Output: 45 // Tom 46 // Tom 47 // Jim 48 // [map[name:Frank] map[name:Jim]] 49 // [map[name:Joe] map[name:Joe]] 50 // [{"name":"Joe"},{"name":"Joe"}] 51 } 52 53 // ExampleNode_Query shows how to query data from go code. 54 func ExampleNode_Query() { 55 myData := []byte(`{"name": "Tom"}`) 56 var data interface{} 57 if err := json.Unmarshal(myData, &data); err != nil { 58 panic(err) 59 } 60 rootNode := dasel.New(data) 61 result, err := rootNode.Query(".name") 62 if err != nil { 63 panic(err) 64 } 65 fmt.Println(result.InterfaceValue()) 66 67 // Output: 68 // Tom 69 } 70 71 // ExampleNode_Put shows how to update data from go code. 72 func ExampleNode_Put() { 73 myData := []byte(`{"name": "Tom"}`) 74 var data interface{} 75 if err := json.Unmarshal(myData, &data); err != nil { 76 panic(err) 77 } 78 rootNode := dasel.New(data) 79 if err := rootNode.Put(".name", "Jim"); err != nil { 80 panic(err) 81 } 82 fmt.Println(rootNode.InterfaceValue()) 83 84 // Output: 85 // map[name:Jim] 86 } 87 88 var ( 89 tom = map[string]interface{}{ 90 "name": "Tom", 91 "age": 28, 92 } 93 amelia = map[string]interface{}{ 94 "name": "Amelia", 95 "age": 26, 96 } 97 people = []map[string]interface{}{tom, amelia} 98 mapC = map[string]interface{}{ 99 "thing": "1", 100 } 101 mapB = map[string]interface{}{ 102 "c": mapC, 103 "people": people, 104 } 105 mapA = map[string]interface{}{ 106 "b": mapB, 107 } 108 mapRoot = map[string]interface{}{ 109 "a": mapA, 110 } 111 ) 112 113 func testParseSelector(in string, exp dasel.Selector) func(t *testing.T) { 114 return func(t *testing.T) { 115 got, err := dasel.ParseSelector(in) 116 if err != nil { 117 t.Errorf("unexpected error: %s", err) 118 } 119 if !reflect.DeepEqual(exp, got) { 120 t.Errorf("expected %v, got %v", exp, got) 121 } 122 } 123 } 124 125 func TestParseSelector(t *testing.T) { 126 t.Run("NonIntIndex", func(t *testing.T) { 127 _, err := dasel.ParseSelector(".[a]") 128 exp := &dasel.InvalidIndexErr{Index: "a"} 129 if err == nil || err.Error() != exp.Error() { 130 t.Errorf("expected error %v, got %v", exp, err) 131 } 132 }) 133 t.Run("InvalidDynamicBracketCount", func(t *testing.T) { 134 _, err := dasel.ParseSelector(".((name=x)") 135 exp := dasel.ErrDynamicSelectorBracketMismatch 136 if err == nil || !errors.Is(err, exp) { 137 t.Errorf("expected error %v, got %v", exp, err) 138 } 139 }) 140 t.Run("InvalidDynamicComparison", func(t *testing.T) { 141 _, err := dasel.ParseSelector(".(x@2)") 142 exp := &dasel.UnknownComparisonOperatorErr{Operator: ""} 143 if err == nil || err.Error() != exp.Error() { 144 t.Errorf("expected error %v, got %v", exp, err) 145 } 146 }) 147 t.Run("MultipleSearchGroups", func(t *testing.T) { 148 _, err := dasel.ParseSelector(".(?:a=b)(a=b)") 149 exp := "require exactly 1 group in search selector" 150 if err == nil || err.Error() != exp { 151 t.Errorf("expected error %v, got %v", exp, err) 152 } 153 }) 154 t.Run("UnknownComparisonOperator", func(t *testing.T) { 155 _, err := dasel.ParseSelector(".(a@b)") 156 exp := "unknown comparison operator: " 157 if err == nil || err.Error() != exp { 158 t.Errorf("expected error %v, got %v", exp, err) 159 } 160 }) 161 t.Run("UnknownSearchComparisonOperator", func(t *testing.T) { 162 _, err := dasel.ParseSelector(".(?:a@b)") 163 exp := "unknown comparison operator: " 164 if err == nil || err.Error() != exp { 165 t.Errorf("expected error %v, got %v", exp, err) 166 } 167 }) 168 t.Run("UnknownSearchKeyComparisonOperator", func(t *testing.T) { 169 _, err := dasel.ParseSelector(".(?:->b)") 170 exp := "unknown comparison operator: >" 171 if err == nil || err.Error() != exp { 172 t.Errorf("expected error %v, got %v", exp, err) 173 } 174 }) 175 t.Run("SearchEqual", testParseSelector(".(?:name=asd)", dasel.Selector{ 176 Raw: ".(?:name=asd)", 177 Current: ".(?:name=asd)", 178 Remaining: "", 179 Type: "SEARCH", 180 Conditions: []dasel.Condition{ 181 &dasel.EqualCondition{ 182 Key: "name", 183 Value: "asd", 184 }, 185 }, 186 })) 187 t.Run("SearchNotEqual", testParseSelector(".(?:name!=asd)", dasel.Selector{ 188 Raw: ".(?:name!=asd)", 189 Current: ".(?:name!=asd)", 190 Remaining: "", 191 Type: "SEARCH", 192 Conditions: []dasel.Condition{ 193 &dasel.EqualCondition{ 194 Key: "name", 195 Value: "asd", 196 Not: true, 197 }, 198 }, 199 })) 200 t.Run("SearchMoreThan", testParseSelector(".(?:name.[#]>3)", dasel.Selector{ 201 Raw: ".(?:name.[#]>3)", 202 Current: ".(?:name.[#]>3)", 203 Remaining: "", 204 Type: "SEARCH", 205 Conditions: []dasel.Condition{ 206 &dasel.SortedComparisonCondition{ 207 Key: "name.[#]", 208 Value: "3", 209 After: true, 210 }, 211 }, 212 })) 213 t.Run("SearchMoreThanEqual", testParseSelector(".(?:name.[#]>=3)", dasel.Selector{ 214 Raw: ".(?:name.[#]>=3)", 215 Current: ".(?:name.[#]>=3)", 216 Remaining: "", 217 Type: "SEARCH", 218 Conditions: []dasel.Condition{ 219 &dasel.SortedComparisonCondition{ 220 Key: "name.[#]", 221 Value: "3", 222 After: true, 223 Equal: true, 224 }, 225 }, 226 })) 227 t.Run("SearchLessThan", testParseSelector(".(?:name.[#]<3)", dasel.Selector{ 228 Raw: ".(?:name.[#]<3)", 229 Current: ".(?:name.[#]<3)", 230 Remaining: "", 231 Type: "SEARCH", 232 Conditions: []dasel.Condition{ 233 &dasel.SortedComparisonCondition{ 234 Key: "name.[#]", 235 Value: "3", 236 }, 237 }, 238 })) 239 t.Run("SearchLessThanEqual", testParseSelector(".(?:name.[#]<=3)", dasel.Selector{ 240 Raw: ".(?:name.[#]<=3)", 241 Current: ".(?:name.[#]<=3)", 242 Remaining: "", 243 Type: "SEARCH", 244 Conditions: []dasel.Condition{ 245 &dasel.SortedComparisonCondition{ 246 Key: "name.[#]", 247 Value: "3", 248 Equal: true, 249 }, 250 }, 251 })) 252 t.Run("SearchKey", testParseSelector(".(?:-=asd)", dasel.Selector{ 253 Raw: ".(?:-=asd)", 254 Current: ".(?:-=asd)", 255 Remaining: "", 256 Type: "SEARCH", 257 Conditions: []dasel.Condition{ 258 &dasel.KeyEqualCondition{ 259 Value: "asd", 260 }, 261 }, 262 })) 263 t.Run("SearchKeyNotEqual", testParseSelector(".(?:-!=asd)", dasel.Selector{ 264 Raw: ".(?:-!=asd)", 265 Current: ".(?:-!=asd)", 266 Remaining: "", 267 Type: "SEARCH", 268 Conditions: []dasel.Condition{ 269 &dasel.KeyEqualCondition{ 270 Value: "asd", 271 Not: true, 272 }, 273 }, 274 })) 275 t.Run("DynamicKey", testParseSelector(".(-=asd)", dasel.Selector{ 276 Raw: ".(-=asd)", 277 Current: ".(-=asd)", 278 Remaining: "", 279 Type: "DYNAMIC", 280 Conditions: []dasel.Condition{ 281 &dasel.KeyEqualCondition{ 282 Value: "asd", 283 }, 284 }, 285 })) 286 t.Run("DynamicKeyNotEqual", testParseSelector(".(-!=asd)", dasel.Selector{ 287 Raw: ".(-!=asd)", 288 Current: ".(-!=asd)", 289 Remaining: "", 290 Type: "DYNAMIC", 291 Conditions: []dasel.Condition{ 292 &dasel.KeyEqualCondition{ 293 Value: "asd", 294 Not: true, 295 }, 296 }, 297 })) 298 t.Run("DynamicEqual", testParseSelector(".(name=asd)", dasel.Selector{ 299 Raw: ".(name=asd)", 300 Current: ".(name=asd)", 301 Remaining: "", 302 Type: "DYNAMIC", 303 Conditions: []dasel.Condition{ 304 &dasel.EqualCondition{ 305 Key: "name", 306 Value: "asd", 307 }, 308 }, 309 })) 310 t.Run("DynamicNotEqual", testParseSelector(".(name!=asd)", dasel.Selector{ 311 Raw: ".(name!=asd)", 312 Current: ".(name!=asd)", 313 Remaining: "", 314 Type: "DYNAMIC", 315 Conditions: []dasel.Condition{ 316 &dasel.EqualCondition{ 317 Key: "name", 318 Value: "asd", 319 Not: true, 320 }, 321 }, 322 })) 323 t.Run("DynamicMoreThan", testParseSelector(".(name.[#]>3)", dasel.Selector{ 324 Raw: ".(name.[#]>3)", 325 Current: ".(name.[#]>3)", 326 Remaining: "", 327 Type: "DYNAMIC", 328 Conditions: []dasel.Condition{ 329 &dasel.SortedComparisonCondition{ 330 Key: "name.[#]", 331 Value: "3", 332 After: true, 333 }, 334 }, 335 })) 336 t.Run("DynamicMoreThanEqual", testParseSelector(".(name.[#]>=3)", dasel.Selector{ 337 Raw: ".(name.[#]>=3)", 338 Current: ".(name.[#]>=3)", 339 Remaining: "", 340 Type: "DYNAMIC", 341 Conditions: []dasel.Condition{ 342 &dasel.SortedComparisonCondition{ 343 Key: "name.[#]", 344 Value: "3", 345 After: true, 346 Equal: true, 347 }, 348 }, 349 })) 350 t.Run("DynamicLessThan", testParseSelector(".(name.[#]<3)", dasel.Selector{ 351 Raw: ".(name.[#]<3)", 352 Current: ".(name.[#]<3)", 353 Remaining: "", 354 Type: "DYNAMIC", 355 Conditions: []dasel.Condition{ 356 &dasel.SortedComparisonCondition{ 357 Key: "name.[#]", 358 Value: "3", 359 }, 360 }, 361 })) 362 t.Run("DynamicLessThanEqual", testParseSelector(".(name.[#]<=3)", dasel.Selector{ 363 Raw: ".(name.[#]<=3)", 364 Current: ".(name.[#]<=3)", 365 Remaining: "", 366 Type: "DYNAMIC", 367 Conditions: []dasel.Condition{ 368 &dasel.SortedComparisonCondition{ 369 Key: "name.[#]", 370 Value: "3", 371 Equal: true, 372 }, 373 }, 374 })) 375 t.Run("Unicode", testParseSelector(".(name=Ägir).b", dasel.Selector{ 376 Raw: ".(name=Ägir).b", 377 Current: ".(name=Ägir)", 378 Remaining: ".b", 379 Type: "DYNAMIC", 380 Conditions: []dasel.Condition{ 381 &dasel.EqualCondition{ 382 Key: "name", 383 Value: "Ägir", 384 }, 385 }, 386 })) 387 } 388 389 func extractValues(nodes []*dasel.Node) []interface{} { 390 gotValues := make([]interface{}, len(nodes)) 391 for i, n := range nodes { 392 gotValues[i] = n.InterfaceValue() 393 } 394 return gotValues 395 } 396 397 func testNodeQueryMultipleArray(selector string, expValues []interface{}) func(t *testing.T) { 398 return func(t *testing.T) { 399 nodes, err := dasel.New([]map[string]interface{}{ 400 { 401 "name": "Tom", 402 "age": "27", 403 }, 404 { 405 "name": "Jim", 406 "age": "27", 407 }, 408 { 409 "name": "Amelia", 410 "age": "25", 411 }, 412 }).QueryMultiple(selector) 413 if err != nil { 414 t.Errorf("unexpected query error: %s", err) 415 return 416 } 417 418 gotValues := extractValues(nodes) 419 420 if !valuesAreEqual(expValues, gotValues) { 421 t.Errorf("expected %v, got %v", expValues, gotValues) 422 } 423 } 424 } 425 426 func testNodeQueryMultipleMap(selector string, expValues []interface{}) func(t *testing.T) { 427 return func(t *testing.T) { 428 nodes, err := dasel.New(map[string]interface{}{ 429 "personA": map[string]interface{}{ 430 "name": "Tom", 431 "age": 27, 432 }, 433 "personB": map[string]interface{}{ 434 "name": "Jim", 435 "age": 27, 436 }, 437 "personC": map[string]interface{}{ 438 "name": "Amelia", 439 "age": 25, 440 }, 441 }).QueryMultiple(selector) 442 if err != nil { 443 t.Errorf("unexpected query error: %s", err) 444 return 445 } 446 447 gotValues := extractValues(nodes) 448 449 if !valuesAreEqual(expValues, gotValues) { 450 t.Errorf("expected %v, got %v", expValues, gotValues) 451 } 452 } 453 } 454 455 func TestNode_QueryMultiple(t *testing.T) { 456 t.Run("SingleResult", testNodeQueryMultipleArray(".[0].name", []interface{}{ 457 "Tom", 458 })) 459 t.Run("SingleResultDynamicEqual", testNodeQueryMultipleArray(".(age=25).name", []interface{}{ 460 "Amelia", 461 })) 462 t.Run("SingleResultDynamicNotEqual", testNodeQueryMultipleArray(".(age!=27).name", []interface{}{ 463 "Amelia", 464 })) 465 t.Run("SingleResultDynamicKeyEqual", testNodeQueryMultipleArray(".(-=0).name", []interface{}{ 466 "Tom", 467 })) 468 t.Run("MultipleResultDynamicKeyNotEqual", testNodeQueryMultipleArray(".(-!=0).name", []interface{}{ 469 "Jim", "Amelia", 470 })) 471 t.Run("MultipleResultSearchKeyNotEqual", testNodeQueryMultipleArray(".[*].(?:-!=name)", []interface{}{ 472 "27", "27", "25", 473 })) 474 t.Run("MultipleResultDynamic", testNodeQueryMultipleArray(".(age=27).name", []interface{}{ 475 "Tom", 476 "Jim", 477 })) 478 t.Run("MultipleResultAnyIndex", testNodeQueryMultipleArray(".[*].name", []interface{}{ 479 "Tom", 480 "Jim", 481 "Amelia", 482 })) 483 484 t.Run("MapSingleResult", testNodeQueryMultipleMap(".personA.name", []interface{}{ 485 "Tom", 486 })) 487 t.Run("MapSingleResultDynamic", testNodeQueryMultipleMap(".(age=25).name", []interface{}{ 488 "Amelia", 489 })) 490 t.Run("MapSingleResultDynamic", testNodeQueryMultipleMap(".(age=27).name", []interface{}{ 491 "Tom", 492 "Jim", 493 })) 494 t.Run("MapMultipleResultAnyIndex", testNodeQueryMultipleMap(".[*].name", []interface{}{ 495 "Tom", 496 "Jim", 497 "Amelia", 498 })) 499 } 500 501 func valuesAreEqual(exp []interface{}, got []interface{}) bool { 502 if len(exp) != len(got) { 503 return false 504 } 505 for _, g := range got { 506 found := false 507 for _, e := range exp { 508 if reflect.DeepEqual(g, e) { 509 found = true 510 break 511 } 512 } 513 if !found { 514 return false 515 } 516 } 517 return true 518 } 519 520 func TestNode_PutMultiple(t *testing.T) { 521 t.Run("SingleResult", func(t *testing.T) { 522 value := []map[string]interface{}{ 523 { 524 "name": "Tom", 525 "age": "27", 526 }, 527 { 528 "name": "Jim", 529 "age": "27", 530 }, 531 { 532 "name": "Amelia", 533 "age": "25", 534 }, 535 } 536 err := dasel.New(value).PutMultiple(".[0].name", "Frank") 537 if err != nil { 538 t.Errorf("unexpected query error: %s", err) 539 return 540 } 541 542 exp := []map[string]interface{}{ 543 { 544 "name": "Frank", 545 "age": "27", 546 }, 547 { 548 "name": "Jim", 549 "age": "27", 550 }, 551 { 552 "name": "Amelia", 553 "age": "25", 554 }, 555 } 556 557 if !reflect.DeepEqual(exp, value) { 558 t.Errorf("expected %v, got %v", exp, value) 559 } 560 }) 561 t.Run("SingleResultDynamic", func(t *testing.T) { 562 value := []map[string]interface{}{ 563 { 564 "name": "Frank", 565 "age": "27", 566 }, 567 { 568 "name": "Jim", 569 "age": "27", 570 }, 571 { 572 "name": "Amelia", 573 "age": "25", 574 }, 575 } 576 err := dasel.New(value).PutMultiple(".(age=25).name", "Frank") 577 if err != nil { 578 t.Errorf("unexpected query error: %s", err) 579 return 580 } 581 582 exp := []map[string]interface{}{ 583 { 584 "name": "Frank", 585 "age": "27", 586 }, 587 { 588 "name": "Jim", 589 "age": "27", 590 }, 591 { 592 "name": "Frank", 593 "age": "25", 594 }, 595 } 596 597 if !reflect.DeepEqual(exp, value) { 598 t.Errorf("expected %v, got %v", exp, value) 599 } 600 }) 601 t.Run("MultipleResultDynamic", func(t *testing.T) { 602 value := []map[string]interface{}{ 603 { 604 "name": "Tom", 605 "age": "27", 606 }, 607 { 608 "name": "Jim", 609 "age": "27", 610 }, 611 { 612 "name": "Amelia", 613 "age": "25", 614 }, 615 } 616 err := dasel.New(value).PutMultiple(".(age=27).name", "Frank") 617 if err != nil { 618 t.Errorf("unexpected query error: %s", err) 619 return 620 } 621 622 exp := []map[string]interface{}{ 623 { 624 "name": "Frank", 625 "age": "27", 626 }, 627 { 628 "name": "Frank", 629 "age": "27", 630 }, 631 { 632 "name": "Amelia", 633 "age": "25", 634 }, 635 } 636 637 if !reflect.DeepEqual(exp, value) { 638 t.Errorf("expected %v, got %v", exp, value) 639 } 640 }) 641 t.Run("MultipleResultAnyIndex", func(t *testing.T) { 642 value := []map[string]interface{}{ 643 { 644 "name": "Tom", 645 "age": "27", 646 }, 647 { 648 "name": "Jim", 649 "age": "27", 650 }, 651 { 652 "name": "Amelia", 653 "age": "25", 654 }, 655 } 656 err := dasel.New(value).PutMultiple(".[*].name", "Frank") 657 if err != nil { 658 t.Errorf("unexpected query error: %s", err) 659 return 660 } 661 662 exp := []map[string]interface{}{ 663 { 664 "name": "Frank", 665 "age": "27", 666 }, 667 { 668 "name": "Frank", 669 "age": "27", 670 }, 671 { 672 "name": "Frank", 673 "age": "25", 674 }, 675 } 676 677 if !reflect.DeepEqual(exp, value) { 678 t.Errorf("expected %v, got %v", exp, value) 679 } 680 }) 681 t.Run("StructAnyIndex", func(t *testing.T) { 682 type user struct { 683 Name string 684 Age int 685 } 686 value := []user{ 687 { 688 Name: "Tom", 689 Age: 27, 690 }, 691 { 692 Name: "Jim", 693 Age: 27, 694 }, 695 { 696 Name: "Amelia", 697 Age: 25, 698 }, 699 } 700 err := dasel.New(value).PutMultiple(".[*].Name", "Frank") 701 if err != nil { 702 t.Errorf("unexpected query error: %s", err) 703 return 704 } 705 706 exp := []user{ 707 { 708 Name: "Frank", 709 Age: 27, 710 }, 711 { 712 Name: "Frank", 713 Age: 27, 714 }, 715 { 716 Name: "Frank", 717 Age: 25, 718 }, 719 } 720 721 if !reflect.DeepEqual(exp, value) { 722 t.Errorf("expected %v, got %v", exp, value) 723 } 724 }) 725 } 726 727 func TestNode_Query(t *testing.T) { 728 parser, err := storage.NewReadParserFromFilename("./tests/assets/example.json") 729 if err != nil { 730 t.Errorf("could not get parser: %s", err) 731 return 732 } 733 734 value, err := storage.LoadFromFile("./tests/assets/example.json", parser) 735 if err != nil { 736 t.Errorf("could not load value from file: %s", err) 737 return 738 } 739 740 t.Run("Valid", func(t *testing.T) { 741 node, err := dasel.New(value).Query("preferences.favouriteColour") 742 if err != nil { 743 t.Errorf("unexpected query error: %s", err) 744 return 745 } 746 if exp, got := "red", fmt.Sprint(node.InterfaceValue()); exp != got { 747 t.Errorf("expected value `%s`, got `%s`", exp, got) 748 } 749 }) 750 t.Run("NotFound", func(t *testing.T) { 751 _, err := dasel.New(value).Query(".colours.[0].a") 752 expErr := fmt.Errorf("could not find value: selector [type:PROPERTY selector:.a] does not support value: [kind:string type:string] red") 753 if err == nil { 754 t.Errorf("expected err %v, got %v", expErr, err) 755 return 756 } 757 if err.Error() != expErr.Error() { 758 t.Errorf("expected err %v, got %v", expErr, err) 759 return 760 } 761 }) 762 t.Run("InvalidSelector", func(t *testing.T) { 763 _, err := dasel.New(value).Query(".colours.[a]") 764 expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"}) 765 if err == nil { 766 t.Errorf("expected err %v, got %v", expErr, err) 767 return 768 } 769 if err.Error() != expErr.Error() { 770 t.Errorf("expected err %v, got %v", expErr, err) 771 return 772 } 773 }) 774 } 775 776 func TestNode_Query_File(t *testing.T) { 777 tests := []struct { 778 Name string 779 Selector string 780 Exp string 781 }{ 782 {Name: "Property", Selector: "name", Exp: "Tom"}, 783 {Name: "ChildProperty", Selector: "preferences.favouriteColour", Exp: "red"}, 784 {Name: "Index", Selector: "colours.[0]", Exp: "red"}, 785 {Name: "Index", Selector: "colours.[1]", Exp: "green"}, 786 {Name: "Index", Selector: "colours.[2]", Exp: "blue"}, 787 {Name: "IndexProperty", Selector: "colourCodes.[0].name", Exp: "red"}, 788 {Name: "IndexProperty", Selector: "colourCodes.[1].name", Exp: "green"}, 789 {Name: "IndexProperty", Selector: "colourCodes.[2].name", Exp: "blue"}, 790 {Name: "DynamicProperty", Selector: "colourCodes.(name=red).rgb", Exp: "ff0000"}, 791 {Name: "DynamicProperty", Selector: "colourCodes.(name=green).rgb", Exp: "00ff00"}, 792 {Name: "DynamicProperty", Selector: "colourCodes.(name=blue).rgb", Exp: "0000ff"}, 793 {Name: "MultipleDynamicProperty", Selector: "colourCodes.(name=red)(rgb=ff0000).name", Exp: "red"}, 794 {Name: "MultipleDynamicProperty", Selector: "colourCodes.(name=green)(rgb=00ff00).name", Exp: "green"}, 795 {Name: "MultipleDynamicProperty", Selector: "colourCodes.(name=blue)(rgb=0000ff).name", Exp: "blue"}, 796 } 797 798 fileTest := func(filename string) func(t *testing.T) { 799 return func(t *testing.T) { 800 parser, err := storage.NewReadParserFromFilename(filename) 801 if err != nil { 802 t.Errorf("could not get parser: %s", err) 803 return 804 } 805 806 value, err := storage.LoadFromFile(filename, parser) 807 if err != nil { 808 t.Errorf("could not load value from file: %s", err) 809 return 810 } 811 812 for _, testCase := range tests { 813 tc := testCase 814 t.Run(tc.Name, func(t *testing.T) { 815 node, err := dasel.New(value).Query(tc.Selector) 816 if err != nil { 817 t.Errorf("unexpected query error: %s", err) 818 return 819 } 820 821 if exp, got := tc.Exp, fmt.Sprint(node.InterfaceValue()); exp != got { 822 t.Errorf("expected value `%s`, got `%s`", exp, got) 823 } 824 }) 825 } 826 } 827 } 828 829 t.Run("JSON", fileTest("./tests/assets/example.json")) 830 t.Run("YAML", fileTest("./tests/assets/example.yaml")) 831 } 832 833 func TestNode_Query_Data(t *testing.T) { 834 t.Run("ParentChildPathToProperty", func(t *testing.T) { 835 rootNode := dasel.New(mapRoot) 836 837 got, err := rootNode.Query(".a.b.c.thing") 838 if err != nil { 839 t.Errorf("unexpected query error: %v", err) 840 return 841 } 842 843 if exp, got := "1", got.InterfaceValue().(string); exp != got { 844 t.Errorf("expected %s, got %s", exp, got) 845 } 846 }) 847 t.Run("ParentChildPathToIndexProperty", func(t *testing.T) { 848 rootNode := dasel.New(mapRoot) 849 850 got, err := rootNode.Query(".a.b.people.[1].name") 851 if err != nil { 852 t.Errorf("unexpected query error: %v", err) 853 return 854 } 855 856 if exp, got := "Amelia", got.InterfaceValue().(string); exp != got { 857 t.Errorf("expected %s, got %s", exp, got) 858 } 859 }) 860 t.Run("ParentChildPathToDynamicProperty", func(t *testing.T) { 861 rootNode := dasel.New(mapRoot) 862 863 got, err := rootNode.Query(".a.b.people.(name=Tom).name") 864 if err != nil { 865 t.Errorf("unexpected query error: %v", err) 866 return 867 } 868 869 if exp, got := "Tom", got.InterfaceValue().(string); exp != got { 870 t.Errorf("expected %s, got %s", exp, got) 871 } 872 }) 873 t.Run("ParentChildPathToMultipleDynamicProperty", func(t *testing.T) { 874 rootNode := dasel.New(mapRoot) 875 876 got, err := rootNode.Query(".a.b.people.(name=Tom)(age=28).name") 877 if err != nil { 878 t.Errorf("unexpected query error: %v", err) 879 return 880 } 881 882 if exp, got := "Tom", got.InterfaceValue().(string); exp != got { 883 t.Errorf("expected %s, got %s", exp, got) 884 } 885 }) 886 t.Run("DynamicPropertyOnMap", func(t *testing.T) { 887 rootNode := dasel.New(map[string]interface{}{ 888 "personA": map[string]interface{}{ 889 "name": "Tom", 890 }, 891 "personB": map[string]interface{}{ 892 "name": "Jim", 893 }, 894 }) 895 896 got, err := rootNode.Query(".(name=Tom).name") 897 if err != nil { 898 t.Errorf("unexpected query error: %v", err) 899 return 900 } 901 902 if exp, got := "Tom", got.InterfaceValue().(string); exp != got { 903 t.Errorf("expected %s, got %s", exp, got) 904 } 905 }) 906 t.Run("SelectFromStruct", func(t *testing.T) { 907 rootNode := dasel.New([]struct { 908 Name string 909 }{ 910 {Name: "Tom"}, 911 {Name: "Jim"}, 912 }) 913 914 got, err := rootNode.Query(".[0].Name") 915 if err != nil { 916 t.Errorf("unexpected query error: %v", err) 917 return 918 } 919 920 if exp, got := "Tom", got.InterfaceValue().(string); exp != got { 921 t.Errorf("expected %s, got %s", exp, got) 922 } 923 }) 924 t.Run("ConditionalSelectFromStruct", func(t *testing.T) { 925 rootNode := dasel.New([]struct { 926 Name string 927 }{ 928 {Name: "Tom"}, 929 {Name: "Jim"}, 930 }) 931 932 got, err := rootNode.Query(".(Name=Tom).Name") 933 if err != nil { 934 t.Errorf("unexpected query error: %v", err) 935 return 936 } 937 938 if exp, got := "Tom", got.InterfaceValue().(string); exp != got { 939 t.Errorf("expected %s, got %s", exp, got) 940 } 941 }) 942 } 943 944 func putQueryTest(rootNode *dasel.Node, putSelector string, newValue interface{}, querySelector string) func(t *testing.T) { 945 return func(t *testing.T) { 946 err := rootNode.Put(putSelector, newValue) 947 if err != nil { 948 t.Errorf("unexpected put error: %v", err) 949 return 950 } 951 952 got, err := rootNode.Query(querySelector) 953 if err != nil { 954 t.Errorf("unexpected query error: %v", err) 955 return 956 } 957 958 if !reflect.DeepEqual(newValue, got.InterfaceValue()) { 959 t.Errorf("expected %v, got %v", newValue, got.InterfaceValue()) 960 } 961 } 962 } 963 964 func deleteTest(rootNode *dasel.Node, deleteSelector string, exp interface{}) func(t *testing.T) { 965 return func(t *testing.T) { 966 err := rootNode.Delete(deleteSelector) 967 if err != nil { 968 t.Errorf("unexpected delete error: %v", err) 969 return 970 } 971 972 gotVal := rootNode.InterfaceValue() 973 if !reflect.DeepEqual(exp, gotVal) && exp != gotVal { 974 t.Errorf("expected [%T] %v, got [%T] %v", exp, exp, gotVal, gotVal) 975 } 976 } 977 } 978 979 func deleteMultipleTest(rootNode *dasel.Node, deleteSelector string, exp interface{}) func(t *testing.T) { 980 return func(t *testing.T) { 981 err := rootNode.DeleteMultiple(deleteSelector) 982 if err != nil { 983 t.Errorf("unexpected delete error: %v", err) 984 return 985 } 986 987 if !reflect.DeepEqual(exp, rootNode.InterfaceValue()) { 988 t.Errorf("expected %v, got %v", exp, rootNode.InterfaceValue()) 989 } 990 } 991 } 992 993 func putQueryMultipleTest(rootNode *dasel.Node, putSelector string, newValue interface{}, querySelector string) func(t *testing.T) { 994 return func(t *testing.T) { 995 err := rootNode.PutMultiple(putSelector, newValue) 996 if err != nil { 997 t.Errorf("unexpected put error: %v", err) 998 return 999 } 1000 1001 got, err := rootNode.QueryMultiple(querySelector) 1002 if err != nil { 1003 t.Errorf("unexpected query error: %v", err) 1004 return 1005 } 1006 1007 for _, n := range got { 1008 if !reflect.DeepEqual(newValue, n.InterfaceValue()) { 1009 t.Errorf("expected %v, got %v", newValue, n.InterfaceValue()) 1010 } 1011 } 1012 } 1013 } 1014 1015 func TestNode_Put_Query(t *testing.T) { 1016 data := map[string]interface{}{ 1017 "id": "123", 1018 "people": []map[string]interface{}{ 1019 { 1020 "id": 1, 1021 "name": "Tom", 1022 }, 1023 { 1024 "id": 2, 1025 "name": "Jim", 1026 }, 1027 }, 1028 "names": []string{ 1029 "Tom", 1030 "Jim", 1031 }, 1032 } 1033 rootNode := dasel.New(data) 1034 1035 t.Run("InvalidSelector", func(t *testing.T) { 1036 err := rootNode.Put("people.[a].name", "Thomas") 1037 expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"}) 1038 if err == nil { 1039 t.Errorf("expected err %v, got %v", expErr, err) 1040 return 1041 } 1042 if err.Error() != expErr.Error() { 1043 t.Errorf("expected err %v, got %v", expErr, err) 1044 return 1045 } 1046 }) 1047 t.Run("ExistingSingleString", putQueryTest(rootNode, "id", "456", "id")) 1048 t.Run("ExistingStringValue", putQueryTest(rootNode, "people.[0].name", "Thomas", "people.(id=1).name")) 1049 t.Run("ExistingIntValue", putQueryTest(rootNode, "people.(id=1).id", 3, "people.(id=3).id")) 1050 t.Run("NewPropertyOnExistingObject", putQueryTest(rootNode, "people.(id=3).age", 27, "people.[0].age")) 1051 t.Run("AppendObjectToList", func(t *testing.T) { 1052 err := rootNode.Put("people.[]", map[string]interface{}{ 1053 "id": 1, 1054 "name": "Bob", 1055 }) 1056 if err != nil { 1057 t.Errorf("unexpected put error: %v", err) 1058 return 1059 } 1060 1061 got, err := rootNode.Query("people.[2].id") 1062 if err != nil { 1063 t.Errorf("unexpected query [1] error: %v", err) 1064 return 1065 } 1066 if exp, got := 1, got.InterfaceValue().(int); exp != got { 1067 t.Errorf("expected %d, got %d", exp, got) 1068 } 1069 got, err = rootNode.Query("people.[2].name") 1070 if err != nil { 1071 t.Errorf("unexpected query [2] error: %v", err) 1072 return 1073 } 1074 if exp, got := "Bob", got.InterfaceValue().(string); exp != got { 1075 t.Errorf("expected %s, got %s", exp, got) 1076 } 1077 }) 1078 t.Run("AppendStringToList", putQueryTest(rootNode, "names.[]", "Bob", "names.[2]")) 1079 t.Run("NilRootNode", putQueryTest(dasel.New(nil), "name", "Thomas", "name")) 1080 t.Run("NilChain", putQueryTest(dasel.New(nil), "my.name", "Thomas", "my.name")) 1081 t.Run("NilChainToListIndex", putQueryTest(dasel.New(nil), "my.favourite.people.[0]", "Tom", "my.favourite.people.[0]")) 1082 t.Run("NilChainToListNextAvailableIndex", putQueryTest(dasel.New(nil), "my.favourite.people.[]", "Tom", "my.favourite.people.[0]")) 1083 t.Run("NilChainToDynamic", putQueryTest(dasel.New(nil), "(name=Jim).name", "Tom", "[0].name")) 1084 } 1085 1086 func TestNode_PutMultiple_Query(t *testing.T) { 1087 data := map[string]interface{}{ 1088 "id": "123", 1089 "people": []map[string]interface{}{ 1090 { 1091 "id": 1, 1092 "name": "Tom", 1093 }, 1094 { 1095 "id": 2, 1096 "name": "Jim", 1097 }, 1098 }, 1099 "names": []string{ 1100 "Tom", 1101 "Jim", 1102 }, 1103 } 1104 rootNode := dasel.New(data) 1105 1106 t.Run("InvalidSelector", func(t *testing.T) { 1107 err := rootNode.PutMultiple("people.[a].name", "Thomas") 1108 expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"}) 1109 if err == nil { 1110 t.Errorf("expected err %v, got %v", expErr, err) 1111 return 1112 } 1113 if err.Error() != expErr.Error() { 1114 t.Errorf("expected err %v, got %v", expErr, err) 1115 return 1116 } 1117 }) 1118 t.Run("ExistingSingleString", putQueryMultipleTest(rootNode, "id", "456", "id")) 1119 t.Run("ExistingStringValue", putQueryMultipleTest(rootNode, "people.[0].name", "Thomas", "people.(id=1).name")) 1120 t.Run("ExistingIntValue", putQueryMultipleTest(rootNode, "people.(id=1).id", 3, "people.(id=3).id")) 1121 t.Run("NewPropertyOnExistingObject", putQueryMultipleTest(rootNode, "people.(id=3).age", 27, "people.[0].age")) 1122 t.Run("AppendObjectToList", func(t *testing.T) { 1123 err := rootNode.PutMultiple("people.[]", map[string]interface{}{ 1124 "id": 1, 1125 "name": "Bob", 1126 }) 1127 if err != nil { 1128 t.Errorf("unexpected put error: %v", err) 1129 return 1130 } 1131 1132 got, err := rootNode.Query("people.[2].id") 1133 if err != nil { 1134 t.Errorf("unexpected query [1] error: %v", err) 1135 return 1136 } 1137 if exp, got := 1, got.InterfaceValue().(int); exp != got { 1138 t.Errorf("expected %d, got %d", exp, got) 1139 } 1140 got, err = rootNode.Query("people.[2].name") 1141 if err != nil { 1142 t.Errorf("unexpected query [2] error: %v", err) 1143 return 1144 } 1145 if exp, got := "Bob", got.InterfaceValue().(string); exp != got { 1146 t.Errorf("expected %s, got %s", exp, got) 1147 } 1148 }) 1149 t.Run("AppendStringToList", putQueryMultipleTest(rootNode, "names.[]", "Bob", "names.[2]")) 1150 t.Run("NilRootNode", putQueryMultipleTest(dasel.New(nil), "name", "Thomas", "name")) 1151 t.Run("NilChain", putQueryMultipleTest(dasel.New(nil), "my.name", "Thomas", "my.name")) 1152 t.Run("NilChainToListIndex", putQueryMultipleTest(dasel.New(nil), "my.favourite.people.[0]", "Tom", "my.favourite.people.[0]")) 1153 t.Run("NilChainToListNextAvailableIndex", putQueryMultipleTest(dasel.New(nil), "my.favourite.people.[]", "Tom", "my.favourite.people.[0]")) 1154 } 1155 1156 func TestNode_Delete(t *testing.T) { 1157 data := func() map[string]interface{} { 1158 return map[string]interface{}{ 1159 "id": "123", 1160 "names": []string{ 1161 "Tom", 1162 "Jim", 1163 }, 1164 "people": []map[string]interface{}{ 1165 { 1166 "id": 1, 1167 "name": "Tom", 1168 }, 1169 { 1170 "id": 2, 1171 "name": "Jim", 1172 }, 1173 }, 1174 } 1175 } 1176 1177 t.Run("InvalidSelector", func(t *testing.T) { 1178 err := dasel.New(data()).Delete("people.[a].name") 1179 expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"}) 1180 if err == nil { 1181 t.Errorf("expected err %v, got %v", expErr, err) 1182 return 1183 } 1184 if err.Error() != expErr.Error() { 1185 t.Errorf("expected err %v, got %v", expErr, err) 1186 return 1187 } 1188 }) 1189 t.Run("ExistingSingleString", deleteTest(dasel.New(data()), "id", map[string]interface{}{ 1190 "names": []string{ 1191 "Tom", 1192 "Jim", 1193 }, 1194 "people": []map[string]interface{}{ 1195 { 1196 "id": 1, 1197 "name": "Tom", 1198 }, 1199 { 1200 "id": 2, 1201 "name": "Jim", 1202 }, 1203 }, 1204 })) 1205 t.Run("ExistingStringValue", deleteTest(dasel.New(data()), "people.[0].name", map[string]interface{}{ 1206 "id": "123", 1207 "names": []string{ 1208 "Tom", 1209 "Jim", 1210 }, 1211 "people": []map[string]interface{}{ 1212 { 1213 "id": 1, 1214 }, 1215 { 1216 "id": 2, 1217 "name": "Jim", 1218 }, 1219 }, 1220 })) 1221 t.Run("ExistingStringInStruct", deleteTest(dasel.New(&struct { 1222 Name string 1223 Age int 1224 }{ 1225 Name: "Tom", 1226 Age: 123, 1227 }), ".Name", &struct { 1228 Name string 1229 Age int 1230 }{ 1231 Age: 123, 1232 })) 1233 t.Run("AnyIndexInStruct", deleteMultipleTest(dasel.New(&struct { 1234 Name string 1235 Age int 1236 }{ 1237 Name: "Tom", 1238 Age: 123, 1239 }), ".[*]", &struct { 1240 Name string 1241 Age int 1242 }{})) 1243 t.Run("ExistingObjectInArray", deleteTest(dasel.New(data()), "people.[0]", map[string]interface{}{ 1244 "id": "123", 1245 "names": []string{ 1246 "Tom", 1247 "Jim", 1248 }, 1249 "people": []map[string]interface{}{ 1250 { 1251 "id": 2, 1252 "name": "Jim", 1253 }, 1254 }, 1255 })) 1256 t.Run("ExistingIntValue", deleteTest(dasel.New(data()), "people.(id=1).id", map[string]interface{}{ 1257 "id": "123", 1258 "names": []string{ 1259 "Tom", 1260 "Jim", 1261 }, 1262 "people": []map[string]interface{}{ 1263 { 1264 "name": "Tom", 1265 }, 1266 { 1267 "id": 2, 1268 "name": "Jim", 1269 }, 1270 }, 1271 })) 1272 t.Run("ExistingArray", deleteMultipleTest(dasel.New(data()), "names", map[string]interface{}{ 1273 "id": "123", 1274 "people": []map[string]interface{}{ 1275 { 1276 "id": 1, 1277 "name": "Tom", 1278 }, 1279 { 1280 "id": 2, 1281 "name": "Jim", 1282 }, 1283 }, 1284 })) 1285 t.Run("RootNodeObject", deleteTest(dasel.New(map[string]interface{}{ 1286 "name": "Tom", 1287 }), ".", map[string]interface{}{})) 1288 t.Run("RootNodeArray", deleteTest(dasel.New([]interface{}{ 1289 "name", "Tom", 1290 }), ".", []interface{}{})) 1291 t.Run("RootNodeUnknown", deleteTest(dasel.New(false), ".", map[string]interface{}{})) 1292 } 1293 1294 func TestNode_DeleteMultiple_Query(t *testing.T) { 1295 data := func() map[string]interface{} { 1296 return map[string]interface{}{ 1297 "id": "123", 1298 "names": []string{ 1299 "Tom", 1300 "Jim", 1301 }, 1302 "people": []map[string]interface{}{ 1303 { 1304 "id": 1, 1305 "name": "Tom", 1306 }, 1307 { 1308 "id": 2, 1309 "name": "Jim", 1310 }, 1311 }, 1312 } 1313 } 1314 1315 t.Run("InvalidSelector", func(t *testing.T) { 1316 err := dasel.New(data()).DeleteMultiple("people.[a].name") 1317 expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"}) 1318 if err == nil { 1319 t.Errorf("expected err %v, got %v", expErr, err) 1320 return 1321 } 1322 if err.Error() != expErr.Error() { 1323 t.Errorf("expected err %v, got %v", expErr, err) 1324 return 1325 } 1326 }) 1327 t.Run("ExistingSingleString", deleteMultipleTest(dasel.New(data()), "id", map[string]interface{}{ 1328 "people": []map[string]interface{}{ 1329 { 1330 "id": 1, 1331 "name": "Tom", 1332 }, 1333 { 1334 "id": 2, 1335 "name": "Jim", 1336 }, 1337 }, 1338 "names": []string{ 1339 "Tom", 1340 "Jim", 1341 }, 1342 })) 1343 t.Run("ExistingStringValue", deleteMultipleTest(dasel.New(data()), "people.[0].name", map[string]interface{}{ 1344 "id": "123", 1345 "names": []string{ 1346 "Tom", 1347 "Jim", 1348 }, 1349 "people": []map[string]interface{}{ 1350 { 1351 "id": 1, 1352 }, 1353 { 1354 "id": 2, 1355 "name": "Jim", 1356 }, 1357 }, 1358 })) 1359 t.Run("WildcardProperty", deleteMultipleTest(dasel.New(data()), "people.[*].name", map[string]interface{}{ 1360 "id": "123", 1361 "names": []string{ 1362 "Tom", 1363 "Jim", 1364 }, 1365 "people": []map[string]interface{}{ 1366 { 1367 "id": 1, 1368 }, 1369 { 1370 "id": 2, 1371 }, 1372 }, 1373 })) 1374 t.Run("ExistingIntValue", deleteMultipleTest(dasel.New(data()), "people.(id=1).id", map[string]interface{}{ 1375 "id": "123", 1376 "names": []string{ 1377 "Tom", 1378 "Jim", 1379 }, 1380 "people": []map[string]interface{}{ 1381 { 1382 "name": "Tom", 1383 }, 1384 { 1385 "id": 2, 1386 "name": "Jim", 1387 }, 1388 }, 1389 })) 1390 t.Run("AllObjectsInArray", deleteMultipleTest(dasel.New(data()), "people.[*]", map[string]interface{}{ 1391 "id": "123", 1392 "names": []string{ 1393 "Tom", 1394 "Jim", 1395 }, 1396 "people": []map[string]interface{}{}, 1397 })) 1398 t.Run("ExistingArray", deleteMultipleTest(dasel.New(data()), "names", map[string]interface{}{ 1399 "id": "123", 1400 "people": []map[string]interface{}{ 1401 { 1402 "id": 1, 1403 "name": "Tom", 1404 }, 1405 { 1406 "id": 2, 1407 "name": "Jim", 1408 }, 1409 }, 1410 })) 1411 t.Run("AllItemsInObject", deleteMultipleTest(dasel.New(data()), ".[*]", map[string]interface{}{})) 1412 t.Run("RootNodeObject", deleteMultipleTest(dasel.New(map[string]interface{}{ 1413 "name": "Tom", 1414 }), ".", map[string]interface{}{})) 1415 t.Run("RootNodeArray", deleteMultipleTest(dasel.New([]interface{}{ 1416 "name", "Tom", 1417 }), ".", []interface{}{})) 1418 t.Run("RootNodeUnknown", deleteMultipleTest(dasel.New(false), ".", map[string]interface{}{})) 1419 } 1420 1421 // TestNode_NewFromFile tests parsing from file. 1422 func TestNode_NewFromFile(t *testing.T) { 1423 noSuchFileName := "no_such_file" 1424 noSuchFileErrMsg := "could not open file: open " + noSuchFileName 1425 unmarshalFailMsg := "could not unmarshal data" 1426 1427 tests := []struct { 1428 name string 1429 file string 1430 parser string 1431 err error 1432 }{ 1433 { 1434 name: "Existing JSON file and JSON Read parser specified", 1435 file: "./tests/assets/example.json", 1436 parser: "json", 1437 err: nil, 1438 }, 1439 { 1440 name: "Existing JSON file and YAML Read parser specified", 1441 file: "./tests/assets/example.json", 1442 parser: "yaml", 1443 // JSON is a subset of YAML v1.2 1444 // https://stackoverflow.com/questions/21584985/what-valid-json-files-are-not-valid-yaml-1-1-files 1445 err: nil, 1446 }, 1447 { 1448 name: "Existing YAML file and YAML Read parser specified", 1449 file: "./tests/assets/example.yaml", 1450 parser: "yaml", 1451 err: nil, 1452 }, 1453 { 1454 name: "Existing YAML file and XML Read parser specified", 1455 file: "./tests/assets/example.yaml", 1456 parser: "xml", 1457 err: errors.New(unmarshalFailMsg), 1458 }, 1459 { 1460 name: "Existing XML file and XML Read parser specified", 1461 file: "./tests/assets/example.xml", 1462 parser: "xml", 1463 err: nil, 1464 }, 1465 { 1466 name: "Existing XML file and JSON Read parser specified", 1467 file: "./tests/assets/example.xml", 1468 parser: "json", 1469 err: errors.New(unmarshalFailMsg), 1470 }, 1471 { 1472 name: "Existing JSON file and invalid Read parser specified", 1473 file: "./tests/assets/example.json", 1474 parser: "bad", 1475 err: storage.UnknownParserErr{Parser: "bad"}, 1476 }, 1477 { 1478 name: "File doesn't exist and JSON Read parser specified", 1479 file: noSuchFileName, 1480 parser: "json", 1481 err: errors.New(noSuchFileErrMsg), 1482 }, 1483 { 1484 name: "File doesn't exist and YAML Read parser specified", 1485 file: noSuchFileName, 1486 parser: "yaml", 1487 err: errors.New(noSuchFileErrMsg), 1488 }, 1489 { 1490 name: "File doesn't exist and YML Read parser specified", 1491 file: noSuchFileName, 1492 parser: "yml", 1493 err: errors.New(noSuchFileErrMsg), 1494 }, 1495 { 1496 name: "File doesn't exist and TOML Read parser specified", 1497 file: noSuchFileName, 1498 parser: "toml", 1499 err: errors.New(noSuchFileErrMsg), 1500 }, 1501 { 1502 name: "File doesn't exist and XML Read parser specified", 1503 file: noSuchFileName, 1504 parser: "xml", 1505 err: errors.New(noSuchFileErrMsg), 1506 }, 1507 { 1508 name: "File doesn't exist and CSV Read parser specified", 1509 file: noSuchFileName, 1510 parser: "csv", 1511 err: errors.New(noSuchFileErrMsg), 1512 }, 1513 { 1514 name: "File doesn't exist and invalid ('bad') Read parser specified", 1515 file: noSuchFileName, 1516 parser: "bad", 1517 err: storage.UnknownParserErr{Parser: "bad"}, 1518 }, 1519 { 1520 name: "File doesn't exist and invalid ('-') Read parser specified", 1521 file: noSuchFileName, 1522 parser: "-", 1523 err: storage.UnknownParserErr{Parser: "-"}, 1524 }, 1525 } 1526 1527 for _, testCase := range tests { 1528 tc := testCase 1529 t.Run(tc.name, func(t *testing.T) { 1530 _, err := dasel.NewFromFile(tc.file, tc.parser) 1531 1532 if tc.err == nil && err != nil { 1533 t.Errorf("expected err %v, got %v", tc.err, err) 1534 return 1535 } 1536 if tc.err != nil && err == nil { 1537 t.Errorf("expected err %v, got %v", tc.err, err) 1538 return 1539 } 1540 if tc.err != nil && err != nil && !strings.Contains(err.Error(), tc.err.Error()) { 1541 t.Errorf("expected err %v, got %v", tc.err, err) 1542 return 1543 } 1544 }) 1545 } 1546 } 1547 1548 // TestNode_Write tests writing to Writer. 1549 func TestNode_Write(t *testing.T) { 1550 type testData = map[string]interface{} 1551 type args struct { 1552 parser string 1553 compact bool 1554 escapeHTML bool 1555 } 1556 1557 commonData := testData{">": "&"} 1558 xmlData := testData{ 1559 "key": testData{ 1560 "value": "<&>", 1561 }, 1562 } 1563 xmlEscapedData := testData{ 1564 "key": testData{ 1565 "value": "<&>", 1566 }, 1567 } 1568 1569 tests := []struct { 1570 name string 1571 data testData 1572 args args 1573 wantWriter string 1574 wantErr bool 1575 }{ 1576 { 1577 name: "JSON, compact, no escape", 1578 data: commonData, 1579 args: args{ 1580 parser: "json", 1581 compact: true, 1582 escapeHTML: false, 1583 }, 1584 wantWriter: "{\">\":\"&\"}\n", 1585 wantErr: false, 1586 }, 1587 { 1588 name: "JSON, pretty, escape", 1589 data: commonData, 1590 args: args{ 1591 parser: "json", 1592 compact: false, 1593 escapeHTML: true, 1594 }, 1595 wantWriter: "{\n \"\\u003e\": \"\\u0026\"\n}\n", 1596 wantErr: false, 1597 }, 1598 1599 { 1600 name: "YAML, compact, no escape", 1601 data: commonData, 1602 args: args{ 1603 parser: "yaml", 1604 compact: true, 1605 escapeHTML: false, 1606 }, 1607 wantWriter: "'>': '&'\n", 1608 wantErr: false, 1609 }, 1610 { 1611 name: "YAML, pretty, escape", 1612 data: commonData, 1613 args: args{ 1614 parser: "yaml", 1615 compact: false, 1616 escapeHTML: true, 1617 }, 1618 wantWriter: "'>': '&'\n", 1619 wantErr: false, 1620 }, 1621 1622 { 1623 name: "YML, compact, no escape", 1624 data: commonData, 1625 args: args{ 1626 parser: "yml", 1627 compact: true, 1628 escapeHTML: false, 1629 }, 1630 wantWriter: "'>': '&'\n", 1631 wantErr: false, 1632 }, 1633 { 1634 name: "YML, pretty, escape", 1635 data: commonData, 1636 args: args{ 1637 parser: "yml", 1638 compact: false, 1639 escapeHTML: true, 1640 }, 1641 wantWriter: "'>': '&'\n", 1642 wantErr: false, 1643 }, 1644 1645 { 1646 name: "TOML, compact, no escape", 1647 data: commonData, 1648 args: args{ 1649 parser: "toml", 1650 compact: true, 1651 escapeHTML: false, 1652 }, 1653 wantWriter: "\">\" = \"&\"\n", 1654 wantErr: false, 1655 }, 1656 { 1657 name: "TOML, pretty, escape", 1658 data: commonData, 1659 args: args{ 1660 parser: "toml", 1661 compact: false, 1662 escapeHTML: true, 1663 }, 1664 wantWriter: "\">\" = \"&\"\n", 1665 wantErr: false, 1666 }, 1667 1668 { 1669 name: "PLAIN, pretty, escape", 1670 data: commonData, 1671 args: args{ 1672 parser: "plain", 1673 compact: false, 1674 escapeHTML: true, 1675 }, 1676 wantWriter: "map[>:&]\n", 1677 wantErr: false, 1678 }, 1679 { 1680 name: "PLAIN, pretty, no escape", 1681 data: commonData, 1682 args: args{ 1683 parser: "plain", 1684 compact: false, 1685 escapeHTML: false, 1686 }, 1687 wantWriter: "map[>:&]\n", 1688 wantErr: false, 1689 }, 1690 1691 { 1692 name: "-, pretty, escape", 1693 data: commonData, 1694 args: args{ 1695 parser: "-", 1696 compact: false, 1697 escapeHTML: true, 1698 }, 1699 wantWriter: "map[>:&]\n", 1700 wantErr: false, 1701 }, 1702 { 1703 name: "-, pretty, no escape", 1704 data: commonData, 1705 args: args{ 1706 parser: "-", 1707 compact: false, 1708 escapeHTML: false, 1709 }, 1710 wantWriter: "map[>:&]\n", 1711 wantErr: false, 1712 }, 1713 1714 { 1715 name: "XML, pretty, no escape", 1716 data: xmlData, 1717 args: args{ 1718 parser: "xml", 1719 compact: false, 1720 escapeHTML: false, 1721 }, 1722 // Invalid XML, but since we were asked not to escape, 1723 // this is probably the best we should do 1724 wantWriter: "<key>\n <value><&></value>\n</key>\n", 1725 wantErr: false, 1726 }, 1727 { 1728 name: "Pre-escaped XML, pretty, no escape", 1729 data: xmlEscapedData, 1730 args: args{ 1731 parser: "xml", 1732 compact: false, 1733 escapeHTML: false, 1734 }, 1735 wantWriter: "<key>\n <value><&></value>\n</key>\n", 1736 wantErr: false, 1737 }, 1738 1739 { 1740 name: "Invalid Write parser: bad", 1741 data: commonData, 1742 args: args{ 1743 parser: "bad", 1744 compact: false, 1745 escapeHTML: false, 1746 }, 1747 wantWriter: "", 1748 wantErr: true, 1749 }, 1750 } 1751 for _, tt := range tests { 1752 t.Run(tt.name, func(t *testing.T) { 1753 writer := &bytes.Buffer{} 1754 node := dasel.New(tt.data) 1755 if err := node.Write(writer, tt.args.parser, []storage.ReadWriteOption{ 1756 storage.EscapeHTMLOption(tt.args.escapeHTML), 1757 storage.PrettyPrintOption(!tt.args.compact), 1758 }); (err != nil) != tt.wantErr { 1759 t.Errorf("Node.Write() error = %v, wantErr %v", err, tt.wantErr) 1760 return 1761 } 1762 if gotWriter := writer.String(); gotWriter != tt.wantWriter { 1763 t.Errorf("Node.Write() = %v want %v", gotWriter, tt.wantWriter) 1764 } 1765 }) 1766 } 1767 }