github.com/hashicorp/hcl/v2@v2.20.0/ext/dynblock/variables_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package dynblock 5 6 import ( 7 "reflect" 8 "testing" 9 10 "github.com/hashicorp/hcl/v2/hcldec" 11 "github.com/zclconf/go-cty/cty" 12 13 "github.com/davecgh/go-spew/spew" 14 15 "github.com/hashicorp/hcl/v2" 16 "github.com/hashicorp/hcl/v2/hclsyntax" 17 ) 18 19 func TestVariables(t *testing.T) { 20 const src = ` 21 22 # We have some references to things inside the "val" attribute inside each 23 # of our "b" blocks, which should be included in the result of WalkVariables 24 # but not WalkExpandVariables. 25 26 a { 27 dynamic "b" { 28 for_each = [for i, v in some_list_0: "${i}=${v},${baz}"] 29 labels = ["${b.value} ${something_else_0}"] 30 content { 31 val = "${b.value} ${something_else_1}" 32 } 33 } 34 } 35 36 dynamic "a" { 37 for_each = some_list_1 38 39 content { 40 b "foo" { 41 val = "${a.value} ${something_else_2}" 42 } 43 44 dynamic "b" { 45 for_each = some_list_2 46 iterator = dyn_b 47 labels = ["${a.value} ${dyn_b.value} ${b} ${something_else_3}"] 48 content { 49 val = "${a.value} ${dyn_b.value} ${something_else_4}" 50 } 51 } 52 } 53 } 54 55 dynamic "a" { 56 for_each = some_list_3 57 iterator = dyn_a 58 59 content { 60 b "foo" { 61 val = "${dyn_a.value} ${something_else_5}" 62 } 63 64 dynamic "b" { 65 for_each = some_list_4 66 labels = ["${dyn_a.value} ${b.value} ${a} ${something_else_6}"] 67 content { 68 val = "${dyn_a.value} ${b.value} ${something_else_7}" 69 } 70 } 71 } 72 } 73 ` 74 75 f, diags := hclsyntax.ParseConfig([]byte(src), "", hcl.Pos{}) 76 if len(diags) != 0 { 77 t.Errorf("unexpected diagnostics during parse") 78 for _, diag := range diags { 79 t.Logf("- %s", diag) 80 } 81 return 82 } 83 84 spec := &hcldec.BlockListSpec{ 85 TypeName: "a", 86 Nested: &hcldec.BlockMapSpec{ 87 TypeName: "b", 88 LabelNames: []string{"key"}, 89 Nested: &hcldec.AttrSpec{ 90 Name: "val", 91 Type: cty.String, 92 }, 93 }, 94 } 95 96 t.Run("WalkVariables", func(t *testing.T) { 97 traversals := VariablesHCLDec(f.Body, spec) 98 got := make([]string, len(traversals)) 99 for i, traversal := range traversals { 100 got[i] = traversal.RootName() 101 } 102 103 // The block structure is traversed one level at a time, so the ordering 104 // here is reflecting first a pass of the root, then the first child 105 // under the root, then the first child under that, etc. 106 want := []string{ 107 "some_list_1", 108 "some_list_3", 109 "some_list_0", 110 "baz", 111 "something_else_0", 112 "something_else_1", // Would not be included for WalkExpandVariables because it only appears in content 113 "some_list_2", 114 "b", // This is correct because it is referenced in a context where the iterator is overridden to be dyn_b 115 "something_else_3", 116 "something_else_2", // Would not be included for WalkExpandVariables because it only appears in content 117 "something_else_4", // Would not be included for WalkExpandVariables because it only appears in content 118 "some_list_4", 119 "a", // This is correct because it is referenced in a context where the iterator is overridden to be dyn_a 120 "something_else_6", 121 "something_else_5", // Would not be included for WalkExpandVariables because it only appears in content 122 "something_else_7", // Would not be included for WalkExpandVariables because it only appears in content 123 } 124 125 if !reflect.DeepEqual(got, want) { 126 t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want)) 127 } 128 }) 129 130 t.Run("WalkExpandVariables", func(t *testing.T) { 131 traversals := ExpandVariablesHCLDec(f.Body, spec) 132 got := make([]string, len(traversals)) 133 for i, traversal := range traversals { 134 got[i] = traversal.RootName() 135 } 136 137 // The block structure is traversed one level at a time, so the ordering 138 // here is reflecting first a pass of the root, then the first child 139 // under the root, then the first child under that, etc. 140 want := []string{ 141 "some_list_1", 142 "some_list_3", 143 "some_list_0", 144 "baz", 145 "something_else_0", 146 "some_list_2", 147 "b", // This is correct because it is referenced in a context where the iterator is overridden to be dyn_b 148 "something_else_3", 149 "some_list_4", 150 "a", // This is correct because it is referenced in a context where the iterator is overridden to be dyn_a 151 "something_else_6", 152 } 153 154 if !reflect.DeepEqual(got, want) { 155 t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want)) 156 } 157 }) 158 }