github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/lang/funcs/collection_test.go (about) 1 package funcs 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/zclconf/go-cty/cty" 8 ) 9 10 func TestElement(t *testing.T) { 11 tests := []struct { 12 List cty.Value 13 Index cty.Value 14 Want cty.Value 15 }{ 16 { 17 cty.ListVal([]cty.Value{ 18 cty.StringVal("hello"), 19 }), 20 cty.NumberIntVal(0), 21 cty.StringVal("hello"), 22 }, 23 { 24 cty.ListVal([]cty.Value{ 25 cty.StringVal("hello"), 26 }), 27 cty.NumberIntVal(1), 28 cty.StringVal("hello"), 29 }, 30 { 31 cty.ListVal([]cty.Value{ 32 cty.StringVal("hello"), 33 cty.StringVal("bonjour"), 34 }), 35 cty.NumberIntVal(0), 36 cty.StringVal("hello"), 37 }, 38 { 39 cty.ListVal([]cty.Value{ 40 cty.StringVal("hello"), 41 cty.StringVal("bonjour"), 42 }), 43 cty.NumberIntVal(1), 44 cty.StringVal("bonjour"), 45 }, 46 { 47 cty.ListVal([]cty.Value{ 48 cty.StringVal("hello"), 49 cty.StringVal("bonjour"), 50 }), 51 cty.NumberIntVal(2), 52 cty.StringVal("hello"), 53 }, 54 55 { 56 cty.TupleVal([]cty.Value{ 57 cty.StringVal("hello"), 58 }), 59 cty.NumberIntVal(0), 60 cty.StringVal("hello"), 61 }, 62 { 63 cty.TupleVal([]cty.Value{ 64 cty.StringVal("hello"), 65 }), 66 cty.NumberIntVal(1), 67 cty.StringVal("hello"), 68 }, 69 { 70 cty.TupleVal([]cty.Value{ 71 cty.StringVal("hello"), 72 cty.StringVal("bonjour"), 73 }), 74 cty.NumberIntVal(0), 75 cty.StringVal("hello"), 76 }, 77 { 78 cty.TupleVal([]cty.Value{ 79 cty.StringVal("hello"), 80 cty.StringVal("bonjour"), 81 }), 82 cty.NumberIntVal(1), 83 cty.StringVal("bonjour"), 84 }, 85 { 86 cty.TupleVal([]cty.Value{ 87 cty.StringVal("hello"), 88 cty.StringVal("bonjour"), 89 }), 90 cty.NumberIntVal(2), 91 cty.StringVal("hello"), 92 }, 93 { 94 cty.TupleVal([]cty.Value{ 95 cty.StringVal("hello"), 96 cty.StringVal("bonjour"), 97 }), 98 cty.UnknownVal(cty.Number), 99 cty.DynamicVal, 100 }, 101 { 102 cty.UnknownVal(cty.Tuple([]cty.Type{cty.String, cty.Bool})), 103 cty.NumberIntVal(1), 104 cty.UnknownVal(cty.Bool), 105 }, 106 { 107 cty.UnknownVal(cty.Tuple([]cty.Type{cty.String, cty.String})), 108 cty.UnknownVal(cty.Number), 109 cty.DynamicVal, 110 }, 111 } 112 113 for _, test := range tests { 114 t.Run(fmt.Sprintf("Element(%#v, %#v)", test.List, test.Index), func(t *testing.T) { 115 got, err := Element(test.List, test.Index) 116 117 if err != nil { 118 t.Fatalf("unexpected error: %s", err) 119 } 120 121 if !got.RawEquals(test.Want) { 122 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 123 } 124 }) 125 } 126 127 } 128 129 func TestLength(t *testing.T) { 130 tests := []struct { 131 Value cty.Value 132 Want cty.Value 133 }{ 134 { 135 cty.ListValEmpty(cty.Number), 136 cty.NumberIntVal(0), 137 }, 138 { 139 cty.ListVal([]cty.Value{cty.True}), 140 cty.NumberIntVal(1), 141 }, 142 { 143 cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}), 144 cty.NumberIntVal(1), 145 }, 146 { 147 cty.SetValEmpty(cty.Number), 148 cty.NumberIntVal(0), 149 }, 150 { 151 cty.SetVal([]cty.Value{cty.True}), 152 cty.NumberIntVal(1), 153 }, 154 { 155 cty.MapValEmpty(cty.Bool), 156 cty.NumberIntVal(0), 157 }, 158 { 159 cty.MapVal(map[string]cty.Value{"hello": cty.True}), 160 cty.NumberIntVal(1), 161 }, 162 { 163 cty.EmptyTupleVal, 164 cty.NumberIntVal(0), 165 }, 166 { 167 cty.UnknownVal(cty.EmptyTuple), 168 cty.NumberIntVal(0), 169 }, 170 { 171 cty.TupleVal([]cty.Value{cty.True}), 172 cty.NumberIntVal(1), 173 }, 174 { 175 cty.EmptyObjectVal, 176 cty.NumberIntVal(0), 177 }, 178 { 179 cty.UnknownVal(cty.EmptyObject), 180 cty.NumberIntVal(0), 181 }, 182 { 183 cty.ObjectVal(map[string]cty.Value{"true": cty.True}), 184 cty.NumberIntVal(1), 185 }, 186 { 187 cty.UnknownVal(cty.List(cty.Bool)), 188 cty.UnknownVal(cty.Number), 189 }, 190 { 191 cty.DynamicVal, 192 cty.UnknownVal(cty.Number), 193 }, 194 { 195 cty.StringVal("hello"), 196 cty.NumberIntVal(5), 197 }, 198 { 199 cty.StringVal(""), 200 cty.NumberIntVal(0), 201 }, 202 { 203 cty.StringVal("1"), 204 cty.NumberIntVal(1), 205 }, 206 { 207 cty.StringVal("Живой Журнал"), 208 cty.NumberIntVal(12), 209 }, 210 { 211 // note that the dieresis here is intentionally a combining 212 // ligature. 213 cty.StringVal("noël"), 214 cty.NumberIntVal(4), 215 }, 216 { 217 // The Es in this string has three combining acute accents. 218 // This tests something that NFC-normalization cannot collapse 219 // into a single precombined codepoint, since otherwise we might 220 // be cheating and relying on the single-codepoint forms. 221 cty.StringVal("wé́́é́́é́́!"), 222 cty.NumberIntVal(5), 223 }, 224 { 225 // Go's normalization forms don't handle this ligature, so we 226 // will produce the wrong result but this is now a compatibility 227 // constraint and so we'll test it. 228 cty.StringVal("baffle"), 229 cty.NumberIntVal(4), 230 }, 231 { 232 cty.StringVal("😸😾"), 233 cty.NumberIntVal(2), 234 }, 235 { 236 cty.UnknownVal(cty.String), 237 cty.UnknownVal(cty.Number), 238 }, 239 { 240 cty.DynamicVal, 241 cty.UnknownVal(cty.Number), 242 }, 243 } 244 245 for _, test := range tests { 246 t.Run(fmt.Sprintf("Length(%#v)", test.Value), func(t *testing.T) { 247 got, err := Length(test.Value) 248 249 if err != nil { 250 t.Fatalf("unexpected error: %s", err) 251 } 252 253 if !got.RawEquals(test.Want) { 254 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 255 } 256 }) 257 } 258 } 259 260 func TestCoalesce(t *testing.T) { 261 tests := []struct { 262 Values []cty.Value 263 Want cty.Value 264 Err bool 265 }{ 266 { 267 []cty.Value{cty.StringVal("first"), cty.StringVal("second"), cty.StringVal("third")}, 268 cty.StringVal("first"), 269 false, 270 }, 271 { 272 []cty.Value{cty.StringVal(""), cty.StringVal("second"), cty.StringVal("third")}, 273 cty.StringVal("second"), 274 false, 275 }, 276 { 277 []cty.Value{cty.StringVal(""), cty.StringVal("")}, 278 cty.NilVal, 279 true, 280 }, 281 { 282 []cty.Value{cty.True}, 283 cty.True, 284 false, 285 }, 286 { 287 []cty.Value{cty.NullVal(cty.Bool), cty.True}, 288 cty.True, 289 false, 290 }, 291 { 292 []cty.Value{cty.NullVal(cty.Bool), cty.False}, 293 cty.False, 294 false, 295 }, 296 { 297 []cty.Value{cty.NullVal(cty.Bool), cty.False, cty.StringVal("hello")}, 298 cty.StringVal("false"), 299 false, 300 }, 301 { 302 []cty.Value{cty.True, cty.UnknownVal(cty.Bool)}, 303 cty.True, 304 false, 305 }, 306 { 307 []cty.Value{cty.UnknownVal(cty.Bool), cty.True}, 308 cty.UnknownVal(cty.Bool), 309 false, 310 }, 311 { 312 []cty.Value{cty.UnknownVal(cty.Bool), cty.StringVal("hello")}, 313 cty.UnknownVal(cty.String), 314 false, 315 }, 316 { 317 []cty.Value{cty.DynamicVal, cty.True}, 318 cty.UnknownVal(cty.Bool), 319 false, 320 }, 321 { 322 []cty.Value{cty.DynamicVal}, 323 cty.DynamicVal, 324 false, 325 }, 326 } 327 328 for _, test := range tests { 329 t.Run(fmt.Sprintf("Coalesce(%#v...)", test.Values), func(t *testing.T) { 330 got, err := Coalesce(test.Values...) 331 332 if test.Err { 333 if err == nil { 334 t.Fatal("succeeded; want error") 335 } 336 return 337 } else if err != nil { 338 t.Fatalf("unexpected error: %s", err) 339 } 340 341 if !got.RawEquals(test.Want) { 342 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 343 } 344 }) 345 } 346 } 347 348 func TestCoalesceList(t *testing.T) { 349 tests := []struct { 350 Values []cty.Value 351 Want cty.Value 352 Err bool 353 }{ 354 { 355 []cty.Value{ 356 cty.ListVal([]cty.Value{ 357 cty.StringVal("first"), cty.StringVal("second"), 358 }), 359 cty.ListVal([]cty.Value{ 360 cty.StringVal("third"), cty.StringVal("fourth"), 361 }), 362 }, 363 cty.ListVal([]cty.Value{ 364 cty.StringVal("first"), cty.StringVal("second"), 365 }), 366 false, 367 }, 368 { 369 []cty.Value{ 370 cty.ListValEmpty(cty.String), 371 cty.ListVal([]cty.Value{ 372 cty.StringVal("third"), cty.StringVal("fourth"), 373 }), 374 }, 375 cty.ListVal([]cty.Value{ 376 cty.StringVal("third"), cty.StringVal("fourth"), 377 }), 378 false, 379 }, 380 { 381 []cty.Value{ 382 cty.ListValEmpty(cty.Number), 383 cty.ListVal([]cty.Value{ 384 cty.NumberIntVal(1), 385 cty.NumberIntVal(2), 386 }), 387 }, 388 cty.ListVal([]cty.Value{ 389 cty.NumberIntVal(1), 390 cty.NumberIntVal(2), 391 }), 392 false, 393 }, 394 { // lists with mixed types 395 []cty.Value{ 396 cty.ListVal([]cty.Value{ 397 cty.StringVal("first"), cty.StringVal("second"), 398 }), 399 cty.ListVal([]cty.Value{ 400 cty.NumberIntVal(1), 401 cty.NumberIntVal(2), 402 }), 403 }, 404 cty.ListVal([]cty.Value{ 405 cty.StringVal("first"), cty.StringVal("second"), 406 }), 407 false, 408 }, 409 { // lists with mixed types 410 []cty.Value{ 411 cty.ListVal([]cty.Value{ 412 cty.NumberIntVal(1), 413 cty.NumberIntVal(2), 414 }), 415 cty.ListVal([]cty.Value{ 416 cty.StringVal("first"), cty.StringVal("second"), 417 }), 418 }, 419 cty.ListVal([]cty.Value{ 420 cty.NumberIntVal(1), cty.NumberIntVal(2), 421 }), 422 false, 423 }, 424 { // list with unknown values 425 []cty.Value{ 426 cty.ListVal([]cty.Value{ 427 cty.StringVal("first"), cty.StringVal("second"), 428 }), 429 cty.ListVal([]cty.Value{ 430 cty.UnknownVal(cty.String), 431 }), 432 }, 433 cty.ListVal([]cty.Value{ 434 cty.StringVal("first"), cty.StringVal("second"), 435 }), 436 false, 437 }, 438 { // list with unknown values 439 []cty.Value{ 440 cty.ListVal([]cty.Value{ 441 cty.UnknownVal(cty.String), 442 }), 443 cty.ListVal([]cty.Value{ 444 cty.StringVal("third"), cty.StringVal("fourth"), 445 }), 446 }, 447 cty.ListVal([]cty.Value{ 448 cty.UnknownVal(cty.String), 449 }), 450 false, 451 }, 452 { 453 []cty.Value{ 454 cty.MapValEmpty(cty.DynamicPseudoType), 455 cty.ListVal([]cty.Value{ 456 cty.StringVal("third"), cty.StringVal("fourth"), 457 }), 458 }, 459 cty.NilVal, 460 true, 461 }, 462 { // unknown list 463 []cty.Value{ 464 cty.ListVal([]cty.Value{ 465 cty.StringVal("third"), cty.StringVal("fourth"), 466 }), 467 cty.UnknownVal(cty.List(cty.String)), 468 }, 469 cty.ListVal([]cty.Value{ 470 cty.StringVal("third"), cty.StringVal("fourth"), 471 }), 472 false, 473 }, 474 { // unknown list 475 []cty.Value{ 476 cty.ListValEmpty(cty.String), 477 cty.UnknownVal(cty.List(cty.String)), 478 }, 479 cty.DynamicVal, 480 false, 481 }, 482 { // unknown list 483 []cty.Value{ 484 cty.UnknownVal(cty.List(cty.String)), 485 cty.ListVal([]cty.Value{ 486 cty.StringVal("third"), cty.StringVal("fourth"), 487 }), 488 }, 489 cty.DynamicVal, 490 false, 491 }, 492 { // unknown tuple 493 []cty.Value{ 494 cty.UnknownVal(cty.Tuple([]cty.Type{cty.String})), 495 cty.ListVal([]cty.Value{ 496 cty.StringVal("third"), cty.StringVal("fourth"), 497 }), 498 }, 499 cty.DynamicVal, 500 false, 501 }, 502 { // empty tuple 503 []cty.Value{ 504 cty.EmptyTupleVal, 505 cty.ListVal([]cty.Value{ 506 cty.StringVal("third"), cty.StringVal("fourth"), 507 }), 508 }, 509 cty.ListVal([]cty.Value{ 510 cty.StringVal("third"), cty.StringVal("fourth"), 511 }), 512 false, 513 }, 514 { // tuple value 515 []cty.Value{ 516 cty.TupleVal([]cty.Value{ 517 cty.StringVal("a"), 518 cty.NumberIntVal(2), 519 }), 520 cty.ListVal([]cty.Value{ 521 cty.StringVal("third"), cty.StringVal("fourth"), 522 }), 523 }, 524 cty.TupleVal([]cty.Value{ 525 cty.StringVal("a"), 526 cty.NumberIntVal(2), 527 }), 528 false, 529 }, 530 { // reject set value 531 []cty.Value{ 532 cty.SetVal([]cty.Value{ 533 cty.StringVal("a"), 534 }), 535 cty.ListVal([]cty.Value{ 536 cty.StringVal("third"), cty.StringVal("fourth"), 537 }), 538 }, 539 cty.NilVal, 540 true, 541 }, 542 } 543 544 for i, test := range tests { 545 t.Run(fmt.Sprintf("%d-coalescelist(%#v)", i, test.Values), func(t *testing.T) { 546 got, err := CoalesceList(test.Values...) 547 548 if test.Err { 549 if err == nil { 550 t.Fatal("succeeded; want error") 551 } 552 return 553 } else if err != nil { 554 t.Fatalf("unexpected error: %s", err) 555 } 556 557 if !got.RawEquals(test.Want) { 558 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 559 } 560 }) 561 } 562 } 563 564 func TestCompact(t *testing.T) { 565 tests := []struct { 566 List cty.Value 567 Want cty.Value 568 Err bool 569 }{ 570 { 571 cty.ListVal([]cty.Value{ 572 cty.StringVal("test"), 573 cty.StringVal(""), 574 cty.StringVal("test"), 575 cty.NullVal(cty.String), 576 }), 577 cty.ListVal([]cty.Value{ 578 cty.StringVal("test"), 579 cty.StringVal("test"), 580 }), 581 false, 582 }, 583 { 584 cty.ListVal([]cty.Value{ 585 cty.StringVal(""), 586 cty.StringVal(""), 587 cty.StringVal(""), 588 }), 589 cty.ListValEmpty(cty.String), 590 false, 591 }, 592 { 593 cty.ListVal([]cty.Value{ 594 cty.NullVal(cty.String), 595 cty.NullVal(cty.String), 596 }), 597 cty.ListValEmpty(cty.String), 598 false, 599 }, 600 { 601 cty.ListValEmpty(cty.String), 602 cty.ListValEmpty(cty.String), 603 false, 604 }, 605 { 606 cty.ListVal([]cty.Value{ 607 cty.StringVal("test"), 608 cty.StringVal("test"), 609 cty.StringVal(""), 610 }), 611 cty.ListVal([]cty.Value{ 612 cty.StringVal("test"), 613 cty.StringVal("test"), 614 }), 615 false, 616 }, 617 { 618 cty.ListVal([]cty.Value{ 619 cty.StringVal("test"), 620 cty.UnknownVal(cty.String), 621 cty.StringVal(""), 622 cty.NullVal(cty.String), 623 }), 624 cty.UnknownVal(cty.List(cty.String)), 625 false, 626 }, 627 { // errors on list of lists 628 cty.ListVal([]cty.Value{ 629 cty.ListVal([]cty.Value{ 630 cty.StringVal("test"), 631 }), 632 cty.ListVal([]cty.Value{ 633 cty.StringVal(""), 634 }), 635 }), 636 cty.NilVal, 637 true, 638 }, 639 } 640 641 for _, test := range tests { 642 t.Run(fmt.Sprintf("compact(%#v)", test.List), func(t *testing.T) { 643 got, err := Compact(test.List) 644 645 if test.Err { 646 if err == nil { 647 t.Fatal("succeeded; want error") 648 } 649 return 650 } else if err != nil { 651 t.Fatalf("unexpected error: %s", err) 652 } 653 654 if !got.RawEquals(test.Want) { 655 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 656 } 657 }) 658 } 659 } 660 661 func TestContains(t *testing.T) { 662 listOfStrings := cty.ListVal([]cty.Value{ 663 cty.StringVal("the"), 664 cty.StringVal("quick"), 665 cty.StringVal("brown"), 666 cty.StringVal("fox"), 667 }) 668 listOfInts := cty.ListVal([]cty.Value{ 669 cty.NumberIntVal(1), 670 cty.NumberIntVal(2), 671 cty.NumberIntVal(3), 672 cty.NumberIntVal(4), 673 }) 674 listWithUnknown := cty.ListVal([]cty.Value{ 675 cty.StringVal("the"), 676 cty.StringVal("quick"), 677 cty.StringVal("brown"), 678 cty.UnknownVal(cty.String), 679 }) 680 681 tests := []struct { 682 List cty.Value 683 Value cty.Value 684 Want cty.Value 685 Err bool 686 }{ 687 { 688 listOfStrings, 689 cty.StringVal("the"), 690 cty.BoolVal(true), 691 false, 692 }, 693 { 694 listWithUnknown, 695 cty.StringVal("the"), 696 cty.BoolVal(true), 697 false, 698 }, 699 { 700 listOfStrings, 701 cty.StringVal("penguin"), 702 cty.BoolVal(false), 703 false, 704 }, 705 { 706 listOfInts, 707 cty.NumberIntVal(1), 708 cty.BoolVal(true), 709 false, 710 }, 711 { 712 listOfInts, 713 cty.NumberIntVal(42), 714 cty.BoolVal(false), 715 false, 716 }, 717 { // And now we mix and match 718 listOfInts, 719 cty.StringVal("1"), 720 cty.BoolVal(false), 721 false, 722 }, 723 { // Check a list with an unknown value 724 cty.ListVal([]cty.Value{ 725 cty.UnknownVal(cty.String), 726 cty.StringVal("quick"), 727 cty.StringVal("brown"), 728 cty.StringVal("fox"), 729 }), 730 cty.StringVal("quick"), 731 cty.BoolVal(true), 732 false, 733 }, 734 { // set val 735 cty.SetVal([]cty.Value{ 736 cty.StringVal("quick"), 737 cty.StringVal("brown"), 738 cty.StringVal("fox"), 739 }), 740 cty.StringVal("quick"), 741 cty.BoolVal(true), 742 false, 743 }, 744 { // tuple val 745 cty.TupleVal([]cty.Value{ 746 cty.StringVal("quick"), 747 cty.StringVal("brown"), 748 cty.NumberIntVal(3), 749 }), 750 cty.NumberIntVal(3), 751 cty.BoolVal(true), 752 false, 753 }, 754 } 755 756 for _, test := range tests { 757 t.Run(fmt.Sprintf("contains(%#v, %#v)", test.List, test.Value), func(t *testing.T) { 758 got, err := Contains(test.List, test.Value) 759 760 if test.Err { 761 if err == nil { 762 t.Fatal("succeeded; want error") 763 } 764 return 765 } else if err != nil { 766 t.Fatalf("unexpected error: %s", err) 767 } 768 769 if !got.RawEquals(test.Want) { 770 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 771 } 772 }) 773 } 774 } 775 776 func TestIndex(t *testing.T) { 777 tests := []struct { 778 List cty.Value 779 Value cty.Value 780 Want cty.Value 781 Err bool 782 }{ 783 { 784 cty.ListVal([]cty.Value{ 785 cty.StringVal("a"), 786 cty.StringVal("b"), 787 cty.StringVal("c"), 788 }), 789 cty.StringVal("a"), 790 cty.NumberIntVal(0), 791 false, 792 }, 793 { 794 cty.ListVal([]cty.Value{ 795 cty.StringVal("a"), 796 cty.StringVal("b"), 797 cty.UnknownVal(cty.String), 798 }), 799 cty.StringVal("a"), 800 cty.NumberIntVal(0), 801 false, 802 }, 803 { 804 cty.ListVal([]cty.Value{ 805 cty.StringVal("a"), 806 cty.StringVal("b"), 807 cty.StringVal("c"), 808 }), 809 cty.StringVal("b"), 810 cty.NumberIntVal(1), 811 false, 812 }, 813 { 814 cty.ListVal([]cty.Value{ 815 cty.StringVal("a"), 816 cty.StringVal("b"), 817 cty.StringVal("c"), 818 }), 819 cty.StringVal("z"), 820 cty.NilVal, 821 true, 822 }, 823 { 824 cty.ListVal([]cty.Value{ 825 cty.StringVal("1"), 826 cty.StringVal("2"), 827 cty.StringVal("3"), 828 }), 829 cty.NumberIntVal(1), 830 cty.NumberIntVal(0), 831 true, 832 }, 833 { 834 cty.ListVal([]cty.Value{ 835 cty.NumberIntVal(1), 836 cty.NumberIntVal(2), 837 cty.NumberIntVal(3), 838 }), 839 cty.NumberIntVal(2), 840 cty.NumberIntVal(1), 841 false, 842 }, 843 { 844 cty.ListVal([]cty.Value{ 845 cty.NumberIntVal(1), 846 cty.NumberIntVal(2), 847 cty.NumberIntVal(3), 848 }), 849 cty.NumberIntVal(4), 850 cty.NilVal, 851 true, 852 }, 853 { 854 cty.ListVal([]cty.Value{ 855 cty.NumberIntVal(1), 856 cty.NumberIntVal(2), 857 cty.NumberIntVal(3), 858 }), 859 cty.StringVal("1"), 860 cty.NumberIntVal(0), 861 true, 862 }, 863 { 864 cty.TupleVal([]cty.Value{ 865 cty.NumberIntVal(1), 866 cty.NumberIntVal(2), 867 cty.NumberIntVal(3), 868 }), 869 cty.NumberIntVal(1), 870 cty.NumberIntVal(0), 871 false, 872 }, 873 } 874 875 for _, test := range tests { 876 t.Run(fmt.Sprintf("index(%#v, %#v)", test.List, test.Value), func(t *testing.T) { 877 got, err := Index(test.List, test.Value) 878 879 if test.Err { 880 if err == nil { 881 t.Fatal("succeeded; want error") 882 } 883 return 884 } else if err != nil { 885 t.Fatalf("unexpected error: %s", err) 886 } 887 888 if !got.RawEquals(test.Want) { 889 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 890 } 891 }) 892 } 893 } 894 895 func TestDistinct(t *testing.T) { 896 tests := []struct { 897 List cty.Value 898 Want cty.Value 899 Err bool 900 }{ 901 { 902 cty.ListVal([]cty.Value{ 903 cty.StringVal("a"), 904 cty.StringVal("b"), 905 cty.StringVal("a"), 906 cty.StringVal("b"), 907 }), 908 cty.ListVal([]cty.Value{ 909 cty.StringVal("a"), 910 cty.StringVal("b"), 911 }), 912 false, 913 }, 914 { 915 cty.ListValEmpty(cty.String), 916 cty.ListValEmpty(cty.String), 917 false, 918 }, 919 { 920 cty.ListVal([]cty.Value{ 921 cty.StringVal("a"), 922 cty.StringVal("b"), 923 cty.StringVal("a"), 924 cty.UnknownVal(cty.String), 925 }), 926 cty.UnknownVal(cty.List(cty.String)), 927 false, 928 }, 929 { 930 cty.ListVal([]cty.Value{ 931 cty.StringVal("a"), 932 cty.StringVal("b"), 933 cty.StringVal("c"), 934 cty.StringVal("d"), 935 }), 936 cty.ListVal([]cty.Value{ 937 cty.StringVal("a"), 938 cty.StringVal("b"), 939 cty.StringVal("c"), 940 cty.StringVal("d"), 941 }), 942 false, 943 }, 944 { 945 cty.ListVal([]cty.Value{ 946 cty.NumberIntVal(1), 947 cty.NumberIntVal(2), 948 cty.NumberIntVal(1), 949 cty.NumberIntVal(2), 950 }), 951 cty.ListVal([]cty.Value{ 952 cty.NumberIntVal(1), 953 cty.NumberIntVal(2), 954 }), 955 false, 956 }, 957 { 958 cty.ListVal([]cty.Value{ 959 cty.ListVal([]cty.Value{ 960 cty.NumberIntVal(1), 961 cty.NumberIntVal(2), 962 }), 963 cty.ListVal([]cty.Value{ 964 cty.NumberIntVal(1), 965 cty.NumberIntVal(2), 966 }), 967 }), 968 cty.ListVal([]cty.Value{ 969 cty.ListVal([]cty.Value{ 970 cty.NumberIntVal(1), 971 cty.NumberIntVal(2), 972 }), 973 }), 974 false, 975 }, 976 { 977 cty.ListVal([]cty.Value{ 978 cty.ListVal([]cty.Value{ 979 cty.NumberIntVal(1), 980 cty.NumberIntVal(2), 981 }), 982 cty.ListVal([]cty.Value{ 983 cty.NumberIntVal(3), 984 cty.NumberIntVal(4), 985 }), 986 }), 987 cty.ListVal([]cty.Value{ 988 cty.ListVal([]cty.Value{ 989 cty.NumberIntVal(1), 990 cty.NumberIntVal(2), 991 }), 992 cty.ListVal([]cty.Value{ 993 cty.NumberIntVal(3), 994 cty.NumberIntVal(4), 995 }), 996 }), 997 false, 998 }, 999 } 1000 1001 for _, test := range tests { 1002 t.Run(fmt.Sprintf("distinct(%#v)", test.List), func(t *testing.T) { 1003 got, err := Distinct(test.List) 1004 1005 if test.Err { 1006 if err == nil { 1007 t.Fatal("succeeded; want error") 1008 } 1009 return 1010 } else if err != nil { 1011 t.Fatalf("unexpected error: %s", err) 1012 } 1013 1014 if !got.RawEquals(test.Want) { 1015 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1016 } 1017 }) 1018 } 1019 } 1020 1021 func TestChunklist(t *testing.T) { 1022 tests := []struct { 1023 List cty.Value 1024 Size cty.Value 1025 Want cty.Value 1026 Err bool 1027 }{ 1028 { 1029 cty.ListVal([]cty.Value{ 1030 cty.StringVal("a"), 1031 cty.StringVal("b"), 1032 cty.StringVal("c"), 1033 }), 1034 cty.NumberIntVal(1), 1035 cty.ListVal([]cty.Value{ 1036 cty.ListVal([]cty.Value{ 1037 cty.StringVal("a"), 1038 }), 1039 cty.ListVal([]cty.Value{ 1040 cty.StringVal("b"), 1041 }), 1042 cty.ListVal([]cty.Value{ 1043 cty.StringVal("c"), 1044 }), 1045 }), 1046 false, 1047 }, 1048 { 1049 cty.ListVal([]cty.Value{ 1050 cty.StringVal("a"), 1051 cty.StringVal("b"), 1052 cty.StringVal("c"), 1053 }), 1054 cty.NumberIntVal(-1), 1055 cty.NilVal, 1056 true, 1057 }, 1058 { 1059 cty.ListVal([]cty.Value{ 1060 cty.StringVal("a"), 1061 cty.StringVal("b"), 1062 cty.StringVal("c"), 1063 }), 1064 cty.NumberIntVal(0), 1065 cty.ListVal([]cty.Value{ 1066 cty.ListVal([]cty.Value{ 1067 cty.StringVal("a"), 1068 cty.StringVal("b"), 1069 cty.StringVal("c"), 1070 }), 1071 }), 1072 false, 1073 }, 1074 { 1075 cty.ListVal([]cty.Value{ 1076 cty.StringVal("a"), 1077 cty.StringVal("b"), 1078 cty.UnknownVal(cty.String), 1079 }), 1080 cty.NumberIntVal(1), 1081 cty.ListVal([]cty.Value{ 1082 cty.ListVal([]cty.Value{ 1083 cty.StringVal("a"), 1084 }), 1085 cty.ListVal([]cty.Value{ 1086 cty.StringVal("b"), 1087 }), 1088 cty.ListVal([]cty.Value{ 1089 cty.UnknownVal(cty.String), 1090 }), 1091 }), 1092 false, 1093 }, 1094 { 1095 cty.UnknownVal(cty.List(cty.String)), 1096 cty.NumberIntVal(1), 1097 cty.UnknownVal(cty.List(cty.List(cty.String))), 1098 false, 1099 }, 1100 { 1101 cty.ListValEmpty(cty.String), 1102 cty.NumberIntVal(3), 1103 cty.ListValEmpty(cty.List(cty.String)), 1104 false, 1105 }, 1106 } 1107 1108 for i, test := range tests { 1109 t.Run(fmt.Sprintf("%d-chunklist(%#v, %#v)", i, test.List, test.Size), func(t *testing.T) { 1110 got, err := Chunklist(test.List, test.Size) 1111 1112 if test.Err { 1113 if err == nil { 1114 t.Fatal("succeeded; want error") 1115 } 1116 return 1117 } else if err != nil { 1118 t.Fatalf("unexpected error: %s", err) 1119 } 1120 1121 if !got.RawEquals(test.Want) { 1122 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1123 } 1124 }) 1125 } 1126 } 1127 1128 func TestFlatten(t *testing.T) { 1129 tests := []struct { 1130 List cty.Value 1131 Want cty.Value 1132 Err bool 1133 }{ 1134 { 1135 cty.ListVal([]cty.Value{ 1136 cty.ListVal([]cty.Value{ 1137 cty.StringVal("a"), 1138 cty.StringVal("b"), 1139 }), 1140 cty.ListVal([]cty.Value{ 1141 cty.StringVal("c"), 1142 cty.StringVal("d"), 1143 }), 1144 }), 1145 cty.TupleVal([]cty.Value{ 1146 cty.StringVal("a"), 1147 cty.StringVal("b"), 1148 cty.StringVal("c"), 1149 cty.StringVal("d"), 1150 }), 1151 false, 1152 }, 1153 // handle single elements as arguments 1154 { 1155 cty.TupleVal([]cty.Value{ 1156 cty.ListVal([]cty.Value{ 1157 cty.StringVal("a"), 1158 cty.StringVal("b"), 1159 }), 1160 cty.StringVal("c"), 1161 }), 1162 cty.TupleVal([]cty.Value{ 1163 cty.StringVal("a"), 1164 cty.StringVal("b"), 1165 cty.StringVal("c"), 1166 }), false, 1167 }, 1168 // handle single elements and mixed primitive types as arguments 1169 { 1170 cty.TupleVal([]cty.Value{ 1171 cty.ListVal([]cty.Value{ 1172 cty.StringVal("a"), 1173 cty.StringVal("b"), 1174 }), 1175 cty.StringVal("c"), 1176 cty.TupleVal([]cty.Value{ 1177 cty.StringVal("x"), 1178 cty.NumberIntVal(1), 1179 }), 1180 }), 1181 cty.TupleVal([]cty.Value{ 1182 cty.StringVal("a"), 1183 cty.StringVal("b"), 1184 cty.StringVal("c"), 1185 cty.StringVal("x"), 1186 cty.NumberIntVal(1), 1187 }), 1188 false, 1189 }, 1190 // Primitive unknowns should still be flattened to a tuple 1191 { 1192 cty.ListVal([]cty.Value{ 1193 cty.ListVal([]cty.Value{ 1194 cty.StringVal("a"), 1195 cty.StringVal("b"), 1196 }), 1197 cty.ListVal([]cty.Value{ 1198 cty.UnknownVal(cty.String), 1199 cty.StringVal("d"), 1200 }), 1201 }), 1202 cty.TupleVal([]cty.Value{ 1203 cty.StringVal("a"), 1204 cty.StringVal("b"), 1205 cty.UnknownVal(cty.String), 1206 cty.StringVal("d"), 1207 }), false, 1208 }, 1209 // An unknown series should return an unknown dynamic value 1210 { 1211 cty.TupleVal([]cty.Value{ 1212 cty.ListVal([]cty.Value{ 1213 cty.StringVal("a"), 1214 cty.StringVal("b"), 1215 }), 1216 cty.TupleVal([]cty.Value{ 1217 cty.UnknownVal(cty.List(cty.String)), 1218 cty.StringVal("d"), 1219 }), 1220 }), 1221 cty.UnknownVal(cty.DynamicPseudoType), false, 1222 }, 1223 { 1224 cty.ListValEmpty(cty.String), 1225 cty.EmptyTupleVal, 1226 false, 1227 }, 1228 { 1229 cty.SetVal([]cty.Value{ 1230 cty.SetVal([]cty.Value{ 1231 cty.StringVal("a"), 1232 cty.StringVal("b"), 1233 }), 1234 cty.SetVal([]cty.Value{ 1235 cty.StringVal("c"), 1236 cty.StringVal("d"), 1237 }), 1238 }), 1239 cty.TupleVal([]cty.Value{ 1240 cty.StringVal("a"), 1241 cty.StringVal("b"), 1242 cty.StringVal("c"), 1243 cty.StringVal("d"), 1244 }), 1245 false, 1246 }, 1247 { 1248 cty.TupleVal([]cty.Value{ 1249 cty.SetVal([]cty.Value{ 1250 cty.StringVal("a"), 1251 cty.StringVal("b"), 1252 }), 1253 cty.ListVal([]cty.Value{ 1254 cty.StringVal("c"), 1255 cty.StringVal("d"), 1256 }), 1257 }), 1258 cty.TupleVal([]cty.Value{ 1259 cty.StringVal("a"), 1260 cty.StringVal("b"), 1261 cty.StringVal("c"), 1262 cty.StringVal("d"), 1263 }), 1264 false, 1265 }, 1266 } 1267 1268 for i, test := range tests { 1269 t.Run(fmt.Sprintf("%d-flatten(%#v)", i, test.List), func(t *testing.T) { 1270 got, err := Flatten(test.List) 1271 1272 if test.Err { 1273 if err == nil { 1274 t.Fatal("succeeded; want error") 1275 } 1276 return 1277 } else if err != nil { 1278 t.Fatalf("unexpected error: %s", err) 1279 } 1280 1281 if !got.RawEquals(test.Want) { 1282 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1283 } 1284 }) 1285 } 1286 } 1287 1288 func TestKeys(t *testing.T) { 1289 tests := []struct { 1290 Map cty.Value 1291 Want cty.Value 1292 Err bool 1293 }{ 1294 { 1295 cty.MapVal(map[string]cty.Value{ 1296 "hello": cty.NumberIntVal(1), 1297 "goodbye": cty.NumberIntVal(42), 1298 }), 1299 cty.ListVal([]cty.Value{ 1300 cty.StringVal("goodbye"), 1301 cty.StringVal("hello"), 1302 }), 1303 false, 1304 }, 1305 { // same as above, but an object type 1306 cty.ObjectVal(map[string]cty.Value{ 1307 "hello": cty.NumberIntVal(1), 1308 "goodbye": cty.StringVal("adieu"), 1309 }), 1310 cty.TupleVal([]cty.Value{ 1311 cty.StringVal("goodbye"), 1312 cty.StringVal("hello"), 1313 }), 1314 false, 1315 }, 1316 { // for an unknown object we can still return the keys, since they are part of the type 1317 cty.UnknownVal(cty.Object(map[string]cty.Type{ 1318 "hello": cty.Number, 1319 "goodbye": cty.String, 1320 })), 1321 cty.TupleVal([]cty.Value{ 1322 cty.StringVal("goodbye"), 1323 cty.StringVal("hello"), 1324 }), 1325 false, 1326 }, 1327 { // an empty object has no keys 1328 cty.EmptyObjectVal, 1329 cty.EmptyTupleVal, 1330 false, 1331 }, 1332 { // an empty map has no keys, but the result should still be properly typed 1333 cty.MapValEmpty(cty.Number), 1334 cty.ListValEmpty(cty.String), 1335 false, 1336 }, 1337 { // Unknown map has unknown keys 1338 cty.UnknownVal(cty.Map(cty.String)), 1339 cty.UnknownVal(cty.List(cty.String)), 1340 false, 1341 }, 1342 { // Not a map at all, so invalid 1343 cty.StringVal("foo"), 1344 cty.NilVal, 1345 true, 1346 }, 1347 { // Can't get keys from a null object 1348 cty.NullVal(cty.Object(map[string]cty.Type{ 1349 "hello": cty.Number, 1350 "goodbye": cty.String, 1351 })), 1352 cty.NilVal, 1353 true, 1354 }, 1355 { // Can't get keys from a null map 1356 cty.NullVal(cty.Map(cty.Number)), 1357 cty.NilVal, 1358 true, 1359 }, 1360 } 1361 1362 for _, test := range tests { 1363 t.Run(fmt.Sprintf("keys(%#v)", test.Map), func(t *testing.T) { 1364 got, err := Keys(test.Map) 1365 1366 if test.Err { 1367 if err == nil { 1368 t.Fatal("succeeded; want error") 1369 } 1370 return 1371 } else if err != nil { 1372 t.Fatalf("unexpected error: %s", err) 1373 } 1374 1375 if !got.RawEquals(test.Want) { 1376 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1377 } 1378 }) 1379 } 1380 } 1381 1382 func TestList(t *testing.T) { 1383 tests := []struct { 1384 Values []cty.Value 1385 Want cty.Value 1386 Err bool 1387 }{ 1388 { 1389 []cty.Value{ 1390 cty.NilVal, 1391 }, 1392 cty.NilVal, 1393 true, 1394 }, 1395 { 1396 []cty.Value{ 1397 cty.StringVal("Hello"), 1398 }, 1399 cty.ListVal([]cty.Value{ 1400 cty.StringVal("Hello"), 1401 }), 1402 false, 1403 }, 1404 { 1405 []cty.Value{ 1406 cty.StringVal("Hello"), 1407 cty.StringVal("World"), 1408 }, 1409 cty.ListVal([]cty.Value{ 1410 cty.StringVal("Hello"), 1411 cty.StringVal("World"), 1412 }), 1413 false, 1414 }, 1415 { 1416 []cty.Value{ 1417 cty.StringVal("Hello"), 1418 cty.NumberIntVal(42), 1419 }, 1420 cty.ListVal([]cty.Value{ 1421 cty.StringVal("Hello"), 1422 cty.StringVal("42"), 1423 }), 1424 false, 1425 }, 1426 { 1427 []cty.Value{ 1428 cty.StringVal("Hello"), 1429 cty.UnknownVal(cty.String), 1430 }, 1431 cty.ListVal([]cty.Value{ 1432 cty.StringVal("Hello"), 1433 cty.UnknownVal(cty.String), 1434 }), 1435 false, 1436 }, 1437 } 1438 1439 for _, test := range tests { 1440 t.Run(fmt.Sprintf("list(%#v)", test.Values), func(t *testing.T) { 1441 got, err := List(test.Values...) 1442 1443 if test.Err { 1444 if err == nil { 1445 t.Fatal("succeeded; want error") 1446 } 1447 return 1448 } else if err != nil { 1449 t.Fatalf("unexpected error: %s", err) 1450 } 1451 1452 if !got.RawEquals(test.Want) { 1453 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1454 } 1455 }) 1456 } 1457 } 1458 1459 func TestLookup(t *testing.T) { 1460 simpleMap := cty.MapVal(map[string]cty.Value{ 1461 "foo": cty.StringVal("bar"), 1462 }) 1463 intsMap := cty.MapVal(map[string]cty.Value{ 1464 "foo": cty.NumberIntVal(42), 1465 }) 1466 mapOfLists := cty.MapVal(map[string]cty.Value{ 1467 "foo": cty.ListVal([]cty.Value{ 1468 cty.StringVal("bar"), 1469 cty.StringVal("baz"), 1470 }), 1471 }) 1472 mapOfMaps := cty.MapVal(map[string]cty.Value{ 1473 "foo": cty.MapVal(map[string]cty.Value{ 1474 "a": cty.StringVal("bar"), 1475 }), 1476 "baz": cty.MapVal(map[string]cty.Value{ 1477 "b": cty.StringVal("bat"), 1478 }), 1479 }) 1480 mapOfTuples := cty.MapVal(map[string]cty.Value{ 1481 "foo": cty.TupleVal([]cty.Value{cty.StringVal("bar")}), 1482 "baz": cty.TupleVal([]cty.Value{cty.StringVal("bat")}), 1483 }) 1484 objectOfMaps := cty.ObjectVal(map[string]cty.Value{ 1485 "foo": cty.MapVal(map[string]cty.Value{ 1486 "a": cty.StringVal("bar"), 1487 }), 1488 "baz": cty.MapVal(map[string]cty.Value{ 1489 "b": cty.StringVal("bat"), 1490 }), 1491 }) 1492 mapWithUnknowns := cty.MapVal(map[string]cty.Value{ 1493 "foo": cty.StringVal("bar"), 1494 "baz": cty.UnknownVal(cty.String), 1495 }) 1496 mapWithObjects := cty.ObjectVal(map[string]cty.Value{ 1497 "foo": cty.StringVal("bar"), 1498 "baz": cty.NumberIntVal(42), 1499 }) 1500 1501 tests := []struct { 1502 Values []cty.Value 1503 Want cty.Value 1504 Err bool 1505 }{ 1506 { 1507 []cty.Value{ 1508 simpleMap, 1509 cty.StringVal("foo"), 1510 }, 1511 cty.StringVal("bar"), 1512 false, 1513 }, 1514 { 1515 []cty.Value{ 1516 mapWithObjects, 1517 cty.StringVal("foo"), 1518 }, 1519 cty.StringVal("bar"), 1520 false, 1521 }, 1522 { 1523 []cty.Value{ 1524 intsMap, 1525 cty.StringVal("foo"), 1526 }, 1527 cty.NumberIntVal(42), 1528 false, 1529 }, 1530 { 1531 []cty.Value{ 1532 mapOfMaps, 1533 cty.StringVal("foo"), 1534 }, 1535 cty.MapVal(map[string]cty.Value{ 1536 "a": cty.StringVal("bar"), 1537 }), 1538 false, 1539 }, 1540 { 1541 []cty.Value{ 1542 objectOfMaps, 1543 cty.StringVal("foo"), 1544 }, 1545 cty.MapVal(map[string]cty.Value{ 1546 "a": cty.StringVal("bar"), 1547 }), 1548 false, 1549 }, 1550 { 1551 []cty.Value{ 1552 mapOfTuples, 1553 cty.StringVal("foo"), 1554 }, 1555 cty.TupleVal([]cty.Value{cty.StringVal("bar")}), 1556 false, 1557 }, 1558 { // Invalid key 1559 []cty.Value{ 1560 simpleMap, 1561 cty.StringVal("bar"), 1562 }, 1563 cty.NilVal, 1564 true, 1565 }, 1566 { // Invalid key 1567 []cty.Value{ 1568 mapWithObjects, 1569 cty.StringVal("bar"), 1570 }, 1571 cty.NilVal, 1572 true, 1573 }, 1574 { // Supplied default with valid key 1575 []cty.Value{ 1576 simpleMap, 1577 cty.StringVal("foo"), 1578 cty.StringVal(""), 1579 }, 1580 cty.StringVal("bar"), 1581 false, 1582 }, 1583 { // Supplied default with valid (int) key 1584 []cty.Value{ 1585 simpleMap, 1586 cty.StringVal("foo"), 1587 cty.NumberIntVal(-1), 1588 }, 1589 cty.StringVal("bar"), 1590 false, 1591 }, 1592 { // Supplied default with valid (int) key 1593 []cty.Value{ 1594 simpleMap, 1595 cty.StringVal("foobar"), 1596 cty.NumberIntVal(-1), 1597 }, 1598 cty.StringVal("-1"), 1599 false, 1600 }, 1601 { // Supplied default with valid key 1602 []cty.Value{ 1603 mapWithObjects, 1604 cty.StringVal("foobar"), 1605 cty.StringVal(""), 1606 }, 1607 cty.StringVal(""), 1608 false, 1609 }, 1610 { // Supplied default with invalid key 1611 []cty.Value{ 1612 simpleMap, 1613 cty.StringVal("baz"), 1614 cty.StringVal(""), 1615 }, 1616 cty.StringVal(""), 1617 false, 1618 }, 1619 { // Supplied default with type mismatch: expects a map return 1620 []cty.Value{ 1621 mapOfMaps, 1622 cty.StringVal("foo"), 1623 cty.StringVal(""), 1624 }, 1625 cty.NilVal, 1626 true, 1627 }, 1628 { // Supplied non-empty default with invalid key 1629 []cty.Value{ 1630 simpleMap, 1631 cty.StringVal("bar"), 1632 cty.StringVal("xyz"), 1633 }, 1634 cty.StringVal("xyz"), 1635 false, 1636 }, 1637 { // too many args 1638 []cty.Value{ 1639 simpleMap, 1640 cty.StringVal("foo"), 1641 cty.StringVal("bar"), 1642 cty.StringVal("baz"), 1643 }, 1644 cty.NilVal, 1645 true, 1646 }, 1647 { // cannot search a map of lists 1648 []cty.Value{ 1649 mapOfLists, 1650 cty.StringVal("baz"), 1651 }, 1652 cty.NilVal, 1653 true, 1654 }, 1655 { 1656 []cty.Value{ 1657 mapWithUnknowns, 1658 cty.StringVal("baz"), 1659 }, 1660 cty.UnknownVal(cty.String), 1661 false, 1662 }, 1663 { 1664 []cty.Value{ 1665 simpleMap, 1666 cty.UnknownVal(cty.String), 1667 }, 1668 cty.UnknownVal(cty.String), 1669 false, 1670 }, 1671 { 1672 []cty.Value{ 1673 cty.ObjectVal(map[string]cty.Value{ 1674 "foo": cty.StringVal("a"), 1675 "bar": cty.StringVal("b"), 1676 }), 1677 cty.UnknownVal(cty.String), 1678 }, 1679 cty.DynamicVal, // if the key is unknown then we don't know which object attribute and thus can't know the type 1680 false, 1681 }, 1682 } 1683 1684 for _, test := range tests { 1685 t.Run(fmt.Sprintf("lookup(%#v)", test.Values), func(t *testing.T) { 1686 got, err := Lookup(test.Values...) 1687 1688 if test.Err { 1689 if err == nil { 1690 t.Fatal("succeeded; want error") 1691 } 1692 return 1693 } else if err != nil { 1694 t.Fatalf("unexpected error: %s", err) 1695 } 1696 1697 if !got.RawEquals(test.Want) { 1698 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1699 } 1700 }) 1701 } 1702 } 1703 1704 func TestMap(t *testing.T) { 1705 tests := []struct { 1706 Values []cty.Value 1707 Want cty.Value 1708 Err bool 1709 }{ 1710 { 1711 []cty.Value{ 1712 cty.StringVal("hello"), 1713 cty.StringVal("world"), 1714 }, 1715 cty.MapVal(map[string]cty.Value{ 1716 "hello": cty.StringVal("world"), 1717 }), 1718 false, 1719 }, 1720 { 1721 []cty.Value{ 1722 cty.StringVal("hello"), 1723 cty.UnknownVal(cty.String), 1724 }, 1725 cty.UnknownVal(cty.Map(cty.String)), 1726 false, 1727 }, 1728 { 1729 []cty.Value{ 1730 cty.StringVal("hello"), 1731 cty.StringVal("world"), 1732 cty.StringVal("what's"), 1733 cty.StringVal("up"), 1734 }, 1735 cty.MapVal(map[string]cty.Value{ 1736 "hello": cty.StringVal("world"), 1737 "what's": cty.StringVal("up"), 1738 }), 1739 false, 1740 }, 1741 { 1742 []cty.Value{ 1743 cty.StringVal("hello"), 1744 cty.NumberIntVal(1), 1745 cty.StringVal("goodbye"), 1746 cty.NumberIntVal(42), 1747 }, 1748 cty.MapVal(map[string]cty.Value{ 1749 "hello": cty.NumberIntVal(1), 1750 "goodbye": cty.NumberIntVal(42), 1751 }), 1752 false, 1753 }, 1754 { // convert numbers to strings 1755 []cty.Value{ 1756 cty.StringVal("hello"), 1757 cty.NumberIntVal(1), 1758 cty.StringVal("goodbye"), 1759 cty.StringVal("42"), 1760 }, 1761 cty.MapVal(map[string]cty.Value{ 1762 "hello": cty.StringVal("1"), 1763 "goodbye": cty.StringVal("42"), 1764 }), 1765 false, 1766 }, 1767 { // map of lists is okay 1768 []cty.Value{ 1769 cty.StringVal("hello"), 1770 cty.ListVal([]cty.Value{ 1771 cty.StringVal("world"), 1772 }), 1773 cty.StringVal("what's"), 1774 cty.ListVal([]cty.Value{ 1775 cty.StringVal("up"), 1776 }), 1777 }, 1778 cty.MapVal(map[string]cty.Value{ 1779 "hello": cty.ListVal([]cty.Value{cty.StringVal("world")}), 1780 "what's": cty.ListVal([]cty.Value{cty.StringVal("up")}), 1781 }), 1782 false, 1783 }, 1784 { // map of maps is okay 1785 []cty.Value{ 1786 cty.StringVal("hello"), 1787 cty.MapVal(map[string]cty.Value{ 1788 "there": cty.StringVal("world"), 1789 }), 1790 cty.StringVal("what's"), 1791 cty.MapVal(map[string]cty.Value{ 1792 "really": cty.StringVal("up"), 1793 }), 1794 }, 1795 cty.MapVal(map[string]cty.Value{ 1796 "hello": cty.MapVal(map[string]cty.Value{ 1797 "there": cty.StringVal("world"), 1798 }), 1799 "what's": cty.MapVal(map[string]cty.Value{ 1800 "really": cty.StringVal("up"), 1801 }), 1802 }), 1803 false, 1804 }, 1805 { // single argument returns an error 1806 []cty.Value{ 1807 cty.StringVal("hello"), 1808 }, 1809 cty.NilVal, 1810 true, 1811 }, 1812 { // duplicate keys returns an error 1813 []cty.Value{ 1814 cty.StringVal("hello"), 1815 cty.StringVal("world"), 1816 cty.StringVal("hello"), 1817 cty.StringVal("universe"), 1818 }, 1819 cty.NilVal, 1820 true, 1821 }, 1822 } 1823 1824 for _, test := range tests { 1825 t.Run(fmt.Sprintf("map(%#v)", test.Values), func(t *testing.T) { 1826 got, err := Map(test.Values...) 1827 if test.Err { 1828 if err == nil { 1829 t.Fatal("succeeded; want error") 1830 } 1831 return 1832 } else if err != nil { 1833 t.Fatalf("unexpected error: %s", err) 1834 } 1835 1836 if !got.RawEquals(test.Want) { 1837 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1838 } 1839 }) 1840 } 1841 } 1842 1843 func TestMatchkeys(t *testing.T) { 1844 tests := []struct { 1845 Keys cty.Value 1846 Values cty.Value 1847 Searchset cty.Value 1848 Want cty.Value 1849 Err bool 1850 }{ 1851 { // normal usage 1852 cty.ListVal([]cty.Value{ 1853 cty.StringVal("a"), 1854 cty.StringVal("b"), 1855 cty.StringVal("c"), 1856 }), 1857 cty.ListVal([]cty.Value{ 1858 cty.StringVal("ref1"), 1859 cty.StringVal("ref2"), 1860 cty.StringVal("ref3"), 1861 }), 1862 cty.ListVal([]cty.Value{ 1863 cty.StringVal("ref1"), 1864 }), 1865 cty.ListVal([]cty.Value{ 1866 cty.StringVal("a"), 1867 }), 1868 false, 1869 }, 1870 { // normal usage 2, check the order 1871 cty.ListVal([]cty.Value{ 1872 cty.StringVal("a"), 1873 cty.StringVal("b"), 1874 cty.StringVal("c"), 1875 }), 1876 cty.ListVal([]cty.Value{ 1877 cty.StringVal("ref1"), 1878 cty.StringVal("ref2"), 1879 cty.StringVal("ref3"), 1880 }), 1881 cty.ListVal([]cty.Value{ 1882 cty.StringVal("ref2"), 1883 cty.StringVal("ref1"), 1884 }), 1885 cty.ListVal([]cty.Value{ 1886 cty.StringVal("a"), 1887 cty.StringVal("b"), 1888 }), 1889 false, 1890 }, 1891 { // no matches 1892 cty.ListVal([]cty.Value{ 1893 cty.StringVal("a"), 1894 cty.StringVal("b"), 1895 cty.StringVal("c"), 1896 }), 1897 cty.ListVal([]cty.Value{ 1898 cty.StringVal("ref1"), 1899 cty.StringVal("ref2"), 1900 cty.StringVal("ref3"), 1901 }), 1902 cty.ListVal([]cty.Value{ 1903 cty.StringVal("ref4"), 1904 }), 1905 cty.ListValEmpty(cty.String), 1906 false, 1907 }, 1908 { // no matches 2 1909 cty.ListVal([]cty.Value{ 1910 cty.StringVal("a"), 1911 cty.StringVal("b"), 1912 cty.StringVal("c"), 1913 }), 1914 cty.ListVal([]cty.Value{ 1915 cty.StringVal("ref1"), 1916 cty.StringVal("ref2"), 1917 cty.StringVal("ref3"), 1918 }), 1919 cty.ListValEmpty(cty.String), 1920 cty.ListValEmpty(cty.String), 1921 false, 1922 }, 1923 { // zero case 1924 cty.ListValEmpty(cty.String), 1925 cty.ListValEmpty(cty.String), 1926 cty.ListVal([]cty.Value{cty.StringVal("nope")}), 1927 cty.ListValEmpty(cty.String), 1928 false, 1929 }, 1930 { // complex values 1931 cty.ListVal([]cty.Value{ 1932 cty.ListVal([]cty.Value{ 1933 cty.StringVal("a"), 1934 cty.StringVal("a"), 1935 }), 1936 }), 1937 cty.ListVal([]cty.Value{ 1938 cty.StringVal("a"), 1939 }), 1940 cty.ListVal([]cty.Value{ 1941 cty.StringVal("a"), 1942 }), 1943 cty.ListVal([]cty.Value{ 1944 cty.ListVal([]cty.Value{ 1945 cty.StringVal("a"), 1946 cty.StringVal("a"), 1947 }), 1948 }), 1949 false, 1950 }, 1951 { // unknowns 1952 cty.ListVal([]cty.Value{ 1953 cty.StringVal("a"), 1954 cty.StringVal("b"), 1955 cty.UnknownVal(cty.String), 1956 }), 1957 cty.ListVal([]cty.Value{ 1958 cty.StringVal("ref1"), 1959 cty.StringVal("ref2"), 1960 cty.UnknownVal(cty.String), 1961 }), 1962 cty.ListVal([]cty.Value{ 1963 cty.StringVal("ref1"), 1964 }), 1965 cty.UnknownVal(cty.List(cty.String)), 1966 false, 1967 }, 1968 { // different types that can be unified 1969 cty.ListVal([]cty.Value{ 1970 cty.StringVal("a"), 1971 }), 1972 cty.ListVal([]cty.Value{ 1973 cty.NumberIntVal(1), 1974 }), 1975 cty.ListVal([]cty.Value{ 1976 cty.StringVal("a"), 1977 }), 1978 cty.ListValEmpty(cty.String), 1979 false, 1980 }, 1981 { // complex values: values is a different type from keys and searchset 1982 cty.ListVal([]cty.Value{ 1983 cty.MapVal(map[string]cty.Value{ 1984 "foo": cty.StringVal("bar"), 1985 }), 1986 cty.MapVal(map[string]cty.Value{ 1987 "foo": cty.StringVal("baz"), 1988 }), 1989 cty.MapVal(map[string]cty.Value{ 1990 "foo": cty.StringVal("beep"), 1991 }), 1992 }), 1993 cty.ListVal([]cty.Value{ 1994 cty.StringVal("a"), 1995 cty.StringVal("b"), 1996 cty.StringVal("c"), 1997 }), 1998 cty.ListVal([]cty.Value{ 1999 cty.StringVal("a"), 2000 cty.StringVal("c"), 2001 }), 2002 cty.ListVal([]cty.Value{ 2003 cty.MapVal(map[string]cty.Value{ 2004 "foo": cty.StringVal("bar"), 2005 }), 2006 cty.MapVal(map[string]cty.Value{ 2007 "foo": cty.StringVal("beep"), 2008 }), 2009 }), 2010 false, 2011 }, 2012 // errors 2013 { // different types 2014 cty.ListVal([]cty.Value{ 2015 cty.StringVal("a"), 2016 }), 2017 cty.ListVal([]cty.Value{ 2018 cty.ListVal([]cty.Value{ 2019 cty.StringVal("a"), 2020 }), 2021 cty.ListVal([]cty.Value{ 2022 cty.StringVal("a"), 2023 }), 2024 }), 2025 cty.ListVal([]cty.Value{ 2026 cty.StringVal("a"), 2027 }), 2028 cty.NilVal, 2029 true, 2030 }, 2031 { // lists of different length 2032 cty.ListVal([]cty.Value{ 2033 cty.StringVal("a"), 2034 }), 2035 cty.ListVal([]cty.Value{ 2036 cty.StringVal("a"), 2037 cty.StringVal("b"), 2038 }), 2039 cty.ListVal([]cty.Value{ 2040 cty.StringVal("a"), 2041 }), 2042 cty.NilVal, 2043 true, 2044 }, 2045 } 2046 2047 for _, test := range tests { 2048 t.Run(fmt.Sprintf("matchkeys(%#v, %#v, %#v)", test.Keys, test.Values, test.Searchset), func(t *testing.T) { 2049 got, err := Matchkeys(test.Keys, test.Values, test.Searchset) 2050 2051 if test.Err { 2052 if err == nil { 2053 t.Fatal("succeeded; want error") 2054 } 2055 return 2056 } else if err != nil { 2057 t.Fatalf("unexpected error: %s", err) 2058 } 2059 2060 if !got.RawEquals(test.Want) { 2061 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 2062 } 2063 }) 2064 } 2065 } 2066 2067 func TestMerge(t *testing.T) { 2068 tests := []struct { 2069 Values []cty.Value 2070 Want cty.Value 2071 Err bool 2072 }{ 2073 { 2074 []cty.Value{ 2075 cty.MapVal(map[string]cty.Value{ 2076 "a": cty.StringVal("b"), 2077 }), 2078 cty.MapVal(map[string]cty.Value{ 2079 "c": cty.StringVal("d"), 2080 }), 2081 }, 2082 cty.ObjectVal(map[string]cty.Value{ 2083 "a": cty.StringVal("b"), 2084 "c": cty.StringVal("d"), 2085 }), 2086 false, 2087 }, 2088 { // handle unknowns 2089 []cty.Value{ 2090 cty.MapVal(map[string]cty.Value{ 2091 "a": cty.UnknownVal(cty.String), 2092 }), 2093 cty.MapVal(map[string]cty.Value{ 2094 "c": cty.StringVal("d"), 2095 }), 2096 }, 2097 cty.DynamicVal, 2098 false, 2099 }, 2100 { // merge with conflicts is ok, last in wins 2101 []cty.Value{ 2102 cty.MapVal(map[string]cty.Value{ 2103 "a": cty.StringVal("b"), 2104 "c": cty.StringVal("d"), 2105 }), 2106 cty.MapVal(map[string]cty.Value{ 2107 "a": cty.StringVal("x"), 2108 }), 2109 }, 2110 cty.ObjectVal(map[string]cty.Value{ 2111 "a": cty.StringVal("x"), 2112 "c": cty.StringVal("d"), 2113 }), 2114 false, 2115 }, 2116 { // only accept maps 2117 []cty.Value{ 2118 cty.MapVal(map[string]cty.Value{ 2119 "a": cty.StringVal("b"), 2120 "c": cty.StringVal("d"), 2121 }), 2122 cty.ListVal([]cty.Value{ 2123 cty.StringVal("a"), 2124 cty.StringVal("x"), 2125 }), 2126 }, 2127 cty.NilVal, 2128 true, 2129 }, 2130 2131 { // argument error, for a null type 2132 []cty.Value{ 2133 cty.MapVal(map[string]cty.Value{ 2134 "a": cty.StringVal("b"), 2135 }), 2136 cty.NullVal(cty.String), 2137 }, 2138 cty.NilVal, 2139 true, 2140 }, 2141 { // merge maps of maps 2142 []cty.Value{ 2143 cty.MapVal(map[string]cty.Value{ 2144 "a": cty.MapVal(map[string]cty.Value{ 2145 "b": cty.StringVal("c"), 2146 }), 2147 }), 2148 cty.MapVal(map[string]cty.Value{ 2149 "d": cty.MapVal(map[string]cty.Value{ 2150 "e": cty.StringVal("f"), 2151 }), 2152 }), 2153 }, 2154 cty.ObjectVal(map[string]cty.Value{ 2155 "a": cty.MapVal(map[string]cty.Value{ 2156 "b": cty.StringVal("c"), 2157 }), 2158 "d": cty.MapVal(map[string]cty.Value{ 2159 "e": cty.StringVal("f"), 2160 }), 2161 }), 2162 false, 2163 }, 2164 { // map of lists 2165 []cty.Value{ 2166 cty.MapVal(map[string]cty.Value{ 2167 "a": cty.ListVal([]cty.Value{ 2168 cty.StringVal("b"), 2169 cty.StringVal("c"), 2170 }), 2171 }), 2172 cty.MapVal(map[string]cty.Value{ 2173 "d": cty.ListVal([]cty.Value{ 2174 cty.StringVal("e"), 2175 cty.StringVal("f"), 2176 }), 2177 }), 2178 }, 2179 cty.ObjectVal(map[string]cty.Value{ 2180 "a": cty.ListVal([]cty.Value{ 2181 cty.StringVal("b"), 2182 cty.StringVal("c"), 2183 }), 2184 "d": cty.ListVal([]cty.Value{ 2185 cty.StringVal("e"), 2186 cty.StringVal("f"), 2187 }), 2188 }), 2189 false, 2190 }, 2191 { // merge map of various kinds 2192 []cty.Value{ 2193 cty.MapVal(map[string]cty.Value{ 2194 "a": cty.ListVal([]cty.Value{ 2195 cty.StringVal("b"), 2196 cty.StringVal("c"), 2197 }), 2198 }), 2199 cty.MapVal(map[string]cty.Value{ 2200 "d": cty.MapVal(map[string]cty.Value{ 2201 "e": cty.StringVal("f"), 2202 }), 2203 }), 2204 }, 2205 cty.ObjectVal(map[string]cty.Value{ 2206 "a": cty.ListVal([]cty.Value{ 2207 cty.StringVal("b"), 2208 cty.StringVal("c"), 2209 }), 2210 "d": cty.MapVal(map[string]cty.Value{ 2211 "e": cty.StringVal("f"), 2212 }), 2213 }), 2214 false, 2215 }, 2216 { // argument error: non map type 2217 []cty.Value{ 2218 cty.MapVal(map[string]cty.Value{ 2219 "a": cty.ListVal([]cty.Value{ 2220 cty.StringVal("b"), 2221 cty.StringVal("c"), 2222 }), 2223 }), 2224 cty.ListVal([]cty.Value{ 2225 cty.StringVal("d"), 2226 cty.StringVal("e"), 2227 }), 2228 }, 2229 cty.NilVal, 2230 true, 2231 }, 2232 } 2233 2234 for _, test := range tests { 2235 t.Run(fmt.Sprintf("merge(%#v)", test.Values), func(t *testing.T) { 2236 got, err := Merge(test.Values...) 2237 2238 if test.Err { 2239 if err == nil { 2240 t.Fatal("succeeded; want error") 2241 } 2242 return 2243 } else if err != nil { 2244 t.Fatalf("unexpected error: %s", err) 2245 } 2246 2247 if !got.RawEquals(test.Want) { 2248 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 2249 } 2250 }) 2251 } 2252 } 2253 2254 func TestReverse(t *testing.T) { 2255 tests := []struct { 2256 List cty.Value 2257 Want cty.Value 2258 Err string 2259 }{ 2260 { 2261 cty.ListValEmpty(cty.String), 2262 cty.ListValEmpty(cty.String), 2263 "", 2264 }, 2265 { 2266 cty.ListVal([]cty.Value{cty.StringVal("a")}), 2267 cty.ListVal([]cty.Value{cty.StringVal("a")}), 2268 "", 2269 }, 2270 { 2271 cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}), 2272 cty.ListVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a")}), 2273 "", 2274 }, 2275 { 2276 cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b"), cty.StringVal("c")}), 2277 cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.StringVal("a")}), 2278 "", 2279 }, 2280 { 2281 cty.ListVal([]cty.Value{cty.UnknownVal(cty.String), cty.StringVal("b"), cty.StringVal("c")}), 2282 cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.UnknownVal(cty.String)}), 2283 "", 2284 }, 2285 { 2286 cty.EmptyTupleVal, 2287 cty.EmptyTupleVal, 2288 "", 2289 }, 2290 { 2291 cty.TupleVal([]cty.Value{cty.StringVal("a")}), 2292 cty.TupleVal([]cty.Value{cty.StringVal("a")}), 2293 "", 2294 }, 2295 { 2296 cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.True}), 2297 cty.TupleVal([]cty.Value{cty.True, cty.StringVal("a")}), 2298 "", 2299 }, 2300 { 2301 cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.True, cty.Zero}), 2302 cty.TupleVal([]cty.Value{cty.Zero, cty.True, cty.StringVal("a")}), 2303 "", 2304 }, 2305 { 2306 cty.SetValEmpty(cty.String), 2307 cty.ListValEmpty(cty.String), 2308 "", 2309 }, 2310 { 2311 cty.SetVal([]cty.Value{cty.StringVal("a")}), 2312 cty.ListVal([]cty.Value{cty.StringVal("a")}), 2313 "", 2314 }, 2315 { 2316 cty.SetVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}), 2317 cty.ListVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a")}), // set-of-string iterates in lexicographical order 2318 "", 2319 }, 2320 { 2321 cty.SetVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a"), cty.StringVal("c")}), 2322 cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.StringVal("a")}), // set-of-string iterates in lexicographical order 2323 "", 2324 }, 2325 { 2326 cty.StringVal("no"), 2327 cty.NilVal, 2328 "can only reverse list or tuple values, not string", 2329 }, 2330 { 2331 cty.True, 2332 cty.NilVal, 2333 "can only reverse list or tuple values, not bool", 2334 }, 2335 { 2336 cty.MapValEmpty(cty.String), 2337 cty.NilVal, 2338 "can only reverse list or tuple values, not map of string", 2339 }, 2340 { 2341 cty.NullVal(cty.List(cty.String)), 2342 cty.NilVal, 2343 "argument must not be null", 2344 }, 2345 { 2346 cty.UnknownVal(cty.List(cty.String)), 2347 cty.UnknownVal(cty.List(cty.String)), 2348 "", 2349 }, 2350 } 2351 2352 for _, test := range tests { 2353 t.Run(fmt.Sprintf("reverse(%#v)", test.List), func(t *testing.T) { 2354 got, err := Reverse(test.List) 2355 2356 if test.Err != "" { 2357 if err == nil { 2358 t.Fatal("succeeded; want error") 2359 } 2360 if got, want := err.Error(), test.Err; got != want { 2361 t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) 2362 } 2363 return 2364 } else if err != nil { 2365 t.Fatalf("unexpected error: %s", err) 2366 } 2367 2368 if !got.RawEquals(test.Want) { 2369 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 2370 } 2371 }) 2372 } 2373 2374 } 2375 2376 func TestSetProduct(t *testing.T) { 2377 tests := []struct { 2378 Sets []cty.Value 2379 Want cty.Value 2380 Err string 2381 }{ 2382 { 2383 nil, 2384 cty.DynamicVal, 2385 "at least two arguments are required", 2386 }, 2387 { 2388 []cty.Value{ 2389 cty.SetValEmpty(cty.String), 2390 }, 2391 cty.DynamicVal, 2392 "at least two arguments are required", 2393 }, 2394 { 2395 []cty.Value{ 2396 cty.SetValEmpty(cty.String), 2397 cty.StringVal("hello"), 2398 }, 2399 cty.DynamicVal, 2400 "a set or a list is required", // this is an ArgError, so is presented against the second argument in particular 2401 }, 2402 { 2403 []cty.Value{ 2404 cty.SetValEmpty(cty.String), 2405 cty.SetValEmpty(cty.String), 2406 }, 2407 cty.SetValEmpty(cty.Tuple([]cty.Type{cty.String, cty.String})), 2408 "", 2409 }, 2410 { 2411 []cty.Value{ 2412 cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2413 cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}), 2414 }, 2415 cty.SetVal([]cty.Value{ 2416 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}), 2417 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}), 2418 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}), 2419 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}), 2420 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}), 2421 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}), 2422 }), 2423 "", 2424 }, 2425 { 2426 []cty.Value{ 2427 cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2428 cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}), 2429 }, 2430 cty.SetVal([]cty.Value{ 2431 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}), 2432 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}), 2433 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}), 2434 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}), 2435 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}), 2436 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}), 2437 }), 2438 "", 2439 }, 2440 { 2441 []cty.Value{ 2442 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2443 cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}), 2444 }, 2445 cty.SetVal([]cty.Value{ 2446 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}), 2447 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}), 2448 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}), 2449 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}), 2450 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}), 2451 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}), 2452 }), 2453 "", 2454 }, 2455 { 2456 []cty.Value{ 2457 cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2458 cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}), 2459 }, 2460 cty.ListVal([]cty.Value{ 2461 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}), 2462 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}), 2463 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}), 2464 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}), 2465 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}), 2466 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}), 2467 }), 2468 "", 2469 }, 2470 { 2471 []cty.Value{ 2472 cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2473 cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}), 2474 }, 2475 cty.ListVal([]cty.Value{ 2476 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}), 2477 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}), 2478 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}), 2479 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}), 2480 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}), 2481 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}), 2482 }), 2483 "", 2484 }, 2485 { 2486 []cty.Value{ 2487 cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2488 cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.True}), 2489 }, 2490 cty.ListVal([]cty.Value{ 2491 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}), 2492 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("true")}), 2493 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}), 2494 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("true")}), 2495 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}), 2496 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("true")}), 2497 }), 2498 "", 2499 }, 2500 { 2501 []cty.Value{ 2502 cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2503 cty.EmptyTupleVal, 2504 }, 2505 cty.ListValEmpty(cty.Tuple([]cty.Type{cty.String, cty.DynamicPseudoType})), 2506 "", 2507 }, 2508 { 2509 []cty.Value{ 2510 cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2511 cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.EmptyObjectVal}), 2512 }, 2513 cty.DynamicVal, 2514 "all elements must be of the same type", // this is an ArgError for the second argument 2515 }, 2516 { 2517 []cty.Value{ 2518 cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2519 cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}), 2520 cty.SetVal([]cty.Value{cty.StringVal("baz")}), 2521 }, 2522 cty.SetVal([]cty.Value{ 2523 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo"), cty.StringVal("baz")}), 2524 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo"), cty.StringVal("baz")}), 2525 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo"), cty.StringVal("baz")}), 2526 cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar"), cty.StringVal("baz")}), 2527 cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar"), cty.StringVal("baz")}), 2528 cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar"), cty.StringVal("baz")}), 2529 }), 2530 "", 2531 }, 2532 { 2533 []cty.Value{ 2534 cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}), 2535 cty.SetValEmpty(cty.String), 2536 }, 2537 cty.SetValEmpty(cty.Tuple([]cty.Type{cty.String, cty.String})), 2538 "", 2539 }, 2540 { 2541 []cty.Value{ 2542 cty.SetVal([]cty.Value{cty.StringVal("foo")}), 2543 cty.SetVal([]cty.Value{cty.StringVal("bar")}), 2544 }, 2545 cty.SetVal([]cty.Value{ 2546 cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}), 2547 }), 2548 "", 2549 }, 2550 { 2551 []cty.Value{ 2552 cty.TupleVal([]cty.Value{cty.StringVal("foo")}), 2553 cty.TupleVal([]cty.Value{cty.StringVal("bar")}), 2554 }, 2555 cty.ListVal([]cty.Value{ 2556 cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}), 2557 }), 2558 "", 2559 }, 2560 { 2561 []cty.Value{ 2562 cty.SetVal([]cty.Value{cty.StringVal("foo")}), 2563 cty.SetVal([]cty.Value{cty.DynamicVal}), 2564 }, 2565 cty.SetVal([]cty.Value{ 2566 cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.DynamicVal}), 2567 }), 2568 "", 2569 }, 2570 { 2571 []cty.Value{ 2572 cty.SetVal([]cty.Value{cty.StringVal("foo")}), 2573 cty.SetVal([]cty.Value{cty.True, cty.DynamicVal}), 2574 }, 2575 cty.SetVal([]cty.Value{ 2576 cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.True}), 2577 cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.UnknownVal(cty.Bool)}), 2578 }), 2579 "", 2580 }, 2581 { 2582 []cty.Value{ 2583 cty.UnknownVal(cty.Set(cty.String)), 2584 cty.SetVal([]cty.Value{cty.True, cty.False}), 2585 }, 2586 cty.UnknownVal(cty.Set(cty.Tuple([]cty.Type{cty.String, cty.Bool}))), 2587 "", 2588 }, 2589 } 2590 2591 for _, test := range tests { 2592 t.Run(fmt.Sprintf("setproduct(%#v)", test.Sets), func(t *testing.T) { 2593 got, err := SetProduct(test.Sets...) 2594 2595 if test.Err != "" { 2596 if err == nil { 2597 t.Fatal("succeeded; want error") 2598 } 2599 if got, want := err.Error(), test.Err; got != want { 2600 t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) 2601 } 2602 return 2603 } else if err != nil { 2604 t.Fatalf("unexpected error: %s", err) 2605 } 2606 2607 if !got.RawEquals(test.Want) { 2608 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 2609 } 2610 }) 2611 } 2612 2613 } 2614 2615 func TestSlice(t *testing.T) { 2616 listOfStrings := cty.ListVal([]cty.Value{ 2617 cty.StringVal("a"), 2618 cty.StringVal("b"), 2619 }) 2620 listOfInts := cty.ListVal([]cty.Value{ 2621 cty.NumberIntVal(1), 2622 cty.NumberIntVal(2), 2623 }) 2624 listWithUnknowns := cty.ListVal([]cty.Value{ 2625 cty.StringVal("a"), 2626 cty.UnknownVal(cty.String), 2627 }) 2628 tuple := cty.TupleVal([]cty.Value{ 2629 cty.StringVal("a"), 2630 cty.NumberIntVal(1), 2631 cty.UnknownVal(cty.List(cty.String)), 2632 }) 2633 tests := []struct { 2634 List cty.Value 2635 StartIndex cty.Value 2636 EndIndex cty.Value 2637 Want cty.Value 2638 Err bool 2639 }{ 2640 { // normal usage 2641 listOfStrings, 2642 cty.NumberIntVal(1), 2643 cty.NumberIntVal(2), 2644 cty.ListVal([]cty.Value{ 2645 cty.StringVal("b"), 2646 }), 2647 false, 2648 }, 2649 { // slice only an unknown value 2650 listWithUnknowns, 2651 cty.NumberIntVal(1), 2652 cty.NumberIntVal(2), 2653 cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}), 2654 false, 2655 }, 2656 { // slice multiple values, which contain an unknown 2657 listWithUnknowns, 2658 cty.NumberIntVal(0), 2659 cty.NumberIntVal(2), 2660 listWithUnknowns, 2661 false, 2662 }, 2663 { // an unknown list should be slicable, returning an unknown list 2664 cty.UnknownVal(cty.List(cty.String)), 2665 cty.NumberIntVal(0), 2666 cty.NumberIntVal(2), 2667 cty.UnknownVal(cty.List(cty.String)), 2668 false, 2669 }, 2670 { // normal usage 2671 listOfInts, 2672 cty.NumberIntVal(1), 2673 cty.NumberIntVal(2), 2674 cty.ListVal([]cty.Value{ 2675 cty.NumberIntVal(2), 2676 }), 2677 false, 2678 }, 2679 { // empty result 2680 listOfStrings, 2681 cty.NumberIntVal(1), 2682 cty.NumberIntVal(1), 2683 cty.ListValEmpty(cty.String), 2684 false, 2685 }, 2686 { // index out of bounds 2687 listOfStrings, 2688 cty.NumberIntVal(1), 2689 cty.NumberIntVal(4), 2690 cty.NilVal, 2691 true, 2692 }, 2693 { // StartIndex index > EndIndex 2694 listOfStrings, 2695 cty.NumberIntVal(2), 2696 cty.NumberIntVal(1), 2697 cty.NilVal, 2698 true, 2699 }, 2700 { // negative StartIndex 2701 listOfStrings, 2702 cty.NumberIntVal(-1), 2703 cty.NumberIntVal(0), 2704 cty.NilVal, 2705 true, 2706 }, 2707 { // sets are not slice-able 2708 cty.SetVal([]cty.Value{ 2709 cty.StringVal("x"), 2710 cty.StringVal("y"), 2711 }), 2712 cty.NumberIntVal(0), 2713 cty.NumberIntVal(0), 2714 cty.NilVal, 2715 true, 2716 }, 2717 { // tuple slice 2718 tuple, 2719 cty.NumberIntVal(1), 2720 cty.NumberIntVal(3), 2721 cty.TupleVal([]cty.Value{ 2722 cty.NumberIntVal(1), 2723 cty.UnknownVal(cty.List(cty.String)), 2724 }), 2725 false, 2726 }, 2727 { // unknown tuple slice 2728 cty.UnknownVal(tuple.Type()), 2729 cty.NumberIntVal(1), 2730 cty.NumberIntVal(3), 2731 cty.UnknownVal(cty.Tuple([]cty.Type{ 2732 cty.Number, 2733 cty.List(cty.String), 2734 })), 2735 false, 2736 }, 2737 { // empty list slice 2738 listOfStrings, 2739 cty.NumberIntVal(2), 2740 cty.NumberIntVal(2), 2741 cty.ListValEmpty(cty.String), 2742 false, 2743 }, 2744 { // empty tuple slice 2745 tuple, 2746 cty.NumberIntVal(3), 2747 cty.NumberIntVal(3), 2748 cty.EmptyTupleVal, 2749 false, 2750 }, 2751 { // list with unknown start offset 2752 listOfStrings, 2753 cty.UnknownVal(cty.Number), 2754 cty.NumberIntVal(2), 2755 cty.UnknownVal(cty.List(cty.String)), 2756 false, 2757 }, 2758 { // list with unknown start offset but end out of bounds 2759 listOfStrings, 2760 cty.UnknownVal(cty.Number), 2761 cty.NumberIntVal(200), 2762 cty.UnknownVal(cty.List(cty.String)), 2763 true, 2764 }, 2765 { // list with unknown start offset but end < 0 2766 listOfStrings, 2767 cty.UnknownVal(cty.Number), 2768 cty.NumberIntVal(-4), 2769 cty.UnknownVal(cty.List(cty.String)), 2770 true, 2771 }, 2772 { // list with unknown end offset 2773 listOfStrings, 2774 cty.UnknownVal(cty.Number), 2775 cty.NumberIntVal(0), 2776 cty.UnknownVal(cty.List(cty.String)), 2777 false, 2778 }, 2779 { // list with unknown end offset but start out of bounds 2780 listOfStrings, 2781 cty.UnknownVal(cty.Number), 2782 cty.NumberIntVal(200), 2783 cty.UnknownVal(cty.List(cty.String)), 2784 true, 2785 }, 2786 { // list with unknown end offset but start < 0 2787 listOfStrings, 2788 cty.UnknownVal(cty.Number), 2789 cty.NumberIntVal(-3), 2790 cty.UnknownVal(cty.List(cty.String)), 2791 true, 2792 }, 2793 { // tuple slice with unknown start offset 2794 tuple, 2795 cty.UnknownVal(cty.Number), 2796 cty.NumberIntVal(3), 2797 cty.DynamicVal, 2798 false, 2799 }, 2800 { // tuple slice with unknown start offset but end out of bounds 2801 tuple, 2802 cty.UnknownVal(cty.Number), 2803 cty.NumberIntVal(200), 2804 cty.DynamicVal, 2805 true, 2806 }, 2807 { // tuple slice with unknown start offset but end < 0 2808 tuple, 2809 cty.UnknownVal(cty.Number), 2810 cty.NumberIntVal(-20), 2811 cty.DynamicVal, 2812 true, 2813 }, 2814 { // tuple slice with unknown end offset 2815 tuple, 2816 cty.NumberIntVal(0), 2817 cty.UnknownVal(cty.Number), 2818 cty.DynamicVal, 2819 false, 2820 }, 2821 { // tuple slice with unknown end offset but start < 0 2822 tuple, 2823 cty.NumberIntVal(-2), 2824 cty.UnknownVal(cty.Number), 2825 cty.DynamicVal, 2826 true, 2827 }, 2828 { // tuple slice with unknown end offset but start out of bounds 2829 tuple, 2830 cty.NumberIntVal(200), 2831 cty.UnknownVal(cty.Number), 2832 cty.DynamicVal, 2833 true, 2834 }, 2835 } 2836 2837 for i, test := range tests { 2838 t.Run(fmt.Sprintf("%d-slice(%#v, %#v, %#v)", i, test.List, test.StartIndex, test.EndIndex), func(t *testing.T) { 2839 got, err := Slice(test.List, test.StartIndex, test.EndIndex) 2840 2841 if test.Err { 2842 if err == nil { 2843 t.Fatal("succeeded; want error") 2844 } 2845 return 2846 } else if err != nil { 2847 t.Fatalf("unexpected error: %s", err) 2848 } 2849 2850 if !got.RawEquals(test.Want) { 2851 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 2852 } 2853 }) 2854 } 2855 } 2856 2857 func TestTranspose(t *testing.T) { 2858 tests := []struct { 2859 Values cty.Value 2860 Want cty.Value 2861 Err bool 2862 }{ 2863 { 2864 cty.MapVal(map[string]cty.Value{ 2865 "key1": cty.ListVal([]cty.Value{ 2866 cty.StringVal("a"), 2867 cty.StringVal("b"), 2868 }), 2869 "key2": cty.ListVal([]cty.Value{ 2870 cty.StringVal("a"), 2871 cty.StringVal("b"), 2872 cty.StringVal("c"), 2873 }), 2874 "key3": cty.ListVal([]cty.Value{ 2875 cty.StringVal("c"), 2876 }), 2877 "key4": cty.ListValEmpty(cty.String), 2878 }), 2879 cty.MapVal(map[string]cty.Value{ 2880 "a": cty.ListVal([]cty.Value{ 2881 cty.StringVal("key1"), 2882 cty.StringVal("key2"), 2883 }), 2884 "b": cty.ListVal([]cty.Value{ 2885 cty.StringVal("key1"), 2886 cty.StringVal("key2"), 2887 }), 2888 "c": cty.ListVal([]cty.Value{ 2889 cty.StringVal("key2"), 2890 cty.StringVal("key3"), 2891 }), 2892 }), 2893 false, 2894 }, 2895 { // map - unknown value 2896 cty.MapVal(map[string]cty.Value{ 2897 "key1": cty.UnknownVal(cty.List(cty.String)), 2898 }), 2899 cty.UnknownVal(cty.Map(cty.List(cty.String))), 2900 false, 2901 }, 2902 { // bad map - empty value 2903 cty.MapVal(map[string]cty.Value{ 2904 "key1": cty.ListValEmpty(cty.String), 2905 }), 2906 cty.NilVal, 2907 true, 2908 }, 2909 { // bad map - value not a list 2910 cty.MapVal(map[string]cty.Value{ 2911 "key1": cty.StringVal("a"), 2912 }), 2913 cty.NilVal, 2914 true, 2915 }, 2916 } 2917 2918 for _, test := range tests { 2919 t.Run(fmt.Sprintf("transpose(%#v)", test.Values), func(t *testing.T) { 2920 got, err := Transpose(test.Values) 2921 2922 if test.Err { 2923 if err == nil { 2924 t.Fatal("succeeded; want error") 2925 } 2926 return 2927 } else if err != nil { 2928 t.Fatalf("unexpected error: %s", err) 2929 } 2930 2931 if !got.RawEquals(test.Want) { 2932 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 2933 } 2934 }) 2935 } 2936 } 2937 2938 func TestValues(t *testing.T) { 2939 tests := []struct { 2940 Values cty.Value 2941 Want cty.Value 2942 Err bool 2943 }{ 2944 { 2945 cty.MapVal(map[string]cty.Value{ 2946 "hello": cty.StringVal("world"), 2947 "what's": cty.StringVal("up"), 2948 }), 2949 cty.ListVal([]cty.Value{ 2950 cty.StringVal("world"), 2951 cty.StringVal("up"), 2952 }), 2953 false, 2954 }, 2955 { 2956 cty.ObjectVal(map[string]cty.Value{ 2957 "what's": cty.StringVal("up"), 2958 "hello": cty.StringVal("world"), 2959 }), 2960 cty.TupleVal([]cty.Value{ 2961 cty.StringVal("world"), 2962 cty.StringVal("up"), 2963 }), 2964 false, 2965 }, 2966 { // empty object 2967 cty.EmptyObjectVal, 2968 cty.EmptyTupleVal, 2969 false, 2970 }, 2971 { 2972 cty.UnknownVal(cty.Object(map[string]cty.Type{ 2973 "what's": cty.String, 2974 "hello": cty.Bool, 2975 })), 2976 cty.UnknownVal(cty.Tuple([]cty.Type{ 2977 cty.Bool, 2978 cty.String, 2979 })), 2980 false, 2981 }, 2982 { // note ordering: keys are sorted first 2983 cty.MapVal(map[string]cty.Value{ 2984 "hello": cty.NumberIntVal(1), 2985 "goodbye": cty.NumberIntVal(42), 2986 }), 2987 cty.ListVal([]cty.Value{ 2988 cty.NumberIntVal(42), 2989 cty.NumberIntVal(1), 2990 }), 2991 false, 2992 }, 2993 { // map of lists 2994 cty.MapVal(map[string]cty.Value{ 2995 "hello": cty.ListVal([]cty.Value{cty.StringVal("world")}), 2996 "what's": cty.ListVal([]cty.Value{cty.StringVal("up")}), 2997 }), 2998 cty.ListVal([]cty.Value{ 2999 cty.ListVal([]cty.Value{cty.StringVal("world")}), 3000 cty.ListVal([]cty.Value{cty.StringVal("up")}), 3001 }), 3002 false, 3003 }, 3004 { // map with unknowns 3005 cty.MapVal(map[string]cty.Value{ 3006 "hello": cty.ListVal([]cty.Value{cty.StringVal("world")}), 3007 "what's": cty.UnknownVal(cty.List(cty.String)), 3008 }), 3009 cty.ListVal([]cty.Value{ 3010 cty.ListVal([]cty.Value{cty.StringVal("world")}), 3011 cty.UnknownVal(cty.List(cty.String)), 3012 }), 3013 false, 3014 }, 3015 { // empty m 3016 cty.MapValEmpty(cty.DynamicPseudoType), 3017 cty.ListValEmpty(cty.DynamicPseudoType), 3018 false, 3019 }, 3020 { // unknown m 3021 cty.UnknownVal(cty.Map(cty.String)), 3022 cty.UnknownVal(cty.List(cty.String)), 3023 false, 3024 }, 3025 } 3026 3027 for _, test := range tests { 3028 t.Run(fmt.Sprintf("values(%#v)", test.Values), func(t *testing.T) { 3029 got, err := Values(test.Values) 3030 3031 if test.Err { 3032 if err == nil { 3033 t.Fatal("succeeded; want error") 3034 } 3035 return 3036 } else if err != nil { 3037 t.Fatalf("unexpected error: %s", err) 3038 } 3039 3040 if !got.RawEquals(test.Want) { 3041 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 3042 } 3043 }) 3044 } 3045 } 3046 3047 func TestZipmap(t *testing.T) { 3048 list1 := cty.ListVal([]cty.Value{ 3049 cty.StringVal("hello"), 3050 cty.StringVal("world"), 3051 }) 3052 list2 := cty.ListVal([]cty.Value{ 3053 cty.StringVal("bar"), 3054 cty.StringVal("baz"), 3055 }) 3056 list3 := cty.ListVal([]cty.Value{ 3057 cty.StringVal("hello"), 3058 cty.StringVal("there"), 3059 cty.StringVal("world"), 3060 }) 3061 list4 := cty.ListVal([]cty.Value{ 3062 cty.NumberIntVal(1), 3063 cty.NumberIntVal(42), 3064 }) 3065 list5 := cty.ListVal([]cty.Value{ 3066 cty.ListVal([]cty.Value{ 3067 cty.StringVal("bar"), 3068 }), 3069 cty.ListVal([]cty.Value{ 3070 cty.StringVal("baz"), 3071 }), 3072 }) 3073 tests := []struct { 3074 Keys cty.Value 3075 Values cty.Value 3076 Want cty.Value 3077 Err bool 3078 }{ 3079 { 3080 list1, 3081 list2, 3082 cty.MapVal(map[string]cty.Value{ 3083 "hello": cty.StringVal("bar"), 3084 "world": cty.StringVal("baz"), 3085 }), 3086 false, 3087 }, 3088 { 3089 list1, 3090 list4, 3091 cty.MapVal(map[string]cty.Value{ 3092 "hello": cty.NumberIntVal(1), 3093 "world": cty.NumberIntVal(42), 3094 }), 3095 false, 3096 }, 3097 { // length mismatch 3098 list1, 3099 list3, 3100 cty.NilVal, 3101 true, 3102 }, 3103 { // map of lists 3104 list1, 3105 list5, 3106 cty.MapVal(map[string]cty.Value{ 3107 "hello": cty.ListVal([]cty.Value{cty.StringVal("bar")}), 3108 "world": cty.ListVal([]cty.Value{cty.StringVal("baz")}), 3109 }), 3110 false, 3111 }, 3112 { // tuple values produce object 3113 cty.ListVal([]cty.Value{ 3114 cty.StringVal("hello"), 3115 cty.StringVal("world"), 3116 }), 3117 cty.TupleVal([]cty.Value{ 3118 cty.StringVal("bar"), 3119 cty.UnknownVal(cty.Bool), 3120 }), 3121 cty.ObjectVal(map[string]cty.Value{ 3122 "hello": cty.StringVal("bar"), 3123 "world": cty.UnknownVal(cty.Bool), 3124 }), 3125 false, 3126 }, 3127 { // empty tuple produces empty object 3128 cty.ListValEmpty(cty.String), 3129 cty.EmptyTupleVal, 3130 cty.EmptyObjectVal, 3131 false, 3132 }, 3133 { // tuple with any unknown keys produces DynamicVal 3134 cty.ListVal([]cty.Value{ 3135 cty.StringVal("hello"), 3136 cty.UnknownVal(cty.String), 3137 }), 3138 cty.TupleVal([]cty.Value{ 3139 cty.StringVal("bar"), 3140 cty.True, 3141 }), 3142 cty.DynamicVal, 3143 false, 3144 }, 3145 { // tuple with all keys unknown produces DynamicVal 3146 cty.UnknownVal(cty.List(cty.String)), 3147 cty.TupleVal([]cty.Value{ 3148 cty.StringVal("bar"), 3149 cty.True, 3150 }), 3151 cty.DynamicVal, 3152 false, 3153 }, 3154 { // list with all keys unknown produces correctly-typed unknown map 3155 cty.UnknownVal(cty.List(cty.String)), 3156 cty.ListVal([]cty.Value{ 3157 cty.StringVal("bar"), 3158 cty.StringVal("baz"), 3159 }), 3160 cty.UnknownVal(cty.Map(cty.String)), 3161 false, 3162 }, 3163 { // unknown tuple as values produces correctly-typed unknown object 3164 cty.ListVal([]cty.Value{ 3165 cty.StringVal("hello"), 3166 cty.StringVal("world"), 3167 }), 3168 cty.UnknownVal(cty.Tuple([]cty.Type{ 3169 cty.String, 3170 cty.Bool, 3171 })), 3172 cty.UnknownVal(cty.Object(map[string]cty.Type{ 3173 "hello": cty.String, 3174 "world": cty.Bool, 3175 })), 3176 false, 3177 }, 3178 { // unknown list as values produces correctly-typed unknown map 3179 cty.ListVal([]cty.Value{ 3180 cty.StringVal("hello"), 3181 cty.StringVal("world"), 3182 }), 3183 cty.UnknownVal(cty.List(cty.String)), 3184 cty.UnknownVal(cty.Map(cty.String)), 3185 false, 3186 }, 3187 { // empty input returns an empty map 3188 cty.ListValEmpty(cty.String), 3189 cty.ListValEmpty(cty.String), 3190 cty.MapValEmpty(cty.String), 3191 false, 3192 }, 3193 { // keys cannot be a list of lists 3194 list5, 3195 list1, 3196 cty.NilVal, 3197 true, 3198 }, 3199 } 3200 3201 for _, test := range tests { 3202 t.Run(fmt.Sprintf("zipmap(%#v, %#v)", test.Keys, test.Values), func(t *testing.T) { 3203 got, err := Zipmap(test.Keys, test.Values) 3204 3205 if test.Err { 3206 if err == nil { 3207 t.Fatal("succeeded; want error") 3208 } 3209 return 3210 } else if err != nil { 3211 t.Fatalf("unexpected error: %s", err) 3212 } 3213 3214 if !got.RawEquals(test.Want) { 3215 t.Errorf("wrong result\n\nkeys: %#v\nvalues: %#v\ngot: %#v\nwant: %#v", test.Keys, test.Values, got, test.Want) 3216 } 3217 }) 3218 } 3219 }