github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/command/jsonformat/computed/renderers/renderer_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package renderers 5 6 import ( 7 "strings" 8 "testing" 9 10 "github.com/terramate-io/tf/command/jsonformat/computed" 11 12 "github.com/google/go-cmp/cmp" 13 "github.com/mitchellh/colorstring" 14 "github.com/zclconf/go-cty/cty" 15 16 "github.com/terramate-io/tf/plans" 17 ) 18 19 func TestRenderers_Human(t *testing.T) { 20 colorize := colorstring.Colorize{ 21 Colors: colorstring.DefaultColors, 22 Disable: true, 23 } 24 25 tcs := map[string]struct { 26 diff computed.Diff 27 expected string 28 opts computed.RenderHumanOpts 29 }{ 30 // We're using the string "null" in these tests to demonstrate the 31 // difference between rendering an actual string and rendering a null 32 // value. 33 "primitive_create_string": { 34 diff: computed.Diff{ 35 Renderer: Primitive(nil, "null", cty.String), 36 Action: plans.Create, 37 }, 38 expected: "\"null\"", 39 }, 40 "primitive_delete_string": { 41 diff: computed.Diff{ 42 Renderer: Primitive("null", nil, cty.String), 43 Action: plans.Delete, 44 }, 45 expected: "\"null\" -> null", 46 }, 47 "primitive_update_string_to_null": { 48 diff: computed.Diff{ 49 Renderer: Primitive("null", nil, cty.String), 50 Action: plans.Update, 51 }, 52 expected: "\"null\" -> null", 53 }, 54 "primitive_update_string_from_null": { 55 diff: computed.Diff{ 56 Renderer: Primitive(nil, "null", cty.String), 57 Action: plans.Update, 58 }, 59 expected: "null -> \"null\"", 60 }, 61 "primitive_update_multiline_string_to_null": { 62 diff: computed.Diff{ 63 Renderer: Primitive("nu\nll", nil, cty.String), 64 Action: plans.Update, 65 }, 66 expected: ` 67 <<-EOT 68 - nu 69 - ll 70 + null 71 EOT 72 `, 73 }, 74 "primitive_update_multiline_string_from_null": { 75 diff: computed.Diff{ 76 Renderer: Primitive(nil, "nu\nll", cty.String), 77 Action: plans.Update, 78 }, 79 expected: ` 80 <<-EOT 81 - null 82 + nu 83 + ll 84 EOT 85 `, 86 }, 87 "primitive_update_json_string_to_null": { 88 diff: computed.Diff{ 89 Renderer: Primitive("[null]", nil, cty.String), 90 Action: plans.Update, 91 }, 92 expected: ` 93 jsonencode( 94 [ 95 - null, 96 ] 97 ) -> null 98 `, 99 }, 100 "primitive_update_json_string_from_null": { 101 diff: computed.Diff{ 102 Renderer: Primitive(nil, "[null]", cty.String), 103 Action: plans.Update, 104 }, 105 expected: ` 106 null -> jsonencode( 107 [ 108 + null, 109 ] 110 ) 111 `, 112 }, 113 "primitive_create_null_string": { 114 diff: computed.Diff{ 115 Renderer: Primitive(nil, nil, cty.String), 116 Action: plans.Create, 117 }, 118 expected: "null", 119 }, 120 "primitive_delete_null_string": { 121 diff: computed.Diff{ 122 Renderer: Primitive(nil, nil, cty.String), 123 Action: plans.Delete, 124 }, 125 expected: "null", 126 }, 127 "primitive_create": { 128 diff: computed.Diff{ 129 Renderer: Primitive(nil, 1.0, cty.Number), 130 Action: plans.Create, 131 }, 132 expected: "1", 133 }, 134 "primitive_delete": { 135 diff: computed.Diff{ 136 Renderer: Primitive(1.0, nil, cty.Number), 137 Action: plans.Delete, 138 }, 139 expected: "1 -> null", 140 }, 141 "primitive_delete_override": { 142 diff: computed.Diff{ 143 Renderer: Primitive(1.0, nil, cty.Number), 144 Action: plans.Delete, 145 }, 146 opts: computed.RenderHumanOpts{OverrideNullSuffix: true}, 147 expected: "1", 148 }, 149 "primitive_update_to_null": { 150 diff: computed.Diff{ 151 Renderer: Primitive(1.0, nil, cty.Number), 152 Action: plans.Update, 153 }, 154 expected: "1 -> null", 155 }, 156 "primitive_update_from_null": { 157 diff: computed.Diff{ 158 Renderer: Primitive(nil, 1.0, cty.Number), 159 Action: plans.Update, 160 }, 161 expected: "null -> 1", 162 }, 163 "primitive_update": { 164 diff: computed.Diff{ 165 Renderer: Primitive(0.0, 1.0, cty.Number), 166 Action: plans.Update, 167 }, 168 expected: "0 -> 1", 169 }, 170 "primitive_update_long_float": { 171 diff: computed.Diff{ 172 Renderer: Primitive(123456789.0, 987654321.0, cty.Number), 173 Action: plans.Update, 174 }, 175 expected: "123456789 -> 987654321", 176 }, 177 "primitive_update_replace": { 178 diff: computed.Diff{ 179 Renderer: Primitive(0.0, 1.0, cty.Number), 180 Action: plans.Update, 181 Replace: true, 182 }, 183 expected: "0 -> 1 # forces replacement", 184 }, 185 "primitive_multiline_string_create": { 186 diff: computed.Diff{ 187 Renderer: Primitive(nil, "hello\nworld", cty.String), 188 Action: plans.Create, 189 }, 190 expected: ` 191 <<-EOT 192 hello 193 world 194 EOT 195 `, 196 }, 197 "primitive_multiline_string_delete": { 198 diff: computed.Diff{ 199 Renderer: Primitive("hello\nworld", nil, cty.String), 200 Action: plans.Delete, 201 }, 202 expected: ` 203 <<-EOT 204 hello 205 world 206 EOT -> null 207 `, 208 }, 209 "primitive_multiline_string_update": { 210 diff: computed.Diff{ 211 Renderer: Primitive("hello\nold\nworld", "hello\nnew\nworld", cty.String), 212 Action: plans.Update, 213 }, 214 expected: ` 215 <<-EOT 216 hello 217 - old 218 + new 219 world 220 EOT 221 `, 222 }, 223 "primitive_json_string_create": { 224 diff: computed.Diff{ 225 Renderer: Primitive(nil, "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String), 226 Action: plans.Create, 227 }, 228 expected: ` 229 jsonencode( 230 { 231 + key_one = "value_one" 232 + key_two = "value_two" 233 } 234 ) 235 `, 236 }, 237 "primitive_json_string_delete": { 238 diff: computed.Diff{ 239 Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", nil, cty.String), 240 Action: plans.Delete, 241 }, 242 expected: ` 243 jsonencode( 244 { 245 - key_one = "value_one" 246 - key_two = "value_two" 247 } 248 ) -> null 249 `, 250 }, 251 "primitive_json_string_update": { 252 diff: computed.Diff{ 253 Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"}", cty.String), 254 Action: plans.Update, 255 }, 256 expected: ` 257 jsonencode( 258 ~ { 259 + key_three = "value_three" 260 # (2 unchanged attributes hidden) 261 } 262 ) 263 `, 264 }, 265 "primitive_json_explicit_nulls": { 266 diff: computed.Diff{ 267 Renderer: Primitive("{\"key_one\":\"value_one\",\"key_two\":\"value_two\"}", "{\"key_one\":null}", cty.String), 268 Action: plans.Update, 269 }, 270 expected: ` 271 jsonencode( 272 ~ { 273 ~ key_one = "value_one" -> null 274 - key_two = "value_two" 275 } 276 ) 277 `, 278 }, 279 "primitive_fake_json_string_update": { 280 diff: computed.Diff{ 281 // This isn't valid JSON, our renderer should be okay with it. 282 Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\",\"key_three\":\"value_three\"", cty.String), 283 Action: plans.Update, 284 }, 285 expected: "\"{\\\"key_one\\\": \\\"value_one\\\",\\\"key_two\\\":\\\"value_two\\\"\" -> \"{\\\"key_one\\\": \\\"value_one\\\",\\\"key_two\\\":\\\"value_two\\\",\\\"key_three\\\":\\\"value_three\\\"\"", 286 }, 287 "primitive_multiline_to_json_update": { 288 diff: computed.Diff{ 289 Renderer: Primitive("hello\nworld", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String), 290 Action: plans.Update, 291 }, 292 expected: ` 293 <<-EOT 294 hello 295 world 296 EOT -> jsonencode( 297 { 298 + key_one = "value_one" 299 + key_two = "value_two" 300 } 301 ) 302 `, 303 }, 304 "primitive_json_to_multiline_update": { 305 diff: computed.Diff{ 306 Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "hello\nworld", cty.String), 307 Action: plans.Update, 308 }, 309 expected: ` 310 jsonencode( 311 { 312 - key_one = "value_one" 313 - key_two = "value_two" 314 } 315 ) -> <<-EOT 316 hello 317 world 318 EOT 319 `, 320 }, 321 "primitive_json_to_string_update": { 322 diff: computed.Diff{ 323 Renderer: Primitive("{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", "hello world", cty.String), 324 Action: plans.Update, 325 }, 326 expected: ` 327 jsonencode( 328 { 329 - key_one = "value_one" 330 - key_two = "value_two" 331 } 332 ) -> "hello world" 333 `, 334 }, 335 "primitive_string_to_json_update": { 336 diff: computed.Diff{ 337 Renderer: Primitive("hello world", "{\"key_one\": \"value_one\",\"key_two\":\"value_two\"}", cty.String), 338 Action: plans.Update, 339 }, 340 expected: ` 341 "hello world" -> jsonencode( 342 { 343 + key_one = "value_one" 344 + key_two = "value_two" 345 } 346 ) 347 `, 348 }, 349 "primitive_multi_to_single_update": { 350 diff: computed.Diff{ 351 Renderer: Primitive("hello\nworld", "hello world", cty.String), 352 Action: plans.Update, 353 }, 354 expected: ` 355 <<-EOT 356 - hello 357 - world 358 + hello world 359 EOT 360 `, 361 }, 362 "primitive_single_to_multi_update": { 363 diff: computed.Diff{ 364 Renderer: Primitive("hello world", "hello\nworld", cty.String), 365 Action: plans.Update, 366 }, 367 expected: ` 368 <<-EOT 369 - hello world 370 + hello 371 + world 372 EOT 373 `, 374 }, 375 "sensitive_update": { 376 diff: computed.Diff{ 377 Renderer: Sensitive(computed.Diff{ 378 Renderer: Primitive(0.0, 1.0, cty.Number), 379 Action: plans.Update, 380 }, true, true), 381 Action: plans.Update, 382 }, 383 expected: "(sensitive value)", 384 }, 385 "sensitive_update_replace": { 386 diff: computed.Diff{ 387 Renderer: Sensitive(computed.Diff{ 388 Renderer: Primitive(0.0, 1.0, cty.Number), 389 Action: plans.Update, 390 Replace: true, 391 }, true, true), 392 Action: plans.Update, 393 Replace: true, 394 }, 395 expected: "(sensitive value) # forces replacement", 396 }, 397 "computed_create": { 398 diff: computed.Diff{ 399 Renderer: Unknown(computed.Diff{}), 400 Action: plans.Create, 401 }, 402 expected: "(known after apply)", 403 }, 404 "computed_update": { 405 diff: computed.Diff{ 406 Renderer: Unknown(computed.Diff{ 407 Renderer: Primitive(0.0, nil, cty.Number), 408 Action: plans.Delete, 409 }), 410 Action: plans.Update, 411 }, 412 expected: "0 -> (known after apply)", 413 }, 414 "computed_create_forces_replacement": { 415 diff: computed.Diff{ 416 Renderer: Unknown(computed.Diff{}), 417 Action: plans.Create, 418 Replace: true, 419 }, 420 expected: "(known after apply) # forces replacement", 421 }, 422 "computed_update_forces_replacement": { 423 diff: computed.Diff{ 424 Renderer: Unknown(computed.Diff{ 425 Renderer: Primitive(0.0, nil, cty.Number), 426 Action: plans.Delete, 427 }), 428 Action: plans.Update, 429 Replace: true, 430 }, 431 expected: "0 -> (known after apply) # forces replacement", 432 }, 433 "object_created": { 434 diff: computed.Diff{ 435 Renderer: Object(map[string]computed.Diff{}), 436 Action: plans.Create, 437 }, 438 expected: "{}", 439 }, 440 "object_created_with_attributes": { 441 diff: computed.Diff{ 442 Renderer: Object(map[string]computed.Diff{ 443 "attribute_one": { 444 Renderer: Primitive(nil, 0.0, cty.Number), 445 Action: plans.Create, 446 }, 447 }), 448 Action: plans.Create, 449 }, 450 expected: ` 451 { 452 + attribute_one = 0 453 } 454 `, 455 }, 456 "object_deleted": { 457 diff: computed.Diff{ 458 Renderer: Object(map[string]computed.Diff{}), 459 Action: plans.Delete, 460 }, 461 expected: "{} -> null", 462 }, 463 "object_deleted_with_attributes": { 464 diff: computed.Diff{ 465 Renderer: Object(map[string]computed.Diff{ 466 "attribute_one": { 467 Renderer: Primitive(0.0, nil, cty.Number), 468 Action: plans.Delete, 469 }, 470 }), 471 Action: plans.Delete, 472 }, 473 expected: ` 474 { 475 - attribute_one = 0 476 } -> null 477 `, 478 }, 479 "nested_object_deleted": { 480 diff: computed.Diff{ 481 Renderer: NestedObject(map[string]computed.Diff{}), 482 Action: plans.Delete, 483 }, 484 expected: "{} -> null", 485 }, 486 "nested_object_deleted_with_attributes": { 487 diff: computed.Diff{ 488 Renderer: NestedObject(map[string]computed.Diff{ 489 "attribute_one": { 490 Renderer: Primitive(0.0, nil, cty.Number), 491 Action: plans.Delete, 492 }, 493 }), 494 Action: plans.Delete, 495 }, 496 expected: ` 497 { 498 - attribute_one = 0 -> null 499 } -> null 500 `, 501 }, 502 "object_create_attribute": { 503 diff: computed.Diff{ 504 Renderer: Object(map[string]computed.Diff{ 505 "attribute_one": { 506 Renderer: Primitive(nil, 0.0, cty.Number), 507 Action: plans.Create, 508 }, 509 }), 510 Action: plans.Update, 511 }, 512 expected: ` 513 { 514 + attribute_one = 0 515 } 516 `, 517 }, 518 "object_update_attribute": { 519 diff: computed.Diff{ 520 Renderer: Object(map[string]computed.Diff{ 521 "attribute_one": { 522 Renderer: Primitive(0.0, 1.0, cty.Number), 523 Action: plans.Update, 524 }, 525 }), 526 Action: plans.Update, 527 }, 528 expected: ` 529 { 530 ~ attribute_one = 0 -> 1 531 } 532 `, 533 }, 534 "object_update_attribute_forces_replacement": { 535 diff: computed.Diff{ 536 Renderer: Object(map[string]computed.Diff{ 537 "attribute_one": { 538 Renderer: Primitive(0.0, 1.0, cty.Number), 539 Action: plans.Update, 540 }, 541 }), 542 Action: plans.Update, 543 Replace: true, 544 }, 545 expected: ` 546 { # forces replacement 547 ~ attribute_one = 0 -> 1 548 } 549 `, 550 }, 551 "object_delete_attribute": { 552 diff: computed.Diff{ 553 Renderer: Object(map[string]computed.Diff{ 554 "attribute_one": { 555 Renderer: Primitive(0.0, nil, cty.Number), 556 Action: plans.Delete, 557 }, 558 }), 559 Action: plans.Update, 560 }, 561 expected: ` 562 { 563 - attribute_one = 0 564 } 565 `, 566 }, 567 "object_ignore_unchanged_attributes": { 568 diff: computed.Diff{ 569 Renderer: Object(map[string]computed.Diff{ 570 "attribute_one": { 571 Renderer: Primitive(0.0, 1.0, cty.Number), 572 Action: plans.Update, 573 }, 574 "attribute_two": { 575 Renderer: Primitive(0.0, 0.0, cty.Number), 576 Action: plans.NoOp, 577 }, 578 "attribute_three": { 579 Renderer: Primitive(nil, 1.0, cty.Number), 580 Action: plans.Create, 581 }, 582 }), 583 Action: plans.Update, 584 }, 585 expected: ` 586 { 587 ~ attribute_one = 0 -> 1 588 + attribute_three = 1 589 # (1 unchanged attribute hidden) 590 } 591 `, 592 }, 593 "object_create_sensitive_attribute": { 594 diff: computed.Diff{ 595 Renderer: Object(map[string]computed.Diff{ 596 "attribute_one": { 597 Renderer: Sensitive(computed.Diff{ 598 Renderer: Primitive(nil, 1.0, cty.Number), 599 Action: plans.Create, 600 }, false, true), 601 Action: plans.Create, 602 }, 603 }), 604 Action: plans.Update, 605 }, 606 expected: ` 607 { 608 + attribute_one = (sensitive value) 609 } 610 `, 611 }, 612 "object_update_sensitive_attribute": { 613 diff: computed.Diff{ 614 Renderer: Object(map[string]computed.Diff{ 615 "attribute_one": { 616 Renderer: Sensitive(computed.Diff{ 617 Renderer: Primitive(0.0, 1.0, cty.Number), 618 Action: plans.Update, 619 }, true, true), 620 Action: plans.Update, 621 }, 622 }), 623 Action: plans.Update, 624 }, 625 expected: ` 626 { 627 ~ attribute_one = (sensitive value) 628 } 629 `, 630 }, 631 "object_delete_sensitive_attribute": { 632 diff: computed.Diff{ 633 Renderer: Object(map[string]computed.Diff{ 634 "attribute_one": { 635 Renderer: Sensitive(computed.Diff{ 636 Renderer: Primitive(0.0, nil, cty.Number), 637 Action: plans.Delete, 638 }, true, false), 639 Action: plans.Delete, 640 }, 641 }), 642 Action: plans.Update, 643 }, 644 expected: ` 645 { 646 - attribute_one = (sensitive value) 647 } 648 `, 649 }, 650 "object_create_computed_attribute": { 651 diff: computed.Diff{ 652 Renderer: Object(map[string]computed.Diff{ 653 "attribute_one": { 654 Renderer: Unknown(computed.Diff{Renderer: nil}), 655 Action: plans.Create, 656 }, 657 }), 658 Action: plans.Update, 659 }, 660 expected: ` 661 { 662 + attribute_one = (known after apply) 663 } 664 `, 665 }, 666 "object_update_computed_attribute": { 667 diff: computed.Diff{ 668 Renderer: Object(map[string]computed.Diff{ 669 "attribute_one": { 670 Renderer: Unknown(computed.Diff{ 671 Renderer: Primitive(1.0, nil, cty.Number), 672 Action: plans.Delete, 673 }), 674 Action: plans.Update, 675 }, 676 }), 677 Action: plans.Update, 678 }, 679 expected: ` 680 { 681 ~ attribute_one = 1 -> (known after apply) 682 } 683 `, 684 }, 685 "object_escapes_attribute_keys": { 686 diff: computed.Diff{ 687 Renderer: Object(map[string]computed.Diff{ 688 "attribute_one": { 689 Renderer: Primitive(1.0, 2.0, cty.Number), 690 Action: plans.Update, 691 }, 692 "attribute:two": { 693 Renderer: Primitive(2.0, 3.0, cty.Number), 694 Action: plans.Update, 695 }, 696 "attribute_six": { 697 Renderer: Primitive(3.0, 4.0, cty.Number), 698 Action: plans.Update, 699 }, 700 }), 701 Action: plans.Update, 702 }, 703 expected: ` 704 { 705 ~ "attribute:two" = 2 -> 3 706 ~ attribute_one = 1 -> 2 707 ~ attribute_six = 3 -> 4 708 } 709 `, 710 }, 711 "map_create_empty": { 712 diff: computed.Diff{ 713 Renderer: Map(map[string]computed.Diff{}), 714 Action: plans.Create, 715 }, 716 expected: "{}", 717 }, 718 "map_create": { 719 diff: computed.Diff{ 720 Renderer: Map(map[string]computed.Diff{ 721 "element_one": { 722 Renderer: Primitive(nil, "new", cty.String), 723 Action: plans.Create, 724 }, 725 }), 726 Action: plans.Create, 727 }, 728 expected: ` 729 { 730 + "element_one" = "new" 731 } 732 `, 733 }, 734 "map_delete_empty": { 735 diff: computed.Diff{ 736 Renderer: Map(map[string]computed.Diff{}), 737 Action: plans.Delete, 738 }, 739 expected: "{} -> null", 740 }, 741 "map_delete": { 742 diff: computed.Diff{ 743 Renderer: Map(map[string]computed.Diff{ 744 "element_one": { 745 Renderer: Primitive("old", nil, cty.String), 746 Action: plans.Delete, 747 }, 748 }), 749 Action: plans.Delete, 750 }, 751 expected: ` 752 { 753 - "element_one" = "old" 754 } -> null 755 `, 756 }, 757 "map_create_element": { 758 diff: computed.Diff{ 759 Renderer: Map(map[string]computed.Diff{ 760 "element_one": { 761 Renderer: Primitive(nil, "new", cty.String), 762 Action: plans.Create, 763 }, 764 }), 765 Action: plans.Update, 766 }, 767 expected: ` 768 { 769 + "element_one" = "new" 770 } 771 `, 772 }, 773 "map_update_element": { 774 diff: computed.Diff{ 775 Renderer: Map(map[string]computed.Diff{ 776 "element_one": { 777 Renderer: Primitive("old", "new", cty.String), 778 Action: plans.Update, 779 }, 780 }), 781 Action: plans.Update, 782 }, 783 expected: ` 784 { 785 ~ "element_one" = "old" -> "new" 786 } 787 `, 788 }, 789 "map_delete_element": { 790 diff: computed.Diff{ 791 Renderer: Map(map[string]computed.Diff{ 792 "element_one": { 793 Renderer: Primitive("old", nil, cty.String), 794 Action: plans.Delete, 795 }, 796 }), 797 Action: plans.Update, 798 }, 799 expected: ` 800 { 801 - "element_one" = "old" -> null 802 } 803 `, 804 }, 805 "map_update_forces_replacement": { 806 diff: computed.Diff{ 807 Renderer: Map(map[string]computed.Diff{ 808 "element_one": { 809 Renderer: Primitive("old", "new", cty.String), 810 Action: plans.Update, 811 }, 812 }), 813 Action: plans.Update, 814 Replace: true, 815 }, 816 expected: ` 817 { # forces replacement 818 ~ "element_one" = "old" -> "new" 819 } 820 `, 821 }, 822 "map_ignore_unchanged_elements": { 823 diff: computed.Diff{ 824 Renderer: Map(map[string]computed.Diff{ 825 "element_one": { 826 Renderer: Primitive(nil, "new", cty.String), 827 Action: plans.Create, 828 }, 829 "element_two": { 830 Renderer: Primitive("old", "old", cty.String), 831 Action: plans.NoOp, 832 }, 833 "element_three": { 834 Renderer: Primitive("old", "new", cty.String), 835 Action: plans.Update, 836 }, 837 }), 838 Action: plans.Update, 839 }, 840 expected: ` 841 { 842 + "element_one" = "new" 843 ~ "element_three" = "old" -> "new" 844 # (1 unchanged element hidden) 845 } 846 `, 847 }, 848 "map_create_sensitive_element": { 849 diff: computed.Diff{ 850 Renderer: Map(map[string]computed.Diff{ 851 "element_one": { 852 Renderer: Sensitive(computed.Diff{ 853 Renderer: Primitive(nil, 1.0, cty.Number), 854 Action: plans.Create, 855 }, false, true), 856 Action: plans.Create, 857 }, 858 }), 859 Action: plans.Update, 860 }, 861 expected: ` 862 { 863 + "element_one" = (sensitive value) 864 } 865 `, 866 }, 867 "map_update_sensitive_element": { 868 diff: computed.Diff{ 869 Renderer: Map(map[string]computed.Diff{ 870 "element_one": { 871 Renderer: Sensitive(computed.Diff{ 872 Renderer: Primitive(0.0, 1.0, cty.Number), 873 Action: plans.Update, 874 }, true, true), 875 Action: plans.Update, 876 }, 877 }), 878 Action: plans.Update, 879 }, 880 expected: ` 881 { 882 ~ "element_one" = (sensitive value) 883 } 884 `, 885 }, 886 "map_update_sensitive_element_status": { 887 diff: computed.Diff{ 888 Renderer: Map(map[string]computed.Diff{ 889 "element_one": { 890 Renderer: Sensitive(computed.Diff{ 891 Renderer: Primitive(0.0, 0.0, cty.Number), 892 Action: plans.NoOp, 893 }, true, false), 894 Action: plans.Update, 895 }, 896 }), 897 Action: plans.Update, 898 }, 899 expected: ` 900 { 901 # Warning: this attribute value will no longer be marked as sensitive 902 # after applying this change. The value is unchanged. 903 ~ "element_one" = (sensitive value) 904 } 905 `, 906 }, 907 "map_delete_sensitive_element": { 908 diff: computed.Diff{ 909 Renderer: Map(map[string]computed.Diff{ 910 "element_one": { 911 Renderer: Sensitive(computed.Diff{ 912 Renderer: Primitive(0.0, nil, cty.Number), 913 Action: plans.Delete, 914 }, true, false), 915 Action: plans.Delete, 916 }, 917 }), 918 Action: plans.Update, 919 }, 920 expected: ` 921 { 922 - "element_one" = (sensitive value) -> null 923 } 924 `, 925 }, 926 "map_create_computed_element": { 927 diff: computed.Diff{ 928 Renderer: Map(map[string]computed.Diff{ 929 "element_one": { 930 Renderer: Unknown(computed.Diff{}), 931 Action: plans.Create, 932 }, 933 }), 934 Action: plans.Update, 935 }, 936 expected: ` 937 { 938 + "element_one" = (known after apply) 939 } 940 `, 941 }, 942 "map_update_computed_element": { 943 diff: computed.Diff{ 944 Renderer: Map(map[string]computed.Diff{ 945 "element_one": { 946 Renderer: Unknown(computed.Diff{ 947 Renderer: Primitive(1.0, nil, cty.Number), 948 Action: plans.Delete, 949 }), 950 Action: plans.Update, 951 }, 952 }), 953 Action: plans.Update, 954 }, 955 expected: ` 956 { 957 ~ "element_one" = 1 -> (known after apply) 958 } 959 `, 960 }, 961 "map_aligns_key": { 962 diff: computed.Diff{ 963 Renderer: Map(map[string]computed.Diff{ 964 "element_one": { 965 Renderer: Primitive(1.0, 2.0, cty.Number), 966 Action: plans.Update, 967 }, 968 "element_two": { 969 Renderer: Primitive(1.0, 3.0, cty.Number), 970 Action: plans.Update, 971 }, 972 "element_three": { 973 Renderer: Primitive(1.0, 4.0, cty.Number), 974 Action: plans.Update, 975 }, 976 }), 977 Action: plans.Update, 978 }, 979 expected: ` 980 { 981 ~ "element_one" = 1 -> 2 982 ~ "element_three" = 1 -> 4 983 ~ "element_two" = 1 -> 3 984 } 985 `, 986 }, 987 "nested_map_does_not_align_keys": { 988 diff: computed.Diff{ 989 Renderer: NestedMap(map[string]computed.Diff{ 990 "element_one": { 991 Renderer: Primitive(1.0, 2.0, cty.Number), 992 Action: plans.Update, 993 }, 994 "element_two": { 995 Renderer: Primitive(1.0, 3.0, cty.Number), 996 Action: plans.Update, 997 }, 998 "element_three": { 999 Renderer: Primitive(1.0, 4.0, cty.Number), 1000 Action: plans.Update, 1001 }, 1002 }), 1003 Action: plans.Update, 1004 }, 1005 expected: ` 1006 { 1007 ~ "element_one" = 1 -> 2 1008 ~ "element_three" = 1 -> 4 1009 ~ "element_two" = 1 -> 3 1010 } 1011 `, 1012 }, 1013 "list_create_empty": { 1014 diff: computed.Diff{ 1015 Renderer: List([]computed.Diff{}), 1016 Action: plans.Create, 1017 }, 1018 expected: "[]", 1019 }, 1020 "list_create": { 1021 diff: computed.Diff{ 1022 Renderer: List([]computed.Diff{ 1023 { 1024 Renderer: Primitive(nil, 1.0, cty.Number), 1025 Action: plans.Create, 1026 }, 1027 }), 1028 Action: plans.Create, 1029 }, 1030 expected: ` 1031 [ 1032 + 1, 1033 ] 1034 `, 1035 }, 1036 "list_delete_empty": { 1037 diff: computed.Diff{ 1038 Renderer: List([]computed.Diff{}), 1039 Action: plans.Delete, 1040 }, 1041 expected: "[] -> null", 1042 }, 1043 "list_delete": { 1044 diff: computed.Diff{ 1045 Renderer: List([]computed.Diff{ 1046 { 1047 Renderer: Primitive(1.0, nil, cty.Number), 1048 Action: plans.Delete, 1049 }, 1050 }), 1051 Action: plans.Delete, 1052 }, 1053 expected: ` 1054 [ 1055 - 1, 1056 ] -> null 1057 `, 1058 }, 1059 "list_create_element": { 1060 diff: computed.Diff{ 1061 Renderer: List([]computed.Diff{ 1062 { 1063 Renderer: Primitive(nil, 1.0, cty.Number), 1064 Action: plans.Create, 1065 }, 1066 }), 1067 Action: plans.Update, 1068 }, 1069 expected: ` 1070 [ 1071 + 1, 1072 ] 1073 `, 1074 }, 1075 "list_update_element": { 1076 diff: computed.Diff{ 1077 Renderer: List([]computed.Diff{ 1078 { 1079 Renderer: Primitive(0.0, 1.0, cty.Number), 1080 Action: plans.Update, 1081 }, 1082 }), 1083 Action: plans.Update, 1084 }, 1085 expected: ` 1086 [ 1087 ~ 0 -> 1, 1088 ] 1089 `, 1090 }, 1091 "list_replace_element": { 1092 diff: computed.Diff{ 1093 Renderer: List([]computed.Diff{ 1094 { 1095 Renderer: Primitive(0.0, nil, cty.Number), 1096 Action: plans.Delete, 1097 }, 1098 { 1099 Renderer: Primitive(nil, 1.0, cty.Number), 1100 Action: plans.Create, 1101 }, 1102 }), 1103 Action: plans.Update, 1104 }, 1105 expected: ` 1106 [ 1107 - 0, 1108 + 1, 1109 ] 1110 `, 1111 }, 1112 "list_delete_element": { 1113 diff: computed.Diff{ 1114 Renderer: List([]computed.Diff{ 1115 { 1116 Renderer: Primitive(0.0, nil, cty.Number), 1117 Action: plans.Delete, 1118 }, 1119 }), 1120 Action: plans.Update, 1121 }, 1122 expected: ` 1123 [ 1124 - 0, 1125 ] 1126 `, 1127 }, 1128 "list_update_forces_replacement": { 1129 diff: computed.Diff{ 1130 Renderer: List([]computed.Diff{ 1131 { 1132 Renderer: Primitive(0.0, 1.0, cty.Number), 1133 Action: plans.Update, 1134 }, 1135 }), 1136 Action: plans.Update, 1137 Replace: true, 1138 }, 1139 expected: ` 1140 [ # forces replacement 1141 ~ 0 -> 1, 1142 ] 1143 `, 1144 }, 1145 "list_update_ignores_unchanged": { 1146 diff: computed.Diff{ 1147 Renderer: NestedList([]computed.Diff{ 1148 { 1149 Renderer: Primitive(0.0, 0.0, cty.Number), 1150 Action: plans.NoOp, 1151 }, 1152 { 1153 Renderer: Primitive(1.0, 1.0, cty.Number), 1154 Action: plans.NoOp, 1155 }, 1156 { 1157 Renderer: Primitive(2.0, 5.0, cty.Number), 1158 Action: plans.Update, 1159 }, 1160 { 1161 Renderer: Primitive(3.0, 3.0, cty.Number), 1162 Action: plans.NoOp, 1163 }, 1164 { 1165 Renderer: Primitive(4.0, 4.0, cty.Number), 1166 Action: plans.NoOp, 1167 }, 1168 }), 1169 Action: plans.Update, 1170 }, 1171 expected: ` 1172 [ 1173 ~ 2 -> 5, 1174 # (4 unchanged elements hidden) 1175 ] 1176 `, 1177 }, 1178 "list_update_ignored_unchanged_with_context": { 1179 diff: computed.Diff{ 1180 Renderer: List([]computed.Diff{ 1181 { 1182 Renderer: Primitive(0.0, 0.0, cty.Number), 1183 Action: plans.NoOp, 1184 }, 1185 { 1186 Renderer: Primitive(1.0, 1.0, cty.Number), 1187 Action: plans.NoOp, 1188 }, 1189 { 1190 Renderer: Primitive(2.0, 5.0, cty.Number), 1191 Action: plans.Update, 1192 }, 1193 { 1194 Renderer: Primitive(3.0, 3.0, cty.Number), 1195 Action: plans.NoOp, 1196 }, 1197 { 1198 Renderer: Primitive(4.0, 4.0, cty.Number), 1199 Action: plans.NoOp, 1200 }, 1201 }), 1202 Action: plans.Update, 1203 }, 1204 expected: ` 1205 [ 1206 # (1 unchanged element hidden) 1207 1, 1208 ~ 2 -> 5, 1209 3, 1210 # (1 unchanged element hidden) 1211 ] 1212 `, 1213 }, 1214 "list_create_sensitive_element": { 1215 diff: computed.Diff{ 1216 Renderer: List([]computed.Diff{ 1217 { 1218 Renderer: Sensitive(computed.Diff{ 1219 Renderer: Primitive(nil, 1.0, cty.Number), 1220 Action: plans.Create, 1221 }, false, true), 1222 Action: plans.Create, 1223 }, 1224 }), 1225 Action: plans.Update, 1226 }, 1227 expected: ` 1228 [ 1229 + (sensitive value), 1230 ] 1231 `, 1232 }, 1233 "list_delete_sensitive_element": { 1234 diff: computed.Diff{ 1235 Renderer: List([]computed.Diff{ 1236 { 1237 Renderer: Sensitive(computed.Diff{ 1238 Renderer: Primitive(1.0, nil, cty.Number), 1239 Action: plans.Delete, 1240 }, true, false), 1241 Action: plans.Delete, 1242 }, 1243 }), 1244 Action: plans.Update, 1245 }, 1246 expected: ` 1247 [ 1248 - (sensitive value), 1249 ] 1250 `, 1251 }, 1252 "list_update_sensitive_element": { 1253 diff: computed.Diff{ 1254 Renderer: List([]computed.Diff{ 1255 { 1256 Renderer: Sensitive(computed.Diff{ 1257 Renderer: Primitive(0.0, 1.0, cty.Number), 1258 Action: plans.Update, 1259 }, true, true), 1260 Action: plans.Update, 1261 }, 1262 }), 1263 Action: plans.Update, 1264 }, 1265 expected: ` 1266 [ 1267 ~ (sensitive value), 1268 ] 1269 `, 1270 }, 1271 "list_update_sensitive_element_status": { 1272 diff: computed.Diff{ 1273 Renderer: List([]computed.Diff{ 1274 { 1275 Renderer: Sensitive(computed.Diff{ 1276 Renderer: Primitive(1.0, 1.0, cty.Number), 1277 Action: plans.NoOp, 1278 }, false, true), 1279 Action: plans.Update, 1280 }, 1281 }), 1282 Action: plans.Update, 1283 }, 1284 expected: ` 1285 [ 1286 # Warning: this attribute value will be marked as sensitive and will not 1287 # display in UI output after applying this change. The value is unchanged. 1288 ~ (sensitive value), 1289 ] 1290 `, 1291 }, 1292 "list_create_computed_element": { 1293 diff: computed.Diff{ 1294 Renderer: List([]computed.Diff{ 1295 { 1296 Renderer: Unknown(computed.Diff{}), 1297 Action: plans.Create, 1298 }, 1299 }), 1300 Action: plans.Update, 1301 }, 1302 expected: ` 1303 [ 1304 + (known after apply), 1305 ] 1306 `, 1307 }, 1308 "list_update_computed_element": { 1309 diff: computed.Diff{ 1310 Renderer: List([]computed.Diff{ 1311 { 1312 Renderer: Unknown(computed.Diff{ 1313 Renderer: Primitive(0.0, nil, cty.Number), 1314 Action: plans.Delete, 1315 }), 1316 Action: plans.Update, 1317 }, 1318 }), 1319 Action: plans.Update, 1320 }, 1321 expected: ` 1322 [ 1323 ~ 0 -> (known after apply), 1324 ] 1325 `, 1326 }, 1327 "set_create_empty": { 1328 diff: computed.Diff{ 1329 Renderer: Set([]computed.Diff{}), 1330 Action: plans.Create, 1331 }, 1332 expected: "[]", 1333 }, 1334 "set_create": { 1335 diff: computed.Diff{ 1336 Renderer: Set([]computed.Diff{ 1337 { 1338 Renderer: Primitive(nil, 1.0, cty.Number), 1339 Action: plans.Create, 1340 }, 1341 }), 1342 Action: plans.Create, 1343 }, 1344 expected: ` 1345 [ 1346 + 1, 1347 ] 1348 `, 1349 }, 1350 "set_delete_empty": { 1351 diff: computed.Diff{ 1352 Renderer: Set([]computed.Diff{}), 1353 Action: plans.Delete, 1354 }, 1355 expected: "[] -> null", 1356 }, 1357 "set_delete": { 1358 diff: computed.Diff{ 1359 Renderer: Set([]computed.Diff{ 1360 { 1361 Renderer: Primitive(1.0, nil, cty.Number), 1362 Action: plans.Delete, 1363 }, 1364 }), 1365 Action: plans.Delete, 1366 }, 1367 expected: ` 1368 [ 1369 - 1, 1370 ] -> null 1371 `, 1372 }, 1373 "set_create_element": { 1374 diff: computed.Diff{ 1375 Renderer: Set([]computed.Diff{ 1376 { 1377 Renderer: Primitive(nil, 1.0, cty.Number), 1378 Action: plans.Create, 1379 }, 1380 }), 1381 Action: plans.Update, 1382 }, 1383 expected: ` 1384 [ 1385 + 1, 1386 ] 1387 `, 1388 }, 1389 "set_update_element": { 1390 diff: computed.Diff{ 1391 Renderer: Set([]computed.Diff{ 1392 { 1393 Renderer: Primitive(0.0, 1.0, cty.Number), 1394 Action: plans.Update, 1395 }, 1396 }), 1397 Action: plans.Update, 1398 }, 1399 expected: ` 1400 [ 1401 ~ 0 -> 1, 1402 ] 1403 `, 1404 }, 1405 "set_replace_element": { 1406 diff: computed.Diff{ 1407 Renderer: Set([]computed.Diff{ 1408 { 1409 Renderer: Primitive(0.0, nil, cty.Number), 1410 Action: plans.Delete, 1411 }, 1412 { 1413 Renderer: Primitive(nil, 1.0, cty.Number), 1414 Action: plans.Create, 1415 }, 1416 }), 1417 Action: plans.Update, 1418 }, 1419 expected: ` 1420 [ 1421 - 0, 1422 + 1, 1423 ] 1424 `, 1425 }, 1426 "set_delete_element": { 1427 diff: computed.Diff{ 1428 Renderer: Set([]computed.Diff{ 1429 { 1430 Renderer: Primitive(0.0, nil, cty.Number), 1431 Action: plans.Delete, 1432 }, 1433 }), 1434 Action: plans.Update, 1435 }, 1436 expected: ` 1437 [ 1438 - 0, 1439 ] 1440 `, 1441 }, 1442 "set_update_forces_replacement": { 1443 diff: computed.Diff{ 1444 Renderer: Set([]computed.Diff{ 1445 { 1446 Renderer: Primitive(0.0, 1.0, cty.Number), 1447 Action: plans.Update, 1448 }, 1449 }), 1450 Action: plans.Update, 1451 Replace: true, 1452 }, 1453 expected: ` 1454 [ # forces replacement 1455 ~ 0 -> 1, 1456 ] 1457 `, 1458 }, 1459 "nested_set_update_forces_replacement": { 1460 diff: computed.Diff{ 1461 Renderer: NestedSet([]computed.Diff{ 1462 { 1463 Renderer: Object(map[string]computed.Diff{ 1464 "attribute_one": { 1465 Renderer: Primitive(0.0, 1.0, cty.Number), 1466 Action: plans.Update, 1467 }, 1468 }), 1469 Action: plans.Update, 1470 }, 1471 }), 1472 Action: plans.Update, 1473 Replace: true, 1474 }, 1475 expected: ` 1476 [ 1477 ~ { # forces replacement 1478 ~ attribute_one = 0 -> 1 1479 }, 1480 ] 1481 `, 1482 }, 1483 "set_update_ignores_unchanged": { 1484 diff: computed.Diff{ 1485 Renderer: Set([]computed.Diff{ 1486 { 1487 Renderer: Primitive(0.0, 0.0, cty.Number), 1488 Action: plans.NoOp, 1489 }, 1490 { 1491 Renderer: Primitive(1.0, 1.0, cty.Number), 1492 Action: plans.NoOp, 1493 }, 1494 { 1495 Renderer: Primitive(2.0, 5.0, cty.Number), 1496 Action: plans.Update, 1497 }, 1498 { 1499 Renderer: Primitive(3.0, 3.0, cty.Number), 1500 Action: plans.NoOp, 1501 }, 1502 { 1503 Renderer: Primitive(4.0, 4.0, cty.Number), 1504 Action: plans.NoOp, 1505 }, 1506 }), 1507 Action: plans.Update, 1508 }, 1509 expected: ` 1510 [ 1511 ~ 2 -> 5, 1512 # (4 unchanged elements hidden) 1513 ] 1514 `, 1515 }, 1516 "set_create_sensitive_element": { 1517 diff: computed.Diff{ 1518 Renderer: Set([]computed.Diff{ 1519 { 1520 Renderer: Sensitive(computed.Diff{ 1521 Renderer: Primitive(nil, 1.0, cty.Number), 1522 Action: plans.Create, 1523 }, false, true), 1524 Action: plans.Create, 1525 }, 1526 }), 1527 Action: plans.Update, 1528 }, 1529 expected: ` 1530 [ 1531 + (sensitive value), 1532 ] 1533 `, 1534 }, 1535 "set_delete_sensitive_element": { 1536 diff: computed.Diff{ 1537 Renderer: Set([]computed.Diff{ 1538 { 1539 Renderer: Sensitive(computed.Diff{ 1540 Renderer: Primitive(1.0, nil, cty.Number), 1541 Action: plans.Delete, 1542 }, false, true), 1543 Action: plans.Delete, 1544 }, 1545 }), 1546 Action: plans.Update, 1547 }, 1548 expected: ` 1549 [ 1550 - (sensitive value), 1551 ] 1552 `, 1553 }, 1554 "set_update_sensitive_element": { 1555 diff: computed.Diff{ 1556 Renderer: Set([]computed.Diff{ 1557 { 1558 Renderer: Sensitive(computed.Diff{ 1559 Renderer: Primitive(0.0, 1.0, cty.Number), 1560 Action: plans.Update, 1561 }, true, true), 1562 Action: plans.Update, 1563 }, 1564 }), 1565 Action: plans.Update, 1566 }, 1567 expected: ` 1568 [ 1569 ~ (sensitive value), 1570 ] 1571 `, 1572 }, 1573 "set_update_sensitive_element_status": { 1574 diff: computed.Diff{ 1575 Renderer: Set([]computed.Diff{ 1576 { 1577 Renderer: Sensitive(computed.Diff{ 1578 Renderer: Primitive(1.0, 2.0, cty.Number), 1579 Action: plans.Update, 1580 }, false, true), 1581 Action: plans.Update, 1582 }, 1583 }), 1584 Action: plans.Update, 1585 }, 1586 expected: ` 1587 [ 1588 # Warning: this attribute value will be marked as sensitive and will not 1589 # display in UI output after applying this change. 1590 ~ (sensitive value), 1591 ] 1592 `, 1593 }, 1594 "set_create_computed_element": { 1595 diff: computed.Diff{ 1596 Renderer: Set([]computed.Diff{ 1597 { 1598 Renderer: Unknown(computed.Diff{}), 1599 Action: plans.Create, 1600 }, 1601 }), 1602 Action: plans.Update, 1603 }, 1604 expected: ` 1605 [ 1606 + (known after apply), 1607 ] 1608 `, 1609 }, 1610 "set_update_computed_element": { 1611 diff: computed.Diff{ 1612 Renderer: Set([]computed.Diff{ 1613 { 1614 Renderer: Unknown(computed.Diff{ 1615 Renderer: Primitive(0.0, nil, cty.Number), 1616 Action: plans.Delete, 1617 }), 1618 Action: plans.Update, 1619 }, 1620 }), 1621 Action: plans.Update, 1622 }, 1623 expected: ` 1624 [ 1625 ~ 0 -> (known after apply), 1626 ] 1627 `, 1628 }, 1629 "create_empty_block": { 1630 diff: computed.Diff{ 1631 Renderer: Block(nil, Blocks{}), 1632 Action: plans.Create, 1633 }, 1634 expected: "{}", 1635 }, 1636 "create_populated_block": { 1637 diff: computed.Diff{ 1638 Renderer: Block(map[string]computed.Diff{ 1639 "string": { 1640 Renderer: Primitive(nil, "root", cty.String), 1641 Action: plans.Create, 1642 }, 1643 "boolean": { 1644 Renderer: Primitive(nil, true, cty.Bool), 1645 Action: plans.Create, 1646 }, 1647 }, Blocks{ 1648 SingleBlocks: map[string]computed.Diff{ 1649 "nested_block": { 1650 Renderer: Block(map[string]computed.Diff{ 1651 "string": { 1652 Renderer: Primitive(nil, "one", cty.String), 1653 Action: plans.Create, 1654 }, 1655 }, Blocks{}), 1656 Action: plans.Create, 1657 }, 1658 "nested_block_two": { 1659 Renderer: Block(map[string]computed.Diff{ 1660 "string": { 1661 Renderer: Primitive(nil, "two", cty.String), 1662 Action: plans.Create, 1663 }, 1664 }, Blocks{}), 1665 Action: plans.Create, 1666 }, 1667 }, 1668 }), 1669 Action: plans.Create, 1670 }, 1671 expected: ` 1672 { 1673 + boolean = true 1674 + string = "root" 1675 1676 + nested_block { 1677 + string = "one" 1678 } 1679 1680 + nested_block_two { 1681 + string = "two" 1682 } 1683 }`, 1684 }, 1685 "update_empty_block": { 1686 diff: computed.Diff{ 1687 Renderer: Block(map[string]computed.Diff{ 1688 "string": { 1689 Renderer: Primitive(nil, "root", cty.String), 1690 Action: plans.Create, 1691 }, 1692 "boolean": { 1693 Renderer: Primitive(nil, true, cty.Bool), 1694 Action: plans.Create, 1695 }, 1696 }, Blocks{ 1697 SingleBlocks: map[string]computed.Diff{ 1698 "nested_block": { 1699 1700 Renderer: Block(map[string]computed.Diff{ 1701 "string": { 1702 Renderer: Primitive(nil, "one", cty.String), 1703 Action: plans.Create, 1704 }, 1705 }, Blocks{}), 1706 Action: plans.Create, 1707 }, 1708 "nested_block_two": { 1709 1710 Renderer: Block(map[string]computed.Diff{ 1711 "string": { 1712 Renderer: Primitive(nil, "two", cty.String), 1713 Action: plans.Create, 1714 }, 1715 }, Blocks{}), 1716 Action: plans.Create, 1717 }, 1718 }, 1719 }), 1720 Action: plans.Update, 1721 }, 1722 expected: ` 1723 { 1724 + boolean = true 1725 + string = "root" 1726 1727 + nested_block { 1728 + string = "one" 1729 } 1730 1731 + nested_block_two { 1732 + string = "two" 1733 } 1734 }`, 1735 }, 1736 "update_populated_block": { 1737 diff: computed.Diff{ 1738 Renderer: Block(map[string]computed.Diff{ 1739 "string": { 1740 Renderer: Primitive(nil, "root", cty.String), 1741 Action: plans.Create, 1742 }, 1743 "boolean": { 1744 Renderer: Primitive(false, true, cty.Bool), 1745 Action: plans.Update, 1746 }, 1747 }, Blocks{ 1748 SingleBlocks: map[string]computed.Diff{ 1749 "nested_block": { 1750 Renderer: Block(map[string]computed.Diff{ 1751 "string": { 1752 Renderer: Primitive(nil, "one", cty.String), 1753 Action: plans.NoOp, 1754 }, 1755 }, Blocks{}), 1756 Action: plans.NoOp, 1757 }, 1758 "nested_block_two": { 1759 Renderer: Block(map[string]computed.Diff{ 1760 "string": { 1761 Renderer: Primitive(nil, "two", cty.String), 1762 Action: plans.Create, 1763 }, 1764 }, Blocks{}), 1765 Action: plans.Create, 1766 }, 1767 }, 1768 }), 1769 Action: plans.Update, 1770 }, 1771 expected: ` 1772 { 1773 ~ boolean = false -> true 1774 + string = "root" 1775 1776 + nested_block_two { 1777 + string = "two" 1778 } 1779 1780 # (1 unchanged block hidden) 1781 }`, 1782 }, 1783 "clear_populated_block": { 1784 diff: computed.Diff{ 1785 Renderer: Block(map[string]computed.Diff{ 1786 "string": { 1787 Renderer: Primitive("root", nil, cty.String), 1788 Action: plans.Delete, 1789 }, 1790 "boolean": { 1791 Renderer: Primitive(true, nil, cty.Bool), 1792 Action: plans.Delete, 1793 }, 1794 }, Blocks{ 1795 SingleBlocks: map[string]computed.Diff{ 1796 "nested_block": { 1797 Renderer: Block(map[string]computed.Diff{ 1798 "string": { 1799 Renderer: Primitive("one", nil, cty.String), 1800 Action: plans.Delete, 1801 }, 1802 }, Blocks{}), 1803 Action: plans.Delete, 1804 }, 1805 "nested_block_two": { 1806 Renderer: Block(map[string]computed.Diff{ 1807 "string": { 1808 Renderer: Primitive("two", nil, cty.String), 1809 Action: plans.Delete, 1810 }, 1811 }, Blocks{}), 1812 Action: plans.Delete, 1813 }, 1814 }, 1815 }), 1816 Action: plans.Update, 1817 }, 1818 expected: ` 1819 { 1820 - boolean = true -> null 1821 - string = "root" -> null 1822 1823 - nested_block { 1824 - string = "one" -> null 1825 } 1826 1827 - nested_block_two { 1828 - string = "two" -> null 1829 } 1830 }`, 1831 }, 1832 "delete_populated_block": { 1833 diff: computed.Diff{ 1834 Renderer: Block(map[string]computed.Diff{ 1835 "string": { 1836 Renderer: Primitive("root", nil, cty.String), 1837 Action: plans.Delete, 1838 }, 1839 "boolean": { 1840 Renderer: Primitive(true, nil, cty.Bool), 1841 Action: plans.Delete, 1842 }, 1843 }, Blocks{ 1844 SingleBlocks: map[string]computed.Diff{ 1845 "nested_block": { 1846 Renderer: Block(map[string]computed.Diff{ 1847 "string": { 1848 Renderer: Primitive("one", nil, cty.String), 1849 Action: plans.Delete, 1850 }, 1851 }, Blocks{}), 1852 Action: plans.Delete, 1853 }, 1854 "nested_block_two": { 1855 Renderer: Block(map[string]computed.Diff{ 1856 "string": { 1857 Renderer: Primitive("two", nil, cty.String), 1858 Action: plans.Delete, 1859 }, 1860 }, Blocks{}), 1861 Action: plans.Delete, 1862 }, 1863 }, 1864 }), 1865 Action: plans.Delete, 1866 }, 1867 expected: ` 1868 { 1869 - boolean = true -> null 1870 - string = "root" -> null 1871 1872 - nested_block { 1873 - string = "one" -> null 1874 } 1875 1876 - nested_block_two { 1877 - string = "two" -> null 1878 } 1879 }`, 1880 }, 1881 "list_block_update": { 1882 diff: computed.Diff{ 1883 Renderer: Block( 1884 nil, 1885 Blocks{ 1886 ListBlocks: map[string][]computed.Diff{ 1887 "list_blocks": { 1888 { 1889 Renderer: Block(map[string]computed.Diff{ 1890 "number": { 1891 Renderer: Primitive(1.0, 2.0, cty.Number), 1892 Action: plans.Update, 1893 }, 1894 "string": { 1895 Renderer: Primitive(nil, "new", cty.String), 1896 Action: plans.Create, 1897 }, 1898 }, Blocks{}), 1899 Action: plans.Update, 1900 }, 1901 { 1902 Renderer: Block(map[string]computed.Diff{ 1903 "number": { 1904 Renderer: Primitive(1.0, nil, cty.Number), 1905 Action: plans.Delete, 1906 }, 1907 "string": { 1908 Renderer: Primitive("old", "new", cty.String), 1909 Action: plans.Update, 1910 }, 1911 }, Blocks{}), 1912 Action: plans.Update, 1913 }, 1914 }, 1915 }, 1916 }), 1917 }, 1918 expected: ` 1919 { 1920 ~ list_blocks { 1921 ~ number = 1 -> 2 1922 + string = "new" 1923 } 1924 ~ list_blocks { 1925 - number = 1 -> null 1926 ~ string = "old" -> "new" 1927 } 1928 }`, 1929 }, 1930 "set_block_update": { 1931 diff: computed.Diff{ 1932 Renderer: Block( 1933 nil, 1934 Blocks{ 1935 SetBlocks: map[string][]computed.Diff{ 1936 "set_blocks": { 1937 { 1938 Renderer: Block(map[string]computed.Diff{ 1939 "number": { 1940 Renderer: Primitive(1.0, 2.0, cty.Number), 1941 Action: plans.Update, 1942 }, 1943 "string": { 1944 Renderer: Primitive(nil, "new", cty.String), 1945 Action: plans.Create, 1946 }, 1947 }, Blocks{}), 1948 Action: plans.Update, 1949 }, 1950 { 1951 Renderer: Block(map[string]computed.Diff{ 1952 "number": { 1953 Renderer: Primitive(1.0, nil, cty.Number), 1954 Action: plans.Delete, 1955 }, 1956 "string": { 1957 Renderer: Primitive("old", "new", cty.String), 1958 Action: plans.Update, 1959 }, 1960 }, Blocks{}), 1961 Action: plans.Update, 1962 }, 1963 }, 1964 }, 1965 }), 1966 }, 1967 expected: ` 1968 { 1969 ~ set_blocks { 1970 ~ number = 1 -> 2 1971 + string = "new" 1972 } 1973 ~ set_blocks { 1974 - number = 1 -> null 1975 ~ string = "old" -> "new" 1976 } 1977 }`, 1978 }, 1979 "map_block_update": { 1980 diff: computed.Diff{ 1981 Renderer: Block( 1982 nil, 1983 Blocks{ 1984 MapBlocks: map[string]map[string]computed.Diff{ 1985 "list_blocks": { 1986 "key_one": { 1987 Renderer: Block(map[string]computed.Diff{ 1988 "number": { 1989 Renderer: Primitive(1.0, 2.0, cty.Number), 1990 Action: plans.Update, 1991 }, 1992 "string": { 1993 Renderer: Primitive(nil, "new", cty.String), 1994 Action: plans.Create, 1995 }, 1996 }, Blocks{}), 1997 Action: plans.Update, 1998 }, 1999 "key:two": { 2000 Renderer: Block(map[string]computed.Diff{ 2001 "number": { 2002 Renderer: Primitive(1.0, nil, cty.Number), 2003 Action: plans.Delete, 2004 }, 2005 "string": { 2006 Renderer: Primitive("old", "new", cty.String), 2007 Action: plans.Update, 2008 }, 2009 }, Blocks{}), 2010 Action: plans.Update, 2011 }, 2012 }, 2013 }, 2014 }), 2015 }, 2016 expected: ` 2017 { 2018 ~ list_blocks "key:two" { 2019 - number = 1 -> null 2020 ~ string = "old" -> "new" 2021 } 2022 ~ list_blocks "key_one" { 2023 ~ number = 1 -> 2 2024 + string = "new" 2025 } 2026 } 2027 `, 2028 }, 2029 "sensitive_block": { 2030 diff: computed.Diff{ 2031 Renderer: SensitiveBlock(computed.Diff{ 2032 Renderer: Block(nil, Blocks{}), 2033 Action: plans.NoOp, 2034 }, true, true), 2035 Action: plans.Update, 2036 }, 2037 expected: ` 2038 { 2039 # At least one attribute in this block is (or was) sensitive, 2040 # so its contents will not be displayed. 2041 } 2042 `, 2043 }, 2044 "delete_empty_block": { 2045 diff: computed.Diff{ 2046 Renderer: Block(nil, Blocks{}), 2047 Action: plans.Delete, 2048 }, 2049 expected: "{}", 2050 }, 2051 "block_escapes_keys": { 2052 diff: computed.Diff{ 2053 Renderer: Block(map[string]computed.Diff{ 2054 "attribute_one": { 2055 Renderer: Primitive(1.0, 2.0, cty.Number), 2056 Action: plans.Update, 2057 }, 2058 "attribute:two": { 2059 Renderer: Primitive(2.0, 3.0, cty.Number), 2060 Action: plans.Update, 2061 }, 2062 "attribute_six": { 2063 Renderer: Primitive(3.0, 4.0, cty.Number), 2064 Action: plans.Update, 2065 }, 2066 }, Blocks{ 2067 SingleBlocks: map[string]computed.Diff{ 2068 "nested_block:one": { 2069 Renderer: Block(map[string]computed.Diff{ 2070 "string": { 2071 Renderer: Primitive("one", "four", cty.String), 2072 Action: plans.Update, 2073 }, 2074 }, Blocks{}), 2075 Action: plans.Update, 2076 }, 2077 "nested_block_two": { 2078 Renderer: Block(map[string]computed.Diff{ 2079 "string": { 2080 Renderer: Primitive("two", "three", cty.String), 2081 Action: plans.Update, 2082 }, 2083 }, Blocks{}), 2084 Action: plans.Update, 2085 }, 2086 }, 2087 }), 2088 Action: plans.Update, 2089 }, 2090 expected: ` 2091 { 2092 ~ "attribute:two" = 2 -> 3 2093 ~ attribute_one = 1 -> 2 2094 ~ attribute_six = 3 -> 4 2095 2096 ~ "nested_block:one" { 2097 ~ string = "one" -> "four" 2098 } 2099 2100 ~ nested_block_two { 2101 ~ string = "two" -> "three" 2102 } 2103 }`, 2104 }, 2105 "block_always_includes_important_attributes": { 2106 diff: computed.Diff{ 2107 Renderer: Block(map[string]computed.Diff{ 2108 "id": { 2109 Renderer: Primitive("root", "root", cty.String), 2110 Action: plans.NoOp, 2111 }, 2112 "boolean": { 2113 Renderer: Primitive(false, false, cty.Bool), 2114 Action: plans.NoOp, 2115 }, 2116 }, Blocks{ 2117 SingleBlocks: map[string]computed.Diff{ 2118 "nested_block": { 2119 Renderer: Block(map[string]computed.Diff{ 2120 "string": { 2121 Renderer: Primitive("one", "one", cty.String), 2122 Action: plans.NoOp, 2123 }, 2124 }, Blocks{}), 2125 Action: plans.NoOp, 2126 }, 2127 "nested_block_two": { 2128 Renderer: Block(map[string]computed.Diff{ 2129 "string": { 2130 Renderer: Primitive("two", "two", cty.String), 2131 Action: plans.NoOp, 2132 }, 2133 }, Blocks{}), 2134 Action: plans.NoOp, 2135 }, 2136 }, 2137 }), 2138 Action: plans.NoOp, 2139 }, 2140 expected: ` 2141 { 2142 id = "root" 2143 # (1 unchanged attribute hidden) 2144 2145 # (2 unchanged blocks hidden) 2146 }`, 2147 }, 2148 "output_map_to_list": { 2149 diff: computed.Diff{ 2150 Renderer: TypeChange(computed.Diff{ 2151 Renderer: Map(map[string]computed.Diff{ 2152 "element_one": { 2153 Renderer: Primitive(0.0, nil, cty.Number), 2154 Action: plans.Delete, 2155 }, 2156 "element_two": { 2157 Renderer: Primitive(1.0, nil, cty.Number), 2158 Action: plans.Delete, 2159 }, 2160 }), 2161 Action: plans.Delete, 2162 }, computed.Diff{ 2163 Renderer: List([]computed.Diff{ 2164 { 2165 Renderer: Primitive(nil, 0.0, cty.Number), 2166 Action: plans.Create, 2167 }, 2168 { 2169 Renderer: Primitive(nil, 1.0, cty.Number), 2170 Action: plans.Create, 2171 }, 2172 }), 2173 Action: plans.Create, 2174 }), 2175 }, 2176 expected: ` 2177 { 2178 - "element_one" = 0 2179 - "element_two" = 1 2180 } -> [ 2181 + 0, 2182 + 1, 2183 ] 2184 `, 2185 }, 2186 "json_string_no_symbols": { 2187 diff: computed.Diff{ 2188 Renderer: Primitive("{\"key\":\"value\"}", "{\"key\":\"value\"}", cty.String), 2189 Action: plans.NoOp, 2190 }, 2191 opts: computed.RenderHumanOpts{ 2192 HideDiffActionSymbols: true, 2193 ShowUnchangedChildren: true, 2194 }, 2195 expected: ` 2196 jsonencode( 2197 { 2198 key = "value" 2199 } 2200 ) 2201 `, 2202 }, 2203 } 2204 for name, tc := range tcs { 2205 t.Run(name, func(t *testing.T) { 2206 2207 opts := tc.opts.Clone() 2208 opts.Colorize = &colorize 2209 2210 expected := strings.TrimSpace(tc.expected) 2211 actual := tc.diff.RenderHuman(0, opts) 2212 if diff := cmp.Diff(expected, actual); len(diff) > 0 { 2213 t.Fatalf("\nexpected:\n%s\nactual:\n%s\ndiff:\n%s\n", expected, actual, diff) 2214 } 2215 }) 2216 } 2217 }