github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/configs/hcl2shim/flatmap_test.go (about) 1 package hcl2shim 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/go-test/deep" 8 9 "github.com/zclconf/go-cty/cty" 10 ) 11 12 func TestFlatmapValueFromHCL2(t *testing.T) { 13 tests := []struct { 14 Value cty.Value 15 Want map[string]string 16 }{ 17 { 18 cty.EmptyObjectVal, 19 map[string]string{}, 20 }, 21 { 22 cty.ObjectVal(map[string]cty.Value{ 23 "foo": cty.StringVal("hello"), 24 }), 25 map[string]string{ 26 "foo": "hello", 27 }, 28 }, 29 { 30 cty.ObjectVal(map[string]cty.Value{ 31 "foo": cty.UnknownVal(cty.Bool), 32 }), 33 map[string]string{ 34 "foo": UnknownVariableValue, 35 }, 36 }, 37 { 38 cty.ObjectVal(map[string]cty.Value{ 39 "foo": cty.NumberIntVal(12), 40 }), 41 map[string]string{ 42 "foo": "12", 43 }, 44 }, 45 { 46 cty.ObjectVal(map[string]cty.Value{ 47 "foo": cty.True, 48 "bar": cty.False, 49 }), 50 map[string]string{ 51 "foo": "true", 52 "bar": "false", 53 }, 54 }, 55 { 56 cty.ObjectVal(map[string]cty.Value{ 57 "foo": cty.StringVal("hello"), 58 "bar": cty.StringVal("world"), 59 "baz": cty.StringVal("whelp"), 60 }), 61 map[string]string{ 62 "foo": "hello", 63 "bar": "world", 64 "baz": "whelp", 65 }, 66 }, 67 { 68 cty.ObjectVal(map[string]cty.Value{ 69 "foo": cty.ListValEmpty(cty.String), 70 }), 71 map[string]string{ 72 "foo.#": "0", 73 }, 74 }, 75 { 76 cty.ObjectVal(map[string]cty.Value{ 77 "foo": cty.UnknownVal(cty.List(cty.String)), 78 }), 79 map[string]string{ 80 "foo.#": UnknownVariableValue, 81 }, 82 }, 83 { 84 cty.ObjectVal(map[string]cty.Value{ 85 "foo": cty.ListVal([]cty.Value{ 86 cty.StringVal("hello"), 87 }), 88 }), 89 map[string]string{ 90 "foo.#": "1", 91 "foo.0": "hello", 92 }, 93 }, 94 { 95 cty.ObjectVal(map[string]cty.Value{ 96 "foo": cty.ListVal([]cty.Value{ 97 cty.StringVal("hello"), 98 cty.StringVal("world"), 99 }), 100 }), 101 map[string]string{ 102 "foo.#": "2", 103 "foo.0": "hello", 104 "foo.1": "world", 105 }, 106 }, 107 { 108 cty.ObjectVal(map[string]cty.Value{ 109 "foo": cty.MapVal(map[string]cty.Value{ 110 "hello": cty.NumberIntVal(12), 111 "hello.world": cty.NumberIntVal(10), 112 }), 113 }), 114 map[string]string{ 115 "foo.%": "2", 116 "foo.hello": "12", 117 "foo.hello.world": "10", 118 }, 119 }, 120 { 121 cty.ObjectVal(map[string]cty.Value{ 122 "foo": cty.UnknownVal(cty.Map(cty.String)), 123 }), 124 map[string]string{ 125 "foo.%": UnknownVariableValue, 126 }, 127 }, 128 { 129 cty.ObjectVal(map[string]cty.Value{ 130 "foo": cty.MapVal(map[string]cty.Value{ 131 "hello": cty.NumberIntVal(12), 132 "hello.world": cty.NumberIntVal(10), 133 }), 134 }), 135 map[string]string{ 136 "foo.%": "2", 137 "foo.hello": "12", 138 "foo.hello.world": "10", 139 }, 140 }, 141 { 142 cty.ObjectVal(map[string]cty.Value{ 143 "foo": cty.SetVal([]cty.Value{ 144 cty.StringVal("hello"), 145 cty.StringVal("world"), 146 }), 147 }), 148 map[string]string{ 149 "foo.#": "2", 150 "foo.0": "hello", 151 "foo.1": "world", 152 }, 153 }, 154 { 155 cty.ObjectVal(map[string]cty.Value{ 156 "foo": cty.UnknownVal(cty.Set(cty.Number)), 157 }), 158 map[string]string{ 159 "foo.#": UnknownVariableValue, 160 }, 161 }, 162 { 163 cty.ObjectVal(map[string]cty.Value{ 164 "foo": cty.ListVal([]cty.Value{ 165 cty.ObjectVal(map[string]cty.Value{ 166 "bar": cty.StringVal("hello"), 167 "baz": cty.StringVal("world"), 168 }), 169 cty.ObjectVal(map[string]cty.Value{ 170 "bar": cty.StringVal("bloo"), 171 "baz": cty.StringVal("blaa"), 172 }), 173 }), 174 }), 175 map[string]string{ 176 "foo.#": "2", 177 "foo.0.bar": "hello", 178 "foo.0.baz": "world", 179 "foo.1.bar": "bloo", 180 "foo.1.baz": "blaa", 181 }, 182 }, 183 { 184 cty.ObjectVal(map[string]cty.Value{ 185 "foo": cty.ListVal([]cty.Value{ 186 cty.ObjectVal(map[string]cty.Value{ 187 "bar": cty.StringVal("hello"), 188 "baz": cty.ListVal([]cty.Value{ 189 cty.True, 190 cty.True, 191 }), 192 }), 193 cty.ObjectVal(map[string]cty.Value{ 194 "bar": cty.StringVal("bloo"), 195 "baz": cty.ListVal([]cty.Value{ 196 cty.False, 197 cty.True, 198 }), 199 }), 200 }), 201 }), 202 map[string]string{ 203 "foo.#": "2", 204 "foo.0.bar": "hello", 205 "foo.0.baz.#": "2", 206 "foo.0.baz.0": "true", 207 "foo.0.baz.1": "true", 208 "foo.1.bar": "bloo", 209 "foo.1.baz.#": "2", 210 "foo.1.baz.0": "false", 211 "foo.1.baz.1": "true", 212 }, 213 }, 214 { 215 cty.ObjectVal(map[string]cty.Value{ 216 "foo": cty.ListVal([]cty.Value{ 217 cty.UnknownVal(cty.Object(map[string]cty.Type{ 218 "bar": cty.String, 219 "baz": cty.List(cty.Bool), 220 "bap": cty.Map(cty.Number), 221 })), 222 }), 223 }), 224 map[string]string{ 225 "foo.#": "1", 226 "foo.0.bar": UnknownVariableValue, 227 "foo.0.baz.#": UnknownVariableValue, 228 "foo.0.bap.%": UnknownVariableValue, 229 }, 230 }, 231 { 232 cty.NullVal(cty.Object(map[string]cty.Type{ 233 "foo": cty.Set(cty.Object(map[string]cty.Type{ 234 "bar": cty.String, 235 })), 236 })), 237 nil, 238 }, 239 } 240 241 for _, test := range tests { 242 t.Run(test.Value.GoString(), func(t *testing.T) { 243 got := FlatmapValueFromHCL2(test.Value) 244 245 for _, problem := range deep.Equal(got, test.Want) { 246 t.Error(problem) 247 } 248 }) 249 } 250 } 251 252 func TestFlatmapValueFromHCL2FromFlatmap(t *testing.T) { 253 tests := []struct { 254 Name string 255 Map map[string]string 256 Type cty.Type 257 }{ 258 { 259 "empty flatmap with collections", 260 map[string]string{}, 261 cty.Object(map[string]cty.Type{ 262 "foo": cty.Map(cty.String), 263 "bar": cty.Set(cty.String), 264 }), 265 }, 266 { 267 "nil flatmap with collections", 268 nil, 269 cty.Object(map[string]cty.Type{ 270 "foo": cty.Map(cty.String), 271 "bar": cty.Set(cty.String), 272 }), 273 }, 274 { 275 "empty flatmap with nested collections", 276 map[string]string{}, 277 cty.Object(map[string]cty.Type{ 278 "foo": cty.Object( 279 map[string]cty.Type{ 280 "baz": cty.Map(cty.String), 281 }, 282 ), 283 "bar": cty.Set(cty.String), 284 }), 285 }, 286 { 287 "partial flatmap with nested collections", 288 map[string]string{ 289 "foo.baz.%": "1", 290 "foo.baz.key": "val", 291 }, 292 cty.Object(map[string]cty.Type{ 293 "foo": cty.Object( 294 map[string]cty.Type{ 295 "baz": cty.Map(cty.String), 296 "biz": cty.Map(cty.String), 297 }, 298 ), 299 "bar": cty.Set(cty.String), 300 }), 301 }, 302 } 303 304 for _, test := range tests { 305 t.Run(test.Name, func(t *testing.T) { 306 val, err := HCL2ValueFromFlatmap(test.Map, test.Type) 307 if err != nil { 308 t.Fatal(err) 309 } 310 311 got := FlatmapValueFromHCL2(val) 312 313 for _, problem := range deep.Equal(got, test.Map) { 314 t.Error(problem) 315 } 316 }) 317 } 318 } 319 func TestHCL2ValueFromFlatmap(t *testing.T) { 320 tests := []struct { 321 Flatmap map[string]string 322 Type cty.Type 323 Want cty.Value 324 WantErr string 325 }{ 326 { 327 Flatmap: map[string]string{}, 328 Type: cty.EmptyObject, 329 Want: cty.EmptyObjectVal, 330 }, 331 { 332 Flatmap: map[string]string{ 333 "ignored": "foo", 334 }, 335 Type: cty.EmptyObject, 336 Want: cty.EmptyObjectVal, 337 }, 338 { 339 Flatmap: map[string]string{ 340 "foo": "blah", 341 "bar": "true", 342 "baz": "12.5", 343 "unk": UnknownVariableValue, 344 }, 345 Type: cty.Object(map[string]cty.Type{ 346 "foo": cty.String, 347 "bar": cty.Bool, 348 "baz": cty.Number, 349 "unk": cty.Bool, 350 }), 351 Want: cty.ObjectVal(map[string]cty.Value{ 352 "foo": cty.StringVal("blah"), 353 "bar": cty.True, 354 "baz": cty.NumberFloatVal(12.5), 355 "unk": cty.UnknownVal(cty.Bool), 356 }), 357 }, 358 { 359 Flatmap: map[string]string{ 360 "foo.#": "0", 361 }, 362 Type: cty.Object(map[string]cty.Type{ 363 "foo": cty.List(cty.String), 364 }), 365 Want: cty.ObjectVal(map[string]cty.Value{ 366 "foo": cty.ListValEmpty(cty.String), 367 }), 368 }, 369 { 370 Flatmap: map[string]string{ 371 "foo.#": UnknownVariableValue, 372 }, 373 Type: cty.Object(map[string]cty.Type{ 374 "foo": cty.List(cty.String), 375 }), 376 Want: cty.ObjectVal(map[string]cty.Value{ 377 "foo": cty.UnknownVal(cty.List(cty.String)), 378 }), 379 }, 380 { 381 Flatmap: map[string]string{ 382 "foo.#": "1", 383 "foo.0": "hello", 384 }, 385 Type: cty.Object(map[string]cty.Type{ 386 "foo": cty.List(cty.String), 387 }), 388 Want: cty.ObjectVal(map[string]cty.Value{ 389 "foo": cty.ListVal([]cty.Value{ 390 cty.StringVal("hello"), 391 }), 392 }), 393 }, 394 { 395 Flatmap: map[string]string{ 396 "foo.#": "2", 397 "foo.0": "true", 398 "foo.1": "false", 399 "foo.2": "ignored", // (because the count is 2, so this is out of range) 400 }, 401 Type: cty.Object(map[string]cty.Type{ 402 "foo": cty.List(cty.Bool), 403 }), 404 Want: cty.ObjectVal(map[string]cty.Value{ 405 "foo": cty.ListVal([]cty.Value{ 406 cty.True, 407 cty.False, 408 }), 409 }), 410 }, 411 { 412 Flatmap: map[string]string{ 413 "foo.#": "2", 414 "foo.0": "hello", 415 }, 416 Type: cty.Object(map[string]cty.Type{ 417 "foo": cty.Tuple([]cty.Type{ 418 cty.String, 419 cty.Bool, 420 }), 421 }), 422 Want: cty.ObjectVal(map[string]cty.Value{ 423 "foo": cty.TupleVal([]cty.Value{ 424 cty.StringVal("hello"), 425 cty.NullVal(cty.Bool), 426 }), 427 }), 428 }, 429 { 430 Flatmap: map[string]string{ 431 "foo.#": UnknownVariableValue, 432 }, 433 Type: cty.Object(map[string]cty.Type{ 434 "foo": cty.Tuple([]cty.Type{ 435 cty.String, 436 cty.Bool, 437 }), 438 }), 439 Want: cty.ObjectVal(map[string]cty.Value{ 440 "foo": cty.UnknownVal(cty.Tuple([]cty.Type{ 441 cty.String, 442 cty.Bool, 443 })), 444 }), 445 }, 446 { 447 Flatmap: map[string]string{ 448 "foo.#": "0", 449 }, 450 Type: cty.Object(map[string]cty.Type{ 451 "foo": cty.Set(cty.String), 452 }), 453 Want: cty.ObjectVal(map[string]cty.Value{ 454 "foo": cty.SetValEmpty(cty.String), 455 }), 456 }, 457 { 458 Flatmap: map[string]string{ 459 "foo.#": UnknownVariableValue, 460 }, 461 Type: cty.Object(map[string]cty.Type{ 462 "foo": cty.Set(cty.String), 463 }), 464 Want: cty.ObjectVal(map[string]cty.Value{ 465 "foo": cty.UnknownVal(cty.Set(cty.String)), 466 }), 467 }, 468 { 469 Flatmap: map[string]string{ 470 "foo.#": "1", 471 "foo.24534534": "hello", 472 }, 473 Type: cty.Object(map[string]cty.Type{ 474 "foo": cty.Set(cty.String), 475 }), 476 Want: cty.ObjectVal(map[string]cty.Value{ 477 "foo": cty.SetVal([]cty.Value{ 478 cty.StringVal("hello"), 479 }), 480 }), 481 }, 482 { 483 Flatmap: map[string]string{ 484 "foo.#": "1", 485 "foo.24534534": "true", 486 "foo.95645644": "true", 487 "foo.34533452": "false", 488 }, 489 Type: cty.Object(map[string]cty.Type{ 490 "foo": cty.Set(cty.Bool), 491 }), 492 Want: cty.ObjectVal(map[string]cty.Value{ 493 "foo": cty.SetVal([]cty.Value{ 494 cty.True, 495 cty.False, 496 }), 497 }), 498 }, 499 { 500 Flatmap: map[string]string{ 501 "foo.%": "0", 502 }, 503 Type: cty.Object(map[string]cty.Type{ 504 "foo": cty.Map(cty.String), 505 }), 506 Want: cty.ObjectVal(map[string]cty.Value{ 507 "foo": cty.MapValEmpty(cty.String), 508 }), 509 }, 510 { 511 Flatmap: map[string]string{ 512 "foo.%": "2", 513 "foo.baz": "true", 514 "foo.bar.baz": "false", 515 }, 516 Type: cty.Object(map[string]cty.Type{ 517 "foo": cty.Map(cty.Bool), 518 }), 519 Want: cty.ObjectVal(map[string]cty.Value{ 520 "foo": cty.MapVal(map[string]cty.Value{ 521 "baz": cty.True, 522 "bar.baz": cty.False, 523 }), 524 }), 525 }, 526 { 527 Flatmap: map[string]string{ 528 "foo.%": UnknownVariableValue, 529 }, 530 Type: cty.Object(map[string]cty.Type{ 531 "foo": cty.Map(cty.Bool), 532 }), 533 Want: cty.ObjectVal(map[string]cty.Value{ 534 "foo": cty.UnknownVal(cty.Map(cty.Bool)), 535 }), 536 }, 537 { 538 Flatmap: map[string]string{ 539 "foo.#": "2", 540 "foo.0.bar": "hello", 541 "foo.0.baz": "1", 542 "foo.1.bar": "world", 543 "foo.1.baz": "false", 544 }, 545 Type: cty.Object(map[string]cty.Type{ 546 "foo": cty.List(cty.Object(map[string]cty.Type{ 547 "bar": cty.String, 548 "baz": cty.Bool, 549 })), 550 }), 551 Want: cty.ObjectVal(map[string]cty.Value{ 552 "foo": cty.ListVal([]cty.Value{ 553 cty.ObjectVal(map[string]cty.Value{ 554 "bar": cty.StringVal("hello"), 555 "baz": cty.True, 556 }), 557 cty.ObjectVal(map[string]cty.Value{ 558 "bar": cty.StringVal("world"), 559 "baz": cty.False, 560 }), 561 }), 562 }), 563 }, 564 { 565 Flatmap: map[string]string{ 566 "foo.#": "2", 567 "foo.34534534.bar": "hello", 568 "foo.34534534.baz": "1", 569 "foo.93453345.bar": "world", 570 "foo.93453345.baz": "false", 571 }, 572 Type: cty.Object(map[string]cty.Type{ 573 "foo": cty.Set(cty.Object(map[string]cty.Type{ 574 "bar": cty.String, 575 "baz": cty.Bool, 576 })), 577 }), 578 Want: cty.ObjectVal(map[string]cty.Value{ 579 "foo": cty.SetVal([]cty.Value{ 580 cty.ObjectVal(map[string]cty.Value{ 581 "bar": cty.StringVal("hello"), 582 "baz": cty.True, 583 }), 584 cty.ObjectVal(map[string]cty.Value{ 585 "bar": cty.StringVal("world"), 586 "baz": cty.False, 587 }), 588 }), 589 }), 590 }, 591 { 592 Flatmap: map[string]string{ 593 "foo.#": "not-valid", 594 }, 595 Type: cty.Object(map[string]cty.Type{ 596 "foo": cty.List(cty.String), 597 }), 598 WantErr: `invalid count value for "foo." in state: strconv.Atoi: parsing "not-valid": invalid syntax`, 599 }, 600 { 601 Flatmap: nil, 602 Type: cty.Object(map[string]cty.Type{ 603 "foo": cty.Set(cty.Object(map[string]cty.Type{ 604 "bar": cty.String, 605 })), 606 }), 607 Want: cty.NullVal(cty.Object(map[string]cty.Type{ 608 "foo": cty.Set(cty.Object(map[string]cty.Type{ 609 "bar": cty.String, 610 })), 611 })), 612 }, 613 { 614 Flatmap: map[string]string{ 615 "foo.#": "2", 616 "foo.0.%": "2", 617 "foo.0.a": "a", 618 "foo.0.b": "b", 619 "foo.1.%": "1", 620 "foo.1.a": "a", 621 }, 622 Type: cty.Object(map[string]cty.Type{ 623 "foo": cty.List(cty.Map(cty.String)), 624 }), 625 626 Want: cty.ObjectVal(map[string]cty.Value{ 627 "foo": cty.ListVal([]cty.Value{ 628 cty.MapVal(map[string]cty.Value{ 629 "a": cty.StringVal("a"), 630 "b": cty.StringVal("b"), 631 }), 632 cty.MapVal(map[string]cty.Value{ 633 "a": cty.StringVal("a"), 634 }), 635 }), 636 }), 637 }, 638 { 639 Flatmap: map[string]string{ 640 "single.#": "1", 641 "single.~1.value": "a", 642 "single.~1.optional": UnknownVariableValue, 643 "two.#": "2", 644 "two.~2381914684.value": "a", 645 "two.~2381914684.optional": UnknownVariableValue, 646 "two.~2798940671.value": "b", 647 "two.~2798940671.optional": UnknownVariableValue, 648 }, 649 Type: cty.Object(map[string]cty.Type{ 650 "single": cty.Set( 651 cty.Object(map[string]cty.Type{ 652 "value": cty.String, 653 "optional": cty.String, 654 }), 655 ), 656 "two": cty.Set( 657 cty.Object(map[string]cty.Type{ 658 "optional": cty.String, 659 "value": cty.String, 660 }), 661 ), 662 }), 663 Want: cty.ObjectVal(map[string]cty.Value{ 664 "single": cty.SetVal([]cty.Value{ 665 cty.ObjectVal(map[string]cty.Value{ 666 "value": cty.StringVal("a"), 667 "optional": cty.UnknownVal(cty.String), 668 }), 669 }), 670 "two": cty.SetVal([]cty.Value{ 671 cty.ObjectVal(map[string]cty.Value{ 672 "value": cty.StringVal("a"), 673 "optional": cty.UnknownVal(cty.String), 674 }), 675 cty.ObjectVal(map[string]cty.Value{ 676 "value": cty.StringVal("b"), 677 "optional": cty.UnknownVal(cty.String), 678 }), 679 }), 680 }), 681 }, 682 { 683 Flatmap: map[string]string{ 684 "foo.#": "1", 685 }, 686 Type: cty.Object(map[string]cty.Type{ 687 "foo": cty.Set(cty.Object(map[string]cty.Type{ 688 "bar": cty.String, 689 })), 690 }), 691 Want: cty.ObjectVal(map[string]cty.Value{ 692 "foo": cty.SetVal([]cty.Value{ 693 cty.ObjectVal(map[string]cty.Value{ 694 "bar": cty.NullVal(cty.String), 695 }), 696 }), 697 }), 698 }, 699 { 700 Flatmap: map[string]string{ 701 "multi.#": "1", 702 "multi.2.set.#": "1", 703 "multi.2.set.3.required": "val", 704 }, 705 Type: cty.Object(map[string]cty.Type{ 706 "multi": cty.Set(cty.Object(map[string]cty.Type{ 707 "set": cty.Set(cty.Object(map[string]cty.Type{ 708 "required": cty.String, 709 })), 710 })), 711 }), 712 Want: cty.ObjectVal(map[string]cty.Value{ 713 "multi": cty.SetVal([]cty.Value{ 714 cty.ObjectVal(map[string]cty.Value{ 715 "set": cty.SetVal([]cty.Value{ 716 cty.ObjectVal(map[string]cty.Value{ 717 "required": cty.StringVal("val"), 718 }), 719 }), 720 }), 721 }), 722 }), 723 }, 724 } 725 726 for i, test := range tests { 727 t.Run(fmt.Sprintf("%d %#v as %#v", i, test.Flatmap, test.Type), func(t *testing.T) { 728 got, err := HCL2ValueFromFlatmap(test.Flatmap, test.Type) 729 730 if test.WantErr != "" { 731 if err == nil { 732 t.Fatalf("succeeded; want error: %s", test.WantErr) 733 } 734 if got, want := err.Error(), test.WantErr; got != want { 735 t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) 736 } 737 if got == cty.NilVal { 738 t.Fatalf("result is cty.NilVal; want valid placeholder value") 739 } 740 return 741 } else { 742 if err != nil { 743 t.Fatalf("unexpected error: %s", err.Error()) 744 } 745 } 746 747 if !got.RawEquals(test.Want) { 748 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 749 } 750 }) 751 } 752 }