github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/strvals/parser_test.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package strvals 17 18 import ( 19 "testing" 20 21 "sigs.k8s.io/yaml" 22 ) 23 24 func TestSetIndex(t *testing.T) { 25 tests := []struct { 26 name string 27 initial []interface{} 28 expect []interface{} 29 add int 30 val int 31 err bool 32 }{ 33 { 34 name: "short", 35 initial: []interface{}{0, 1}, 36 expect: []interface{}{0, 1, 2}, 37 add: 2, 38 val: 2, 39 err: false, 40 }, 41 { 42 name: "equal", 43 initial: []interface{}{0, 1}, 44 expect: []interface{}{0, 2}, 45 add: 1, 46 val: 2, 47 err: false, 48 }, 49 { 50 name: "long", 51 initial: []interface{}{0, 1, 2, 3, 4, 5}, 52 expect: []interface{}{0, 1, 2, 4, 4, 5}, 53 add: 3, 54 val: 4, 55 err: false, 56 }, 57 { 58 name: "negative", 59 initial: []interface{}{0, 1, 2, 3, 4, 5}, 60 expect: []interface{}{0, 1, 2, 3, 4, 5}, 61 add: -1, 62 val: 4, 63 err: true, 64 }, 65 { 66 name: "large", 67 initial: []interface{}{0, 1, 2, 3, 4, 5}, 68 expect: []interface{}{0, 1, 2, 3, 4, 5}, 69 add: MaxIndex + 1, 70 val: 4, 71 err: true, 72 }, 73 } 74 75 for _, tt := range tests { 76 got, err := setIndex(tt.initial, tt.add, tt.val) 77 78 if err != nil && tt.err == false { 79 t.Fatalf("%s: Expected no error but error returned", tt.name) 80 } else if err == nil && tt.err == true { 81 t.Fatalf("%s: Expected error but no error returned", tt.name) 82 } 83 84 if len(got) != len(tt.expect) { 85 t.Fatalf("%s: Expected length %d, got %d", tt.name, len(tt.expect), len(got)) 86 } 87 88 if !tt.err { 89 if gg := got[tt.add].(int); gg != tt.val { 90 t.Errorf("%s, Expected value %d, got %d", tt.name, tt.val, gg) 91 } 92 } 93 94 for k, v := range got { 95 if v != tt.expect[k] { 96 t.Errorf("%s, Expected value %d, got %d", tt.name, tt.expect[k], v) 97 } 98 } 99 } 100 } 101 102 func TestParseSet(t *testing.T) { 103 testsString := []struct { 104 str string 105 expect map[string]interface{} 106 err bool 107 }{ 108 { 109 str: "long_int_string=1234567890", 110 expect: map[string]interface{}{"long_int_string": "1234567890"}, 111 err: false, 112 }, 113 { 114 str: "boolean=true", 115 expect: map[string]interface{}{"boolean": "true"}, 116 err: false, 117 }, 118 { 119 str: "is_null=null", 120 expect: map[string]interface{}{"is_null": "null"}, 121 err: false, 122 }, 123 { 124 str: "zero=0", 125 expect: map[string]interface{}{"zero": "0"}, 126 err: false, 127 }, 128 } 129 tests := []struct { 130 str string 131 expect map[string]interface{} 132 err bool 133 }{ 134 { 135 "name1=null,f=false,t=true", 136 map[string]interface{}{"name1": nil, "f": false, "t": true}, 137 false, 138 }, 139 { 140 "name1=value1", 141 map[string]interface{}{"name1": "value1"}, 142 false, 143 }, 144 { 145 "name1=value1,name2=value2", 146 map[string]interface{}{"name1": "value1", "name2": "value2"}, 147 false, 148 }, 149 { 150 "name1=value1,name2=value2,", 151 map[string]interface{}{"name1": "value1", "name2": "value2"}, 152 false, 153 }, 154 { 155 str: "name1=value1,,,,name2=value2,", 156 err: true, 157 }, 158 { 159 str: "name1=,name2=value2", 160 expect: map[string]interface{}{"name1": "", "name2": "value2"}, 161 }, 162 { 163 str: "leading_zeros=00009", 164 expect: map[string]interface{}{"leading_zeros": "00009"}, 165 }, 166 { 167 str: "zero_int=0", 168 expect: map[string]interface{}{"zero_int": 0}, 169 }, 170 { 171 str: "long_int=1234567890", 172 expect: map[string]interface{}{"long_int": 1234567890}, 173 }, 174 { 175 str: "boolean=true", 176 expect: map[string]interface{}{"boolean": true}, 177 }, 178 { 179 str: "is_null=null", 180 expect: map[string]interface{}{"is_null": nil}, 181 err: false, 182 }, 183 { 184 str: "name1,name2=", 185 err: true, 186 }, 187 { 188 str: "name1,name2=value2", 189 err: true, 190 }, 191 { 192 str: "name1,name2=value2\\", 193 err: true, 194 }, 195 { 196 str: "name1,name2", 197 err: true, 198 }, 199 { 200 "name1=one\\,two,name2=three\\,four", 201 map[string]interface{}{"name1": "one,two", "name2": "three,four"}, 202 false, 203 }, 204 { 205 "name1=one\\=two,name2=three\\=four", 206 map[string]interface{}{"name1": "one=two", "name2": "three=four"}, 207 false, 208 }, 209 { 210 "name1=one two three,name2=three two one", 211 map[string]interface{}{"name1": "one two three", "name2": "three two one"}, 212 false, 213 }, 214 { 215 "outer.inner=value", 216 map[string]interface{}{"outer": map[string]interface{}{"inner": "value"}}, 217 false, 218 }, 219 { 220 "outer.middle.inner=value", 221 map[string]interface{}{"outer": map[string]interface{}{"middle": map[string]interface{}{"inner": "value"}}}, 222 false, 223 }, 224 { 225 "outer.inner1=value,outer.inner2=value2", 226 map[string]interface{}{"outer": map[string]interface{}{"inner1": "value", "inner2": "value2"}}, 227 false, 228 }, 229 { 230 "outer.inner1=value,outer.middle.inner=value", 231 map[string]interface{}{ 232 "outer": map[string]interface{}{ 233 "inner1": "value", 234 "middle": map[string]interface{}{ 235 "inner": "value", 236 }, 237 }, 238 }, 239 false, 240 }, 241 { 242 str: "name1.name2", 243 err: true, 244 }, 245 { 246 str: "name1.name2,name1.name3", 247 err: true, 248 }, 249 { 250 str: "name1.name2=", 251 expect: map[string]interface{}{"name1": map[string]interface{}{"name2": ""}}, 252 }, 253 { 254 str: "name1.=name2", 255 err: true, 256 }, 257 { 258 str: "name1.,name2", 259 err: true, 260 }, 261 { 262 "name1={value1,value2}", 263 map[string]interface{}{"name1": []string{"value1", "value2"}}, 264 false, 265 }, 266 { 267 "name1={value1,value2},name2={value1,value2}", 268 map[string]interface{}{ 269 "name1": []string{"value1", "value2"}, 270 "name2": []string{"value1", "value2"}, 271 }, 272 false, 273 }, 274 { 275 "name1={1021,902}", 276 map[string]interface{}{"name1": []int{1021, 902}}, 277 false, 278 }, 279 { 280 "name1.name2={value1,value2}", 281 map[string]interface{}{"name1": map[string]interface{}{"name2": []string{"value1", "value2"}}}, 282 false, 283 }, 284 { 285 str: "name1={1021,902", 286 err: true, 287 }, 288 // List support 289 { 290 str: "list[0]=foo", 291 expect: map[string]interface{}{"list": []string{"foo"}}, 292 }, 293 { 294 str: "list[0].foo=bar", 295 expect: map[string]interface{}{ 296 "list": []interface{}{ 297 map[string]interface{}{"foo": "bar"}, 298 }, 299 }, 300 }, 301 { 302 str: "list[0].foo=bar,list[0].hello=world", 303 expect: map[string]interface{}{ 304 "list": []interface{}{ 305 map[string]interface{}{"foo": "bar", "hello": "world"}, 306 }, 307 }, 308 }, 309 { 310 str: "list[0].foo=bar,list[-30].hello=world", 311 err: true, 312 }, 313 { 314 str: "list[0]=foo,list[1]=bar", 315 expect: map[string]interface{}{"list": []string{"foo", "bar"}}, 316 }, 317 { 318 str: "list[0]=foo,list[1]=bar,", 319 expect: map[string]interface{}{"list": []string{"foo", "bar"}}, 320 }, 321 { 322 str: "list[0]=foo,list[3]=bar", 323 expect: map[string]interface{}{"list": []interface{}{"foo", nil, nil, "bar"}}, 324 }, 325 { 326 str: "list[0]=foo,list[-20]=bar", 327 err: true, 328 }, 329 { 330 str: "illegal[0]name.foo=bar", 331 err: true, 332 }, 333 { 334 str: "noval[0]", 335 expect: map[string]interface{}{"noval": []interface{}{}}, 336 }, 337 { 338 str: "noval[0]=", 339 expect: map[string]interface{}{"noval": []interface{}{""}}, 340 }, 341 { 342 str: "nested[0][0]=1", 343 expect: map[string]interface{}{"nested": []interface{}{[]interface{}{1}}}, 344 }, 345 { 346 str: "nested[1][1]=1", 347 expect: map[string]interface{}{"nested": []interface{}{nil, []interface{}{nil, 1}}}, 348 }, 349 { 350 str: "name1.name2[0].foo=bar,name1.name2[1].foo=bar", 351 expect: map[string]interface{}{ 352 "name1": map[string]interface{}{ 353 "name2": []map[string]interface{}{{"foo": "bar"}, {"foo": "bar"}}, 354 }, 355 }, 356 }, 357 { 358 str: "name1.name2[1].foo=bar,name1.name2[0].foo=bar", 359 expect: map[string]interface{}{ 360 "name1": map[string]interface{}{ 361 "name2": []map[string]interface{}{{"foo": "bar"}, {"foo": "bar"}}, 362 }, 363 }, 364 }, 365 { 366 str: "name1.name2[1].foo=bar", 367 expect: map[string]interface{}{ 368 "name1": map[string]interface{}{ 369 "name2": []map[string]interface{}{nil, {"foo": "bar"}}, 370 }, 371 }, 372 }, 373 { 374 str: "]={}].", 375 err: true, 376 }, 377 } 378 379 for _, tt := range tests { 380 got, err := Parse(tt.str) 381 if err != nil { 382 if tt.err { 383 continue 384 } 385 t.Fatalf("%s: %s", tt.str, err) 386 } 387 if tt.err { 388 t.Errorf("%s: Expected error. Got nil", tt.str) 389 } 390 391 y1, err := yaml.Marshal(tt.expect) 392 if err != nil { 393 t.Fatal(err) 394 } 395 y2, err := yaml.Marshal(got) 396 if err != nil { 397 t.Fatalf("Error serializing parsed value: %s", err) 398 } 399 400 if string(y1) != string(y2) { 401 t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2) 402 } 403 } 404 for _, tt := range testsString { 405 got, err := ParseString(tt.str) 406 if err != nil { 407 if tt.err { 408 continue 409 } 410 t.Fatalf("%s: %s", tt.str, err) 411 } 412 if tt.err { 413 t.Errorf("%s: Expected error. Got nil", tt.str) 414 } 415 416 y1, err := yaml.Marshal(tt.expect) 417 if err != nil { 418 t.Fatal(err) 419 } 420 y2, err := yaml.Marshal(got) 421 if err != nil { 422 t.Fatalf("Error serializing parsed value: %s", err) 423 } 424 425 if string(y1) != string(y2) { 426 t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2) 427 } 428 } 429 } 430 431 func TestParseInto(t *testing.T) { 432 tests := []struct { 433 input string 434 input2 string 435 got map[string]interface{} 436 expect map[string]interface{} 437 err bool 438 }{ 439 { 440 input: "outer.inner1=value1,outer.inner3=value3,outer.inner4=4", 441 got: map[string]interface{}{ 442 "outer": map[string]interface{}{ 443 "inner1": "overwrite", 444 "inner2": "value2", 445 }, 446 }, 447 expect: map[string]interface{}{ 448 "outer": map[string]interface{}{ 449 "inner1": "value1", 450 "inner2": "value2", 451 "inner3": "value3", 452 "inner4": 4, 453 }}, 454 err: false, 455 }, 456 { 457 input: "listOuter[0][0].type=listValue", 458 input2: "listOuter[0][0].status=alive", 459 got: map[string]interface{}{}, 460 expect: map[string]interface{}{ 461 "listOuter": [][]interface{}{{map[string]string{ 462 "type": "listValue", 463 "status": "alive", 464 }}}, 465 }, 466 err: false, 467 }, 468 { 469 input: "listOuter[0][0].type=listValue", 470 input2: "listOuter[1][0].status=alive", 471 got: map[string]interface{}{}, 472 expect: map[string]interface{}{ 473 "listOuter": [][]interface{}{ 474 { 475 map[string]string{"type": "listValue"}, 476 }, 477 { 478 map[string]string{"status": "alive"}, 479 }, 480 }, 481 }, 482 err: false, 483 }, 484 { 485 input: "listOuter[0][1][0].type=listValue", 486 input2: "listOuter[0][0][1].status=alive", 487 got: map[string]interface{}{ 488 "listOuter": []interface{}{ 489 []interface{}{ 490 []interface{}{ 491 map[string]string{"exited": "old"}, 492 }, 493 }, 494 }, 495 }, 496 expect: map[string]interface{}{ 497 "listOuter": [][][]interface{}{ 498 { 499 { 500 map[string]string{"exited": "old"}, 501 map[string]string{"status": "alive"}, 502 }, 503 { 504 map[string]string{"type": "listValue"}, 505 }, 506 }, 507 }, 508 }, 509 err: false, 510 }, 511 } 512 for _, tt := range tests { 513 if err := ParseInto(tt.input, tt.got); err != nil { 514 t.Fatal(err) 515 } 516 if tt.err { 517 t.Errorf("%s: Expected error. Got nil", tt.input) 518 } 519 520 if tt.input2 != "" { 521 if err := ParseInto(tt.input2, tt.got); err != nil { 522 t.Fatal(err) 523 } 524 if tt.err { 525 t.Errorf("%s: Expected error. Got nil", tt.input2) 526 } 527 } 528 529 y1, err := yaml.Marshal(tt.expect) 530 if err != nil { 531 t.Fatal(err) 532 } 533 y2, err := yaml.Marshal(tt.got) 534 if err != nil { 535 t.Fatalf("Error serializing parsed value: %s", err) 536 } 537 538 if string(y1) != string(y2) { 539 t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.input, y1, y2) 540 } 541 } 542 } 543 544 func TestParseIntoString(t *testing.T) { 545 got := map[string]interface{}{ 546 "outer": map[string]interface{}{ 547 "inner1": "overwrite", 548 "inner2": "value2", 549 }, 550 } 551 input := "outer.inner1=1,outer.inner3=3" 552 expect := map[string]interface{}{ 553 "outer": map[string]interface{}{ 554 "inner1": "1", 555 "inner2": "value2", 556 "inner3": "3", 557 }, 558 } 559 560 if err := ParseIntoString(input, got); err != nil { 561 t.Fatal(err) 562 } 563 564 y1, err := yaml.Marshal(expect) 565 if err != nil { 566 t.Fatal(err) 567 } 568 y2, err := yaml.Marshal(got) 569 if err != nil { 570 t.Fatalf("Error serializing parsed value: %s", err) 571 } 572 573 if string(y1) != string(y2) { 574 t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) 575 } 576 } 577 578 func TestParseJSON(t *testing.T) { 579 tests := []struct { 580 input string 581 got map[string]interface{} 582 expect map[string]interface{} 583 err bool 584 }{ 585 { // set json scalars values, and replace one existing key 586 input: "outer.inner1=\"1\",outer.inner3=3,outer.inner4=true,outer.inner5=\"true\"", 587 got: map[string]interface{}{ 588 "outer": map[string]interface{}{ 589 "inner1": "overwrite", 590 "inner2": "value2", 591 }, 592 }, 593 expect: map[string]interface{}{ 594 "outer": map[string]interface{}{ 595 "inner1": "1", 596 "inner2": "value2", 597 "inner3": 3, 598 "inner4": true, 599 "inner5": "true", 600 }, 601 }, 602 err: false, 603 }, 604 { // set json objects and arrays, and replace one existing key 605 input: "outer.inner1={\"a\":\"1\",\"b\":2,\"c\":[1,2,3]},outer.inner3=[\"new value 1\",\"new value 2\"],outer.inner4={\"aa\":\"1\",\"bb\":2,\"cc\":[1,2,3]},outer.inner5=[{\"A\":\"1\",\"B\":2,\"C\":[1,2,3]}]", 606 got: map[string]interface{}{ 607 "outer": map[string]interface{}{ 608 "inner1": map[string]interface{}{ 609 "x": "overwrite", 610 }, 611 "inner2": "value2", 612 "inner3": []interface{}{ 613 "overwrite", 614 }, 615 }, 616 }, 617 expect: map[string]interface{}{ 618 "outer": map[string]interface{}{ 619 "inner1": map[string]interface{}{"a": "1", "b": 2, "c": []interface{}{1, 2, 3}}, 620 "inner2": "value2", 621 "inner3": []interface{}{"new value 1", "new value 2"}, 622 "inner4": map[string]interface{}{"aa": "1", "bb": 2, "cc": []interface{}{1, 2, 3}}, 623 "inner5": []interface{}{map[string]interface{}{"A": "1", "B": 2, "C": []interface{}{1, 2, 3}}}, 624 }, 625 }, 626 err: false, 627 }, 628 { // null assigment, and no value assigned (equivalent to null) 629 input: "outer.inner1=,outer.inner3={\"aa\":\"1\",\"bb\":2,\"cc\":[1,2,3]},outer.inner3.cc[1]=null", 630 got: map[string]interface{}{ 631 "outer": map[string]interface{}{ 632 "inner1": map[string]interface{}{ 633 "x": "overwrite", 634 }, 635 "inner2": "value2", 636 }, 637 }, 638 expect: map[string]interface{}{ 639 "outer": map[string]interface{}{ 640 "inner1": nil, 641 "inner2": "value2", 642 "inner3": map[string]interface{}{"aa": "1", "bb": 2, "cc": []interface{}{1, nil, 3}}, 643 }, 644 }, 645 err: false, 646 }, 647 { // syntax error 648 input: "outer.inner1={\"a\":\"1\",\"b\":2,\"c\":[1,2,3]},outer.inner3=[\"new value 1\",\"new value 2\"],outer.inner4={\"aa\":\"1\",\"bb\":2,\"cc\":[1,2,3]},outer.inner5={\"A\":\"1\",\"B\":2,\"C\":[1,2,3]}]", 649 got: nil, 650 expect: nil, 651 err: true, 652 }, 653 } 654 for _, tt := range tests { 655 if err := ParseJSON(tt.input, tt.got); err != nil { 656 if tt.err { 657 continue 658 } 659 t.Fatalf("%s: %s", tt.input, err) 660 } 661 if tt.err { 662 t.Fatalf("%s: Expected error. Got nil", tt.input) 663 } 664 y1, err := yaml.Marshal(tt.expect) 665 if err != nil { 666 t.Fatalf("Error serializing expected value: %s", err) 667 } 668 y2, err := yaml.Marshal(tt.got) 669 if err != nil { 670 t.Fatalf("Error serializing parsed value: %s", err) 671 } 672 673 if string(y1) != string(y2) { 674 t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.input, y1, y2) 675 } 676 } 677 } 678 679 func TestParseFile(t *testing.T) { 680 input := "name1=path1" 681 expect := map[string]interface{}{ 682 "name1": "value1", 683 } 684 rs2v := func(rs []rune) (interface{}, error) { 685 v := string(rs) 686 if v != "path1" { 687 t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v) 688 return "", nil 689 } 690 return "value1", nil 691 } 692 693 got, err := ParseFile(input, rs2v) 694 if err != nil { 695 t.Fatal(err) 696 } 697 698 y1, err := yaml.Marshal(expect) 699 if err != nil { 700 t.Fatal(err) 701 } 702 y2, err := yaml.Marshal(got) 703 if err != nil { 704 t.Fatalf("Error serializing parsed value: %s", err) 705 } 706 707 if string(y1) != string(y2) { 708 t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) 709 } 710 } 711 712 func TestParseIntoFile(t *testing.T) { 713 got := map[string]interface{}{} 714 input := "name1=path1" 715 expect := map[string]interface{}{ 716 "name1": "value1", 717 } 718 rs2v := func(rs []rune) (interface{}, error) { 719 v := string(rs) 720 if v != "path1" { 721 t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v) 722 return "", nil 723 } 724 return "value1", nil 725 } 726 727 if err := ParseIntoFile(input, got, rs2v); err != nil { 728 t.Fatal(err) 729 } 730 731 y1, err := yaml.Marshal(expect) 732 if err != nil { 733 t.Fatal(err) 734 } 735 y2, err := yaml.Marshal(got) 736 if err != nil { 737 t.Fatalf("Error serializing parsed value: %s", err) 738 } 739 740 if string(y1) != string(y2) { 741 t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) 742 } 743 } 744 745 func TestToYAML(t *testing.T) { 746 // The TestParse does the hard part. We just verify that YAML formatting is 747 // happening. 748 o, err := ToYAML("name=value") 749 if err != nil { 750 t.Fatal(err) 751 } 752 expect := "name: value" 753 if o != expect { 754 t.Errorf("Expected %q, got %q", expect, o) 755 } 756 }