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