blob: a8fed7981b20ee5b2ec7ae93c48ea6f7b819c992 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package blocktoattr
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
hcljson "github.com/hashicorp/hcl/v2/json"
"github.com/hashicorp/terraform/internal/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,
},
"bar": {
Type: cty.Map(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},
},
},
},
},
},
"misplaced dynamic block": {
src: `
dynamic "bar" {
for_each = beep
content {
key = val
}
}
`,
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},
},
},
},
},
},
}
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))
}
})
}
}