github.com/hugorut/terraform@v1.1.3/src/lang/funcs/collection_test.go (about) 1 package funcs 2 3 import ( 4 "fmt" 5 "math" 6 "testing" 7 8 "github.com/zclconf/go-cty/cty" 9 ) 10 11 func TestLength(t *testing.T) { 12 tests := []struct { 13 Value cty.Value 14 Want cty.Value 15 }{ 16 { 17 cty.ListValEmpty(cty.Number), 18 cty.NumberIntVal(0), 19 }, 20 { 21 cty.ListVal([]cty.Value{cty.True}), 22 cty.NumberIntVal(1), 23 }, 24 { 25 cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}), 26 cty.NumberIntVal(1), 27 }, 28 { 29 cty.SetValEmpty(cty.Number), 30 cty.NumberIntVal(0), 31 }, 32 { 33 cty.SetVal([]cty.Value{cty.True}), 34 cty.NumberIntVal(1), 35 }, 36 { 37 cty.MapValEmpty(cty.Bool), 38 cty.NumberIntVal(0), 39 }, 40 { 41 cty.MapVal(map[string]cty.Value{"hello": cty.True}), 42 cty.NumberIntVal(1), 43 }, 44 { 45 cty.EmptyTupleVal, 46 cty.NumberIntVal(0), 47 }, 48 { 49 cty.UnknownVal(cty.EmptyTuple), 50 cty.NumberIntVal(0), 51 }, 52 { 53 cty.TupleVal([]cty.Value{cty.True}), 54 cty.NumberIntVal(1), 55 }, 56 { 57 cty.EmptyObjectVal, 58 cty.NumberIntVal(0), 59 }, 60 { 61 cty.UnknownVal(cty.EmptyObject), 62 cty.NumberIntVal(0), 63 }, 64 { 65 cty.ObjectVal(map[string]cty.Value{"true": cty.True}), 66 cty.NumberIntVal(1), 67 }, 68 { 69 cty.UnknownVal(cty.List(cty.Bool)), 70 cty.UnknownVal(cty.Number), 71 }, 72 { 73 cty.DynamicVal, 74 cty.UnknownVal(cty.Number), 75 }, 76 { 77 cty.StringVal("hello"), 78 cty.NumberIntVal(5), 79 }, 80 { 81 cty.StringVal(""), 82 cty.NumberIntVal(0), 83 }, 84 { 85 cty.StringVal("1"), 86 cty.NumberIntVal(1), 87 }, 88 { 89 cty.StringVal("Живой Журнал"), 90 cty.NumberIntVal(12), 91 }, 92 { 93 // note that the dieresis here is intentionally a combining 94 // ligature. 95 cty.StringVal("noël"), 96 cty.NumberIntVal(4), 97 }, 98 { 99 // The Es in this string has three combining acute accents. 100 // This tests something that NFC-normalization cannot collapse 101 // into a single precombined codepoint, since otherwise we might 102 // be cheating and relying on the single-codepoint forms. 103 cty.StringVal("wé́́é́́é́́!"), 104 cty.NumberIntVal(5), 105 }, 106 { 107 // Go's normalization forms don't handle this ligature, so we 108 // will produce the wrong result but this is now a compatibility 109 // constraint and so we'll test it. 110 cty.StringVal("baffle"), 111 cty.NumberIntVal(4), 112 }, 113 { 114 cty.StringVal("😸😾"), 115 cty.NumberIntVal(2), 116 }, 117 { 118 cty.UnknownVal(cty.String), 119 cty.UnknownVal(cty.Number), 120 }, 121 { 122 cty.DynamicVal, 123 cty.UnknownVal(cty.Number), 124 }, 125 { // Marked collections return a marked length 126 cty.ListVal([]cty.Value{ 127 cty.StringVal("hello"), 128 cty.StringVal("world"), 129 }).Mark("secret"), 130 cty.NumberIntVal(2).Mark("secret"), 131 }, 132 { // Marks on values in unmarked collections do not propagate 133 cty.ListVal([]cty.Value{ 134 cty.StringVal("hello").Mark("a"), 135 cty.StringVal("world").Mark("b"), 136 }), 137 cty.NumberIntVal(2), 138 }, 139 { // Marked strings return a marked length 140 cty.StringVal("hello world").Mark("secret"), 141 cty.NumberIntVal(11).Mark("secret"), 142 }, 143 { // Marked tuples return a marked length 144 cty.TupleVal([]cty.Value{ 145 cty.StringVal("hello"), 146 cty.StringVal("world"), 147 }).Mark("secret"), 148 cty.NumberIntVal(2).Mark("secret"), 149 }, 150 { // Marks on values in unmarked tuples do not propagate 151 cty.TupleVal([]cty.Value{ 152 cty.StringVal("hello").Mark("a"), 153 cty.StringVal("world").Mark("b"), 154 }), 155 cty.NumberIntVal(2), 156 }, 157 { // Marked objects return a marked length 158 cty.ObjectVal(map[string]cty.Value{ 159 "a": cty.StringVal("hello"), 160 "b": cty.StringVal("world"), 161 "c": cty.StringVal("nice to meet you"), 162 }).Mark("secret"), 163 cty.NumberIntVal(3).Mark("secret"), 164 }, 165 { // Marks on object attribute values do not propagate 166 cty.ObjectVal(map[string]cty.Value{ 167 "a": cty.StringVal("hello").Mark("a"), 168 "b": cty.StringVal("world").Mark("b"), 169 "c": cty.StringVal("nice to meet you").Mark("c"), 170 }), 171 cty.NumberIntVal(3), 172 }, 173 } 174 175 for _, test := range tests { 176 t.Run(fmt.Sprintf("Length(%#v)", test.Value), func(t *testing.T) { 177 got, err := Length(test.Value) 178 179 if err != nil { 180 t.Fatalf("unexpected error: %s", err) 181 } 182 183 if !got.RawEquals(test.Want) { 184 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 185 } 186 }) 187 } 188 } 189 190 func TestAllTrue(t *testing.T) { 191 tests := []struct { 192 Collection cty.Value 193 Want cty.Value 194 Err bool 195 }{ 196 { 197 cty.ListValEmpty(cty.Bool), 198 cty.True, 199 false, 200 }, 201 { 202 cty.ListVal([]cty.Value{cty.True}), 203 cty.True, 204 false, 205 }, 206 { 207 cty.ListVal([]cty.Value{cty.False}), 208 cty.False, 209 false, 210 }, 211 { 212 cty.ListVal([]cty.Value{cty.True, cty.False}), 213 cty.False, 214 false, 215 }, 216 { 217 cty.ListVal([]cty.Value{cty.False, cty.True}), 218 cty.False, 219 false, 220 }, 221 { 222 cty.ListVal([]cty.Value{cty.True, cty.NullVal(cty.Bool)}), 223 cty.False, 224 false, 225 }, 226 { 227 cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}), 228 cty.UnknownVal(cty.Bool), 229 false, 230 }, 231 { 232 cty.ListVal([]cty.Value{ 233 cty.UnknownVal(cty.Bool), 234 cty.UnknownVal(cty.Bool), 235 }), 236 cty.UnknownVal(cty.Bool), 237 false, 238 }, 239 { 240 cty.UnknownVal(cty.List(cty.Bool)), 241 cty.UnknownVal(cty.Bool), 242 false, 243 }, 244 { 245 cty.NullVal(cty.List(cty.Bool)), 246 cty.NilVal, 247 true, 248 }, 249 } 250 251 for _, test := range tests { 252 t.Run(fmt.Sprintf("alltrue(%#v)", test.Collection), func(t *testing.T) { 253 got, err := AllTrue(test.Collection) 254 255 if test.Err { 256 if err == nil { 257 t.Fatal("succeeded; want error") 258 } 259 return 260 } else if err != nil { 261 t.Fatalf("unexpected error: %s", err) 262 } 263 264 if !got.RawEquals(test.Want) { 265 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 266 } 267 }) 268 } 269 } 270 271 func TestAnyTrue(t *testing.T) { 272 tests := []struct { 273 Collection cty.Value 274 Want cty.Value 275 Err bool 276 }{ 277 { 278 cty.ListValEmpty(cty.Bool), 279 cty.False, 280 false, 281 }, 282 { 283 cty.ListVal([]cty.Value{cty.True}), 284 cty.True, 285 false, 286 }, 287 { 288 cty.ListVal([]cty.Value{cty.False}), 289 cty.False, 290 false, 291 }, 292 { 293 cty.ListVal([]cty.Value{cty.True, cty.False}), 294 cty.True, 295 false, 296 }, 297 { 298 cty.ListVal([]cty.Value{cty.False, cty.True}), 299 cty.True, 300 false, 301 }, 302 { 303 cty.ListVal([]cty.Value{cty.NullVal(cty.Bool), cty.True}), 304 cty.True, 305 false, 306 }, 307 { 308 cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}), 309 cty.UnknownVal(cty.Bool), 310 false, 311 }, 312 { 313 cty.ListVal([]cty.Value{ 314 cty.UnknownVal(cty.Bool), 315 cty.False, 316 }), 317 cty.UnknownVal(cty.Bool), 318 false, 319 }, 320 { 321 cty.ListVal([]cty.Value{ 322 cty.UnknownVal(cty.Bool), 323 cty.True, 324 }), 325 cty.True, 326 false, 327 }, 328 { 329 cty.UnknownVal(cty.List(cty.Bool)), 330 cty.UnknownVal(cty.Bool), 331 false, 332 }, 333 { 334 cty.NullVal(cty.List(cty.Bool)), 335 cty.NilVal, 336 true, 337 }, 338 } 339 340 for _, test := range tests { 341 t.Run(fmt.Sprintf("anytrue(%#v)", test.Collection), func(t *testing.T) { 342 got, err := AnyTrue(test.Collection) 343 344 if test.Err { 345 if err == nil { 346 t.Fatal("succeeded; want error") 347 } 348 return 349 } else if err != nil { 350 t.Fatalf("unexpected error: %s", err) 351 } 352 353 if !got.RawEquals(test.Want) { 354 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 355 } 356 }) 357 } 358 } 359 360 func TestCoalesce(t *testing.T) { 361 tests := []struct { 362 Values []cty.Value 363 Want cty.Value 364 Err bool 365 }{ 366 { 367 []cty.Value{cty.StringVal("first"), cty.StringVal("second"), cty.StringVal("third")}, 368 cty.StringVal("first"), 369 false, 370 }, 371 { 372 []cty.Value{cty.StringVal(""), cty.StringVal("second"), cty.StringVal("third")}, 373 cty.StringVal("second"), 374 false, 375 }, 376 { 377 []cty.Value{cty.StringVal(""), cty.StringVal("")}, 378 cty.NilVal, 379 true, 380 }, 381 { 382 []cty.Value{cty.True}, 383 cty.True, 384 false, 385 }, 386 { 387 []cty.Value{cty.NullVal(cty.Bool), cty.True}, 388 cty.True, 389 false, 390 }, 391 { 392 []cty.Value{cty.NullVal(cty.Bool), cty.False}, 393 cty.False, 394 false, 395 }, 396 { 397 []cty.Value{cty.NullVal(cty.Bool), cty.False, cty.StringVal("hello")}, 398 cty.StringVal("false"), 399 false, 400 }, 401 { 402 []cty.Value{cty.True, cty.UnknownVal(cty.Bool)}, 403 cty.True, 404 false, 405 }, 406 { 407 []cty.Value{cty.UnknownVal(cty.Bool), cty.True}, 408 cty.UnknownVal(cty.Bool), 409 false, 410 }, 411 { 412 []cty.Value{cty.UnknownVal(cty.Bool), cty.StringVal("hello")}, 413 cty.UnknownVal(cty.String), 414 false, 415 }, 416 { 417 []cty.Value{cty.DynamicVal, cty.True}, 418 cty.UnknownVal(cty.Bool), 419 false, 420 }, 421 { 422 []cty.Value{cty.DynamicVal}, 423 cty.DynamicVal, 424 false, 425 }, 426 } 427 428 for _, test := range tests { 429 t.Run(fmt.Sprintf("Coalesce(%#v...)", test.Values), func(t *testing.T) { 430 got, err := Coalesce(test.Values...) 431 432 if test.Err { 433 if err == nil { 434 t.Fatal("succeeded; want error") 435 } 436 return 437 } else if err != nil { 438 t.Fatalf("unexpected error: %s", err) 439 } 440 441 if !got.RawEquals(test.Want) { 442 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 443 } 444 }) 445 } 446 } 447 448 func TestIndex(t *testing.T) { 449 tests := []struct { 450 List cty.Value 451 Value cty.Value 452 Want cty.Value 453 Err bool 454 }{ 455 { 456 cty.ListVal([]cty.Value{ 457 cty.StringVal("a"), 458 cty.StringVal("b"), 459 cty.StringVal("c"), 460 }), 461 cty.StringVal("a"), 462 cty.NumberIntVal(0), 463 false, 464 }, 465 { 466 cty.ListVal([]cty.Value{ 467 cty.StringVal("a"), 468 cty.StringVal("b"), 469 cty.UnknownVal(cty.String), 470 }), 471 cty.StringVal("a"), 472 cty.NumberIntVal(0), 473 false, 474 }, 475 { 476 cty.ListVal([]cty.Value{ 477 cty.StringVal("a"), 478 cty.StringVal("b"), 479 cty.StringVal("c"), 480 }), 481 cty.StringVal("b"), 482 cty.NumberIntVal(1), 483 false, 484 }, 485 { 486 cty.ListVal([]cty.Value{ 487 cty.StringVal("a"), 488 cty.StringVal("b"), 489 cty.StringVal("c"), 490 }), 491 cty.StringVal("z"), 492 cty.NilVal, 493 true, 494 }, 495 { 496 cty.ListVal([]cty.Value{ 497 cty.StringVal("1"), 498 cty.StringVal("2"), 499 cty.StringVal("3"), 500 }), 501 cty.NumberIntVal(1), 502 cty.NumberIntVal(0), 503 true, 504 }, 505 { 506 cty.ListVal([]cty.Value{ 507 cty.NumberIntVal(1), 508 cty.NumberIntVal(2), 509 cty.NumberIntVal(3), 510 }), 511 cty.NumberIntVal(2), 512 cty.NumberIntVal(1), 513 false, 514 }, 515 { 516 cty.ListVal([]cty.Value{ 517 cty.NumberIntVal(1), 518 cty.NumberIntVal(2), 519 cty.NumberIntVal(3), 520 }), 521 cty.NumberIntVal(4), 522 cty.NilVal, 523 true, 524 }, 525 { 526 cty.ListVal([]cty.Value{ 527 cty.NumberIntVal(1), 528 cty.NumberIntVal(2), 529 cty.NumberIntVal(3), 530 }), 531 cty.StringVal("1"), 532 cty.NumberIntVal(0), 533 true, 534 }, 535 { 536 cty.TupleVal([]cty.Value{ 537 cty.NumberIntVal(1), 538 cty.NumberIntVal(2), 539 cty.NumberIntVal(3), 540 }), 541 cty.NumberIntVal(1), 542 cty.NumberIntVal(0), 543 false, 544 }, 545 } 546 547 for _, test := range tests { 548 t.Run(fmt.Sprintf("index(%#v, %#v)", test.List, test.Value), func(t *testing.T) { 549 got, err := Index(test.List, test.Value) 550 551 if test.Err { 552 if err == nil { 553 t.Fatal("succeeded; want error") 554 } 555 return 556 } else if err != nil { 557 t.Fatalf("unexpected error: %s", err) 558 } 559 560 if !got.RawEquals(test.Want) { 561 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 562 } 563 }) 564 } 565 } 566 567 func TestLookup(t *testing.T) { 568 simpleMap := cty.MapVal(map[string]cty.Value{ 569 "foo": cty.StringVal("bar"), 570 }) 571 intsMap := cty.MapVal(map[string]cty.Value{ 572 "foo": cty.NumberIntVal(42), 573 }) 574 mapOfLists := cty.MapVal(map[string]cty.Value{ 575 "foo": cty.ListVal([]cty.Value{ 576 cty.StringVal("bar"), 577 cty.StringVal("baz"), 578 }), 579 }) 580 mapOfMaps := cty.MapVal(map[string]cty.Value{ 581 "foo": cty.MapVal(map[string]cty.Value{ 582 "a": cty.StringVal("bar"), 583 }), 584 "baz": cty.MapVal(map[string]cty.Value{ 585 "b": cty.StringVal("bat"), 586 }), 587 }) 588 mapOfTuples := cty.MapVal(map[string]cty.Value{ 589 "foo": cty.TupleVal([]cty.Value{cty.StringVal("bar")}), 590 "baz": cty.TupleVal([]cty.Value{cty.StringVal("bat")}), 591 }) 592 objectOfMaps := cty.ObjectVal(map[string]cty.Value{ 593 "foo": cty.MapVal(map[string]cty.Value{ 594 "a": cty.StringVal("bar"), 595 }), 596 "baz": cty.MapVal(map[string]cty.Value{ 597 "b": cty.StringVal("bat"), 598 }), 599 }) 600 mapWithUnknowns := cty.MapVal(map[string]cty.Value{ 601 "foo": cty.StringVal("bar"), 602 "baz": cty.UnknownVal(cty.String), 603 }) 604 mapWithObjects := cty.ObjectVal(map[string]cty.Value{ 605 "foo": cty.StringVal("bar"), 606 "baz": cty.NumberIntVal(42), 607 }) 608 609 tests := []struct { 610 Values []cty.Value 611 Want cty.Value 612 Err bool 613 }{ 614 { 615 []cty.Value{ 616 simpleMap, 617 cty.StringVal("foo"), 618 }, 619 cty.StringVal("bar"), 620 false, 621 }, 622 { 623 []cty.Value{ 624 mapWithObjects, 625 cty.StringVal("foo"), 626 }, 627 cty.StringVal("bar"), 628 false, 629 }, 630 { 631 []cty.Value{ 632 intsMap, 633 cty.StringVal("foo"), 634 }, 635 cty.NumberIntVal(42), 636 false, 637 }, 638 { 639 []cty.Value{ 640 mapOfMaps, 641 cty.StringVal("foo"), 642 }, 643 cty.MapVal(map[string]cty.Value{ 644 "a": cty.StringVal("bar"), 645 }), 646 false, 647 }, 648 { 649 []cty.Value{ 650 objectOfMaps, 651 cty.StringVal("foo"), 652 }, 653 cty.MapVal(map[string]cty.Value{ 654 "a": cty.StringVal("bar"), 655 }), 656 false, 657 }, 658 { 659 []cty.Value{ 660 mapOfTuples, 661 cty.StringVal("foo"), 662 }, 663 cty.TupleVal([]cty.Value{cty.StringVal("bar")}), 664 false, 665 }, 666 { // Invalid key 667 []cty.Value{ 668 simpleMap, 669 cty.StringVal("bar"), 670 }, 671 cty.NilVal, 672 true, 673 }, 674 { // Invalid key 675 []cty.Value{ 676 mapWithObjects, 677 cty.StringVal("bar"), 678 }, 679 cty.NilVal, 680 true, 681 }, 682 { // Supplied default with valid key 683 []cty.Value{ 684 simpleMap, 685 cty.StringVal("foo"), 686 cty.StringVal(""), 687 }, 688 cty.StringVal("bar"), 689 false, 690 }, 691 { // Supplied default with valid (int) key 692 []cty.Value{ 693 simpleMap, 694 cty.StringVal("foo"), 695 cty.NumberIntVal(-1), 696 }, 697 cty.StringVal("bar"), 698 false, 699 }, 700 { // Supplied default with valid (int) key 701 []cty.Value{ 702 simpleMap, 703 cty.StringVal("foobar"), 704 cty.NumberIntVal(-1), 705 }, 706 cty.StringVal("-1"), 707 false, 708 }, 709 { // Supplied default with valid key 710 []cty.Value{ 711 mapWithObjects, 712 cty.StringVal("foobar"), 713 cty.StringVal(""), 714 }, 715 cty.StringVal(""), 716 false, 717 }, 718 { // Supplied default with invalid key 719 []cty.Value{ 720 simpleMap, 721 cty.StringVal("baz"), 722 cty.StringVal(""), 723 }, 724 cty.StringVal(""), 725 false, 726 }, 727 { // Supplied default with type mismatch: expects a map return 728 []cty.Value{ 729 mapOfMaps, 730 cty.StringVal("foo"), 731 cty.StringVal(""), 732 }, 733 cty.NilVal, 734 true, 735 }, 736 { // Supplied non-empty default with invalid key 737 []cty.Value{ 738 simpleMap, 739 cty.StringVal("bar"), 740 cty.StringVal("xyz"), 741 }, 742 cty.StringVal("xyz"), 743 false, 744 }, 745 { // too many args 746 []cty.Value{ 747 simpleMap, 748 cty.StringVal("foo"), 749 cty.StringVal("bar"), 750 cty.StringVal("baz"), 751 }, 752 cty.NilVal, 753 true, 754 }, 755 { // cannot search a map of lists 756 []cty.Value{ 757 mapOfLists, 758 cty.StringVal("baz"), 759 }, 760 cty.NilVal, 761 true, 762 }, 763 { 764 []cty.Value{ 765 mapWithUnknowns, 766 cty.StringVal("baz"), 767 }, 768 cty.UnknownVal(cty.String), 769 false, 770 }, 771 { 772 []cty.Value{ 773 mapWithUnknowns, 774 cty.StringVal("foo"), 775 }, 776 cty.StringVal("bar"), 777 false, 778 }, 779 { 780 []cty.Value{ 781 simpleMap, 782 cty.UnknownVal(cty.String), 783 }, 784 cty.UnknownVal(cty.String), 785 false, 786 }, 787 { 788 []cty.Value{ 789 cty.ObjectVal(map[string]cty.Value{ 790 "foo": cty.StringVal("a"), 791 "bar": cty.StringVal("b"), 792 }), 793 cty.UnknownVal(cty.String), 794 }, 795 cty.DynamicVal, // if the key is unknown then we don't know which object attribute and thus can't know the type 796 false, 797 }, 798 { // successful marked collection lookup returns marked value 799 []cty.Value{ 800 cty.MapVal(map[string]cty.Value{ 801 "boop": cty.StringVal("beep"), 802 }).Mark("a"), 803 cty.StringVal("boop"), 804 cty.StringVal("nope"), 805 }, 806 cty.StringVal("beep").Mark("a"), 807 false, 808 }, 809 { // apply collection marks to unknown return vaue 810 []cty.Value{ 811 cty.MapVal(map[string]cty.Value{ 812 "boop": cty.StringVal("beep"), 813 "frob": cty.UnknownVal(cty.String), 814 }).Mark("a"), 815 cty.StringVal("frob"), 816 cty.StringVal("nope"), 817 }, 818 cty.UnknownVal(cty.String).Mark("a"), 819 false, 820 }, 821 { // propagate collection marks to default when returning 822 []cty.Value{ 823 cty.MapVal(map[string]cty.Value{ 824 "boop": cty.StringVal("beep"), 825 }).Mark("a"), 826 cty.StringVal("frob"), 827 cty.StringVal("nope").Mark("b"), 828 }, 829 cty.StringVal("nope").WithMarks(cty.NewValueMarks("a", "b")), 830 false, 831 }, 832 { // on unmarked collection, return only marks from found value 833 []cty.Value{ 834 cty.MapVal(map[string]cty.Value{ 835 "boop": cty.StringVal("beep").Mark("a"), 836 "frob": cty.StringVal("honk").Mark("b"), 837 }), 838 cty.StringVal("frob"), 839 cty.StringVal("nope").Mark("c"), 840 }, 841 cty.StringVal("honk").Mark("b"), 842 false, 843 }, 844 { // on unmarked collection, return default exactly on missing 845 []cty.Value{ 846 cty.MapVal(map[string]cty.Value{ 847 "boop": cty.StringVal("beep").Mark("a"), 848 "frob": cty.StringVal("honk").Mark("b"), 849 }), 850 cty.StringVal("squish"), 851 cty.StringVal("nope").Mark("c"), 852 }, 853 cty.StringVal("nope").Mark("c"), 854 false, 855 }, 856 { // retain marks on default if converted 857 []cty.Value{ 858 cty.MapVal(map[string]cty.Value{ 859 "boop": cty.StringVal("beep").Mark("a"), 860 "frob": cty.StringVal("honk").Mark("b"), 861 }), 862 cty.StringVal("squish"), 863 cty.NumberIntVal(5).Mark("c"), 864 }, 865 cty.StringVal("5").Mark("c"), 866 false, 867 }, 868 { // propagate marks from key 869 []cty.Value{ 870 cty.MapVal(map[string]cty.Value{ 871 "boop": cty.StringVal("beep"), 872 "frob": cty.StringVal("honk"), 873 }), 874 cty.StringVal("boop").Mark("a"), 875 cty.StringVal("nope"), 876 }, 877 cty.StringVal("beep").Mark("a"), 878 false, 879 }, 880 } 881 882 for _, test := range tests { 883 t.Run(fmt.Sprintf("lookup(%#v)", test.Values), func(t *testing.T) { 884 got, err := Lookup(test.Values...) 885 886 if test.Err { 887 if err == nil { 888 t.Fatal("succeeded; want error") 889 } 890 return 891 } else if err != nil { 892 t.Fatalf("unexpected error: %s", err) 893 } 894 895 if !got.RawEquals(test.Want) { 896 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 897 } 898 }) 899 } 900 } 901 902 func TestMatchkeys(t *testing.T) { 903 tests := []struct { 904 Keys cty.Value 905 Values cty.Value 906 Searchset cty.Value 907 Want cty.Value 908 Err bool 909 }{ 910 { // normal usage 911 cty.ListVal([]cty.Value{ 912 cty.StringVal("a"), 913 cty.StringVal("b"), 914 cty.StringVal("c"), 915 }), 916 cty.ListVal([]cty.Value{ 917 cty.StringVal("ref1"), 918 cty.StringVal("ref2"), 919 cty.StringVal("ref3"), 920 }), 921 cty.ListVal([]cty.Value{ 922 cty.StringVal("ref1"), 923 }), 924 cty.ListVal([]cty.Value{ 925 cty.StringVal("a"), 926 }), 927 false, 928 }, 929 { // normal usage 2, check the order 930 cty.ListVal([]cty.Value{ 931 cty.StringVal("a"), 932 cty.StringVal("b"), 933 cty.StringVal("c"), 934 }), 935 cty.ListVal([]cty.Value{ 936 cty.StringVal("ref1"), 937 cty.StringVal("ref2"), 938 cty.StringVal("ref3"), 939 }), 940 cty.ListVal([]cty.Value{ 941 cty.StringVal("ref2"), 942 cty.StringVal("ref1"), 943 }), 944 cty.ListVal([]cty.Value{ 945 cty.StringVal("a"), 946 cty.StringVal("b"), 947 }), 948 false, 949 }, 950 { // no matches 951 cty.ListVal([]cty.Value{ 952 cty.StringVal("a"), 953 cty.StringVal("b"), 954 cty.StringVal("c"), 955 }), 956 cty.ListVal([]cty.Value{ 957 cty.StringVal("ref1"), 958 cty.StringVal("ref2"), 959 cty.StringVal("ref3"), 960 }), 961 cty.ListVal([]cty.Value{ 962 cty.StringVal("ref4"), 963 }), 964 cty.ListValEmpty(cty.String), 965 false, 966 }, 967 { // no matches 2 968 cty.ListVal([]cty.Value{ 969 cty.StringVal("a"), 970 cty.StringVal("b"), 971 cty.StringVal("c"), 972 }), 973 cty.ListVal([]cty.Value{ 974 cty.StringVal("ref1"), 975 cty.StringVal("ref2"), 976 cty.StringVal("ref3"), 977 }), 978 cty.ListValEmpty(cty.String), 979 cty.ListValEmpty(cty.String), 980 false, 981 }, 982 { // zero case 983 cty.ListValEmpty(cty.String), 984 cty.ListValEmpty(cty.String), 985 cty.ListVal([]cty.Value{cty.StringVal("nope")}), 986 cty.ListValEmpty(cty.String), 987 false, 988 }, 989 { // complex values 990 cty.ListVal([]cty.Value{ 991 cty.ListVal([]cty.Value{ 992 cty.StringVal("a"), 993 cty.StringVal("a"), 994 }), 995 }), 996 cty.ListVal([]cty.Value{ 997 cty.StringVal("a"), 998 }), 999 cty.ListVal([]cty.Value{ 1000 cty.StringVal("a"), 1001 }), 1002 cty.ListVal([]cty.Value{ 1003 cty.ListVal([]cty.Value{ 1004 cty.StringVal("a"), 1005 cty.StringVal("a"), 1006 }), 1007 }), 1008 false, 1009 }, 1010 { // unknowns 1011 cty.ListVal([]cty.Value{ 1012 cty.StringVal("a"), 1013 cty.StringVal("b"), 1014 cty.UnknownVal(cty.String), 1015 }), 1016 cty.ListVal([]cty.Value{ 1017 cty.StringVal("ref1"), 1018 cty.StringVal("ref2"), 1019 cty.UnknownVal(cty.String), 1020 }), 1021 cty.ListVal([]cty.Value{ 1022 cty.StringVal("ref1"), 1023 }), 1024 cty.UnknownVal(cty.List(cty.String)), 1025 false, 1026 }, 1027 { // different types that can be unified 1028 cty.ListVal([]cty.Value{ 1029 cty.StringVal("a"), 1030 }), 1031 cty.ListVal([]cty.Value{ 1032 cty.NumberIntVal(1), 1033 }), 1034 cty.ListVal([]cty.Value{ 1035 cty.StringVal("a"), 1036 }), 1037 cty.ListValEmpty(cty.String), 1038 false, 1039 }, 1040 { // complex values: values is a different type from keys and searchset 1041 cty.ListVal([]cty.Value{ 1042 cty.MapVal(map[string]cty.Value{ 1043 "foo": cty.StringVal("bar"), 1044 }), 1045 cty.MapVal(map[string]cty.Value{ 1046 "foo": cty.StringVal("baz"), 1047 }), 1048 cty.MapVal(map[string]cty.Value{ 1049 "foo": cty.StringVal("beep"), 1050 }), 1051 }), 1052 cty.ListVal([]cty.Value{ 1053 cty.StringVal("a"), 1054 cty.StringVal("b"), 1055 cty.StringVal("c"), 1056 }), 1057 cty.ListVal([]cty.Value{ 1058 cty.StringVal("a"), 1059 cty.StringVal("c"), 1060 }), 1061 cty.ListVal([]cty.Value{ 1062 cty.MapVal(map[string]cty.Value{ 1063 "foo": cty.StringVal("bar"), 1064 }), 1065 cty.MapVal(map[string]cty.Value{ 1066 "foo": cty.StringVal("beep"), 1067 }), 1068 }), 1069 false, 1070 }, 1071 // errors 1072 { // different types 1073 cty.ListVal([]cty.Value{ 1074 cty.StringVal("a"), 1075 }), 1076 cty.ListVal([]cty.Value{ 1077 cty.ListVal([]cty.Value{ 1078 cty.StringVal("a"), 1079 }), 1080 cty.ListVal([]cty.Value{ 1081 cty.StringVal("a"), 1082 }), 1083 }), 1084 cty.ListVal([]cty.Value{ 1085 cty.StringVal("a"), 1086 }), 1087 cty.NilVal, 1088 true, 1089 }, 1090 { // lists of different length 1091 cty.ListVal([]cty.Value{ 1092 cty.StringVal("a"), 1093 }), 1094 cty.ListVal([]cty.Value{ 1095 cty.StringVal("a"), 1096 cty.StringVal("b"), 1097 }), 1098 cty.ListVal([]cty.Value{ 1099 cty.StringVal("a"), 1100 }), 1101 cty.NilVal, 1102 true, 1103 }, 1104 } 1105 1106 for _, test := range tests { 1107 t.Run(fmt.Sprintf("matchkeys(%#v, %#v, %#v)", test.Keys, test.Values, test.Searchset), func(t *testing.T) { 1108 got, err := Matchkeys(test.Keys, test.Values, test.Searchset) 1109 1110 if test.Err { 1111 if err == nil { 1112 t.Fatal("succeeded; want error") 1113 } 1114 return 1115 } else if err != nil { 1116 t.Fatalf("unexpected error: %s", err) 1117 } 1118 1119 if !got.RawEquals(test.Want) { 1120 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1121 } 1122 }) 1123 } 1124 } 1125 1126 func TestOne(t *testing.T) { 1127 tests := []struct { 1128 List cty.Value 1129 Want cty.Value 1130 Err string 1131 }{ 1132 { 1133 cty.ListVal([]cty.Value{ 1134 cty.NumberIntVal(1), 1135 }), 1136 cty.NumberIntVal(1), 1137 "", 1138 }, 1139 { 1140 cty.ListValEmpty(cty.Number), 1141 cty.NullVal(cty.Number), 1142 "", 1143 }, 1144 { 1145 cty.ListVal([]cty.Value{ 1146 cty.NumberIntVal(1), 1147 cty.NumberIntVal(2), 1148 cty.NumberIntVal(3), 1149 }), 1150 cty.NilVal, 1151 "must be a list, set, or tuple value with either zero or one elements", 1152 }, 1153 { 1154 cty.ListVal([]cty.Value{ 1155 cty.UnknownVal(cty.Number), 1156 }), 1157 cty.UnknownVal(cty.Number), 1158 "", 1159 }, 1160 { 1161 cty.ListVal([]cty.Value{ 1162 cty.UnknownVal(cty.Number), 1163 cty.UnknownVal(cty.Number), 1164 }), 1165 cty.NilVal, 1166 "must be a list, set, or tuple value with either zero or one elements", 1167 }, 1168 { 1169 cty.UnknownVal(cty.List(cty.String)), 1170 cty.UnknownVal(cty.String), 1171 "", 1172 }, 1173 { 1174 cty.NullVal(cty.List(cty.String)), 1175 cty.NilVal, 1176 "argument must not be null", 1177 }, 1178 { 1179 cty.ListVal([]cty.Value{ 1180 cty.NumberIntVal(1), 1181 }).Mark("boop"), 1182 cty.NumberIntVal(1).Mark("boop"), 1183 "", 1184 }, 1185 { 1186 cty.ListValEmpty(cty.Bool).Mark("boop"), 1187 cty.NullVal(cty.Bool).Mark("boop"), 1188 "", 1189 }, 1190 { 1191 cty.ListVal([]cty.Value{ 1192 cty.NumberIntVal(1).Mark("boop"), 1193 }), 1194 cty.NumberIntVal(1).Mark("boop"), 1195 "", 1196 }, 1197 1198 { 1199 cty.SetVal([]cty.Value{ 1200 cty.NumberIntVal(1), 1201 }), 1202 cty.NumberIntVal(1), 1203 "", 1204 }, 1205 { 1206 cty.SetValEmpty(cty.Number), 1207 cty.NullVal(cty.Number), 1208 "", 1209 }, 1210 { 1211 cty.SetVal([]cty.Value{ 1212 cty.NumberIntVal(1), 1213 cty.NumberIntVal(2), 1214 cty.NumberIntVal(3), 1215 }), 1216 cty.NilVal, 1217 "must be a list, set, or tuple value with either zero or one elements", 1218 }, 1219 { 1220 cty.SetVal([]cty.Value{ 1221 cty.UnknownVal(cty.Number), 1222 }), 1223 cty.UnknownVal(cty.Number), 1224 "", 1225 }, 1226 { 1227 cty.SetVal([]cty.Value{ 1228 cty.UnknownVal(cty.Number), 1229 cty.UnknownVal(cty.Number), 1230 }), 1231 // The above would be valid if those two unknown values were 1232 // equal known values, so this returns unknown rather than failing. 1233 cty.UnknownVal(cty.Number), 1234 "", 1235 }, 1236 { 1237 cty.UnknownVal(cty.Set(cty.String)), 1238 cty.UnknownVal(cty.String), 1239 "", 1240 }, 1241 { 1242 cty.NullVal(cty.Set(cty.String)), 1243 cty.NilVal, 1244 "argument must not be null", 1245 }, 1246 { 1247 cty.SetVal([]cty.Value{ 1248 cty.NumberIntVal(1), 1249 }).Mark("boop"), 1250 cty.NumberIntVal(1).Mark("boop"), 1251 "", 1252 }, 1253 { 1254 cty.SetValEmpty(cty.Bool).Mark("boop"), 1255 cty.NullVal(cty.Bool).Mark("boop"), 1256 "", 1257 }, 1258 { 1259 cty.SetVal([]cty.Value{ 1260 cty.NumberIntVal(1).Mark("boop"), 1261 }), 1262 cty.NumberIntVal(1).Mark("boop"), 1263 "", 1264 }, 1265 1266 { 1267 cty.TupleVal([]cty.Value{ 1268 cty.NumberIntVal(1), 1269 }), 1270 cty.NumberIntVal(1), 1271 "", 1272 }, 1273 { 1274 cty.EmptyTupleVal, 1275 cty.NullVal(cty.DynamicPseudoType), 1276 "", 1277 }, 1278 { 1279 cty.TupleVal([]cty.Value{ 1280 cty.NumberIntVal(1), 1281 cty.NumberIntVal(2), 1282 cty.NumberIntVal(3), 1283 }), 1284 cty.NilVal, 1285 "must be a list, set, or tuple value with either zero or one elements", 1286 }, 1287 { 1288 cty.TupleVal([]cty.Value{ 1289 cty.UnknownVal(cty.Number), 1290 }), 1291 cty.UnknownVal(cty.Number), 1292 "", 1293 }, 1294 { 1295 cty.TupleVal([]cty.Value{ 1296 cty.UnknownVal(cty.Number), 1297 cty.UnknownVal(cty.Number), 1298 }), 1299 cty.NilVal, 1300 "must be a list, set, or tuple value with either zero or one elements", 1301 }, 1302 { 1303 cty.UnknownVal(cty.EmptyTuple), 1304 // Could actually return null here, but don't for consistency with unknown lists 1305 cty.UnknownVal(cty.DynamicPseudoType), 1306 "", 1307 }, 1308 { 1309 cty.UnknownVal(cty.Tuple([]cty.Type{cty.Bool})), 1310 cty.UnknownVal(cty.Bool), 1311 "", 1312 }, 1313 { 1314 cty.UnknownVal(cty.Tuple([]cty.Type{cty.Bool, cty.Number})), 1315 cty.NilVal, 1316 "must be a list, set, or tuple value with either zero or one elements", 1317 }, 1318 { 1319 cty.NullVal(cty.EmptyTuple), 1320 cty.NilVal, 1321 "argument must not be null", 1322 }, 1323 { 1324 cty.NullVal(cty.Tuple([]cty.Type{cty.Bool})), 1325 cty.NilVal, 1326 "argument must not be null", 1327 }, 1328 { 1329 cty.NullVal(cty.Tuple([]cty.Type{cty.Bool, cty.Number})), 1330 cty.NilVal, 1331 "argument must not be null", 1332 }, 1333 { 1334 cty.TupleVal([]cty.Value{ 1335 cty.NumberIntVal(1), 1336 }).Mark("boop"), 1337 cty.NumberIntVal(1).Mark("boop"), 1338 "", 1339 }, 1340 { 1341 cty.EmptyTupleVal.Mark("boop"), 1342 cty.NullVal(cty.DynamicPseudoType).Mark("boop"), 1343 "", 1344 }, 1345 { 1346 cty.TupleVal([]cty.Value{ 1347 cty.NumberIntVal(1).Mark("boop"), 1348 }), 1349 cty.NumberIntVal(1).Mark("boop"), 1350 "", 1351 }, 1352 1353 { 1354 cty.DynamicVal, 1355 cty.DynamicVal, 1356 "", 1357 }, 1358 { 1359 cty.NullVal(cty.DynamicPseudoType), 1360 cty.NilVal, 1361 "argument must not be null", 1362 }, 1363 { 1364 cty.MapValEmpty(cty.String), 1365 cty.NilVal, 1366 "must be a list, set, or tuple value with either zero or one elements", 1367 }, 1368 { 1369 cty.EmptyObjectVal, 1370 cty.NilVal, 1371 "must be a list, set, or tuple value with either zero or one elements", 1372 }, 1373 { 1374 cty.True, 1375 cty.NilVal, 1376 "must be a list, set, or tuple value with either zero or one elements", 1377 }, 1378 { 1379 cty.UnknownVal(cty.Bool), 1380 cty.NilVal, 1381 "must be a list, set, or tuple value with either zero or one elements", 1382 }, 1383 } 1384 1385 for _, test := range tests { 1386 t.Run(fmt.Sprintf("one(%#v)", test.List), func(t *testing.T) { 1387 got, err := One(test.List) 1388 1389 if test.Err != "" { 1390 if err == nil { 1391 t.Fatal("succeeded; want error") 1392 } else if got, want := err.Error(), test.Err; got != want { 1393 t.Fatalf("wrong error\n got: %s\nwant: %s", got, want) 1394 } 1395 return 1396 } else if err != nil { 1397 t.Fatalf("unexpected error: %s", err) 1398 } 1399 1400 if !test.Want.RawEquals(got) { 1401 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1402 } 1403 }) 1404 } 1405 } 1406 1407 func TestSum(t *testing.T) { 1408 tests := []struct { 1409 List cty.Value 1410 Want cty.Value 1411 Err string 1412 }{ 1413 { 1414 cty.ListVal([]cty.Value{ 1415 cty.NumberIntVal(1), 1416 cty.NumberIntVal(2), 1417 cty.NumberIntVal(3), 1418 }), 1419 cty.NumberIntVal(6), 1420 "", 1421 }, 1422 { 1423 cty.ListVal([]cty.Value{ 1424 cty.NumberIntVal(1476), 1425 cty.NumberIntVal(2093), 1426 cty.NumberIntVal(2092495), 1427 cty.NumberIntVal(64589234), 1428 cty.NumberIntVal(234), 1429 }), 1430 cty.NumberIntVal(66685532), 1431 "", 1432 }, 1433 { 1434 cty.ListVal([]cty.Value{ 1435 cty.StringVal("a"), 1436 cty.StringVal("b"), 1437 cty.StringVal("c"), 1438 }), 1439 cty.UnknownVal(cty.String), 1440 "argument must be list, set, or tuple of number values", 1441 }, 1442 { 1443 cty.ListVal([]cty.Value{ 1444 cty.NumberIntVal(10), 1445 cty.NumberIntVal(-19), 1446 cty.NumberIntVal(5), 1447 }), 1448 cty.NumberIntVal(-4), 1449 "", 1450 }, 1451 { 1452 cty.ListVal([]cty.Value{ 1453 cty.NumberFloatVal(10.2), 1454 cty.NumberFloatVal(19.4), 1455 cty.NumberFloatVal(5.7), 1456 }), 1457 cty.NumberFloatVal(35.3), 1458 "", 1459 }, 1460 { 1461 cty.ListVal([]cty.Value{ 1462 cty.NumberFloatVal(-10.2), 1463 cty.NumberFloatVal(-19.4), 1464 cty.NumberFloatVal(-5.7), 1465 }), 1466 cty.NumberFloatVal(-35.3), 1467 "", 1468 }, 1469 { 1470 cty.ListVal([]cty.Value{cty.NullVal(cty.Number)}), 1471 cty.NilVal, 1472 "argument must be list, set, or tuple of number values", 1473 }, 1474 { 1475 cty.ListVal([]cty.Value{ 1476 cty.NumberIntVal(5), 1477 cty.NullVal(cty.Number), 1478 }), 1479 cty.NilVal, 1480 "argument must be list, set, or tuple of number values", 1481 }, 1482 { 1483 cty.SetVal([]cty.Value{ 1484 cty.StringVal("a"), 1485 cty.StringVal("b"), 1486 cty.StringVal("c"), 1487 }), 1488 cty.UnknownVal(cty.String), 1489 "argument must be list, set, or tuple of number values", 1490 }, 1491 { 1492 cty.SetVal([]cty.Value{ 1493 cty.NumberIntVal(10), 1494 cty.NumberIntVal(-19), 1495 cty.NumberIntVal(5), 1496 }), 1497 cty.NumberIntVal(-4), 1498 "", 1499 }, 1500 { 1501 cty.SetVal([]cty.Value{ 1502 cty.NumberIntVal(10), 1503 cty.NumberIntVal(25), 1504 cty.NumberIntVal(30), 1505 }), 1506 cty.NumberIntVal(65), 1507 "", 1508 }, 1509 { 1510 cty.SetVal([]cty.Value{ 1511 cty.NumberFloatVal(2340.8), 1512 cty.NumberFloatVal(10.2), 1513 cty.NumberFloatVal(3), 1514 }), 1515 cty.NumberFloatVal(2354), 1516 "", 1517 }, 1518 { 1519 cty.SetVal([]cty.Value{ 1520 cty.NumberFloatVal(2), 1521 }), 1522 cty.NumberFloatVal(2), 1523 "", 1524 }, 1525 { 1526 cty.SetVal([]cty.Value{ 1527 cty.NumberFloatVal(-2), 1528 cty.NumberFloatVal(-50), 1529 cty.NumberFloatVal(-20), 1530 cty.NumberFloatVal(-123), 1531 cty.NumberFloatVal(-4), 1532 }), 1533 cty.NumberFloatVal(-199), 1534 "", 1535 }, 1536 { 1537 cty.TupleVal([]cty.Value{ 1538 cty.NumberIntVal(12), 1539 cty.StringVal("a"), 1540 cty.NumberIntVal(38), 1541 }), 1542 cty.UnknownVal(cty.String), 1543 "argument must be list, set, or tuple of number values", 1544 }, 1545 { 1546 cty.NumberIntVal(12), 1547 cty.NilVal, 1548 "cannot sum noniterable", 1549 }, 1550 { 1551 cty.ListValEmpty(cty.Number), 1552 cty.NilVal, 1553 "cannot sum an empty list", 1554 }, 1555 { 1556 cty.MapVal(map[string]cty.Value{"hello": cty.True}), 1557 cty.NilVal, 1558 "argument must be list, set, or tuple. Received map of bool", 1559 }, 1560 { 1561 cty.UnknownVal(cty.Number), 1562 cty.UnknownVal(cty.Number), 1563 "", 1564 }, 1565 { 1566 cty.UnknownVal(cty.List(cty.Number)), 1567 cty.UnknownVal(cty.Number), 1568 "", 1569 }, 1570 { // known list containing unknown values 1571 cty.ListVal([]cty.Value{cty.UnknownVal(cty.Number)}), 1572 cty.UnknownVal(cty.Number), 1573 "", 1574 }, 1575 { // numbers too large to represent as float64 1576 cty.ListVal([]cty.Value{ 1577 cty.MustParseNumberVal("1e+500"), 1578 cty.MustParseNumberVal("1e+500"), 1579 }), 1580 cty.MustParseNumberVal("2e+500"), 1581 "", 1582 }, 1583 { // edge case we have a special error handler for 1584 cty.ListVal([]cty.Value{ 1585 cty.NumberFloatVal(math.Inf(1)), 1586 cty.NumberFloatVal(math.Inf(-1)), 1587 }), 1588 cty.NilVal, 1589 "can't compute sum of opposing infinities", 1590 }, 1591 } 1592 1593 for _, test := range tests { 1594 t.Run(fmt.Sprintf("sum(%#v)", test.List), func(t *testing.T) { 1595 got, err := Sum(test.List) 1596 1597 if test.Err != "" { 1598 if err == nil { 1599 t.Fatal("succeeded; want error") 1600 } else if got, want := err.Error(), test.Err; got != want { 1601 t.Fatalf("wrong error\n got: %s\nwant: %s", got, want) 1602 } 1603 return 1604 } else if err != nil { 1605 t.Fatalf("unexpected error: %s", err) 1606 } 1607 1608 if !got.RawEquals(test.Want) { 1609 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1610 } 1611 }) 1612 } 1613 } 1614 1615 func TestTranspose(t *testing.T) { 1616 tests := []struct { 1617 Values cty.Value 1618 Want cty.Value 1619 Err bool 1620 }{ 1621 { 1622 cty.MapVal(map[string]cty.Value{ 1623 "key1": cty.ListVal([]cty.Value{ 1624 cty.StringVal("a"), 1625 cty.StringVal("b"), 1626 }), 1627 "key2": cty.ListVal([]cty.Value{ 1628 cty.StringVal("a"), 1629 cty.StringVal("b"), 1630 cty.StringVal("c"), 1631 }), 1632 "key3": cty.ListVal([]cty.Value{ 1633 cty.StringVal("c"), 1634 }), 1635 "key4": cty.ListValEmpty(cty.String), 1636 }), 1637 cty.MapVal(map[string]cty.Value{ 1638 "a": cty.ListVal([]cty.Value{ 1639 cty.StringVal("key1"), 1640 cty.StringVal("key2"), 1641 }), 1642 "b": cty.ListVal([]cty.Value{ 1643 cty.StringVal("key1"), 1644 cty.StringVal("key2"), 1645 }), 1646 "c": cty.ListVal([]cty.Value{ 1647 cty.StringVal("key2"), 1648 cty.StringVal("key3"), 1649 }), 1650 }), 1651 false, 1652 }, 1653 { // map - unknown value 1654 cty.MapVal(map[string]cty.Value{ 1655 "key1": cty.UnknownVal(cty.List(cty.String)), 1656 }), 1657 cty.UnknownVal(cty.Map(cty.List(cty.String))), 1658 false, 1659 }, 1660 { // bad map - empty value 1661 cty.MapVal(map[string]cty.Value{ 1662 "key1": cty.ListValEmpty(cty.String), 1663 }), 1664 cty.MapValEmpty(cty.List(cty.String)), 1665 false, 1666 }, 1667 { // bad map - value not a list 1668 cty.MapVal(map[string]cty.Value{ 1669 "key1": cty.StringVal("a"), 1670 }), 1671 cty.NilVal, 1672 true, 1673 }, 1674 { // marks (deep or shallow) on any elements will propegate to the entire return value 1675 cty.MapVal(map[string]cty.Value{ 1676 "key1": cty.ListVal([]cty.Value{ 1677 cty.StringVal("a").Mark("beep"), // mark on the inner list element 1678 cty.StringVal("b"), 1679 }), 1680 "key2": cty.ListVal([]cty.Value{ 1681 cty.StringVal("a"), 1682 cty.StringVal("b"), 1683 cty.StringVal("c"), 1684 }).Mark("boop"), // mark on the map element 1685 "key3": cty.ListVal([]cty.Value{ 1686 cty.StringVal("c"), 1687 }), 1688 "key4": cty.ListValEmpty(cty.String), 1689 }), 1690 cty.MapVal(map[string]cty.Value{ 1691 "a": cty.ListVal([]cty.Value{ 1692 cty.StringVal("key1"), 1693 cty.StringVal("key2"), 1694 }), 1695 "b": cty.ListVal([]cty.Value{ 1696 cty.StringVal("key1"), 1697 cty.StringVal("key2"), 1698 }), 1699 "c": cty.ListVal([]cty.Value{ 1700 cty.StringVal("key2"), 1701 cty.StringVal("key3")}), 1702 }).WithMarks(cty.NewValueMarks("beep", "boop")), 1703 false, 1704 }, 1705 { // Marks on the input value will be applied to the return value 1706 cty.MapVal(map[string]cty.Value{ 1707 "key1": cty.ListVal([]cty.Value{ 1708 cty.StringVal("a"), 1709 cty.StringVal("b"), 1710 }), 1711 "key2": cty.ListVal([]cty.Value{ 1712 cty.StringVal("a"), 1713 cty.StringVal("b"), 1714 cty.StringVal("c"), 1715 }), 1716 "key3": cty.ListVal([]cty.Value{ 1717 cty.StringVal("c"), 1718 }), 1719 }).Mark("beep"), // mark on the entire input value 1720 cty.MapVal(map[string]cty.Value{ 1721 "a": cty.ListVal([]cty.Value{ 1722 cty.StringVal("key1"), 1723 cty.StringVal("key2"), 1724 }), 1725 "b": cty.ListVal([]cty.Value{ 1726 cty.StringVal("key1"), 1727 cty.StringVal("key2"), 1728 }), 1729 "c": cty.ListVal([]cty.Value{ 1730 cty.StringVal("key2"), 1731 cty.StringVal("key3"), 1732 }), 1733 }).Mark("beep"), 1734 false, 1735 }, 1736 { // Marks on the entire input value AND inner elements (deep or shallow) ALL apply to the return 1737 cty.MapVal(map[string]cty.Value{ 1738 "key1": cty.ListVal([]cty.Value{ 1739 cty.StringVal("a"), 1740 cty.StringVal("b"), 1741 }).Mark("beep"), // mark on the map element 1742 "key2": cty.ListVal([]cty.Value{ 1743 cty.StringVal("a"), 1744 cty.StringVal("b"), 1745 cty.StringVal("c"), 1746 }), 1747 "key3": cty.ListVal([]cty.Value{ 1748 cty.StringVal("c").Mark("boop"), // mark on the inner list element 1749 }), 1750 }).Mark("bloop"), // mark on the entire input value 1751 cty.MapVal(map[string]cty.Value{ 1752 "a": cty.ListVal([]cty.Value{ 1753 cty.StringVal("key1"), 1754 cty.StringVal("key2"), 1755 }), 1756 "b": cty.ListVal([]cty.Value{ 1757 cty.StringVal("key1"), 1758 cty.StringVal("key2"), 1759 }), 1760 "c": cty.ListVal([]cty.Value{ 1761 cty.StringVal("key2"), 1762 cty.StringVal("key3"), 1763 }), 1764 }).WithMarks(cty.NewValueMarks("beep", "boop", "bloop")), 1765 false, 1766 }, 1767 } 1768 1769 for _, test := range tests { 1770 t.Run(fmt.Sprintf("transpose(%#v)", test.Values), func(t *testing.T) { 1771 got, err := Transpose(test.Values) 1772 1773 if test.Err { 1774 if err == nil { 1775 t.Fatal("succeeded; want error") 1776 } 1777 return 1778 } else if err != nil { 1779 t.Fatalf("unexpected error: %s", err) 1780 } 1781 1782 if !got.RawEquals(test.Want) { 1783 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 1784 } 1785 }) 1786 } 1787 }