github.com/opentofu/opentofu@v1.7.1/internal/lang/blocktoattr/variables_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package blocktoattr 7 8 import ( 9 "testing" 10 11 "github.com/google/go-cmp/cmp" 12 "github.com/google/go-cmp/cmp/cmpopts" 13 "github.com/hashicorp/hcl/v2" 14 "github.com/hashicorp/hcl/v2/hclsyntax" 15 hcljson "github.com/hashicorp/hcl/v2/json" 16 "github.com/opentofu/opentofu/internal/configs/configschema" 17 "github.com/zclconf/go-cty/cty" 18 ) 19 20 func TestExpandedVariables(t *testing.T) { 21 fooSchema := &configschema.Block{ 22 Attributes: map[string]*configschema.Attribute{ 23 "foo": { 24 Type: cty.List(cty.Object(map[string]cty.Type{ 25 "bar": cty.String, 26 })), 27 Optional: true, 28 }, 29 "bar": { 30 Type: cty.Map(cty.String), 31 Optional: true, 32 }, 33 }, 34 } 35 36 tests := map[string]struct { 37 src string 38 json bool 39 schema *configschema.Block 40 want []hcl.Traversal 41 }{ 42 "empty": { 43 src: ``, 44 schema: &configschema.Block{}, 45 want: nil, 46 }, 47 "attribute syntax": { 48 src: ` 49 foo = [ 50 { 51 bar = baz 52 }, 53 ] 54 `, 55 schema: fooSchema, 56 want: []hcl.Traversal{ 57 { 58 hcl.TraverseRoot{ 59 Name: "baz", 60 SrcRange: hcl.Range{ 61 Filename: "test.tf", 62 Start: hcl.Pos{Line: 4, Column: 11, Byte: 23}, 63 End: hcl.Pos{Line: 4, Column: 14, Byte: 26}, 64 }, 65 }, 66 }, 67 }, 68 }, 69 "block syntax": { 70 src: ` 71 foo { 72 bar = baz 73 } 74 `, 75 schema: fooSchema, 76 want: []hcl.Traversal{ 77 { 78 hcl.TraverseRoot{ 79 Name: "baz", 80 SrcRange: hcl.Range{ 81 Filename: "test.tf", 82 Start: hcl.Pos{Line: 3, Column: 9, Byte: 15}, 83 End: hcl.Pos{Line: 3, Column: 12, Byte: 18}, 84 }, 85 }, 86 }, 87 }, 88 }, 89 "block syntax with nested blocks": { 90 src: ` 91 foo { 92 bar { 93 boop = baz 94 } 95 } 96 `, 97 schema: &configschema.Block{ 98 Attributes: map[string]*configschema.Attribute{ 99 "foo": { 100 Type: cty.List(cty.Object(map[string]cty.Type{ 101 "bar": cty.List(cty.Object(map[string]cty.Type{ 102 "boop": cty.String, 103 })), 104 })), 105 Optional: true, 106 }, 107 }, 108 }, 109 want: []hcl.Traversal{ 110 { 111 hcl.TraverseRoot{ 112 Name: "baz", 113 SrcRange: hcl.Range{ 114 Filename: "test.tf", 115 Start: hcl.Pos{Line: 4, Column: 12, Byte: 26}, 116 End: hcl.Pos{Line: 4, Column: 15, Byte: 29}, 117 }, 118 }, 119 }, 120 }, 121 }, 122 "dynamic block syntax": { 123 src: ` 124 dynamic "foo" { 125 for_each = beep 126 content { 127 bar = baz 128 } 129 } 130 `, 131 schema: fooSchema, 132 want: []hcl.Traversal{ 133 { 134 hcl.TraverseRoot{ 135 Name: "beep", 136 SrcRange: hcl.Range{ 137 Filename: "test.tf", 138 Start: hcl.Pos{Line: 3, Column: 14, Byte: 30}, 139 End: hcl.Pos{Line: 3, Column: 18, Byte: 34}, 140 }, 141 }, 142 }, 143 { 144 hcl.TraverseRoot{ 145 Name: "baz", 146 SrcRange: hcl.Range{ 147 Filename: "test.tf", 148 Start: hcl.Pos{Line: 5, Column: 11, Byte: 57}, 149 End: hcl.Pos{Line: 5, Column: 14, Byte: 60}, 150 }, 151 }, 152 }, 153 }, 154 }, 155 "misplaced dynamic block": { 156 src: ` 157 dynamic "bar" { 158 for_each = beep 159 content { 160 key = val 161 } 162 } 163 `, 164 schema: fooSchema, 165 want: []hcl.Traversal{ 166 { 167 hcl.TraverseRoot{ 168 Name: "beep", 169 SrcRange: hcl.Range{ 170 Filename: "test.tf", 171 Start: hcl.Pos{Line: 3, Column: 14, Byte: 30}, 172 End: hcl.Pos{Line: 3, Column: 18, Byte: 34}, 173 }, 174 }, 175 }, 176 }, 177 }, 178 } 179 180 for name, test := range tests { 181 t.Run(name, func(t *testing.T) { 182 var f *hcl.File 183 var diags hcl.Diagnostics 184 if test.json { 185 f, diags = hcljson.Parse([]byte(test.src), "test.tf.json") 186 } else { 187 f, diags = hclsyntax.ParseConfig([]byte(test.src), "test.tf", hcl.Pos{Line: 1, Column: 1}) 188 } 189 if diags.HasErrors() { 190 for _, diag := range diags { 191 t.Errorf("unexpected diagnostic: %s", diag) 192 } 193 t.FailNow() 194 } 195 196 got := ExpandedVariables(f.Body, test.schema) 197 198 co := cmpopts.IgnoreUnexported(hcl.TraverseRoot{}) 199 if !cmp.Equal(got, test.want, co) { 200 t.Errorf("wrong result\n%s", cmp.Diff(test.want, got, co)) 201 } 202 }) 203 } 204 205 }