github.com/tomwright/dasel@v1.27.3/internal/command/root_put_test.go (about) 1 package command_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "github.com/tomwright/dasel/internal/command" 7 "io" 8 "os" 9 "strings" 10 "testing" 11 ) 12 13 func TestRootCMD_Put(t *testing.T) { 14 t.Run("InvalidFile", expectErr( 15 []string{"put", "string", "-f", "bad.json", "-s", "x", "y"}, 16 "could not open input file", 17 )) 18 t.Run("MissingParser", expectErr( 19 []string{"put", "string", "-s", "x", "y"}, 20 "parser flag required when reading from stdin", 21 )) 22 t.Run("StdinStdout", expectOutput( 23 `{"name": "Tom"}`, 24 []string{"put", "string", "-f", "stdin", "-o", "stdout", "-p", "json", "-s", ".name", "Frank"}, 25 `{ 26 "name": "Frank" 27 } 28 `, 29 )) 30 t.Run("StdinStdoutAlias", expectOutput( 31 `{"name": "Tom"}`, 32 []string{"put", "string", "-f", "-", "-o", "-", "-p", "json", "-s", ".name", "Frank"}, 33 `{ 34 "name": "Frank" 35 } 36 `, 37 )) 38 39 t.Run("InvalidSingleSelector", expectErrFromInput( 40 `{"name": "Tom"}`, 41 []string{"put", "string", "-f", "stdin", "-o", "stdout", "-p", "json", "-s", "[-]", "Frank"}, 42 "invalid index: -", 43 )) 44 t.Run("InvalidMultiSelector", expectErrFromInput( 45 `{"name": "Tom"}`, 46 []string{"put", "string", "-f", "stdin", "-o", "stdout", "-p", "json", "-m", "-s", "[-]", "Frank"}, 47 "invalid index: -", 48 )) 49 50 t.Run("InvalidObjectSingleSelector", expectErrFromInput( 51 `{"name": "Tom"}`, 52 []string{"put", "object", "-f", "stdin", "-o", "stdout", "-p", "json", "-t", "string", "-s", "[-]", "Frank"}, 53 "invalid index: -", 54 )) 55 t.Run("InvalidMultiSelector", expectErrFromInput( 56 `{"name": "Tom"}`, 57 []string{"put", "object", "-f", "stdin", "-o", "stdout", "-p", "json", "-m", "-t", "string", "-s", "[-]", "Frank"}, 58 "invalid index: -", 59 )) 60 } 61 62 func putTest(in string, varType string, parser string, selector string, value string, out string, expErr error, additionalArgs ...string) func(t *testing.T) { 63 args := []string{ 64 "put", varType, 65 } 66 args = append(args, additionalArgs...) 67 args = append(args, "-p", parser, selector, value) 68 69 return baseTest(in, out, expErr, args...) 70 } 71 72 func baseTest(in string, out string, expErr error, args ...string) func(t *testing.T) { 73 return func(t *testing.T) { 74 cmd := command.NewRootCMD() 75 outputBuffer := bytes.NewBuffer([]byte{}) 76 77 cmd.SetOut(outputBuffer) 78 cmd.SetIn(strings.NewReader(in)) 79 cmd.SetArgs(args) 80 81 err := cmd.Execute() 82 83 if expErr == nil && err != nil { 84 t.Errorf("expected err %v, got %v", expErr, err) 85 return 86 } 87 if expErr != nil && err == nil { 88 t.Errorf("expected err %v, got %v", expErr, err) 89 return 90 } 91 if expErr != nil && err != nil && err.Error() != expErr.Error() { 92 t.Errorf("expected err %v, got %v", expErr, err) 93 return 94 } 95 96 output, err := io.ReadAll(outputBuffer) 97 if err != nil { 98 t.Errorf("unexpected error reading output buffer: %s", err) 99 return 100 } 101 102 outputStr := string(output) 103 if out != outputStr { 104 t.Errorf("expected result %v, got %v", out, outputStr) 105 } 106 } 107 } 108 109 func putFileTest(in string, varType string, parser string, selector string, value string, out string, outFile string, expErr error, additionalArgs ...string) func(t *testing.T) { 110 return func(t *testing.T) { 111 defer func() { 112 _ = os.Remove(outFile) 113 }() 114 cmd := command.NewRootCMD() 115 116 args := []string{ 117 "put", varType, 118 } 119 args = append(args, additionalArgs...) 120 args = append(args, "-p", parser, "-o", outFile, selector, value) 121 122 cmd.SetIn(strings.NewReader(in)) 123 cmd.SetArgs(args) 124 125 err := cmd.Execute() 126 127 if expErr == nil && err != nil { 128 t.Errorf("expected err %v, got %v", expErr, err) 129 return 130 } 131 if expErr != nil && err == nil { 132 t.Errorf("expected err %v, got %v", expErr, err) 133 return 134 } 135 if expErr != nil && err != nil && err.Error() != expErr.Error() { 136 t.Errorf("expected err %v, got %v", expErr, err) 137 return 138 } 139 140 output, err := os.ReadFile(outFile) 141 if err != nil { 142 t.Errorf("could not read output file: %s", err) 143 return 144 } 145 146 out = strings.TrimSpace(out) 147 outputStr := strings.TrimSpace(string(output)) 148 if out != outputStr { 149 t.Errorf("expected result %v, got %v", out, outputStr) 150 } 151 } 152 } 153 154 func TestRootCMD_Put_JSON(t *testing.T) { 155 t.Run("String", putStringTest(`{ 156 "id": "x" 157 }`, "json", "id", "y", `{ 158 "id": "y" 159 } 160 `, nil)) 161 t.Run("Int", putIntTest(`{ 162 "id": 123 163 }`, "json", "id", "456", `{ 164 "id": 456 165 } 166 `, nil)) 167 t.Run("Bool", putBoolTest(`{ 168 "id": true 169 }`, "json", "id", "false", `{ 170 "id": false 171 } 172 `, nil)) 173 t.Run("OverwriteObject", putObjectTest(`{ 174 "numbers": [ 175 { 176 "rank": 1, 177 "number": "one" 178 }, 179 { 180 "rank": 2, 181 "number": "two" 182 }, 183 { 184 "rank": 3, 185 "number": "three" 186 } 187 ] 188 }`, "json", ".numbers.[0]", []string{"number=five", "rank=5"}, []string{"string", "int"}, `{ 189 "numbers": [ 190 { 191 "number": "five", 192 "rank": 5 193 }, 194 { 195 "number": "two", 196 "rank": 2 197 }, 198 { 199 "number": "three", 200 "rank": 3 201 } 202 ] 203 }`, nil)) 204 205 t.Run("OverwriteObjectAtRoot", putObjectTest(`{ 206 "rank": 1, 207 "number": "one" 208 }`, "json", ".", []string{"number=five", "rank=5"}, []string{"string", "int"}, `{ 209 "number": "five", 210 "rank": 5 211 }`, nil)) 212 213 t.Run("OverwriteObjectAtRootCompact", putObjectTest(`{ 214 "rank": 1, 215 "number": "one" 216 }`, "json", ".", []string{"number=five", "rank=5"}, []string{"string", "int"}, `{"number":"five","rank":5} 217 `, nil, "-c")) 218 219 t.Run("MultipleObject", putObjectTest(`{ 220 "numbers": [ 221 { 222 "rank": 1, 223 "number": "one" 224 }, 225 { 226 "rank": 2, 227 "number": "two" 228 }, 229 { 230 "rank": 3, 231 "number": "three" 232 } 233 ] 234 }`, "json", ".numbers.[*]", []string{"number=five", "rank=5"}, []string{"string", "int"}, `{ 235 "numbers": [ 236 { 237 "number": "five", 238 "rank": 5 239 }, 240 { 241 "number": "five", 242 "rank": 5 243 }, 244 { 245 "number": "five", 246 "rank": 5 247 } 248 ] 249 }`, nil, "-m")) 250 251 t.Run("AppendObject", putObjectTest(`{ 252 "numbers": [ 253 { 254 "rank": 1, 255 "number": "one" 256 }, 257 { 258 "rank": 2, 259 "number": "two" 260 }, 261 { 262 "rank": 3, 263 "number": "three" 264 } 265 ] 266 }`, "json", ".numbers.[]", []string{"rank=4", "number=four"}, []string{"int", "string"}, `{ 267 "numbers": [ 268 { 269 "number": "one", 270 "rank": 1 271 }, 272 { 273 "number": "two", 274 "rank": 2 275 }, 276 { 277 "number": "three", 278 "rank": 3 279 }, 280 { 281 "number": "four", 282 "rank": 4 283 } 284 ] 285 }`, nil)) 286 287 t.Run("EmptyObject", putObjectTest(`{ 288 "numbers": [ 289 { 290 "rank": 1, 291 "number": "one" 292 }, 293 { 294 "rank": 2, 295 "number": "two" 296 }, 297 { 298 "rank": 3, 299 "number": "three" 300 } 301 ] 302 }`, "json", ".numbers.[]", []string{}, []string{}, `{ 303 "numbers": [ 304 { 305 "number": "one", 306 "rank": 1 307 }, 308 { 309 "number": "two", 310 "rank": 2 311 }, 312 { 313 "number": "three", 314 "rank": 3 315 }, 316 {} 317 ] 318 }`, nil)) 319 320 t.Run("AppendObjectMulti", putObjectTest(`{ 321 "numbers": [ 322 { 323 "rank": 1, 324 "number": "one" 325 }, 326 { 327 "rank": 2, 328 "number": "two" 329 }, 330 { 331 "rank": 3, 332 "number": "three" 333 } 334 ] 335 }`, "json", ".numbers.[]", []string{"rank=4", "number=four"}, []string{"int", "string"}, `{ 336 "numbers": [ 337 { 338 "number": "one", 339 "rank": 1 340 }, 341 { 342 "number": "two", 343 "rank": 2 344 }, 345 { 346 "number": "three", 347 "rank": 3 348 }, 349 { 350 "number": "four", 351 "rank": 4 352 } 353 ] 354 }`, nil, "-m")) 355 356 t.Run("MultipleString", putStringTest(`[ 357 {"value": "A"}, 358 {"value": "B"}, 359 {"value": "C"} 360 ]`, "json", "[*].value", "X", `[ 361 { 362 "value": "X" 363 }, 364 { 365 "value": "X" 366 }, 367 { 368 "value": "X" 369 } 370 ] 371 `, nil, "-m")) 372 373 t.Run("KeySearch", putStringTest(`{ 374 "users": [ 375 { 376 "primary": true, 377 "name": { 378 "first": "Tom", 379 "last": "Wright" 380 } 381 }, 382 { 383 "primary": false, 384 "extra": { 385 "name": { 386 "first": "Joe", 387 "last": "Blogs" 388 } 389 }, 390 "name": { 391 "first": "Jim", 392 "last": "Wright" 393 } 394 } 395 ] 396 }`, "json", ".(?:-=name).first", "Bobby", `{ 397 "users": [ 398 { 399 "name": { 400 "first": "Bobby", 401 "last": "Wright" 402 }, 403 "primary": true 404 }, 405 { 406 "extra": { 407 "name": { 408 "first": "Bobby", 409 "last": "Blogs" 410 } 411 }, 412 "name": { 413 "first": "Bobby", 414 "last": "Wright" 415 }, 416 "primary": false 417 } 418 ] 419 } 420 `, nil, "-m")) 421 422 t.Run("ValueSearch", putStringTest(`{ 423 "users": [ 424 { 425 "primary": true, 426 "name": { 427 "first": "Tom", 428 "last": "Wright" 429 } 430 }, 431 { 432 "primary": false, 433 "extra": { 434 "name": { 435 "first": "Joe", 436 "last": "Blogs" 437 } 438 }, 439 "name": { 440 "first": "Jim", 441 "last": "Wright" 442 } 443 } 444 ] 445 }`, "json", ".(?:.=Wright)", "Wrighto", `{ 446 "users": [ 447 { 448 "name": { 449 "first": "Tom", 450 "last": "Wrighto" 451 }, 452 "primary": true 453 }, 454 { 455 "extra": { 456 "name": { 457 "first": "Joe", 458 "last": "Blogs" 459 } 460 }, 461 "name": { 462 "first": "Jim", 463 "last": "Wrighto" 464 }, 465 "primary": false 466 } 467 ] 468 } 469 `, nil, "-m")) 470 471 t.Run("KeyValueSearch", putStringTest(`{ 472 "users": [ 473 { 474 "primary": true, 475 "name": { 476 "first": "Tom", 477 "last": "Wright" 478 } 479 }, 480 { 481 "primary": false, 482 "extra": { 483 "name": { 484 "first": "Joe", 485 "last": "Blogs" 486 } 487 }, 488 "name": { 489 "first": "Jim", 490 "last": "Wright" 491 } 492 } 493 ] 494 }`, "json", ".(?:.last=Wright).first", "Fred", `{ 495 "users": [ 496 { 497 "name": { 498 "first": "Fred", 499 "last": "Wright" 500 }, 501 "primary": true 502 }, 503 { 504 "extra": { 505 "name": { 506 "first": "Joe", 507 "last": "Blogs" 508 } 509 }, 510 "name": { 511 "first": "Fred", 512 "last": "Wright" 513 }, 514 "primary": false 515 } 516 ] 517 } 518 `, nil, "-m")) 519 520 t.Run("StringMultiObjectDocument", putStringTest(`{ 521 "id": "x" 522 } 523 { 524 "id": "y" 525 }`, "json", ".[0].id", "z", `{ 526 "id": "z" 527 } 528 { 529 "id": "y" 530 } 531 `, nil)) 532 533 t.Run("StringMultiArrayDocument", putStringTest(`[ 534 "a", 535 "b", 536 "c" 537 ] 538 [ 539 "d", 540 "e", 541 "f" 542 ]`, "json", ".[1].[1]", "z", `[ 543 "a", 544 "b", 545 "c" 546 ] 547 [ 548 "d", 549 "z", 550 "f" 551 ] 552 `, nil)) 553 554 t.Run("InsertDocumentAtProperty", putDocumentTest(`{}`, "json", ".person", `{"name":"Tom"}`, `{ 555 "person": { 556 "name": "Tom" 557 } 558 } 559 `, nil)) 560 561 t.Run("InsertDocumentAtPropertyCompact", putDocumentTest(`{}`, "json", ".person", `{"name":"Tom"}`, `{"person":{"name":"Tom"}} 562 `, nil, "-c")) 563 564 t.Run("InvalidDocumentParser", putDocumentTest(`{}`, "json", ".person", `name: Tom`, ``, 565 fmt.Errorf("could not get document parser: unknown parser: bad"), "-d", "bad")) 566 567 t.Run("InsertDocumentAtPropertyWithDifferentParser", putDocumentTest(`{}`, "json", ".person", `name: Tom`, `{ 568 "person": { 569 "name": "Tom" 570 } 571 } 572 `, nil, "-d", "yaml")) 573 574 t.Run("AppendDocumentToProperty", putDocumentTest(`{"people": []}`, "json", ".people.[]", `{"name":"Tom"}`, `{ 575 "people": [ 576 { 577 "name": "Tom" 578 } 579 ] 580 } 581 `, nil)) 582 583 t.Run("AppendDocumentToPropertyMulti", putDocumentTest(`{"people": []}{"people": []}`, "json", ".[*].people.[]", `{"name":"Tom"}`, `{ 584 "people": [ 585 { 586 "name": "Tom" 587 } 588 ] 589 } 590 { 591 "people": [ 592 { 593 "name": "Tom" 594 } 595 ] 596 } 597 `, nil, "-m")) 598 599 t.Run("InsertDocumentAtRoot", putDocumentTest(`{}`, "json", ".", `{"name":"Tom"}`, `{ 600 "name": "Tom" 601 } 602 `, nil)) 603 604 t.Run("AppendDocumentAtRoot", putDocumentTest(`[]`, "json", ".[]", `{"name":"Tom"}`, `[ 605 { 606 "name": "Tom" 607 } 608 ] 609 `, nil)) 610 611 t.Run("AppendDocumentAtRootMulti", putDocumentTest(`[][]`, "json", ".[*].[]", `{"name":"Tom"}`, `[ 612 { 613 "name": "Tom" 614 } 615 ] 616 [ 617 { 618 "name": "Tom" 619 } 620 ] 621 `, nil, "-m")) 622 623 // https://github.com/TomWright/dasel/issues/66 624 t.Run("PutJSONDocumentAtYAMLProperty", putDocumentTest(`foo: true 625 bar: 5 626 baz: 627 qux: false 628 quux: "yes" 629 quuz: 7`, "yaml", ".baz", `{"qux": false,"quux": "no","quuz": 8}`, `bar: 5 630 baz: 631 quux: "no" 632 quuz: 8 633 qux: false 634 foo: true 635 `, nil, "-d", "json")) 636 637 t.Run("MergeInputDocumentsPut", putIntTest(` 638 { 639 "number": 1 640 } 641 { 642 "number": 2 643 } 644 { 645 "number": 3 646 } 647 `, "json", ".[0].number", `4`, `[ 648 { 649 "number": 4 650 }, 651 { 652 "number": 2 653 }, 654 { 655 "number": 3 656 } 657 ] 658 `, nil, "--merge-input-documents")) 659 660 t.Run("ValueFlag", func(t *testing.T) { 661 // Test -v/--value flag 662 // Workaround for https://github.com/TomWright/dasel/issues/117 663 664 t.Run("StringWithDash", baseTest(`{ 665 "id": "x" 666 }`, `{ 667 "id": "-abc" 668 } 669 `, nil, "put", "string", "-p", "json", "-v", "-abc", ".id")) 670 671 t.Run("NegativeInt", baseTest(`{ 672 "id": 1 673 }`, `{ 674 "id": -1 675 } 676 `, nil, "put", "int", "-p", "json", "-v", "-1", ".id")) 677 }) 678 t.Run("StringWithDashWithSelectorFlag", baseTest(`{ 679 "id": "x" 680 }`, `{ 681 "id": "-abc" 682 } 683 `, nil, "put", "string", "-p", "json", "-v", "-abc", "-s", ".id")) 684 685 t.Run("NegativeIntWithSelectorFlag", baseTest(`{ 686 "id": 1 687 }`, `{ 688 "id": -1 689 } 690 `, nil, "put", "int", "-p", "json", "-v", "-1", "-s", ".id")) 691 692 t.Run("PutStringEscapeHTMLOn", putStringTest(`{ 693 "user": "Old" 694 } 695 `, "json", `.user`, `Tom <contact@tomwright.me>`, `{ 696 "user": "Tom \u003ccontact@tomwright.me\u003e" 697 } 698 `, nil, "--escape-html=true")) 699 700 t.Run("PutStringEscapeHTMLOff", putStringTest(`{ 701 "user": "Tom <contact@tomwright.me>" 702 } 703 `, "json", `.user`, `Tom <contact@tomwright.me>`, `{ 704 "user": "Tom <contact@tomwright.me>" 705 } 706 `, nil, "--escape-html=false")) 707 708 t.Run("PutObjectEscapeHTMLOn", putObjectTest(`{ 709 "user": "Old" 710 } 711 `, "json", `.`, []string{`user=Tom <contact@tomwright.me>`}, []string{"string"}, `{ 712 "user": "Tom \u003ccontact@tomwright.me\u003e" 713 } 714 `, nil, "--escape-html=true")) 715 716 t.Run("PutObjectEscapeHTMLOff", putObjectTest(`{ 717 "user": "Old" 718 } 719 `, "json", `.`, []string{`user=Tom <contact@tomwright.me>`}, []string{"string"}, `{ 720 "user": "Tom <contact@tomwright.me>" 721 } 722 `, nil, "--escape-html=false")) 723 724 t.Run("PutDocumentEscapeHTMLOn", putDocumentTest(`{ 725 "user": "Old" 726 } 727 `, "json", `.`, `{"user": "Tom <contact@tomwright.me>"}`, `{ 728 "user": "Tom \u003ccontact@tomwright.me\u003e" 729 } 730 `, nil, "--escape-html=true")) 731 732 t.Run("PutDocumentEscapeHTMLOff", putDocumentTest(`{ 733 "user": "Tom <contact@tomwright.me>" 734 } 735 `, "json", `.`, `{"user": "Tom <contact@tomwright.me>"}`, `{ 736 "user": "Tom <contact@tomwright.me>" 737 } 738 `, nil, "--escape-html=false")) 739 740 t.Run("StringFromFile", putStringTest(`{ 741 "id": "x" 742 }`, "json", ".value", "", `{ 743 "id": "x", 744 "value": "This is a string value" 745 } 746 `, nil, "--value-file", "../../tests/assets/string-value.txt")) 747 748 t.Run("IntFromFile", putIntTest(`{ 749 "id": "x" 750 }`, "json", ".value", "", `{ 751 "id": "x", 752 "value": 12345 753 } 754 `, nil, "--value-file", "../../tests/assets/int-value.txt")) 755 756 t.Run("DocumentFromFile", putDocumentTest(`{ 757 "id": "x" 758 }`, "json", ".value", "", `{ 759 "id": "x", 760 "value": { 761 "this": "is a value" 762 } 763 } 764 `, nil, "--value-file", "../../tests/assets/json-value.json")) 765 } 766 767 func TestRootCMD_Put_YAML(t *testing.T) { 768 t.Run("String", putStringTest(` 769 id: "x" 770 name: "Tom" 771 `, "yaml", "id", "y", `id: "y" 772 name: Tom 773 `, nil)) 774 t.Run("StringInFile", putFileTest(` 775 id: "x" 776 name: "Tom" 777 `, "string", "yaml", "id", "y", `id: "y" 778 name: Tom 779 `, "TestRootCMD_Put_YAML_out.yaml", nil)) 780 t.Run("Int", putIntTest(` 781 id: 123 782 `, "yaml", "id", "456", `id: 456 783 `, nil)) 784 t.Run("Bool", putBoolTest(` 785 id: true 786 `, "yaml", "id", "false", `id: false 787 `, nil)) 788 t.Run("OverwriteObject", putObjectTest(` 789 numbers: 790 - number: one 791 rank: 1 792 - number: two 793 rank: 2 794 - number: three 795 rank: 3 796 `, "yaml", ".numbers.[0]", []string{"number=five", "rank=5"}, []string{"string", "int"}, ` 797 numbers: 798 - number: five 799 rank: 5 800 - number: two 801 rank: 2 802 - number: three 803 rank: 3 804 `, nil)) 805 t.Run("StringInMultiDocument", putStringTest(` 806 id: "x" 807 --- 808 id: "y" 809 --- 810 id: "z" 811 `, "yaml", "[1].id", "1", `id: x 812 --- 813 id: "1" 814 --- 815 id: z 816 `, nil)) 817 818 t.Run("StringWithDotInName", putStringTest(` 819 id: "asd" 820 my.name: "Tom" 821 `, "yaml", `my\.name`, "Jim", `id: asd 822 my.name: Jim 823 `, nil)) 824 825 t.Run("NewValInExistingMap", putStringTest(` 826 metadata: 827 annotations: 828 node.longhorn.io/default-disks-config: '[ { "name":"fast", "path":"/mnt/data-fast1", "allowScheduling":true, "tags":["fast"]}, { "name":"slow", "path":"/mnt/data-slow1", "allowScheduling":true, "tags":["slow"]} ]' 829 `, "yaml", `metadata.labels.node\.longhorn\.io\/create-default-disk`, "config", `metadata: 830 annotations: 831 node.longhorn.io/default-disks-config: '[ { "name":"fast", "path":"/mnt/data-fast1", 832 "allowScheduling":true, "tags":["fast"]}, { "name":"slow", "path":"/mnt/data-slow1", 833 "allowScheduling":true, "tags":["slow"]} ]' 834 labels: 835 node.longhorn.io/create-default-disk: config 836 `, nil)) 837 838 // https://github.com/TomWright/dasel/issues/102 839 // Worked in v1.13.2 840 t.Run("BlankInput", putStringTest(``, "yaml", `[0].job_name`, "logging", `- job_name: logging 841 `, nil)) 842 } 843 844 func TestRootCMD_Put_TOML(t *testing.T) { 845 t.Run("String", putStringTest(` 846 id = "x" 847 `, "toml", "id", "y", `id = "y" 848 `, nil)) 849 t.Run("Int", putIntTest(` 850 id = 123 851 `, "toml", "id", "456", `id = 456 852 `, nil)) 853 t.Run("Bool", putBoolTest(` 854 id = true 855 `, "toml", "id", "false", `id = false 856 `, nil)) 857 t.Run("OverwriteObject", putObjectTest(` 858 [[numbers]] 859 number = "one" 860 rank = 1 861 862 [[numbers]] 863 number = "two" 864 rank = 2 865 866 [[numbers]] 867 number = "three" 868 rank = 3 869 `, "toml", ".numbers.[0]", []string{"number=five", "rank=5"}, []string{"string", "int"}, ` 870 [[numbers]] 871 number = "five" 872 rank = 5 873 874 [[numbers]] 875 number = "two" 876 rank = 2 877 878 [[numbers]] 879 number = "three" 880 rank = 3 881 `, nil)) 882 } 883 884 func TestRootCMD_Put_XML(t *testing.T) { 885 t.Run("String", putStringTest(`<data><id>x</id></data>`, "xml", ".data.id", "y", `<data> 886 <id>y</id> 887 </data> 888 `, nil)) 889 t.Run("Int", putIntTest(`<data><id>1</id></data>`, "xml", ".data.id", "2", `<data> 890 <id>2</id> 891 </data> 892 `, nil)) 893 t.Run("Bool", putBoolTest(`<data><id>false</id></data>`, "xml", ".data.id", "true", `<data> 894 <id>true</id> 895 </data> 896 `, nil)) 897 t.Run("OverwriteObject", putObjectTest(`<data><id>x</id></data>`, "xml", ".data", []string{"id=y", "rank=5"}, []string{"string", "int"}, `<data> 898 <id>y</id> 899 <rank>5</rank> 900 </data> 901 `, nil)) 902 t.Run("AppendObject", putObjectTest(`<data><item><value>1</value></item><item><value>2</value></item></data>`, "xml", ".data.item.[]", []string{"value=3"}, []string{"int"}, `<data> 903 <item> 904 <value>1</value> 905 </item> 906 <item> 907 <value>2</value> 908 </item> 909 <item> 910 <value>3</value> 911 </item> 912 </data> 913 `, nil)) 914 } 915 916 func TestRootCMD_Put_CSV(t *testing.T) { 917 t.Run("String", putStringTest(`id,name 918 1,Tom 919 2,Jim 920 `, "csv", ".[0].id", "3", `id,name 921 3,Tom 922 2,Jim 923 `, nil)) 924 t.Run("NewString", putStringTest(`id,name 925 1,Tom 926 2,Jim 927 `, "csv", ".[0].age", "27", `id,name,age 928 1,Tom,27 929 2,Jim, 930 `, nil)) 931 } 932 933 func putObjectTest(in string, parser string, selector string, values []string, types []string, out string, expErr error, additionalArgs ...string) func(t *testing.T) { 934 return func(t *testing.T) { 935 cmd := command.NewRootCMD() 936 outputBuffer := bytes.NewBuffer([]byte{}) 937 938 args := []string{ 939 "put", "object", "-p", parser, "-o", "stdout", 940 } 941 for _, t := range types { 942 args = append(args, "-t", t) 943 } 944 args = append(args, additionalArgs...) 945 args = append(args, selector) 946 args = append(args, values...) 947 948 cmd.SetOut(outputBuffer) 949 cmd.SetIn(strings.NewReader(in)) 950 cmd.SetArgs(args) 951 952 err := cmd.Execute() 953 954 if expErr == nil && err != nil { 955 t.Errorf("expected err %v, got %v", expErr, err) 956 return 957 } 958 if expErr != nil && err == nil { 959 t.Errorf("expected err %v, got %v", expErr, err) 960 return 961 } 962 if expErr != nil && err != nil && err.Error() != expErr.Error() { 963 t.Errorf("expected err %v, got %v", expErr, err) 964 return 965 } 966 967 output, err := io.ReadAll(outputBuffer) 968 if err != nil { 969 t.Errorf("unexpected error reading output buffer: %s", err) 970 return 971 } 972 973 out = strings.TrimSpace(out) 974 outputStr := strings.TrimSpace(string(output)) 975 if out != outputStr { 976 t.Errorf("expected result %v, got %v", out, outputStr) 977 } 978 } 979 } 980 981 func putDocumentTest(in string, parser string, selector string, document string, out string, expErr error, additionalArgs ...string) func(t *testing.T) { 982 return func(t *testing.T) { 983 cmd := command.NewRootCMD() 984 outputBuffer := bytes.NewBuffer([]byte{}) 985 986 args := []string{ 987 "put", "document", "-p", parser, "-o", "stdout", 988 } 989 args = append(args, additionalArgs...) 990 args = append(args, selector) 991 args = append(args, document) 992 993 cmd.SetOut(outputBuffer) 994 cmd.SetIn(strings.NewReader(in)) 995 cmd.SetArgs(args) 996 997 err := cmd.Execute() 998 999 if expErr == nil && err != nil { 1000 t.Errorf("expected err %v, got %v", expErr, err) 1001 return 1002 } 1003 if expErr != nil && err == nil { 1004 t.Errorf("expected err %v, got %v", expErr, err) 1005 return 1006 } 1007 if expErr != nil && err != nil && err.Error() != expErr.Error() { 1008 t.Errorf("expected err %v, got %v", expErr, err) 1009 return 1010 } 1011 if expErr != nil { 1012 return 1013 } 1014 1015 output, err := io.ReadAll(outputBuffer) 1016 if err != nil { 1017 t.Errorf("unexpected error reading output buffer: %s", err) 1018 return 1019 } 1020 1021 out = strings.TrimSpace(out) 1022 outputStr := strings.TrimSpace(string(output)) 1023 if out != outputStr { 1024 t.Errorf("expected result %v, got %v", out, outputStr) 1025 } 1026 } 1027 } 1028 1029 func putStringTest(in string, parser string, selector string, value string, out string, expErr error, additionalArgs ...string) func(t *testing.T) { 1030 return putTest(in, "string", parser, selector, value, out, expErr, additionalArgs...) 1031 } 1032 1033 func putIntTest(in string, parser string, selector string, value string, out string, expErr error, additionalArgs ...string) func(t *testing.T) { 1034 return putTest(in, "int", parser, selector, value, out, expErr, additionalArgs...) 1035 } 1036 1037 func putBoolTest(in string, parser string, selector string, value string, out string, expErr error, additionalArgs ...string) func(t *testing.T) { 1038 return putTest(in, "bool", parser, selector, value, out, expErr, additionalArgs...) 1039 }