mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 18:01:01 -06:00
ffcf9fc51b
When a top-level list-of-object contains an attribute that is also list-of-object we need to do the fixup again inside the nested body (using our synthetic attributes-only schema) so that the attr-as-blocks mechanism can apply within the nested blocks too.
174 lines
3.4 KiB
Go
174 lines
3.4 KiB
Go
package blocktoattr
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"github.com/hashicorp/hcl2/hcl"
|
|
"github.com/hashicorp/hcl2/hcl/hclsyntax"
|
|
hcljson "github.com/hashicorp/hcl2/hcl/json"
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
func TestExpandedVariables(t *testing.T) {
|
|
fooSchema := &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
Type: cty.List(cty.Object(map[string]cty.Type{
|
|
"bar": cty.String,
|
|
})),
|
|
Optional: true,
|
|
},
|
|
},
|
|
}
|
|
|
|
tests := map[string]struct {
|
|
src string
|
|
json bool
|
|
schema *configschema.Block
|
|
want []hcl.Traversal
|
|
}{
|
|
"empty": {
|
|
src: ``,
|
|
schema: &configschema.Block{},
|
|
want: nil,
|
|
},
|
|
"attribute syntax": {
|
|
src: `
|
|
foo = [
|
|
{
|
|
bar = baz
|
|
},
|
|
]
|
|
`,
|
|
schema: fooSchema,
|
|
want: []hcl.Traversal{
|
|
{
|
|
hcl.TraverseRoot{
|
|
Name: "baz",
|
|
SrcRange: hcl.Range{
|
|
Filename: "test.tf",
|
|
Start: hcl.Pos{Line: 4, Column: 11, Byte: 23},
|
|
End: hcl.Pos{Line: 4, Column: 14, Byte: 26},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"block syntax": {
|
|
src: `
|
|
foo {
|
|
bar = baz
|
|
}
|
|
`,
|
|
schema: fooSchema,
|
|
want: []hcl.Traversal{
|
|
{
|
|
hcl.TraverseRoot{
|
|
Name: "baz",
|
|
SrcRange: hcl.Range{
|
|
Filename: "test.tf",
|
|
Start: hcl.Pos{Line: 3, Column: 9, Byte: 15},
|
|
End: hcl.Pos{Line: 3, Column: 12, Byte: 18},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"block syntax with nested blocks": {
|
|
src: `
|
|
foo {
|
|
bar {
|
|
boop = baz
|
|
}
|
|
}
|
|
`,
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
Type: cty.List(cty.Object(map[string]cty.Type{
|
|
"bar": cty.List(cty.Object(map[string]cty.Type{
|
|
"boop": cty.String,
|
|
})),
|
|
})),
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
want: []hcl.Traversal{
|
|
{
|
|
hcl.TraverseRoot{
|
|
Name: "baz",
|
|
SrcRange: hcl.Range{
|
|
Filename: "test.tf",
|
|
Start: hcl.Pos{Line: 4, Column: 12, Byte: 26},
|
|
End: hcl.Pos{Line: 4, Column: 15, Byte: 29},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"dynamic block syntax": {
|
|
src: `
|
|
dynamic "foo" {
|
|
for_each = beep
|
|
content {
|
|
bar = baz
|
|
}
|
|
}
|
|
`,
|
|
schema: fooSchema,
|
|
want: []hcl.Traversal{
|
|
{
|
|
hcl.TraverseRoot{
|
|
Name: "beep",
|
|
SrcRange: hcl.Range{
|
|
Filename: "test.tf",
|
|
Start: hcl.Pos{Line: 3, Column: 14, Byte: 30},
|
|
End: hcl.Pos{Line: 3, Column: 18, Byte: 34},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
hcl.TraverseRoot{
|
|
Name: "baz",
|
|
SrcRange: hcl.Range{
|
|
Filename: "test.tf",
|
|
Start: hcl.Pos{Line: 5, Column: 11, Byte: 57},
|
|
End: hcl.Pos{Line: 5, Column: 14, Byte: 60},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
var f *hcl.File
|
|
var diags hcl.Diagnostics
|
|
if test.json {
|
|
f, diags = hcljson.Parse([]byte(test.src), "test.tf.json")
|
|
} else {
|
|
f, diags = hclsyntax.ParseConfig([]byte(test.src), "test.tf", hcl.Pos{Line: 1, Column: 1})
|
|
}
|
|
if diags.HasErrors() {
|
|
for _, diag := range diags {
|
|
t.Errorf("unexpected diagnostic: %s", diag)
|
|
}
|
|
t.FailNow()
|
|
}
|
|
|
|
got := ExpandedVariables(f.Body, test.schema)
|
|
|
|
co := cmpopts.IgnoreUnexported(hcl.TraverseRoot{})
|
|
if !cmp.Equal(got, test.want, co) {
|
|
t.Errorf("wrong result\n%s", cmp.Diff(test.want, got, co))
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|