| package addrs |
| |
| import ( |
| "fmt" |
| "strings" |
| "testing" |
| |
| "github.com/hashicorp/hcl/v2" |
| "github.com/hashicorp/hcl/v2/hclsyntax" |
| "github.com/hashicorp/terraform/internal/tfdiags" |
| ) |
| |
| func TestModuleInstanceMoveDestination(t *testing.T) { |
| tests := []struct { |
| DeclModule string |
| StmtFrom, StmtTo string |
| Receiver string |
| WantMatch bool |
| WantResult string |
| }{ |
| { |
| ``, |
| `module.foo`, |
| `module.bar`, |
| `module.foo`, |
| true, |
| `module.bar`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar`, |
| `module.foo[1]`, |
| true, |
| `module.bar[1]`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar`, |
| `module.foo["a"]`, |
| true, |
| `module.bar["a"]`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar.module.foo`, |
| `module.foo`, |
| true, |
| `module.bar.module.foo`, |
| }, |
| { |
| ``, |
| `module.foo.module.bar`, |
| `module.bar`, |
| `module.foo.module.bar`, |
| true, |
| `module.bar`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo[1]`, |
| true, |
| `module.foo[2]`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo`, |
| `module.foo[1]`, |
| true, |
| `module.foo`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo`, |
| true, |
| `module.foo[1]`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo.module.bar`, |
| true, |
| `module.foo[1].module.bar`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo.module.bar[0]`, |
| true, |
| `module.foo[1].module.bar[0]`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar.module.foo`, |
| `module.foo[0]`, |
| true, |
| `module.bar.module.foo[0]`, |
| }, |
| { |
| ``, |
| `module.foo.module.bar`, |
| `module.bar`, |
| `module.foo.module.bar[0]`, |
| true, |
| `module.bar[0]`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.baz`, |
| `module.foo.module.bar`, |
| true, |
| `module.foo.module.baz`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.baz`, |
| `module.foo[1].module.bar`, |
| true, |
| `module.foo[1].module.baz`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.foo[1].module.bar`, |
| true, |
| `module.foo[1].module.bar[1]`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo`, |
| false, // the receiver has a non-matching instance key (NoKey) |
| ``, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo[2]`, |
| false, // the receiver is already the "to" address |
| ``, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar`, |
| ``, |
| false, // the root module can never be moved |
| ``, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.boz`, |
| false, // the receiver is outside the declaration module |
| ``, |
| }, |
| { |
| `foo.bar`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.boz`, |
| false, // the receiver is outside the declaration module |
| ``, |
| }, |
| { |
| `foo.bar`, |
| `module.a`, |
| `module.b`, |
| `module.boz`, |
| false, // the receiver is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.c`, |
| false, // the receiver is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2[0]`, |
| `module.b1.module.b2[1]`, |
| `module.c`, |
| false, // the receiver is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.a1.module.b2`, |
| false, // the receiver is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.b1.module.a2`, |
| false, // the receiver is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2[0]`, |
| `module.b1.module.b2[1]`, |
| `module.a1.module.b2[0]`, |
| false, // the receiver is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `foo_instance.bar`, |
| `foo_instance.baz`, |
| `module.foo`, |
| false, // a resource address can never match a module instance |
| ``, |
| }, |
| } |
| |
| for _, test := range tests { |
| t.Run( |
| fmt.Sprintf( |
| "%s: %s to %s with %s", |
| test.DeclModule, |
| test.StmtFrom, test.StmtTo, |
| test.Receiver, |
| ), |
| func(t *testing.T) { |
| |
| parseStmtEP := func(t *testing.T, input string) *MoveEndpoint { |
| t.Helper() |
| |
| traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos) |
| if hclDiags.HasErrors() { |
| // We're not trying to test the HCL parser here, so any |
| // failures at this point are likely to be bugs in the |
| // test case itself. |
| t.Fatalf("syntax error: %s", hclDiags.Error()) |
| } |
| |
| moveEp, diags := ParseMoveEndpoint(traversal) |
| if diags.HasErrors() { |
| t.Fatalf("unexpected error: %s", diags.Err().Error()) |
| } |
| return moveEp |
| } |
| |
| fromEPLocal := parseStmtEP(t, test.StmtFrom) |
| toEPLocal := parseStmtEP(t, test.StmtTo) |
| |
| declModule := RootModule |
| if test.DeclModule != "" { |
| declModule = strings.Split(test.DeclModule, ".") |
| } |
| fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal) |
| if fromEP == nil || toEP == nil { |
| t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto: %s", fromEPLocal, toEPLocal) |
| } |
| |
| receiverAddr := RootModuleInstance |
| if test.Receiver != "" { |
| var diags tfdiags.Diagnostics |
| receiverAddr, diags = ParseModuleInstanceStr(test.Receiver) |
| if diags.HasErrors() { |
| t.Fatalf("invalid reciever address: %s", diags.Err().Error()) |
| } |
| } |
| gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP) |
| if !test.WantMatch { |
| if gotMatch { |
| t.Errorf("unexpected match\nreceiver: %s\nfrom: %s\nto: %s\nresult: %s", test.Receiver, fromEP, toEP, gotAddr) |
| } |
| return |
| } |
| |
| if !gotMatch { |
| t.Errorf("unexpected non-match\nreceiver: %s\nfrom: %s\nto: %s", test.Receiver, fromEP, toEP) |
| } |
| |
| if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr { |
| t.Errorf("wrong result\ngot: %s\nwant: %s", gotStr, wantStr) |
| } |
| }, |
| ) |
| } |
| } |
| |
| func TestAbsResourceInstanceMoveDestination(t *testing.T) { |
| tests := []struct { |
| DeclModule string |
| StmtFrom, StmtTo string |
| Receiver string |
| 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`, |
| `module.bar`, |
| `module.foo.test_object.beep`, |
| true, |
| `module.bar.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar`, |
| `module.foo[1].test_object.beep`, |
| true, |
| `module.bar[1].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar`, |
| `module.foo["a"].test_object.beep`, |
| true, |
| `module.bar["a"].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar.module.foo`, |
| `module.foo.test_object.beep`, |
| true, |
| `module.bar.module.foo.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo.module.bar`, |
| `module.bar`, |
| `module.foo.module.bar.test_object.beep`, |
| true, |
| `module.bar.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo[1].test_object.beep`, |
| true, |
| `module.foo[2].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo`, |
| `module.foo[1].test_object.beep`, |
| true, |
| `module.foo.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo.test_object.beep`, |
| true, |
| `module.foo[1].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo.module.bar.test_object.beep`, |
| true, |
| `module.foo[1].module.bar.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo.module.bar[0].test_object.beep`, |
| true, |
| `module.foo[1].module.bar[0].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar.module.foo`, |
| `module.foo[0].test_object.beep`, |
| true, |
| `module.bar.module.foo[0].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo.module.bar`, |
| `module.bar`, |
| `module.foo.module.bar[0].test_object.beep`, |
| true, |
| `module.bar[0].test_object.beep`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.baz`, |
| `module.foo.module.bar.test_object.beep`, |
| true, |
| `module.foo.module.baz.test_object.beep`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.baz`, |
| `module.foo[1].module.bar.test_object.beep`, |
| true, |
| `module.foo[1].module.baz.test_object.beep`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.foo[1].module.bar.test_object.beep`, |
| true, |
| `module.foo[1].module.bar[1].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo.test_object.beep`, |
| false, // the receiver module has a non-matching instance key (NoKey) |
| ``, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo[2].test_object.beep`, |
| false, // the receiver is already at the "to" address |
| ``, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.boz.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| `foo.bar`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.boz.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| `foo.bar`, |
| `module.a`, |
| `module.b`, |
| `module.boz.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.c.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2[0]`, |
| `module.b1.module.b2[1]`, |
| `module.c.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.a1.module.b2.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.b1.module.a2.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2[0]`, |
| `module.b1.module.b2[1]`, |
| `module.a1.module.b2[0].test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `foo_instance.bar`, |
| `foo_instance.baz`, |
| `module.foo.test_object.beep`, |
| false, // the resource address is unrelated to the move statements |
| ``, |
| }, |
| } |
| |
| for _, test := range tests { |
| t.Run( |
| fmt.Sprintf( |
| "%s: %s to %s with %s", |
| test.DeclModule, |
| test.StmtFrom, test.StmtTo, |
| test.Receiver, |
| ), |
| func(t *testing.T) { |
| |
| parseStmtEP := func(t *testing.T, input string) *MoveEndpoint { |
| t.Helper() |
| |
| traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos) |
| if hclDiags.HasErrors() { |
| // We're not trying to test the HCL parser here, so any |
| // failures at this point are likely to be bugs in the |
| // test case itself. |
| t.Fatalf("syntax error: %s", hclDiags.Error()) |
| } |
| |
| moveEp, diags := ParseMoveEndpoint(traversal) |
| if diags.HasErrors() { |
| t.Fatalf("unexpected error: %s", diags.Err().Error()) |
| } |
| return moveEp |
| } |
| |
| fromEPLocal := parseStmtEP(t, test.StmtFrom) |
| toEPLocal := parseStmtEP(t, test.StmtTo) |
| |
| declModule := RootModule |
| if test.DeclModule != "" { |
| declModule = strings.Split(test.DeclModule, ".") |
| } |
| fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal) |
| if fromEP == nil || toEP == nil { |
| t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto: %s", fromEPLocal, toEPLocal) |
| } |
| |
| receiverAddr, diags := ParseAbsResourceInstanceStr(test.Receiver) |
| if diags.HasErrors() { |
| t.Fatalf("invalid reciever address: %s", diags.Err().Error()) |
| } |
| gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP) |
| if !test.WantMatch { |
| if gotMatch { |
| t.Errorf("unexpected match\nreceiver: %s\nfrom: %s\nto: %s\nresult: %s", test.Receiver, fromEP, toEP, gotAddr) |
| } |
| return |
| } |
| |
| if !gotMatch { |
| t.Fatalf("unexpected non-match\nreceiver: %s (%T)\nfrom: %s\nto: %s\ngot: (no match)\nwant: %s", test.Receiver, receiverAddr, fromEP, toEP, test.WantResult) |
| } |
| |
| if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr { |
| t.Errorf("wrong result\ngot: %s\nwant: %s", gotStr, wantStr) |
| } |
| }, |
| ) |
| } |
| } |
| |
| func TestAbsResourceMoveDestination(t *testing.T) { |
| tests := []struct { |
| DeclModule string |
| StmtFrom, StmtTo string |
| Receiver string |
| WantMatch bool |
| WantResult string |
| }{ |
| { |
| ``, |
| `test_object.beep`, |
| `test_object.boop`, |
| `test_object.beep`, |
| true, |
| `test_object.boop`, |
| }, |
| { |
| ``, |
| `test_object.beep`, |
| `module.foo.test_object.beep`, |
| `test_object.beep`, |
| true, |
| `module.foo.test_object.beep`, |
| }, |
| { |
| ``, |
| `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`, |
| }, |
| { |
| ``, |
| `test_object.beep`, |
| `test_object.boop`, |
| `test_object.boop`, |
| false, // the reciever is already the "to" address |
| ``, |
| }, |
| { |
| `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`, |
| `module.bar`, |
| `module.foo.test_object.beep`, |
| true, |
| `module.bar.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar`, |
| `module.foo[1].test_object.beep`, |
| true, |
| `module.bar[1].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar`, |
| `module.foo["a"].test_object.beep`, |
| true, |
| `module.bar["a"].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar.module.foo`, |
| `module.foo.test_object.beep`, |
| true, |
| `module.bar.module.foo.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo.module.bar`, |
| `module.bar`, |
| `module.foo.module.bar.test_object.beep`, |
| true, |
| `module.bar.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo[1].test_object.beep`, |
| true, |
| `module.foo[2].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo`, |
| `module.foo[1].test_object.beep`, |
| true, |
| `module.foo.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo.test_object.beep`, |
| true, |
| `module.foo[1].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo.module.bar.test_object.beep`, |
| true, |
| `module.foo[1].module.bar.test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.foo[1]`, |
| `module.foo.module.bar[0].test_object.beep`, |
| true, |
| `module.foo[1].module.bar[0].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo`, |
| `module.bar.module.foo`, |
| `module.foo[0].test_object.beep`, |
| true, |
| `module.bar.module.foo[0].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo.module.bar`, |
| `module.bar`, |
| `module.foo.module.bar[0].test_object.beep`, |
| true, |
| `module.bar[0].test_object.beep`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.baz`, |
| `module.foo.module.bar.test_object.beep`, |
| true, |
| `module.foo.module.baz.test_object.beep`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.baz`, |
| `module.foo[1].module.bar.test_object.beep`, |
| true, |
| `module.foo[1].module.baz.test_object.beep`, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.foo[1].module.bar.test_object.beep`, |
| true, |
| `module.foo[1].module.bar[1].test_object.beep`, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo.test_object.beep`, |
| false, // the receiver module has a non-matching instance key (NoKey) |
| ``, |
| }, |
| { |
| ``, |
| `module.foo[1]`, |
| `module.foo[2]`, |
| `module.foo[2].test_object.beep`, |
| false, // the receiver is already at the "to" address |
| ``, |
| }, |
| { |
| `foo`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.boz.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| `foo.bar`, |
| `module.bar`, |
| `module.bar[1]`, |
| `module.boz.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| `foo.bar`, |
| `module.a`, |
| `module.b`, |
| `module.boz.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.c.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2[0]`, |
| `module.b1.module.b2[1]`, |
| `module.c.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.a1.module.b2.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2`, |
| `module.b1.module.b2`, |
| `module.b1.module.a2.test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `module.a1.module.a2[0]`, |
| `module.b1.module.b2[1]`, |
| `module.a1.module.b2[0].test_object.beep`, |
| false, // the receiver module is outside the declaration module |
| ``, |
| }, |
| { |
| ``, |
| `foo_instance.bar`, |
| `foo_instance.baz`, |
| `module.foo.test_object.beep`, |
| false, // the resource address is unrelated to the move statements |
| ``, |
| }, |
| } |
| |
| for i, test := range tests { |
| t.Run( |
| fmt.Sprintf( |
| "[%02d] %s: %s to %s with %s", |
| i, |
| test.DeclModule, |
| test.StmtFrom, test.StmtTo, |
| test.Receiver, |
| ), |
| func(t *testing.T) { |
| |
| parseStmtEP := func(t *testing.T, input string) *MoveEndpoint { |
| t.Helper() |
| |
| traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos) |
| if hclDiags.HasErrors() { |
| // We're not trying to test the HCL parser here, so any |
| // failures at this point are likely to be bugs in the |
| // test case itself. |
| t.Fatalf("syntax error: %s", hclDiags.Error()) |
| } |
| |
| moveEp, diags := ParseMoveEndpoint(traversal) |
| if diags.HasErrors() { |
| t.Fatalf("unexpected error: %s", diags.Err().Error()) |
| } |
| return moveEp |
| } |
| |
| fromEPLocal := parseStmtEP(t, test.StmtFrom) |
| toEPLocal := parseStmtEP(t, test.StmtTo) |
| |
| declModule := RootModule |
| if test.DeclModule != "" { |
| declModule = strings.Split(test.DeclModule, ".") |
| } |
| fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal) |
| if fromEP == nil || toEP == nil { |
| t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto: %s", fromEPLocal, toEPLocal) |
| } |
| |
| // We only have an AbsResourceInstance parser, not an |
| // AbsResourceParser, and so we'll just cheat and parse this |
| // as a resource instance but fail if it includes an instance |
| // key. |
| receiverInstanceAddr, diags := ParseAbsResourceInstanceStr(test.Receiver) |
| if diags.HasErrors() { |
| t.Fatalf("invalid reciever address: %s", diags.Err().Error()) |
| } |
| if receiverInstanceAddr.Resource.Key != NoKey { |
| t.Fatalf("invalid reciever address: must be a resource, not a resource instance") |
| } |
| receiverAddr := receiverInstanceAddr.ContainingResource() |
| gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP) |
| if !test.WantMatch { |
| if gotMatch { |
| t.Errorf("unexpected match\nreceiver: %s (%T)\nfrom: %s\nto: %s\nresult: %s", test.Receiver, receiverAddr, fromEP, toEP, gotAddr) |
| } |
| return |
| } |
| |
| if !gotMatch { |
| t.Fatalf("unexpected non-match\nreceiver: %s (%T)\nfrom: %s\nto: %s\ngot: no match\nwant: %s", test.Receiver, receiverAddr, fromEP, toEP, test.WantResult) |
| } |
| |
| if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr { |
| t.Errorf("wrong result\ngot: %s\nwant: %s", gotStr, wantStr) |
| } |
| }, |
| ) |
| } |
| } |
| |
| func TestMoveEndpointChainAndNested(t *testing.T) { |
| tests := []struct { |
| Endpoint, Other AbsMoveable |
| EndpointMod, OtherMod Module |
| 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: true, |
| }, |
| |
| { |
| 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, |
| }, |
| |
| { |
| Endpoint: mustParseAbsResourceInstanceStr("resource.baz"), |
| EndpointMod: Module{"foo"}, |
| Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"), |
| CanChainFrom: true, |
| }, |
| |
| { |
| Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"), |
| Other: mustParseAbsResourceInstanceStr("resource.baz"), |
| OtherMod: Module{"foo"}, |
| CanChainFrom: true, |
| }, |
| |
| { |
| Endpoint: mustParseAbsResourceInstanceStr("resource.baz"), |
| EndpointMod: Module{"foo"}, |
| Other: mustParseAbsResourceInstanceStr("resource.baz"), |
| OtherMod: Module{"foo"}, |
| CanChainFrom: true, |
| }, |
| |
| { |
| Endpoint: mustParseAbsResourceInstanceStr("resource.baz").ContainingResource(), |
| EndpointMod: Module{"foo"}, |
| Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(), |
| CanChainFrom: true, |
| }, |
| |
| { |
| Endpoint: mustParseModuleInstanceStr("module.foo[2].module.baz"), |
| Other: mustParseModuleInstanceStr("module.baz"), |
| OtherMod: Module{"foo"}, |
| CanChainFrom: true, |
| }, |
| |
| { |
| Endpoint: AbsModuleCall{ |
| Call: ModuleCall{Name: "bing"}, |
| }, |
| EndpointMod: Module{"foo", "baz"}, |
| Other: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.baz"), |
| Call: ModuleCall{Name: "bing"}, |
| }, |
| OtherMod: Module{"foo"}, |
| CanChainFrom: true, |
| }, |
| |
| { |
| Endpoint: mustParseAbsResourceInstanceStr("resource.baz"), |
| EndpointMod: Module{"foo"}, |
| Other: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz").ContainingResource(), |
| NestedWithin: true, |
| }, |
| |
| { |
| Endpoint: mustParseAbsResourceInstanceStr("module.foo[2].resource.baz"), |
| Other: mustParseAbsResourceInstanceStr("resource.baz").ContainingResource(), |
| OtherMod: Module{"foo"}, |
| NestedWithin: true, |
| }, |
| |
| { |
| Endpoint: mustParseAbsResourceInstanceStr("resource.baz"), |
| EndpointMod: Module{"foo"}, |
| Other: mustParseAbsResourceInstanceStr("resource.baz").ContainingResource(), |
| OtherMod: Module{"foo"}, |
| NestedWithin: true, |
| }, |
| |
| { |
| Endpoint: mustParseAbsResourceInstanceStr("ressurce.baz").ContainingResource(), |
| EndpointMod: Module{"foo"}, |
| Other: mustParseModuleInstanceStr("module.foo[2]"), |
| NestedWithin: true, |
| }, |
| |
| { |
| Endpoint: AbsModuleCall{ |
| Call: ModuleCall{Name: "bang"}, |
| }, |
| EndpointMod: Module{"foo", "baz", "bing"}, |
| Other: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.baz"), |
| Call: ModuleCall{Name: "bing"}, |
| }, |
| OtherMod: Module{"foo"}, |
| NestedWithin: true, |
| }, |
| |
| { |
| Endpoint: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.bing"), |
| Call: ModuleCall{Name: "bang"}, |
| }, |
| EndpointMod: Module{"foo", "baz"}, |
| Other: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.foo.module.baz"), |
| Call: ModuleCall{Name: "bing"}, |
| }, |
| NestedWithin: 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, |
| module: test.EndpointMod, |
| } |
| |
| other := &MoveEndpointInModule{ |
| relSubject: test.Other, |
| module: test.OtherMod, |
| } |
| |
| if endpoint.CanChainFrom(other) != test.CanChainFrom { |
| t.Errorf("expected %s CanChainFrom %s == %t", endpoint, other, test.CanChainFrom) |
| } |
| |
| if endpoint.NestedWithin(other) != test.NestedWithin { |
| t.Errorf("expected %s NestedWithin %s == %t", endpoint, other, test.NestedWithin) |
| } |
| }, |
| ) |
| } |
| } |
| |
| func TestSelectsModule(t *testing.T) { |
| tests := []struct { |
| Endpoint *MoveEndpointInModule |
| Addr ModuleInstance |
| Selects bool |
| }{ |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.foo[2]"), |
| Call: ModuleCall{Name: "bar"}, |
| }, |
| }, |
| Addr: mustParseModuleInstanceStr("module.foo[2].module.bar[1]"), |
| Selects: true, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| module: mustParseModuleInstanceStr("module.foo").Module(), |
| relSubject: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.bar[2]"), |
| Call: ModuleCall{Name: "baz"}, |
| }, |
| }, |
| Addr: mustParseModuleInstanceStr("module.foo[2].module.bar[2].module.baz"), |
| Selects: true, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| module: mustParseModuleInstanceStr("module.foo").Module(), |
| relSubject: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.bar[2]"), |
| Call: ModuleCall{Name: "baz"}, |
| }, |
| }, |
| Addr: mustParseModuleInstanceStr("module.foo[2].module.bar[1].module.baz"), |
| Selects: false, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.bar"), |
| Call: ModuleCall{Name: "baz"}, |
| }, |
| }, |
| Addr: mustParseModuleInstanceStr("module.bar[1].module.baz"), |
| Selects: false, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| module: mustParseModuleInstanceStr("module.foo").Module(), |
| relSubject: mustParseAbsResourceInstanceStr(`module.bar.resource.name["key"]`), |
| }, |
| Addr: mustParseModuleInstanceStr(`module.foo[1].module.bar`), |
| Selects: true, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: mustParseModuleInstanceStr(`module.bar.module.baz["key"]`), |
| }, |
| Addr: mustParseModuleInstanceStr(`module.bar.module.baz["key"]`), |
| Selects: true, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: mustParseAbsResourceInstanceStr(`module.bar.module.baz["key"].resource.name`).ContainingResource(), |
| }, |
| Addr: mustParseModuleInstanceStr(`module.bar.module.baz["key"]`), |
| Selects: true, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| module: mustParseModuleInstanceStr("module.nope").Module(), |
| relSubject: mustParseAbsResourceInstanceStr(`module.bar.resource.name["key"]`), |
| }, |
| Addr: mustParseModuleInstanceStr(`module.foo[1].module.bar`), |
| Selects: false, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: mustParseModuleInstanceStr(`module.bar.module.baz["key"]`), |
| }, |
| Addr: mustParseModuleInstanceStr(`module.bar.module.baz["nope"]`), |
| Selects: false, |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: mustParseAbsResourceInstanceStr(`module.nope.module.baz["key"].resource.name`).ContainingResource(), |
| }, |
| Addr: mustParseModuleInstanceStr(`module.bar.module.baz["key"]`), |
| Selects: false, |
| }, |
| } |
| |
| for i, test := range tests { |
| t.Run(fmt.Sprintf("[%02d]%s.SelectsModule(%s)", i, test.Endpoint, test.Addr), |
| func(t *testing.T) { |
| if test.Endpoint.SelectsModule(test.Addr) != test.Selects { |
| t.Errorf("expected %s SelectsModule %s == %t", test.Endpoint, test.Addr, test.Selects) |
| } |
| }, |
| ) |
| } |
| } |
| |
| func TestSelectsResource(t *testing.T) { |
| matchingResource := Resource{ |
| Mode: ManagedResourceMode, |
| Type: "foo", |
| Name: "matching", |
| } |
| unmatchingResource := Resource{ |
| Mode: ManagedResourceMode, |
| Type: "foo", |
| Name: "unmatching", |
| } |
| childMod := Module{ |
| "child", |
| } |
| childModMatchingInst := ModuleInstance{ |
| ModuleInstanceStep{Name: "child", InstanceKey: StringKey("matching")}, |
| } |
| childModUnmatchingInst := ModuleInstance{ |
| ModuleInstanceStep{Name: "child", InstanceKey: StringKey("unmatching")}, |
| } |
| |
| tests := []struct { |
| Endpoint *MoveEndpointInModule |
| Addr AbsResource |
| Selects bool |
| }{ |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: matchingResource.Absolute(nil), |
| }, |
| Addr: matchingResource.Absolute(nil), |
| Selects: true, // exact match |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: unmatchingResource.Absolute(nil), |
| }, |
| Addr: matchingResource.Absolute(nil), |
| Selects: false, // wrong resource name |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: unmatchingResource.Instance(IntKey(1)).Absolute(nil), |
| }, |
| Addr: matchingResource.Absolute(nil), |
| Selects: false, // wrong resource name |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: matchingResource.Instance(NoKey).Absolute(nil), |
| }, |
| Addr: matchingResource.Absolute(nil), |
| Selects: true, // matches one instance |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: matchingResource.Instance(IntKey(0)).Absolute(nil), |
| }, |
| Addr: matchingResource.Absolute(nil), |
| Selects: true, // matches one instance |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: matchingResource.Instance(StringKey("a")).Absolute(nil), |
| }, |
| Addr: matchingResource.Absolute(nil), |
| Selects: true, // matches one instance |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| module: childMod, |
| relSubject: matchingResource.Absolute(nil), |
| }, |
| Addr: matchingResource.Absolute(childModMatchingInst), |
| Selects: true, // in one of the instances of the module where the statement was written |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: matchingResource.Absolute(childModMatchingInst), |
| }, |
| Addr: matchingResource.Absolute(childModMatchingInst), |
| Selects: true, // exact match |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: matchingResource.Instance(IntKey(2)).Absolute(childModMatchingInst), |
| }, |
| Addr: matchingResource.Absolute(childModMatchingInst), |
| Selects: true, // matches one instance |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: matchingResource.Absolute(childModMatchingInst), |
| }, |
| Addr: matchingResource.Absolute(childModUnmatchingInst), |
| Selects: false, // the containing module instance doesn't match |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr("module.foo[2]"), |
| Call: ModuleCall{Name: "bar"}, |
| }, |
| }, |
| Addr: matchingResource.Absolute(mustParseModuleInstanceStr("module.foo[2]")), |
| Selects: false, // a module call can't match a resource |
| }, |
| { |
| Endpoint: &MoveEndpointInModule{ |
| relSubject: mustParseModuleInstanceStr("module.foo[2]"), |
| }, |
| Addr: matchingResource.Absolute(mustParseModuleInstanceStr("module.foo[2]")), |
| Selects: false, // a module instance can't match a resource |
| }, |
| } |
| |
| for i, test := range tests { |
| t.Run(fmt.Sprintf("[%02d]%s SelectsResource(%s)", i, test.Endpoint, test.Addr), |
| func(t *testing.T) { |
| if got, want := test.Endpoint.SelectsResource(test.Addr), test.Selects; got != want { |
| t.Errorf("wrong result\nReceiver: %s\nArgument: %s\ngot: %t\nwant: %t", test.Endpoint, test.Addr, got, want) |
| } |
| }, |
| ) |
| } |
| } |
| |
| func TestIsModuleMoveReIndex(t *testing.T) { |
| tests := []struct { |
| from, to AbsMoveable |
| expect bool |
| }{ |
| { |
| from: mustParseModuleInstanceStr(`module.bar`), |
| to: mustParseModuleInstanceStr(`module.bar`), |
| expect: true, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar`), |
| to: mustParseModuleInstanceStr(`module.bar[0]`), |
| expect: true, |
| }, |
| { |
| from: AbsModuleCall{ |
| Call: ModuleCall{Name: "bar"}, |
| }, |
| to: mustParseModuleInstanceStr(`module.bar[0]`), |
| expect: true, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar["a"]`), |
| to: AbsModuleCall{ |
| Call: ModuleCall{Name: "bar"}, |
| }, |
| expect: true, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.foo`), |
| to: mustParseModuleInstanceStr(`module.bar`), |
| expect: false, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar`), |
| to: mustParseModuleInstanceStr(`module.foo[0]`), |
| expect: false, |
| }, |
| { |
| from: AbsModuleCall{ |
| Call: ModuleCall{Name: "bar"}, |
| }, |
| to: mustParseModuleInstanceStr(`module.foo[0]`), |
| expect: false, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar["a"]`), |
| to: AbsModuleCall{ |
| Call: ModuleCall{Name: "foo"}, |
| }, |
| expect: false, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar.module.baz`), |
| to: mustParseModuleInstanceStr(`module.bar.module.baz`), |
| expect: true, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar.module.baz`), |
| to: mustParseModuleInstanceStr(`module.bar.module.baz[0]`), |
| expect: true, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar.module.baz`), |
| to: mustParseModuleInstanceStr(`module.baz.module.baz`), |
| expect: false, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar.module.baz`), |
| to: mustParseModuleInstanceStr(`module.baz.module.baz[0]`), |
| expect: false, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar.module.baz`), |
| to: mustParseModuleInstanceStr(`module.bar[0].module.baz`), |
| expect: true, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar[0].module.baz`), |
| to: mustParseModuleInstanceStr(`module.bar.module.baz[0]`), |
| expect: true, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar[0].module.baz`), |
| to: mustParseModuleInstanceStr(`module.bar[1].module.baz[0]`), |
| expect: true, |
| }, |
| { |
| from: AbsModuleCall{ |
| Call: ModuleCall{Name: "baz"}, |
| }, |
| to: mustParseModuleInstanceStr(`module.bar.module.baz[0]`), |
| expect: false, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar.module.baz[0]`), |
| to: AbsModuleCall{ |
| Call: ModuleCall{Name: "baz"}, |
| }, |
| expect: false, |
| }, |
| |
| { |
| from: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr(`module.bar[0]`), |
| Call: ModuleCall{Name: "baz"}, |
| }, |
| to: mustParseModuleInstanceStr(`module.bar.module.baz[0]`), |
| expect: true, |
| }, |
| |
| { |
| from: mustParseModuleInstanceStr(`module.bar.module.baz[0]`), |
| to: AbsModuleCall{ |
| Module: mustParseModuleInstanceStr(`module.bar[0]`), |
| Call: ModuleCall{Name: "baz"}, |
| }, |
| expect: true, |
| }, |
| |
| { |
| from: mustParseModuleInstanceStr(`module.baz`), |
| to: mustParseModuleInstanceStr(`module.bar.module.baz[0]`), |
| expect: false, |
| }, |
| { |
| from: mustParseModuleInstanceStr(`module.bar.module.baz[0]`), |
| to: mustParseModuleInstanceStr(`module.baz`), |
| expect: false, |
| }, |
| } |
| |
| for i, test := range tests { |
| t.Run(fmt.Sprintf("[%02d]IsModuleMoveReIndex(%s, %s)", i, test.from, test.to), |
| func(t *testing.T) { |
| from := &MoveEndpointInModule{ |
| relSubject: test.from, |
| } |
| |
| to := &MoveEndpointInModule{ |
| relSubject: test.to, |
| } |
| |
| if got := from.IsModuleReIndex(to); got != test.expect { |
| t.Errorf("expected %t, got %t", test.expect, got) |
| } |
| }, |
| ) |
| } |
| } |
| |
| func mustParseAbsResourceInstanceStr(s string) AbsResourceInstance { |
| r, diags := ParseAbsResourceInstanceStr(s) |
| if diags.HasErrors() { |
| panic(diags.ErrWithWarnings().Error()) |
| } |
| return r |
| } |