github.com/tomwright/dasel@v1.27.3/internal/command/root_select_test.go (about) 1 package command_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "github.com/tomwright/dasel/internal/command" 7 "io" 8 "strings" 9 "testing" 10 ) 11 12 const jsonDataSingle = `{"x": "asd"}` 13 const yamlDataSingle = `x: asd` 14 const tomlDataSingle = `x="asd"` 15 const xmlDataSingle = `<x>asd</x>` 16 17 const jsonData = `{ 18 "id": "1111", 19 "details": { 20 "name": "Tom", 21 "age": 27, 22 "addresses": [ 23 { 24 "street": "101 Some Street", 25 "town": "Some Town", 26 "county": "Some Country", 27 "postcode": "XXX XXX", 28 "primary": true 29 }, 30 { 31 "street": "34 Another Street", 32 "town": "Another Town", 33 "county": "Another County", 34 "postcode": "YYY YYY" 35 } 36 ] 37 } 38 }` 39 40 const yamlData = ` 41 id: 1111 42 details: 43 name: Tom 44 age: 27 45 addresses: 46 - street: 101 Some Street 47 town: Some Town 48 county: Some County 49 postcode: XXX XXX 50 primary: true 51 - street: 34 Another Street 52 town: Another Town 53 county: Another County 54 postcode: YYY YYY 55 ` 56 57 const tomlData = `id = "1111" 58 [details] 59 name = "Tom" 60 age = 27 61 [[details.addresses]] 62 street = "101 Some Street" 63 town = "Some Town" 64 county = "Some County" 65 postcode = "XXX XXX" 66 primary = true 67 [[details.addresses]] 68 street = "34 Another Street" 69 town = "Another Town" 70 county = "Another County" 71 postcode = "YYY YYY" 72 ` 73 74 const xmlData = `<data> 75 <id>1111</id> 76 <details> 77 <name>Tom</name> 78 <age>27</age> 79 <addresses primary="true"> 80 <street>101 Some Street</street> 81 <town>Some Town</town> 82 <county>Some County</county> 83 <postcode>XXX XXX</postcode> 84 </addresses> 85 <addresses> 86 <street>34 Another Street</street> 87 <town>Another Town</town> 88 <county>Another County</county> 89 <postcode>YYY YYY</postcode> 90 </addresses> 91 </details> 92 </data> 93 ` 94 95 const csvData = `id,name 96 1,Tom 97 2,Jim 98 ` 99 100 func newline(x string) string { 101 return x + "\n" 102 } 103 104 func TestRootCMD_Select(t *testing.T) { 105 t.Run("InvalidFile", expectErr( 106 []string{"select", "-f", "bad.json", "-s", "x"}, 107 "could not open input file", 108 )) 109 t.Run("MissingParser", expectErr( 110 []string{"select", "-s", "x"}, 111 "parser flag required when reading from stdin", 112 )) 113 t.Run("Stdin", expectOutput( 114 `{"name": "Tom"}`, 115 []string{"select", "-f", "stdin", "-p", "json", "-s", ".name"}, 116 `"Tom" 117 `, 118 )) 119 t.Run("StdinAlias", expectOutput( 120 `{"name": "Tom"}`, 121 []string{"select", "-f", "-", "-p", "json", "-s", ".name"}, 122 `"Tom" 123 `, 124 )) 125 126 t.Run("InvalidSingleSelector", expectErrFromInput( 127 `{"name": "Tom"}`, 128 []string{"select", "-p", "json", "-s", "[-]"}, 129 "invalid index: -", 130 )) 131 t.Run("InvalidMultiSelector", expectErrFromInput( 132 `{"name": "Tom"}`, 133 []string{"select", "-p", "json", "-m", "-s", "[-]"}, 134 "invalid index: -", 135 )) 136 } 137 138 func selectTest(in string, parser string, selector string, output string, expErr error, additionalArgs ...string) func(t *testing.T) { 139 return selectTestCheck(in, parser, selector, func(out string) error { 140 if out != output { 141 return fmt.Errorf("expected %v, got %v", output, out) 142 } 143 return nil 144 }, expErr, additionalArgs...) 145 } 146 147 func selectTestContainsLines(in string, parser string, selector string, output []string, expErr error, additionalArgs ...string) func(t *testing.T) { 148 return selectTestCheck(in, parser, selector, func(out string) error { 149 splitOut := strings.Split(out, "\n") 150 for _, s := range output { 151 found := false 152 for _, got := range splitOut { 153 if s == got { 154 found = true 155 break 156 } 157 } 158 if !found { 159 return fmt.Errorf("required value not found: %s", s) 160 } 161 } 162 return nil 163 }, expErr, additionalArgs...) 164 } 165 166 func selectTestCheck(in string, parser string, selector string, checkFn func(out string) error, expErr error, additionalArgs ...string) func(t *testing.T) { 167 return func(t *testing.T) { 168 cmd := command.NewRootCMD() 169 outputBuffer := bytes.NewBuffer([]byte{}) 170 171 args := []string{ 172 "select", "-p", parser, 173 } 174 if additionalArgs != nil { 175 args = append(args, additionalArgs...) 176 } 177 args = append(args, selector) 178 179 cmd.SetOut(outputBuffer) 180 cmd.SetIn(strings.NewReader(in)) 181 cmd.SetArgs(args) 182 183 err := cmd.Execute() 184 185 if expErr == nil && err != nil { 186 t.Errorf("expected err %v, got %v", expErr, err) 187 return 188 } 189 if expErr != nil && err == nil { 190 t.Errorf("expected err %v, got %v", expErr, err) 191 return 192 } 193 if expErr != nil && err != nil && err.Error() != expErr.Error() { 194 t.Errorf("expected err %v, got %v", expErr, err) 195 return 196 } 197 198 output, err := io.ReadAll(outputBuffer) 199 if err != nil { 200 t.Errorf("unexpected error reading output buffer: %s", err) 201 return 202 } 203 204 if err := checkFn(string(output)); err != nil { 205 t.Errorf("unexpected output: %s", err) 206 } 207 } 208 } 209 210 func selectTestFromFile(inputPath string, selector string, out string, expErr error) func(t *testing.T) { 211 return func(t *testing.T) { 212 cmd := command.NewRootCMD() 213 outputBuffer := bytes.NewBuffer([]byte{}) 214 215 args := []string{ 216 "select", "-f", inputPath, "-s", selector, 217 } 218 219 cmd.SetOut(outputBuffer) 220 cmd.SetArgs(args) 221 222 err := cmd.Execute() 223 224 if expErr == nil && err != nil { 225 t.Errorf("expected err %v, got %v", expErr, err) 226 return 227 } 228 if expErr != nil && err == nil { 229 t.Errorf("expected err %v, got %v", expErr, err) 230 return 231 } 232 if expErr != nil && err != nil && err.Error() != expErr.Error() { 233 t.Errorf("expected err %v, got %v", expErr, err) 234 return 235 } 236 237 output, err := io.ReadAll(outputBuffer) 238 if err != nil { 239 t.Errorf("unexpected error reading output buffer: %s", err) 240 return 241 } 242 243 if out != string(output) { 244 t.Errorf("expected result %v, got %v", out, string(output)) 245 } 246 } 247 } 248 249 func TestRootCmd_Select_JSON(t *testing.T) { 250 t.Run("RootElement", selectTest(jsonDataSingle, "json", ".", newline(`{ 251 "x": "asd" 252 }`), nil)) 253 t.Run("SingleProperty", selectTest(jsonData, "json", ".id", newline(`"1111"`), nil)) 254 t.Run("ObjectProperty", selectTest(jsonData, "json", ".details.name", newline(`"Tom"`), nil)) 255 t.Run("Index", selectTest(jsonData, "json", ".details.addresses.[0].street", newline(`"101 Some Street"`), nil)) 256 t.Run("Index", selectTest(jsonData, "json", ".details.addresses.[1].street", newline(`"34 Another Street"`), nil)) 257 t.Run("DynamicString", selectTest(jsonData, "json", ".details.addresses.(postcode=XXX XXX).street", newline(`"101 Some Street"`), nil)) 258 t.Run("DynamicString", selectTest(jsonData, "json", ".details.addresses.(postcode=YYY YYY).street", newline(`"34 Another Street"`), nil)) 259 t.Run("QueryFromFile", selectTestFromFile("./../../tests/assets/example.json", ".preferences.favouriteColour", newline(`"red"`), nil)) 260 261 t.Run("MultiProperty", selectTest(jsonData, "json", ".details.addresses.[*].street", newline(`"101 Some Street" 262 "34 Another Street"`), nil, "-m")) 263 264 t.Run("MultiRoot", selectTest(jsonDataSingle, "json", ".", newline(`{ 265 "x": "asd" 266 }`), nil, "-m")) 267 268 t.Run("SubSelector", selectTest(`{ 269 "users": [ 270 { 271 "primary": true, 272 "name": { 273 "first": "Tom", 274 "last": "Wright" 275 } 276 }, 277 { 278 "primary": false, 279 "name": { 280 "first": "Jim", 281 "last": "Wright" 282 } 283 } 284 ] 285 }`, "json", ".users.(name.first=Tom).primary", newline(`true`), nil)) 286 287 t.Run("SubSubSelector", selectTest(`{ 288 "users": [ 289 { 290 "name": { 291 "first": "Tom", 292 "last": "Wright" 293 }, 294 "addresses": [ 295 { 296 "primary": true, 297 "number": 123 298 }, 299 { 300 "primary": false, 301 "number": 456 302 } 303 ] 304 } 305 ] 306 }`, "json", ".users.(.addresses.(.primary=true).number=123).name.first", newline(`"Tom"`), nil)) 307 308 t.Run("SubSubAndSelector", selectTest(`{ 309 "users": [ 310 { 311 "name": { 312 "first": "Tom", 313 "last": "Wright" 314 }, 315 "addresses": [ 316 { 317 "primary": true, 318 "number": 123 319 }, 320 { 321 "primary": false, 322 "number": 456 323 } 324 ] 325 } 326 ] 327 }`, "json", ".users.(.addresses.(.primary=true).number=123)(.name.last=Wright).name.first", newline(`"Tom"`), nil)) 328 329 t.Run("KeySearch", selectTestContainsLines(`{ 330 "users": [ 331 { 332 "primary": true, 333 "name": { 334 "first": "Tom", 335 "last": "Wright" 336 } 337 }, 338 { 339 "primary": false, 340 "extra": { 341 "name": { 342 "first": "Joe", 343 "last": "Blogs" 344 } 345 }, 346 "name": { 347 "first": "Jim", 348 "last": "Wright" 349 } 350 } 351 ] 352 }`, "json", ".(?:-=name).first", []string{`"Tom"`, `"Joe"`, `"Jim"`}, nil, "-m")) 353 354 t.Run("NullNotFound", selectTest(`{}`, "json", ".asd", newline(`null`), nil, "-n")) 355 t.Run("NullNotFoundMulti", selectTest(`{}`, "json", ".asd", newline(`null`), nil, "-m", "-n")) 356 357 t.Run("ObjectKeysSelector", selectTestContainsLines(jsonData, "json", ".-", []string{`"id"`, 358 `"details"`}, nil, "-m")) 359 360 t.Run("ArrayIndexesSelector", selectTest(jsonData, "json", ".details.addresses.-", newline(`"0" 361 "1"`), nil, "-m")) 362 363 t.Run("RootElementCompactShortFlag", selectTest(`{ 364 "x": "asd" 365 }`, "json", ".", newline(`{"x":"asd"}`), nil, "-c")) 366 t.Run("RootElementCompactLongFlag", selectTest(`{ 367 "x": "asd" 368 }`, "json", ".", newline(`{"x":"asd"}`), nil, "--compact")) 369 370 t.Run("LengthFlagList", selectTest(`{ 371 "x": [ "a", "b", "c" ] 372 }`, "json", ".x", newline(`3`), nil, "--length")) 373 t.Run("LengthFlagMap", selectTest(`{ 374 "x": { "a": 1, "b": 2, "c": 3 } 375 }`, "json", ".x", newline(`3`), nil, "--length")) 376 t.Run("LengthFlagString", selectTest(`{ 377 "x": "asd" 378 }`, "json", ".x", newline(`3`), nil, "--length")) 379 t.Run("LengthFlagInt", selectTest(`{ 380 "x": 123 381 }`, "json", ".x", newline(`3`), nil, "--length")) 382 t.Run("LengthFlagBool", selectTest(`{ 383 "x": true 384 }`, "json", ".x", newline(`4`), nil, "--length")) 385 t.Run("LengthFlagMulti", selectTest(`[ 386 [ "a", "b", "c" ], 387 { "a": 1 }, 388 "hello there", 389 12345, 390 123.45, 391 true 392 ]`, "json", ".[*]", newline(`3 393 1 394 11 395 5 396 6 397 4`), nil, "--length", "-m")) 398 399 t.Run("NullInput", selectTest(`null`, "json", `.`, newline("{}"), nil)) 400 t.Run("EmptyDocument", selectTest(`{}`, "json", `.`, newline("{}"), nil)) 401 t.Run("EmptyArray", selectTest(`[]`, "json", `.`, newline("[]"), nil)) 402 t.Run("BlankInput", selectTest(``, "json", `.`, newline("{}"), nil)) 403 404 t.Run("LengthSelector", selectTest(jsonData, "json", `.details.addresses.[#]`, newline("2"), nil)) 405 t.Run("LengthSelectorMultiple", selectTest(jsonData, "json", `.details.addresses.[#]`, newline("2"), nil, "-m")) 406 t.Run("LengthSelectorMultiple", selectTest(jsonData, "json", `.details.addresses.[*].[#]`, newline("5\n4"), nil, "-m")) 407 t.Run("LengthDynamicSelector", selectTest(`{ 408 "a": { 409 "id": 1, 410 "uses": [1] 411 }, 412 "b": { 413 "id": 2, 414 "uses": [1, 2] 415 }, 416 "c": { 417 "id": 3, 418 "uses": [1, 2, 3] 419 } 420 }`, "json", `.(.uses.[#]=2).id`, newline("2"), nil)) 421 t.Run("LengthDynamicSelectorMultiple", selectTest(`[ 422 { 423 "id": 1, 424 "uses": [1] 425 }, 426 { 427 "id": 2, 428 "uses": [1, 2] 429 }, 430 { 431 "id": 3, 432 "uses": [1, 2, 3] 433 }, 434 { 435 "id": 4, 436 "uses": [3, 4] 437 } 438 ]`, "json", `.(.uses.[#]=2).id`, newline("2\n4"), nil, "-m")) 439 t.Run("LengthDynamicSelectorMoreThan", selectTest(`[ 440 { 441 "id": 1, 442 "uses": [1] 443 }, 444 { 445 "id": 2, 446 "uses": [1, 2] 447 }, 448 { 449 "id": 3, 450 "uses": [1, 2, 3] 451 }, 452 { 453 "id": 4, 454 "uses": [3, 4] 455 } 456 ]`, "json", `.(.uses.[#]>2).id`, newline("3"), nil, "-m")) 457 458 t.Run("MergeInputDocuments", selectTest(`{ 459 "number": 1 460 } 461 { 462 "number": 2 463 } 464 { 465 "number": 3 466 } 467 `, "json", `.`, `[ 468 { 469 "number": 1 470 }, 471 { 472 "number": 2 473 }, 474 { 475 "number": 3 476 } 477 ] 478 `, nil, "--merge-input-documents")) 479 480 t.Run("EscapeHTMLOn", selectTest(`{ 481 "user": "Tom <contact@tomwright.me>" 482 } 483 `, "json", `.`, `{ 484 "user": "Tom \u003ccontact@tomwright.me\u003e" 485 } 486 `, nil, "--escape-html=true")) 487 488 t.Run("EscapeHTMLOff", selectTest(`{ 489 "user": "Tom <contact@tomwright.me>" 490 } 491 `, "json", `.`, `{ 492 "user": "Tom <contact@tomwright.me>" 493 } 494 `, nil, "--escape-html=false")) 495 496 t.Run("MixedDynamicSelectors", selectTest(`{ 497 "plugins": [ 498 "@semantic-release/commit-analyzer", 499 "@semantic-release/release-notes-generator", 500 "@semantic-release/gitlab", 501 [ 502 "@semantic-release/git", 503 { 504 "assets": [ 505 "tbump.toml", 506 "**/pyproject.toml", 507 "**/setup.py", 508 "README.md" 509 ], 510 "message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}" 511 } 512 ], 513 [ 514 "@semantic-release/git", 515 { 516 "assets": [ 517 "y" 518 ], 519 "message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}" 520 } 521 ] 522 ] 523 }`, "json", `.plugins.([@]=array).([@]=map).assets`, `[ 524 "tbump.toml", 525 "**/pyproject.toml", 526 "**/setup.py", 527 "README.md" 528 ] 529 [ 530 "y" 531 ] 532 `, nil, "-m")) 533 534 t.Run("SearchOptional", selectTest(`{ 535 "users": [ 536 { 537 "name": "Tom", 538 "blocked": true 539 }, 540 { 541 "name": "Jim", 542 "blocked": false 543 }, 544 { 545 "name": "Frank" 546 } 547 ] 548 }`, "json", `.users.(#:blocked=true).name`, `Tom 549 `, nil, "-m", "--plain")) 550 551 } 552 553 func TestRootCmd_Select_YAML(t *testing.T) { 554 t.Run("RootElement", selectTest(yamlDataSingle, "yaml", ".", newline(`x: asd`), nil)) 555 t.Run("SingleProperty", selectTest(yamlData, "yaml", ".id", newline(`1111`), nil)) 556 t.Run("ObjectProperty", selectTest(yamlData, "yaml", ".details.name", newline(`Tom`), nil)) 557 t.Run("Index", selectTest(yamlData, "yaml", ".details.addresses.[0].street", newline(`101 Some Street`), nil)) 558 t.Run("Index", selectTest(yamlData, "yaml", ".details.addresses.[1].street", newline(`34 Another Street`), nil)) 559 t.Run("DynamicString", selectTest(yamlData, "yaml", ".details.addresses.(postcode=XXX XXX).street", newline(`101 Some Street`), nil)) 560 t.Run("DynamicString", selectTest(yamlData, "yaml", ".details.addresses.(postcode=YYY YYY).street", newline(`34 Another Street`), nil)) 561 t.Run("QueryFromFile", selectTestFromFile("./../../tests/assets/example.yaml", ".preferences.favouriteColour", newline(`red`), nil)) 562 563 // Following test implemented as a result of issue #35. 564 t.Run("MultipleSeparateDynamic", selectTest(` 565 apiVersion: apps/v1 566 kind: Deployment 567 metadata: 568 name: harbor-exporter 569 labels: 570 app: harbor-exporter 571 spec: 572 replicas: 1 573 selector: 574 matchLabels: 575 app: harbor-exporter 576 strategy: 577 type: RollingUpdate 578 template: 579 metadata: 580 labels: 581 app: harbor-exporter 582 spec: 583 serviceAccountName: default 584 restartPolicy: Always 585 securityContext: 586 runAsNonRoot: true 587 runAsUser: 1000 588 containers: 589 - name: harbor-exporter 590 image: "c4po/harbor-exporter:debug" 591 imagePullPolicy: Always 592 env: 593 - name: HARBOR_URI 594 # name of the Service for harbor-core 595 value: http://harbor-core.harbor # change prefix to the name of your Helm release 596 - name: HARBOR_USERNAME 597 value: "admin" 598 - name: HARBOR_PASSWORD 599 valueFrom: 600 secretKeyRef: 601 name: harbor-core # change prefix to the name of your Helm release 602 key: HARBOR_ADMIN_PASSWORD 603 604 securityContext: 605 capabilities: 606 drop: 607 - SETPCAP 608 - MKNOD 609 - AUDIT_WRITE 610 - CHOWN 611 - NET_RAW 612 - DAC_OVERRIDE 613 - FOWNER 614 - FSETID 615 - KILL 616 - SETGID 617 - SETUID 618 - NET_BIND_SERVICE 619 - SYS_CHROOT 620 - SETFCAP 621 readOnlyRootFilesystem: true 622 resources: 623 limits: 624 cpu: 400m 625 memory: 256Mi 626 requests: 627 cpu: 100m 628 memory: 64Mi 629 ports: 630 - containerPort: 9107 631 name: http 632 livenessProbe: 633 httpGet: 634 path: /-/healthy 635 port: http 636 initialDelaySeconds: 5 637 timeoutSeconds: 5 638 periodSeconds: 5 639 readinessProbe: 640 httpGet: 641 path: /-/ready 642 port: http 643 initialDelaySeconds: 1 644 timeoutSeconds: 5 645 periodSeconds: 5 646 `, "yaml", "spec.template.spec.containers.(name=harbor-exporter).env.(name=HARBOR_URI).value", newline(`http://harbor-core.harbor`), nil)) 647 648 // https://github.com/TomWright/dasel/issues/99 649 // Worked in v1.13.3 650 t.Run("NullInput", selectTest(`null`, "yaml", `.`, newline("{}"), nil)) 651 t.Run("EmptyDocument", selectTest(`---`, "yaml", `.`, newline("{}"), nil)) 652 t.Run("BlankInput", selectTest(``, "yaml", `.`, newline("{}"), nil)) 653 654 // https://github.com/TomWright/dasel/discussions/244 655 t.Run("DynamicSelectorContainingEqualsInValue", selectTest(` 656 options: 657 k3s: 658 extraArgs: 659 - arg: --no-deploy=traefik 660 nodeFilters: 661 - server:* 662 - arg: --kube-apiserver-arg=feature-gates=HPAContainerMetrics=true 663 nodeFilters: 664 - server:* 665 `, "yaml", `.options.k3s.extraArgs.(arg=--no-deploy=traefik)`, newline(`arg: --no-deploy=traefik 666 nodeFilters: 667 - server:*`), nil)) 668 } 669 670 func TestRootCmd_Select_TOML(t *testing.T) { 671 t.Run("RootElement", selectTest(tomlDataSingle, "toml", ".", newline(`x = "asd"`), nil)) 672 t.Run("SingleProperty", selectTest(tomlData, "toml", ".id", newline(`1111`), nil)) 673 t.Run("ObjectProperty", selectTest(tomlData, "toml", ".details.name", newline(`Tom`), nil)) 674 t.Run("Index", selectTest(tomlData, "toml", ".details.addresses.[0].street", newline(`101 Some Street`), nil)) 675 t.Run("Index", selectTest(tomlData, "toml", ".details.addresses.[1].street", newline(`34 Another Street`), nil)) 676 t.Run("DynamicString", selectTest(tomlData, "toml", ".details.addresses.(postcode=XXX XXX).street", newline(`101 Some Street`), nil)) 677 t.Run("DynamicString", selectTest(tomlData, "toml", ".details.addresses.(postcode=YYY YYY).street", newline(`34 Another Street`), nil)) 678 } 679 680 func TestRootCMD_Select_XML(t *testing.T) { 681 t.Run("RootElement", selectTest(xmlDataSingle, "xml", ".", newline(`<x>asd</x>`), nil)) 682 t.Run("SingleProperty", selectTest(xmlData, "xml", ".data.id", "1111\n", nil)) 683 t.Run("ObjectProperty", selectTest(xmlData, "xml", ".data.details.name", "Tom\n", nil)) 684 t.Run("Index", selectTest(xmlData, "xml", ".data.details.addresses.[0].street", "101 Some Street\n", nil)) 685 t.Run("Index", selectTest(xmlData, "xml", ".data.details.addresses.[1].street", "34 Another Street\n", nil)) 686 t.Run("DynamicString", selectTest(xmlData, "xml", ".data.details.addresses.(postcode=XXX XXX).street", "101 Some Street\n", nil)) 687 t.Run("DynamicString", selectTest(xmlData, "xml", ".data.details.addresses.(postcode=YYY YYY).street", "34 Another Street\n", nil)) 688 t.Run("Attribute", selectTest(xmlData, "xml", ".data.details.addresses.(-primary=true).street", "101 Some Street\n", nil)) 689 690 t.Run("KeySearch", selectTestContainsLines(` 691 <food> 692 <tart> 693 <apple color="yellow"/> 694 </tart> 695 <pie> 696 <crust quality="flaky"/> 697 <filling> 698 <apple color="red"/> 699 </filling> 700 </pie> 701 <apple color="green"/> 702 </food> 703 `, "xml", ".food.(?:keyValue=apple).-color", []string{"yellow", "red", "green"}, nil, "-m")) 704 } 705 706 func TestRootCMD_Select_CSV(t *testing.T) { 707 t.Run("RootElement", selectTest(csvData, "csv", ".", csvData, nil)) 708 t.Run("SingleProperty", selectTest(csvData, "csv", ".[0].id", "1\n", nil)) 709 t.Run("SingleProperty", selectTest(csvData, "csv", ".[1].id", "2\n", nil)) 710 711 // https://github.com/TomWright/dasel/issues/110 712 t.Run("ObjectArrayJSONToCSV", selectTest(` 713 [ 714 { 715 "id": "ABS", 716 "name": "Australian Bureau of Statistics" 717 }, 718 { 719 "id": "ECB", 720 "name": "European Central Bank" 721 }, 722 { 723 "id": "ESTAT", 724 "name": "Eurostat" 725 }, 726 { 727 "id": "ILO", 728 "name": "International Labor Organization" 729 } 730 ] 731 `, "json", ".", `id,name 732 ABS,Australian Bureau of Statistics 733 ECB,European Central Bank 734 ESTAT,Eurostat 735 ILO,International Labor Organization 736 `, nil, "-w", "csv")) 737 738 // https://github.com/TomWright/dasel/issues/159 739 t.Run("SelectFilterOnUnicode", selectTest(` 740 { 741 "data": [ 742 {"name": "Fu Shun", "ship_type": "Destroyer"}, 743 {"name": "Sheffield", "ship_type": "Light Cruiser"}, 744 {"name": "Ägir", "ship_type": "Large Cruiser"} 745 ] 746 } 747 `, "json", ".data.(name=Ägir).ship_type", `"Large Cruiser" 748 `, nil)) 749 } 750 751 func TestRootCmd_Select_JSON_Format(t *testing.T) { 752 t.Run("RootElementFormattedToProperty", selectTest(jsonData, "json", ".", newline(`1111`), nil, 753 "--format", `{{ query ".id" }}`)) 754 t.Run("SelectorFormatted", selectTest(jsonData, "json", ".id", newline(`1111`), nil, 755 "--format", `{{ . }}`)) 756 t.Run("SelectorFormattedMultiple", selectTest(jsonData, "json", ".details.addresses.[*]", 757 newline(`101 Some Street 758 34 Another Street`), nil, 759 "-m", "--format", `{{ query ".street" }}`)) 760 t.Run("SelectorFormattedToMultiple", selectTest(jsonData, "json", ".", 761 newline(`101 Some Street 762 34 Another Street`), nil, 763 "-m", "--format", `{{ queryMultiple ".details.addresses.[*]" | format "{{ .street }}{{ if not isLast }}{{ newline }}{{end}}" }}`)) 764 765 // https://github.com/TomWright/dasel/discussions/146 766 t.Run("Discussion146", selectTest( 767 `[{"name": "click", "version": "7.1.2", "latest_version": "8.0.1", "latest_filetype": "wheel"}, {"name": "decorator", "version": "4.4.2", "latest_version": "5.0.9", "latest_filetype": "wheel"}, {"name": "ipython", "version": "7.20.0", "latest_version": "7.25.0", "latest_filetype": "wheel"}, {"name": "pandas", "version": "1.3.0", "latest_version": "1.3.1", "latest_filetype": "wheel"}, {"name": "parso", "version": "0.8.1", "latest_version": "0.8.2", "latest_filetype": "wheel"}, {"name": "pip", "version": "21.1.3", "latest_version": "21.2.1", "latest_filetype": "wheel"}, {"name": "prompt-toolkit", "version": "3.0.14", "latest_version": "3.0.19", "latest_filetype": "wheel"}, {"name": "Pygments", "version": "2.7.4", "latest_version": "2.9.0", "latest_filetype": "wheel"}, {"name": "setuptools", "version": "49.2.1", "latest_version": "57.4.0", "latest_filetype": "wheel"}, {"name": "tomli", "version": "1.0.4", "latest_version": "1.1.0", "latest_filetype": "wheel"}]`, 768 "json", ".(name!=setuptools)(name!=six)(name!=pip)(name!=pip-tools)", 769 newline(`click 770 7.1.2 771 8.0.1 772 decorator 773 4.4.2 774 5.0.9 775 ipython 776 7.20.0 777 7.25.0 778 pandas 779 1.3.0 780 1.3.1 781 parso 782 0.8.1 783 0.8.2 784 prompt-toolkit 785 3.0.14 786 3.0.19 787 Pygments 788 2.7.4 789 2.9.0 790 tomli 791 1.0.4 792 1.1.0`), nil, 793 "-m", "--format", `{{ query ".name" }}{{ newline }}{{ query ".version" }}{{ newline }}{{ query ".latest_version" }}`)) 794 }