addrs: MoveDestination for AbsResourceInstance-based move endpoints

Previously our MoveDestination methods only honored move statements whose
endpoints were module calls, module instances, or resources.

Now we'll additionally handle when the endpoints are individual resource
instances. This situation only applies to
AbsResourceInstance.MoveDestination because no other objects can be
contained inside of a resource instance.

This completes all of the MoveDestination cases for all supported move
statement types and moveable object types.
This commit is contained in:
Martin Atkins 2021-07-27 17:17:51 -07:00
parent 5e86bab159
commit 45d16b4a2b
2 changed files with 163 additions and 4 deletions

View File

@ -354,8 +354,54 @@ func (r AbsResourceInstance) MoveDestination(fromMatch, toMatch *MoveEndpointInM
}
return newResource.Instance(r.Resource.Key), true
case AbsResourceInstance:
// TODO: Implement
return AbsResourceInstance{}, false
fromRelSubject, ok := fromMatch.relSubject.(AbsResourceInstance)
if !ok {
// The only other possible type for a resource move is
// AbsResourceInstance, and that can never match an AbsResource.
return AbsResourceInstance{}, false
}
// fromMatch can only possibly match the reciever if the resource
// portions are identical, regardless of the module paths.
if fromRelSubject.Resource != r.Resource {
return AbsResourceInstance{}, false
}
// The module path portion of relSubject must have a prefix that
// matches the module where our endpoints were declared.
if len(fromMatch.module) > len(r.Module) {
return AbsResourceInstance{}, false // too short to possibly match
}
for i := range fromMatch.module {
if fromMatch.module[i] != r.Module[i].Name {
return AbsResourceInstance{}, false // this step doesn't match
}
}
// The remaining steps of the module path must _exactly_ match
// the relative module path in the "fromMatch" address.
mPrefix, mRel := r.Module[:len(fromMatch.module)], r.Module[len(fromMatch.module):]
if len(mRel) != len(fromRelSubject.Module) {
return AbsResourceInstance{}, false // can't match if lengths are different
}
for i := range mRel {
if mRel[i] != fromRelSubject.Module[i] {
return AbsResourceInstance{}, false // all of the steps must match
}
}
// If we got here then we have a match, and so our result is the
// module instance where the statement was declared (mPrefix) followed
// by the "to" relative address in toMatch.
toRelSubject := toMatch.relSubject.(AbsResourceInstance)
var mNew ModuleInstance
if len(mPrefix) > 0 || len(toRelSubject.Module) > 0 {
mNew = make(ModuleInstance, 0, len(mPrefix)+len(toRelSubject.Module))
mNew = append(mNew, mPrefix...)
mNew = append(mNew, toRelSubject.Module...)
}
ret := toRelSubject.Resource.Absolute(mNew)
return ret, true
default:
panic("invalid address type for resource-kind move endpoint")
}

View File

@ -312,6 +312,121 @@ func TestAbsResourceInstanceMoveDestination(t *testing.T) {
WantMatch bool
WantResult string
}{
{
``,
`test_object.beep`,
`test_object.boop`,
`test_object.beep`,
true,
`test_object.boop`,
},
{
``,
`test_object.beep`,
`test_object.beep[2]`,
`test_object.beep`,
true,
`test_object.beep[2]`,
},
{
``,
`test_object.beep`,
`module.foo.test_object.beep`,
`test_object.beep`,
true,
`module.foo.test_object.beep`,
},
{
``,
`test_object.beep[2]`,
`module.foo.test_object.beep["a"]`,
`test_object.beep[2]`,
true,
`module.foo.test_object.beep["a"]`,
},
{
``,
`test_object.beep`,
`module.foo[0].test_object.beep`,
`test_object.beep`,
true,
`module.foo[0].test_object.beep`,
},
{
``,
`module.foo.test_object.beep`,
`test_object.beep`,
`module.foo.test_object.beep`,
true,
`test_object.beep`,
},
{
``,
`module.foo[0].test_object.beep`,
`test_object.beep`,
`module.foo[0].test_object.beep`,
true,
`test_object.beep`,
},
{
`foo`,
`test_object.beep`,
`test_object.boop`,
`module.foo[0].test_object.beep`,
true,
`module.foo[0].test_object.boop`,
},
{
`foo`,
`test_object.beep`,
`test_object.beep[1]`,
`module.foo[0].test_object.beep`,
true,
`module.foo[0].test_object.beep[1]`,
},
{
``,
`test_object.beep`,
`test_object.boop`,
`test_object.boop`,
false, // the reciever is already the "to" address
``,
},
{
``,
`test_object.beep[1]`,
`test_object.beep[2]`,
`test_object.beep[5]`,
false, // the receiver has a non-matching instance key
``,
},
{
`foo`,
`test_object.beep`,
`test_object.boop`,
`test_object.beep`,
false, // the receiver is not inside an instance of module "foo"
``,
},
{
`foo.bar`,
`test_object.beep`,
`test_object.boop`,
`test_object.beep`,
false, // the receiver is not inside an instance of module "foo.bar"
``,
},
{
``,
`module.foo[0].test_object.beep`,
`test_object.beep`,
`module.foo[1].test_object.beep`,
false, // receiver is in a different instance of module.foo
``,
},
// Moving a module also moves all of the resources declared within it.
// The following tests all cover variations of that rule.
{
``,
`module.foo`,
@ -618,7 +733,6 @@ func TestAbsResourceMoveDestination(t *testing.T) {
true,
`module.foo[0].test_object.beep`,
},
{
``,
`module.foo.test_object.beep`,
@ -643,7 +757,6 @@ func TestAbsResourceMoveDestination(t *testing.T) {
true,
`module.foo[0].test_object.boop`,
},
{
``,
`test_object.beep`,