terraform/internal/addrs/parse_target_test.go

389 lines
8.4 KiB
Go

package addrs
import (
"testing"
"github.com/go-test/deep"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/internal/tfdiags"
)
func TestParseTarget(t *testing.T) {
tests := []struct {
Input string
Want *Target
WantErr string
}{
{
`module.foo`,
&Target{
Subject: ModuleInstance{
{
Name: "foo",
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 11, Byte: 10},
},
},
``,
},
{
`module.foo[2]`,
&Target{
Subject: ModuleInstance{
{
Name: "foo",
InstanceKey: IntKey(2),
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 14, Byte: 13},
},
},
``,
},
{
`module.foo[2].module.bar`,
&Target{
Subject: ModuleInstance{
{
Name: "foo",
InstanceKey: IntKey(2),
},
{
Name: "bar",
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
},
},
``,
},
{
`aws_instance.foo`,
&Target{
Subject: AbsResource{
Resource: Resource{
Mode: ManagedResourceMode,
Type: "aws_instance",
Name: "foo",
},
Module: RootModuleInstance,
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 17, Byte: 16},
},
},
``,
},
{
`aws_instance.foo[1]`,
&Target{
Subject: AbsResourceInstance{
Resource: ResourceInstance{
Resource: Resource{
Mode: ManagedResourceMode,
Type: "aws_instance",
Name: "foo",
},
Key: IntKey(1),
},
Module: RootModuleInstance,
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 20, Byte: 19},
},
},
``,
},
{
`data.aws_instance.foo`,
&Target{
Subject: AbsResource{
Resource: Resource{
Mode: DataResourceMode,
Type: "aws_instance",
Name: "foo",
},
Module: RootModuleInstance,
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 22, Byte: 21},
},
},
``,
},
{
`data.aws_instance.foo[1]`,
&Target{
Subject: AbsResourceInstance{
Resource: ResourceInstance{
Resource: Resource{
Mode: DataResourceMode,
Type: "aws_instance",
Name: "foo",
},
Key: IntKey(1),
},
Module: RootModuleInstance,
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
},
},
``,
},
{
`module.foo.aws_instance.bar`,
&Target{
Subject: AbsResource{
Resource: Resource{
Mode: ManagedResourceMode,
Type: "aws_instance",
Name: "bar",
},
Module: ModuleInstance{
{Name: "foo"},
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 28, Byte: 27},
},
},
``,
},
{
`module.foo.module.bar.aws_instance.baz`,
&Target{
Subject: AbsResource{
Resource: Resource{
Mode: ManagedResourceMode,
Type: "aws_instance",
Name: "baz",
},
Module: ModuleInstance{
{Name: "foo"},
{Name: "bar"},
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 39, Byte: 38},
},
},
``,
},
{
`module.foo.module.bar.aws_instance.baz["hello"]`,
&Target{
Subject: AbsResourceInstance{
Resource: ResourceInstance{
Resource: Resource{
Mode: ManagedResourceMode,
Type: "aws_instance",
Name: "baz",
},
Key: StringKey("hello"),
},
Module: ModuleInstance{
{Name: "foo"},
{Name: "bar"},
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 48, Byte: 47},
},
},
``,
},
{
`module.foo.data.aws_instance.bar`,
&Target{
Subject: AbsResource{
Resource: Resource{
Mode: DataResourceMode,
Type: "aws_instance",
Name: "bar",
},
Module: ModuleInstance{
{Name: "foo"},
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 33, Byte: 32},
},
},
``,
},
{
`module.foo.module.bar.data.aws_instance.baz`,
&Target{
Subject: AbsResource{
Resource: Resource{
Mode: DataResourceMode,
Type: "aws_instance",
Name: "baz",
},
Module: ModuleInstance{
{Name: "foo"},
{Name: "bar"},
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 44, Byte: 43},
},
},
``,
},
{
`module.foo.module.bar[0].data.aws_instance.baz`,
&Target{
Subject: AbsResource{
Resource: Resource{
Mode: DataResourceMode,
Type: "aws_instance",
Name: "baz",
},
Module: ModuleInstance{
{Name: "foo", InstanceKey: NoKey},
{Name: "bar", InstanceKey: IntKey(0)},
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 47, Byte: 46},
},
},
``,
},
{
`module.foo.module.bar["a"].data.aws_instance.baz["hello"]`,
&Target{
Subject: AbsResourceInstance{
Resource: ResourceInstance{
Resource: Resource{
Mode: DataResourceMode,
Type: "aws_instance",
Name: "baz",
},
Key: StringKey("hello"),
},
Module: ModuleInstance{
{Name: "foo", InstanceKey: NoKey},
{Name: "bar", InstanceKey: StringKey("a")},
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 58, Byte: 57},
},
},
``,
},
{
`module.foo.module.bar.data.aws_instance.baz["hello"]`,
&Target{
Subject: AbsResourceInstance{
Resource: ResourceInstance{
Resource: Resource{
Mode: DataResourceMode,
Type: "aws_instance",
Name: "baz",
},
Key: StringKey("hello"),
},
Module: ModuleInstance{
{Name: "foo"},
{Name: "bar"},
},
},
SourceRange: tfdiags.SourceRange{
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 53, Byte: 52},
},
},
``,
},
{
`aws_instance`,
nil,
`Resource specification must include a resource type and name.`,
},
{
`module`,
nil,
`Prefix "module." must be followed by a module name.`,
},
{
`module["baz"]`,
nil,
`Prefix "module." must be followed by a module name.`,
},
{
`module.baz.bar`,
nil,
`Resource specification must include a resource type and name.`,
},
{
`aws_instance.foo.bar`,
nil,
`Resource instance key must be given in square brackets.`,
},
{
`aws_instance.foo[1].baz`,
nil,
`Unexpected extra operators after address.`,
},
}
for _, test := range tests {
t.Run(test.Input, func(t *testing.T) {
traversal, travDiags := hclsyntax.ParseTraversalAbs([]byte(test.Input), "", hcl.Pos{Line: 1, Column: 1})
if travDiags.HasErrors() {
t.Fatal(travDiags.Error())
}
got, diags := ParseTarget(traversal)
switch len(diags) {
case 0:
if test.WantErr != "" {
t.Fatalf("succeeded; want error: %s", test.WantErr)
}
case 1:
if test.WantErr == "" {
t.Fatalf("unexpected diagnostics: %s", diags.Err())
}
if got, want := diags[0].Description().Detail, test.WantErr; got != want {
t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want)
}
default:
t.Fatalf("too many diagnostics: %s", diags.Err())
}
if diags.HasErrors() {
return
}
for _, problem := range deep.Equal(got, test.Want) {
t.Errorf(problem)
}
})
}
}