1package stdlib 2 3import ( 4 "fmt" 5 "testing" 6 7 "github.com/zclconf/go-cty/cty" 8) 9 10func TestHasIndex(t *testing.T) { 11 tests := []struct { 12 Collection cty.Value 13 Key cty.Value 14 Want cty.Value 15 }{ 16 { 17 cty.ListValEmpty(cty.Number), 18 cty.NumberIntVal(2), 19 cty.False, 20 }, 21 { 22 cty.ListVal([]cty.Value{cty.True}), 23 cty.NumberIntVal(0), 24 cty.True, 25 }, 26 { 27 cty.ListVal([]cty.Value{cty.True}), 28 cty.StringVal("hello"), 29 cty.False, 30 }, 31 { 32 cty.MapValEmpty(cty.Bool), 33 cty.StringVal("hello"), 34 cty.False, 35 }, 36 { 37 cty.MapVal(map[string]cty.Value{"hello": cty.True}), 38 cty.StringVal("hello"), 39 cty.True, 40 }, 41 { 42 cty.EmptyTupleVal, 43 cty.StringVal("hello"), 44 cty.False, 45 }, 46 { 47 cty.EmptyTupleVal, 48 cty.NumberIntVal(0), 49 cty.False, 50 }, 51 { 52 cty.TupleVal([]cty.Value{cty.True}), 53 cty.NumberIntVal(0), 54 cty.True, 55 }, 56 { 57 cty.ListValEmpty(cty.Number), 58 cty.UnknownVal(cty.Number), 59 cty.UnknownVal(cty.Bool), 60 }, 61 { 62 cty.UnknownVal(cty.List(cty.Bool)), 63 cty.UnknownVal(cty.Number), 64 cty.UnknownVal(cty.Bool), 65 }, 66 { 67 cty.ListValEmpty(cty.Number), 68 cty.DynamicVal, 69 cty.UnknownVal(cty.Bool), 70 }, 71 { 72 cty.DynamicVal, 73 cty.DynamicVal, 74 cty.UnknownVal(cty.Bool), 75 }, 76 } 77 78 for _, test := range tests { 79 t.Run(fmt.Sprintf("HasIndex(%#v,%#v)", test.Collection, test.Key), func(t *testing.T) { 80 got, err := HasIndex(test.Collection, test.Key) 81 82 if err != nil { 83 t.Fatalf("unexpected error: %s", err) 84 } 85 86 if !got.RawEquals(test.Want) { 87 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 88 } 89 }) 90 } 91} 92 93func TestContains(t *testing.T) { 94 listOfStrings := cty.ListVal([]cty.Value{ 95 cty.StringVal("the"), 96 cty.StringVal("quick"), 97 cty.StringVal("brown"), 98 cty.StringVal("fox"), 99 }) 100 listOfInts := cty.ListVal([]cty.Value{ 101 cty.NumberIntVal(1), 102 cty.NumberIntVal(2), 103 cty.NumberIntVal(3), 104 cty.NumberIntVal(4), 105 }) 106 listWithUnknown := cty.ListVal([]cty.Value{ 107 cty.StringVal("the"), 108 cty.StringVal("quick"), 109 cty.StringVal("brown"), 110 cty.UnknownVal(cty.String), 111 }) 112 113 tests := []struct { 114 List cty.Value 115 Value cty.Value 116 Want cty.Value 117 Err bool 118 }{ 119 { 120 listOfStrings, 121 cty.StringVal("the"), 122 cty.BoolVal(true), 123 false, 124 }, 125 { 126 listWithUnknown, 127 cty.StringVal("the"), 128 cty.BoolVal(true), 129 false, 130 }, 131 { 132 listWithUnknown, 133 cty.StringVal("orange"), 134 cty.UnknownVal(cty.Bool), 135 false, 136 }, 137 { 138 listOfStrings, 139 cty.StringVal("penguin"), 140 cty.BoolVal(false), 141 false, 142 }, 143 { 144 listOfInts, 145 cty.NumberIntVal(1), 146 cty.BoolVal(true), 147 false, 148 }, 149 { 150 listOfInts, 151 cty.NumberIntVal(42), 152 cty.BoolVal(false), 153 false, 154 }, 155 { // And now we mix and match 156 listOfInts, 157 cty.StringVal("1"), 158 cty.BoolVal(false), 159 false, 160 }, 161 { // Check a list with an unknown value 162 cty.ListVal([]cty.Value{ 163 cty.UnknownVal(cty.String), 164 cty.StringVal("quick"), 165 cty.StringVal("brown"), 166 cty.StringVal("fox"), 167 }), 168 cty.StringVal("quick"), 169 cty.BoolVal(true), 170 false, 171 }, 172 { 173 cty.ListVal([]cty.Value{ 174 cty.UnknownVal(cty.String), 175 cty.StringVal("brown"), 176 cty.StringVal("fox"), 177 }), 178 cty.StringVal("quick"), 179 cty.UnknownVal(cty.Bool), 180 false, 181 }, 182 { // set val 183 cty.SetVal([]cty.Value{ 184 cty.StringVal("quick"), 185 cty.StringVal("brown"), 186 cty.StringVal("fox"), 187 }), 188 cty.StringVal("quick"), 189 cty.BoolVal(true), 190 false, 191 }, 192 { 193 cty.SetVal([]cty.Value{ 194 cty.UnknownVal(cty.String), 195 cty.StringVal("brown"), 196 cty.StringVal("fox"), 197 }), 198 cty.StringVal("quick"), 199 cty.UnknownVal(cty.Bool), 200 false, 201 }, 202 { // nested unknown 203 cty.ListVal([]cty.Value{ 204 cty.ObjectVal(map[string]cty.Value{ 205 "a": cty.UnknownVal(cty.String), 206 }), 207 }), 208 cty.ObjectVal(map[string]cty.Value{ 209 "a": cty.StringVal("b"), 210 }), 211 cty.UnknownVal(cty.Bool), 212 false, 213 }, 214 { // tuple val 215 cty.TupleVal([]cty.Value{ 216 cty.StringVal("quick"), 217 cty.StringVal("brown"), 218 cty.NumberIntVal(3), 219 }), 220 cty.NumberIntVal(3), 221 cty.BoolVal(true), 222 false, 223 }, 224 } 225 226 for _, test := range tests { 227 t.Run(fmt.Sprintf("contains(%#v, %#v)", test.List, test.Value), func(t *testing.T) { 228 got, err := Contains(test.List, test.Value) 229 230 if test.Err { 231 if err == nil { 232 t.Fatal("succeeded; want error") 233 } 234 return 235 } else if err != nil { 236 t.Fatalf("unexpected error: %s", err) 237 } 238 239 if !got.RawEquals(test.Want) { 240 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 241 } 242 }) 243 } 244} 245 246func TestMerge(t *testing.T) { 247 tests := []struct { 248 Values []cty.Value 249 Want cty.Value 250 Err bool 251 }{ 252 { 253 []cty.Value{ 254 cty.MapVal(map[string]cty.Value{ 255 "a": cty.StringVal("b"), 256 }), 257 cty.MapVal(map[string]cty.Value{ 258 "c": cty.StringVal("d"), 259 }), 260 }, 261 cty.MapVal(map[string]cty.Value{ 262 "a": cty.StringVal("b"), 263 "c": cty.StringVal("d"), 264 }), 265 false, 266 }, 267 { // handle unknowns 268 []cty.Value{ 269 cty.MapVal(map[string]cty.Value{ 270 "a": cty.UnknownVal(cty.String), 271 }), 272 cty.MapVal(map[string]cty.Value{ 273 "c": cty.StringVal("d"), 274 }), 275 }, 276 cty.MapVal(map[string]cty.Value{ 277 "a": cty.UnknownVal(cty.String), 278 "c": cty.StringVal("d"), 279 }), 280 false, 281 }, 282 { // handle null map 283 []cty.Value{ 284 cty.NullVal(cty.Map(cty.String)), 285 cty.MapVal(map[string]cty.Value{ 286 "c": cty.StringVal("d"), 287 }), 288 }, 289 cty.MapVal(map[string]cty.Value{ 290 "c": cty.StringVal("d"), 291 }), 292 false, 293 }, 294 { // all inputs are null 295 []cty.Value{ 296 cty.NullVal(cty.Map(cty.String)), 297 cty.NullVal(cty.Object(map[string]cty.Type{ 298 "a": cty.List(cty.String), 299 })), 300 }, 301 cty.EmptyObjectVal, 302 false, 303 }, 304 { // single null input 305 []cty.Value{ 306 cty.MapValEmpty(cty.String), 307 }, 308 cty.MapValEmpty(cty.String), 309 false, 310 }, 311 { // handle null object 312 []cty.Value{ 313 cty.MapVal(map[string]cty.Value{ 314 "c": cty.StringVal("d"), 315 }), 316 cty.NullVal(cty.Object(map[string]cty.Type{ 317 "a": cty.List(cty.String), 318 })), 319 }, 320 cty.ObjectVal(map[string]cty.Value{ 321 "c": cty.StringVal("d"), 322 }), 323 false, 324 }, 325 { // handle unknowns 326 []cty.Value{ 327 cty.UnknownVal(cty.Map(cty.String)), 328 cty.MapVal(map[string]cty.Value{ 329 "c": cty.StringVal("d"), 330 }), 331 }, 332 cty.UnknownVal(cty.Map(cty.String)), 333 false, 334 }, 335 { // handle dynamic unknown 336 []cty.Value{ 337 cty.UnknownVal(cty.DynamicPseudoType), 338 cty.MapVal(map[string]cty.Value{ 339 "c": cty.StringVal("d"), 340 }), 341 }, 342 cty.DynamicVal, 343 false, 344 }, 345 { // merge with conflicts is ok, last in wins 346 []cty.Value{ 347 cty.MapVal(map[string]cty.Value{ 348 "a": cty.StringVal("b"), 349 "c": cty.StringVal("d"), 350 }), 351 cty.MapVal(map[string]cty.Value{ 352 "a": cty.StringVal("x"), 353 }), 354 }, 355 cty.MapVal(map[string]cty.Value{ 356 "a": cty.StringVal("x"), 357 "c": cty.StringVal("d"), 358 }), 359 false, 360 }, 361 { // only accept maps 362 []cty.Value{ 363 cty.MapVal(map[string]cty.Value{ 364 "a": cty.StringVal("b"), 365 "c": cty.StringVal("d"), 366 }), 367 cty.ListVal([]cty.Value{ 368 cty.StringVal("a"), 369 cty.StringVal("x"), 370 }), 371 }, 372 cty.NilVal, 373 true, 374 }, 375 376 { // argument error, for a null type 377 []cty.Value{ 378 cty.MapVal(map[string]cty.Value{ 379 "a": cty.StringVal("b"), 380 }), 381 cty.NullVal(cty.String), 382 }, 383 cty.NilVal, 384 true, 385 }, 386 { // merge maps of maps 387 []cty.Value{ 388 cty.MapVal(map[string]cty.Value{ 389 "a": cty.MapVal(map[string]cty.Value{ 390 "b": cty.StringVal("c"), 391 }), 392 }), 393 cty.MapVal(map[string]cty.Value{ 394 "d": cty.MapVal(map[string]cty.Value{ 395 "e": cty.StringVal("f"), 396 }), 397 }), 398 }, 399 cty.MapVal(map[string]cty.Value{ 400 "a": cty.MapVal(map[string]cty.Value{ 401 "b": cty.StringVal("c"), 402 }), 403 "d": cty.MapVal(map[string]cty.Value{ 404 "e": cty.StringVal("f"), 405 }), 406 }), 407 false, 408 }, 409 { // map of lists 410 []cty.Value{ 411 cty.MapVal(map[string]cty.Value{ 412 "a": cty.ListVal([]cty.Value{ 413 cty.StringVal("b"), 414 cty.StringVal("c"), 415 }), 416 }), 417 cty.MapVal(map[string]cty.Value{ 418 "d": cty.ListVal([]cty.Value{ 419 cty.StringVal("e"), 420 cty.StringVal("f"), 421 }), 422 }), 423 }, 424 cty.MapVal(map[string]cty.Value{ 425 "a": cty.ListVal([]cty.Value{ 426 cty.StringVal("b"), 427 cty.StringVal("c"), 428 }), 429 "d": cty.ListVal([]cty.Value{ 430 cty.StringVal("e"), 431 cty.StringVal("f"), 432 }), 433 }), 434 false, 435 }, 436 { // merge map of various kinds 437 []cty.Value{ 438 cty.MapVal(map[string]cty.Value{ 439 "a": cty.ListVal([]cty.Value{ 440 cty.StringVal("b"), 441 cty.StringVal("c"), 442 }), 443 }), 444 cty.MapVal(map[string]cty.Value{ 445 "d": cty.MapVal(map[string]cty.Value{ 446 "e": cty.StringVal("f"), 447 }), 448 }), 449 }, 450 cty.ObjectVal(map[string]cty.Value{ 451 "a": cty.ListVal([]cty.Value{ 452 cty.StringVal("b"), 453 cty.StringVal("c"), 454 }), 455 "d": cty.MapVal(map[string]cty.Value{ 456 "e": cty.StringVal("f"), 457 }), 458 }), 459 false, 460 }, 461 { // merge objects of various shapes 462 []cty.Value{ 463 cty.ObjectVal(map[string]cty.Value{ 464 "a": cty.ListVal([]cty.Value{ 465 cty.StringVal("b"), 466 }), 467 }), 468 cty.ObjectVal(map[string]cty.Value{ 469 "d": cty.DynamicVal, 470 }), 471 }, 472 cty.ObjectVal(map[string]cty.Value{ 473 "a": cty.ListVal([]cty.Value{ 474 cty.StringVal("b"), 475 }), 476 "d": cty.DynamicVal, 477 }), 478 false, 479 }, 480 { // merge maps and objects 481 []cty.Value{ 482 cty.MapVal(map[string]cty.Value{ 483 "a": cty.ListVal([]cty.Value{ 484 cty.StringVal("b"), 485 }), 486 }), 487 cty.ObjectVal(map[string]cty.Value{ 488 "d": cty.NumberIntVal(2), 489 }), 490 }, 491 cty.ObjectVal(map[string]cty.Value{ 492 "a": cty.ListVal([]cty.Value{ 493 cty.StringVal("b"), 494 }), 495 "d": cty.NumberIntVal(2), 496 }), 497 false, 498 }, 499 { // attr a type and value is overridden 500 []cty.Value{ 501 cty.ObjectVal(map[string]cty.Value{ 502 "a": cty.ListVal([]cty.Value{ 503 cty.StringVal("b"), 504 }), 505 "b": cty.StringVal("b"), 506 }), 507 cty.ObjectVal(map[string]cty.Value{ 508 "a": cty.ObjectVal(map[string]cty.Value{ 509 "e": cty.StringVal("f"), 510 }), 511 }), 512 }, 513 cty.ObjectVal(map[string]cty.Value{ 514 "a": cty.ObjectVal(map[string]cty.Value{ 515 "e": cty.StringVal("f"), 516 }), 517 "b": cty.StringVal("b"), 518 }), 519 false, 520 }, 521 { // argument error: non map type 522 []cty.Value{ 523 cty.MapVal(map[string]cty.Value{ 524 "a": cty.ListVal([]cty.Value{ 525 cty.StringVal("b"), 526 cty.StringVal("c"), 527 }), 528 }), 529 cty.ListVal([]cty.Value{ 530 cty.StringVal("d"), 531 cty.StringVal("e"), 532 }), 533 }, 534 cty.NilVal, 535 true, 536 }, 537 { // Empty maps are allowed in merge 538 []cty.Value{ 539 cty.MapValEmpty(cty.String), 540 cty.MapValEmpty(cty.String), 541 }, 542 cty.MapValEmpty(cty.String), 543 false, 544 }, 545 } 546 547 for _, test := range tests { 548 t.Run(fmt.Sprintf("merge(%#v)", test.Values), func(t *testing.T) { 549 got, err := Merge(test.Values...) 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 567func TestIndex(t *testing.T) { 568 tests := []struct { 569 Collection cty.Value 570 Key cty.Value 571 Want cty.Value 572 }{ 573 { 574 cty.ListVal([]cty.Value{cty.True}), 575 cty.NumberIntVal(0), 576 cty.True, 577 }, 578 { 579 cty.MapVal(map[string]cty.Value{"hello": cty.True}), 580 cty.StringVal("hello"), 581 cty.True, 582 }, 583 { 584 cty.TupleVal([]cty.Value{cty.True, cty.StringVal("hello")}), 585 cty.NumberIntVal(0), 586 cty.True, 587 }, 588 { 589 cty.TupleVal([]cty.Value{cty.True, cty.StringVal("hello")}), 590 cty.NumberIntVal(1), 591 cty.StringVal("hello"), 592 }, 593 { 594 cty.ListValEmpty(cty.Number), 595 cty.UnknownVal(cty.Number), 596 cty.UnknownVal(cty.Number), 597 }, 598 { 599 cty.UnknownVal(cty.List(cty.Bool)), 600 cty.UnknownVal(cty.Number), 601 cty.UnknownVal(cty.Bool), 602 }, 603 { 604 cty.ListValEmpty(cty.Number), 605 cty.DynamicVal, 606 cty.UnknownVal(cty.Number), 607 }, 608 { 609 cty.MapValEmpty(cty.Number), 610 cty.DynamicVal, 611 cty.UnknownVal(cty.Number), 612 }, 613 { 614 cty.DynamicVal, 615 cty.StringVal("hello"), 616 cty.DynamicVal, 617 }, 618 { 619 cty.DynamicVal, 620 cty.DynamicVal, 621 cty.DynamicVal, 622 }, 623 } 624 625 for _, test := range tests { 626 t.Run(fmt.Sprintf("Index(%#v,%#v)", test.Collection, test.Key), func(t *testing.T) { 627 got, err := Index(test.Collection, test.Key) 628 629 if err != nil { 630 t.Fatalf("unexpected error: %s", err) 631 } 632 633 if !got.RawEquals(test.Want) { 634 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 635 } 636 }) 637 } 638} 639 640func TestLength(t *testing.T) { 641 tests := []struct { 642 Collection cty.Value 643 Want cty.Value 644 }{ 645 { 646 cty.ListValEmpty(cty.Number), 647 cty.NumberIntVal(0), 648 }, 649 { 650 cty.ListVal([]cty.Value{cty.True}), 651 cty.NumberIntVal(1), 652 }, 653 { 654 cty.SetValEmpty(cty.Number), 655 cty.NumberIntVal(0), 656 }, 657 { 658 cty.SetVal([]cty.Value{cty.True}), 659 cty.NumberIntVal(1), 660 }, 661 { 662 cty.SetVal([]cty.Value{cty.True, cty.False}), 663 cty.NumberIntVal(2), 664 }, 665 { 666 cty.SetVal([]cty.Value{cty.True, cty.UnknownVal(cty.Bool)}), 667 cty.UnknownVal(cty.Number), // Don't know if the unknown in the input represents cty.True or cty.False 668 }, 669 { 670 cty.SetVal([]cty.Value{cty.UnknownVal(cty.Bool)}), 671 cty.NumberIntVal(1), // Will be one regardless of what value the unknown in the input is representing 672 }, 673 { 674 cty.MapValEmpty(cty.Bool), 675 cty.NumberIntVal(0), 676 }, 677 { 678 cty.MapVal(map[string]cty.Value{"hello": cty.True}), 679 cty.NumberIntVal(1), 680 }, 681 { 682 cty.EmptyTupleVal, 683 cty.NumberIntVal(0), 684 }, 685 { 686 cty.TupleVal([]cty.Value{cty.True}), 687 cty.NumberIntVal(1), 688 }, 689 { 690 cty.UnknownVal(cty.List(cty.Bool)), 691 cty.UnknownVal(cty.Number), 692 }, 693 { 694 cty.DynamicVal, 695 cty.UnknownVal(cty.Number), 696 }, 697 } 698 699 for _, test := range tests { 700 t.Run(fmt.Sprintf("Length(%#v)", test.Collection), func(t *testing.T) { 701 got, err := Length(test.Collection) 702 703 if err != nil { 704 t.Fatalf("unexpected error: %s", err) 705 } 706 707 if !got.RawEquals(test.Want) { 708 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 709 } 710 }) 711 } 712} 713 714func TestLookup(t *testing.T) { 715 tests := []struct { 716 Collection cty.Value 717 Key cty.Value 718 Default cty.Value 719 Want cty.Value 720 }{ 721 { 722 cty.MapValEmpty(cty.String), 723 cty.StringVal("baz"), 724 cty.StringVal("foo"), 725 cty.StringVal("foo"), 726 }, 727 { 728 cty.MapVal(map[string]cty.Value{ 729 "foo": cty.StringVal("bar"), 730 }), 731 cty.StringVal("foo"), 732 cty.StringVal("nope"), 733 cty.StringVal("bar"), 734 }, 735 } 736 737 for _, test := range tests { 738 t.Run(fmt.Sprintf("Lookup(%#v,%#v,%#v)", test.Collection, test.Key, test.Default), func(t *testing.T) { 739 got, err := Lookup(test.Collection, test.Key, test.Default) 740 741 if err != nil { 742 t.Fatalf("unexpected error: %s", err) 743 } 744 745 if !got.RawEquals(test.Want) { 746 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 747 } 748 }) 749 } 750} 751 752func TestElement(t *testing.T) { 753 listOfStrings := cty.ListVal([]cty.Value{ 754 cty.StringVal("the"), 755 cty.StringVal("quick"), 756 cty.StringVal("brown"), 757 cty.StringVal("fox"), 758 }) 759 listOfInts := cty.ListVal([]cty.Value{ 760 cty.NumberIntVal(1), 761 cty.NumberIntVal(2), 762 cty.NumberIntVal(3), 763 cty.NumberIntVal(4), 764 }) 765 listWithUnknown := cty.ListVal([]cty.Value{ 766 cty.StringVal("the"), 767 cty.StringVal("quick"), 768 cty.StringVal("brown"), 769 cty.UnknownVal(cty.String), 770 }) 771 772 tests := []struct { 773 List cty.Value 774 Index cty.Value 775 Want cty.Value 776 Err bool 777 }{ 778 { 779 listOfStrings, 780 cty.NumberIntVal(2), 781 cty.StringVal("brown"), 782 false, 783 }, 784 { // index greater than length(list) 785 listOfStrings, 786 cty.NumberIntVal(5), 787 cty.StringVal("quick"), 788 false, 789 }, 790 { // list of lists 791 cty.ListVal([]cty.Value{listOfStrings, listOfStrings}), 792 cty.NumberIntVal(0), 793 listOfStrings, 794 false, 795 }, 796 { 797 listOfStrings, 798 cty.UnknownVal(cty.Number), 799 cty.UnknownVal(cty.String), 800 false, 801 }, 802 { 803 listOfInts, 804 cty.NumberIntVal(2), 805 cty.NumberIntVal(3), 806 false, 807 }, 808 { 809 listWithUnknown, 810 cty.NumberIntVal(2), 811 cty.StringVal("brown"), 812 false, 813 }, 814 { 815 listWithUnknown, 816 cty.NumberIntVal(3), 817 cty.UnknownVal(cty.String), 818 false, 819 }, 820 { 821 listOfStrings, 822 cty.NumberIntVal(-1), 823 cty.DynamicVal, 824 true, // index cannot be a negative number 825 }, 826 { 827 listOfStrings, 828 cty.StringVal("brown"), // definitely not an index 829 cty.DynamicVal, 830 true, 831 }, 832 } 833 834 for _, test := range tests { 835 t.Run(fmt.Sprintf("Element(%#v,%#v)", test.List, test.Index), func(t *testing.T) { 836 got, err := Element(test.List, test.Index) 837 838 if test.Err { 839 if err == nil { 840 t.Fatal("succeeded; want error") 841 } 842 return 843 } else if err != nil { 844 t.Fatalf("unexpected error: %s", err) 845 } 846 847 if !got.RawEquals(test.Want) { 848 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 849 } 850 }) 851 } 852} 853 854func TestCoalesceList(t *testing.T) { 855 tests := map[string]struct { 856 Values []cty.Value 857 Want cty.Value 858 Err bool 859 }{ 860 "returns first list if non-empty": { 861 []cty.Value{ 862 cty.ListVal([]cty.Value{ 863 cty.StringVal("a"), 864 cty.StringVal("b"), 865 }), 866 cty.ListVal([]cty.Value{ 867 cty.StringVal("c"), 868 cty.StringVal("d"), 869 }), 870 }, 871 cty.ListVal([]cty.Value{ 872 cty.StringVal("a"), 873 cty.StringVal("b"), 874 }), 875 false, 876 }, 877 "returns second list if first is empty": { 878 []cty.Value{ 879 cty.ListValEmpty(cty.String), 880 cty.ListVal([]cty.Value{ 881 cty.StringVal("c"), 882 cty.StringVal("d"), 883 }), 884 }, 885 cty.ListVal([]cty.Value{ 886 cty.StringVal("c"), 887 cty.StringVal("d"), 888 }), 889 false, 890 }, 891 "return type is dynamic, not unified": { 892 []cty.Value{ 893 cty.ListValEmpty(cty.String), 894 cty.ListVal([]cty.Value{ 895 cty.NumberIntVal(3), 896 cty.NumberIntVal(4), 897 }), 898 }, 899 cty.ListVal([]cty.Value{ 900 cty.NumberIntVal(3), 901 cty.NumberIntVal(4), 902 }), 903 false, 904 }, 905 "works with tuples": { 906 []cty.Value{ 907 cty.EmptyTupleVal, 908 cty.TupleVal([]cty.Value{ 909 cty.StringVal("c"), 910 cty.StringVal("d"), 911 }), 912 }, 913 cty.TupleVal([]cty.Value{ 914 cty.StringVal("c"), 915 cty.StringVal("d"), 916 }), 917 false, 918 }, 919 "unknown arguments": { 920 []cty.Value{ 921 cty.UnknownVal(cty.List(cty.String)), 922 cty.ListVal([]cty.Value{ 923 cty.StringVal("c"), 924 cty.StringVal("d"), 925 }), 926 }, 927 cty.DynamicVal, 928 false, 929 }, 930 "null arguments": { 931 []cty.Value{ 932 cty.NullVal(cty.List(cty.String)), 933 cty.ListVal([]cty.Value{ 934 cty.StringVal("c"), 935 cty.StringVal("d"), 936 }), 937 }, 938 cty.ListVal([]cty.Value{ 939 cty.StringVal("c"), 940 cty.StringVal("d"), 941 }), 942 false, 943 }, 944 "all null arguments": { 945 []cty.Value{ 946 cty.NullVal(cty.List(cty.String)), 947 cty.NullVal(cty.List(cty.String)), 948 }, 949 cty.NilVal, 950 true, 951 }, 952 "invalid arguments": { 953 []cty.Value{ 954 cty.MapVal(map[string]cty.Value{"a": cty.True}), 955 cty.ObjectVal(map[string]cty.Value{"b": cty.False}), 956 }, 957 cty.NilVal, 958 true, 959 }, 960 "no arguments": { 961 []cty.Value{}, 962 cty.NilVal, 963 true, 964 }, 965 } 966 967 for name, test := range tests { 968 t.Run(name, func(t *testing.T) { 969 got, err := CoalesceList(test.Values...) 970 971 if test.Err { 972 if err == nil { 973 t.Fatal("succeeded; want error") 974 } 975 return 976 } else if err != nil { 977 t.Fatalf("unexpected error: %s", err) 978 } 979 980 if !got.RawEquals(test.Want) { 981 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 982 } 983 }) 984 } 985} 986