mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 18:01:01 -06:00
b861f5a4d7
If the last step in a module target is an unkeyed instance, and it's being compared against keyed instances, we have to assume it was intended to be used as a Module rather than a ModuleInstance.
232 lines
4.8 KiB
Go
232 lines
4.8 KiB
Go
package addrs
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
func TestTargetContains(t *testing.T) {
|
|
for _, test := range []struct {
|
|
addr, other Targetable
|
|
expect bool
|
|
}{
|
|
{
|
|
mustParseTarget("module.foo"),
|
|
mustParseTarget("module.bar"),
|
|
false,
|
|
},
|
|
{
|
|
mustParseTarget("module.foo"),
|
|
mustParseTarget("module.foo"),
|
|
true,
|
|
},
|
|
{
|
|
RootModuleInstance,
|
|
mustParseTarget("module.foo"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.foo"),
|
|
RootModuleInstance,
|
|
false,
|
|
},
|
|
{
|
|
mustParseTarget("module.foo"),
|
|
mustParseTarget("module.foo.module.bar[0]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.foo"),
|
|
mustParseTarget("module.foo.module.bar[0]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.foo[2]"),
|
|
mustParseTarget("module.foo[2].module.bar[0]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.foo"),
|
|
mustParseTarget("module.foo.test_resource.bar"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.foo"),
|
|
mustParseTarget("module.foo.test_resource.bar[0]"),
|
|
true,
|
|
},
|
|
|
|
// Resources
|
|
{
|
|
mustParseTarget("test_resource.foo"),
|
|
mustParseTarget("test_resource.foo[\"bar\"]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget(`test_resource.foo["bar"]`),
|
|
mustParseTarget(`test_resource.foo["bar"]`),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("test_resource.foo"),
|
|
mustParseTarget("test_resource.foo[2]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("test_resource.foo"),
|
|
mustParseTarget("module.bar.test_resource.foo[2]"),
|
|
false,
|
|
},
|
|
{
|
|
mustParseTarget("module.bar.test_resource.foo"),
|
|
mustParseTarget("module.bar.test_resource.foo[2]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.bar.test_resource.foo"),
|
|
mustParseTarget("module.bar[0].test_resource.foo[2]"),
|
|
false,
|
|
},
|
|
{
|
|
mustParseTarget("module.bar.test_resource.foo"),
|
|
mustParseTarget("module.bar.test_resource.foo[0]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.bax"),
|
|
mustParseTarget("module.bax[0].test_resource.foo[0]"),
|
|
true,
|
|
},
|
|
|
|
// Config paths, while never returned from parsing a target, must still
|
|
// be targetable
|
|
{
|
|
ConfigResource{
|
|
Module: []string{"bar"},
|
|
Resource: Resource{
|
|
Mode: ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "foo",
|
|
},
|
|
},
|
|
mustParseTarget("module.bar.test_resource.foo[2]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.bar"),
|
|
ConfigResource{
|
|
Module: []string{"bar"},
|
|
Resource: Resource{
|
|
Mode: ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "foo",
|
|
},
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.bar.test_resource.foo"),
|
|
ConfigResource{
|
|
Module: []string{"bar"},
|
|
Resource: Resource{
|
|
Mode: ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "foo",
|
|
},
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
ConfigResource{
|
|
Resource: Resource{
|
|
Mode: ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "foo",
|
|
},
|
|
},
|
|
mustParseTarget("module.bar.test_resource.foo[2]"),
|
|
false,
|
|
},
|
|
{
|
|
ConfigResource{
|
|
Module: []string{"bar"},
|
|
Resource: Resource{
|
|
Mode: ManagedResourceMode,
|
|
Type: "test_resource",
|
|
Name: "foo",
|
|
},
|
|
},
|
|
mustParseTarget("module.bar[0].test_resource.foo"),
|
|
true,
|
|
},
|
|
|
|
// Modules are also never the result of parsing a target, but also need
|
|
// to be targetable
|
|
{
|
|
Module{"bar"},
|
|
Module{"bar", "baz"},
|
|
true,
|
|
},
|
|
{
|
|
Module{"bar"},
|
|
mustParseTarget("module.bar[0]"),
|
|
true,
|
|
},
|
|
{
|
|
// Parsing an ambiguous module path needs to ensure the
|
|
// ModuleInstance could contain the Module. This is safe because if
|
|
// the module could be expanded, it must have an index, meaning no
|
|
// index indicates that the module instance and module are
|
|
// functionally equivalent.
|
|
mustParseTarget("module.bar"),
|
|
Module{"bar"},
|
|
true,
|
|
},
|
|
{
|
|
// A specific ModuleInstance cannot contain a module
|
|
mustParseTarget("module.bar[0]"),
|
|
Module{"bar"},
|
|
false,
|
|
},
|
|
{
|
|
Module{"bar", "baz"},
|
|
mustParseTarget("module.bar[0].module.baz.test_resource.foo[1]"),
|
|
true,
|
|
},
|
|
{
|
|
mustParseTarget("module.bar[0].module.baz"),
|
|
Module{"bar", "baz"},
|
|
false,
|
|
},
|
|
} {
|
|
t.Run(fmt.Sprintf("%s-in-%s", test.other, test.addr), func(t *testing.T) {
|
|
got := test.addr.TargetContains(test.other)
|
|
if got != test.expect {
|
|
t.Fatalf("expected %q.TargetContains(%q) == %t", test.addr, test.other, test.expect)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResourceContains(t *testing.T) {
|
|
for _, test := range []struct {
|
|
in, other Targetable
|
|
expect bool
|
|
}{} {
|
|
t.Run(fmt.Sprintf("%s-in-%s", test.other, test.in), func(t *testing.T) {
|
|
got := test.in.TargetContains(test.other)
|
|
if got != test.expect {
|
|
t.Fatalf("expected %q.TargetContains(%q) == %t", test.in, test.other, test.expect)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func mustParseTarget(str string) Targetable {
|
|
t, diags := ParseTargetStr(str)
|
|
if diags != nil {
|
|
panic(fmt.Sprintf("%s: %s", str, diags.ErrWithWarnings()))
|
|
}
|
|
return t.Subject
|
|
}
|