mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-27 09:21:14 -06:00
CanChainFrom and NestedWithin
Add implementations of CanChainFrom and NestedWithin for MoveEndpointInModule. CanChainFrom allows the linking of move statements of the same address, which means the prior destination address must equal the following source address. If the destination and source addresses are of different types, they must be covered by NestedWithin rather than CanChainFrom. NestedWithin checks if the destination contains the source address. Any matching types would be covered by CanChainFrom.
This commit is contained in:
parent
493ec4e6c5
commit
6087b1bdb9
@ -218,7 +218,35 @@ func (e *MoveEndpointInModule) SelectsModule(addr ModuleInstance) bool {
|
||||
// the reciever is the "to" from one statement and the other given address
|
||||
// is the "from" of another statement.
|
||||
func (e *MoveEndpointInModule) CanChainFrom(other *MoveEndpointInModule) bool {
|
||||
// TODO: implement
|
||||
eSub := e.relSubject
|
||||
oSub := other.relSubject
|
||||
|
||||
switch oSub := oSub.(type) {
|
||||
case AbsModuleCall:
|
||||
switch eSub := eSub.(type) {
|
||||
case AbsModuleCall:
|
||||
return eSub.Equal(oSub)
|
||||
}
|
||||
|
||||
case ModuleInstance:
|
||||
switch eSub := eSub.(type) {
|
||||
case ModuleInstance:
|
||||
return eSub.Equal(oSub)
|
||||
}
|
||||
|
||||
case AbsResource:
|
||||
switch eSub := eSub.(type) {
|
||||
case AbsResource:
|
||||
return eSub.Equal(oSub)
|
||||
}
|
||||
|
||||
case AbsResourceInstance:
|
||||
switch eSub := eSub.(type) {
|
||||
case AbsResourceInstance:
|
||||
return eSub.Equal(oSub)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@ -226,7 +254,52 @@ func (e *MoveEndpointInModule) CanChainFrom(other *MoveEndpointInModule) bool {
|
||||
// contained within one of the objects that the given other address could
|
||||
// select.
|
||||
func (e *MoveEndpointInModule) NestedWithin(other *MoveEndpointInModule) bool {
|
||||
// TODO: implement
|
||||
eSub := e.relSubject
|
||||
oSub := other.relSubject
|
||||
|
||||
switch oSub := oSub.(type) {
|
||||
case AbsModuleCall:
|
||||
withinModuleCall := func(mod ModuleInstance, call AbsModuleCall) bool {
|
||||
// parent modules don't match at all
|
||||
if !call.Module.IsAncestor(mod) {
|
||||
return false
|
||||
}
|
||||
|
||||
rem := mod[len(call.Module):]
|
||||
return rem[0].Name == call.Call.Name
|
||||
}
|
||||
|
||||
// Module calls can contain module instances, resources, and resource
|
||||
// instances.
|
||||
switch eSub := eSub.(type) {
|
||||
case AbsResource:
|
||||
return withinModuleCall(eSub.Module, oSub)
|
||||
|
||||
case AbsResourceInstance:
|
||||
return withinModuleCall(eSub.Module, oSub)
|
||||
|
||||
case ModuleInstance:
|
||||
return withinModuleCall(eSub, oSub)
|
||||
}
|
||||
|
||||
case ModuleInstance:
|
||||
// Module instances can contain resources and resource instances.
|
||||
switch eSub := eSub.(type) {
|
||||
case AbsResource:
|
||||
return eSub.Module.Equal(oSub) || oSub.IsAncestor(eSub.Module)
|
||||
|
||||
case AbsResourceInstance:
|
||||
return eSub.Module.Equal(oSub) || oSub.IsAncestor(eSub.Module)
|
||||
}
|
||||
|
||||
case AbsResource:
|
||||
// A resource can only contain a resource instance.
|
||||
switch eSub := eSub.(type) {
|
||||
case AbsResourceInstance:
|
||||
return eSub.ContainingResource().Equal(oSub)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -1074,3 +1074,179 @@ func TestAbsResourceMoveDestination(t *testing.T) {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMoveEndpointChainAndNested(t *testing.T) {
|
||||
tests := []struct {
|
||||
Endpoint, Other AbsMoveable
|
||||
CanChainFrom, NestedWithin bool
|
||||
}{
|
||||
{
|
||||
Endpoint: AbsModuleCall{
|
||||
Module: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Call: ModuleCall{Name: "bar"},
|
||||
},
|
||||
Other: AbsModuleCall{
|
||||
Module: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Call: ModuleCall{Name: "bar"},
|
||||
},
|
||||
CanChainFrom: true,
|
||||
NestedWithin: false,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Other: AbsModuleCall{
|
||||
Module: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Call: ModuleCall{Name: "bar"},
|
||||
},
|
||||
CanChainFrom: false,
|
||||
NestedWithin: false,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseModuleInstanceStr("module.foo[2].module.bar[2]"),
|
||||
Other: AbsModuleCall{
|
||||
Module: RootModuleInstance,
|
||||
Call: ModuleCall{Name: "foo"},
|
||||
},
|
||||
CanChainFrom: false,
|
||||
NestedWithin: true,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].module.bar.resource.baz").ContainingResource(),
|
||||
Other: AbsModuleCall{
|
||||
Module: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Call: ModuleCall{Name: "bar"},
|
||||
},
|
||||
CanChainFrom: false,
|
||||
NestedWithin: true,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].module.bar[3].resource.baz[2]"),
|
||||
Other: AbsModuleCall{
|
||||
Module: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Call: ModuleCall{Name: "bar"},
|
||||
},
|
||||
CanChainFrom: false,
|
||||
NestedWithin: true,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: AbsModuleCall{
|
||||
Module: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Call: ModuleCall{Name: "bar"},
|
||||
},
|
||||
Other: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
CanChainFrom: false,
|
||||
NestedWithin: false,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Other: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
CanChainFrom: true,
|
||||
NestedWithin: false,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
|
||||
Other: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
CanChainFrom: false,
|
||||
NestedWithin: true,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].module.bar.resource.baz"),
|
||||
Other: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
CanChainFrom: false,
|
||||
NestedWithin: true,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: AbsModuleCall{
|
||||
Module: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Call: ModuleCall{Name: "bar"},
|
||||
},
|
||||
Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
|
||||
CanChainFrom: false,
|
||||
NestedWithin: false,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
|
||||
CanChainFrom: false,
|
||||
NestedWithin: false,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
|
||||
Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
|
||||
CanChainFrom: true,
|
||||
NestedWithin: false,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
|
||||
Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz[2]").ContainingResource(),
|
||||
CanChainFrom: false,
|
||||
NestedWithin: true,
|
||||
},
|
||||
|
||||
{
|
||||
Endpoint: AbsModuleCall{
|
||||
Module: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Call: ModuleCall{Name: "bar"},
|
||||
},
|
||||
Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
|
||||
CanChainFrom: false,
|
||||
},
|
||||
{
|
||||
Endpoint: mustParseModuleInstanceStr("module.foo[2]"),
|
||||
Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
|
||||
CanChainFrom: false,
|
||||
},
|
||||
{
|
||||
Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(),
|
||||
Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
|
||||
CanChainFrom: false,
|
||||
},
|
||||
{
|
||||
Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
|
||||
Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"),
|
||||
CanChainFrom: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("[%02d]%s.CanChainFrom(%s)", i, test.Endpoint, test.Other),
|
||||
func(t *testing.T) {
|
||||
endpoint := &MoveEndpointInModule{
|
||||
relSubject: test.Endpoint,
|
||||
}
|
||||
|
||||
other := &MoveEndpointInModule{
|
||||
relSubject: test.Other,
|
||||
}
|
||||
|
||||
if endpoint.CanChainFrom(other) != test.CanChainFrom {
|
||||
t.Errorf("expected %s CanChainFrom %s == %t", test.Endpoint, test.Other, test.CanChainFrom)
|
||||
}
|
||||
|
||||
if endpoint.NestedWithin(other) != test.NestedWithin {
|
||||
t.Errorf("expected %s NestedWithin %s == %t", test.Endpoint, test.Other, test.NestedWithin)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func mustParseAbsResourceInstanceStr(s string) AbsResourceInstance {
|
||||
r, diags := ParseAbsResourceInstanceStr(s)
|
||||
if diags.HasErrors() {
|
||||
panic(diags.ErrWithWarnings().Error())
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user