github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/configs/moved_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package configs
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/google/go-cmp/cmp"
    10  	"github.com/hashicorp/hcl/v2"
    11  	"github.com/hashicorp/hcl/v2/hcltest"
    12  	"github.com/terramate-io/tf/addrs"
    13  )
    14  
    15  func TestMovedBlock_decode(t *testing.T) {
    16  	blockRange := hcl.Range{
    17  		Filename: "mock.tf",
    18  		Start:    hcl.Pos{Line: 3, Column: 12, Byte: 27},
    19  		End:      hcl.Pos{Line: 3, Column: 19, Byte: 34},
    20  	}
    21  
    22  	foo_expr := hcltest.MockExprTraversalSrc("test_instance.foo")
    23  	bar_expr := hcltest.MockExprTraversalSrc("test_instance.bar")
    24  
    25  	foo_index_expr := hcltest.MockExprTraversalSrc("test_instance.foo[1]")
    26  	bar_index_expr := hcltest.MockExprTraversalSrc("test_instance.bar[\"one\"]")
    27  
    28  	mod_foo_expr := hcltest.MockExprTraversalSrc("module.foo")
    29  	mod_bar_expr := hcltest.MockExprTraversalSrc("module.bar")
    30  
    31  	tests := map[string]struct {
    32  		input *hcl.Block
    33  		want  *Moved
    34  		err   string
    35  	}{
    36  		"success": {
    37  			&hcl.Block{
    38  				Type: "moved",
    39  				Body: hcltest.MockBody(&hcl.BodyContent{
    40  					Attributes: hcl.Attributes{
    41  						"from": {
    42  							Name: "from",
    43  							Expr: foo_expr,
    44  						},
    45  						"to": {
    46  							Name: "to",
    47  							Expr: bar_expr,
    48  						},
    49  					},
    50  				}),
    51  				DefRange: blockRange,
    52  			},
    53  			&Moved{
    54  				From:      mustMoveEndpointFromExpr(foo_expr),
    55  				To:        mustMoveEndpointFromExpr(bar_expr),
    56  				DeclRange: blockRange,
    57  			},
    58  			``,
    59  		},
    60  		"indexed resources": {
    61  			&hcl.Block{
    62  				Type: "moved",
    63  				Body: hcltest.MockBody(&hcl.BodyContent{
    64  					Attributes: hcl.Attributes{
    65  						"from": {
    66  							Name: "from",
    67  							Expr: foo_index_expr,
    68  						},
    69  						"to": {
    70  							Name: "to",
    71  							Expr: bar_index_expr,
    72  						},
    73  					},
    74  				}),
    75  				DefRange: blockRange,
    76  			},
    77  			&Moved{
    78  				From:      mustMoveEndpointFromExpr(foo_index_expr),
    79  				To:        mustMoveEndpointFromExpr(bar_index_expr),
    80  				DeclRange: blockRange,
    81  			},
    82  			``,
    83  		},
    84  		"modules": {
    85  			&hcl.Block{
    86  				Type: "moved",
    87  				Body: hcltest.MockBody(&hcl.BodyContent{
    88  					Attributes: hcl.Attributes{
    89  						"from": {
    90  							Name: "from",
    91  							Expr: mod_foo_expr,
    92  						},
    93  						"to": {
    94  							Name: "to",
    95  							Expr: mod_bar_expr,
    96  						},
    97  					},
    98  				}),
    99  				DefRange: blockRange,
   100  			},
   101  			&Moved{
   102  				From:      mustMoveEndpointFromExpr(mod_foo_expr),
   103  				To:        mustMoveEndpointFromExpr(mod_bar_expr),
   104  				DeclRange: blockRange,
   105  			},
   106  			``,
   107  		},
   108  		"error: missing argument": {
   109  			&hcl.Block{
   110  				Type: "moved",
   111  				Body: hcltest.MockBody(&hcl.BodyContent{
   112  					Attributes: hcl.Attributes{
   113  						"from": {
   114  							Name: "from",
   115  							Expr: foo_expr,
   116  						},
   117  					},
   118  				}),
   119  				DefRange: blockRange,
   120  			},
   121  			&Moved{
   122  				From:      mustMoveEndpointFromExpr(foo_expr),
   123  				DeclRange: blockRange,
   124  			},
   125  			"Missing required argument",
   126  		},
   127  		"error: type mismatch": {
   128  			&hcl.Block{
   129  				Type: "moved",
   130  				Body: hcltest.MockBody(&hcl.BodyContent{
   131  					Attributes: hcl.Attributes{
   132  						"to": {
   133  							Name: "to",
   134  							Expr: foo_expr,
   135  						},
   136  						"from": {
   137  							Name: "from",
   138  							Expr: mod_foo_expr,
   139  						},
   140  					},
   141  				}),
   142  				DefRange: blockRange,
   143  			},
   144  			&Moved{
   145  				To:        mustMoveEndpointFromExpr(foo_expr),
   146  				From:      mustMoveEndpointFromExpr(mod_foo_expr),
   147  				DeclRange: blockRange,
   148  			},
   149  			"Invalid \"moved\" addresses",
   150  		},
   151  	}
   152  
   153  	for name, test := range tests {
   154  		t.Run(name, func(t *testing.T) {
   155  			got, diags := decodeMovedBlock(test.input)
   156  
   157  			if diags.HasErrors() {
   158  				if test.err == "" {
   159  					t.Fatalf("unexpected error: %s", diags.Errs())
   160  				}
   161  				if gotErr := diags[0].Summary; gotErr != test.err {
   162  					t.Errorf("wrong error, got %q, want %q", gotErr, test.err)
   163  				}
   164  			} else if test.err != "" {
   165  				t.Fatal("expected error")
   166  			}
   167  
   168  			if !cmp.Equal(got, test.want, cmp.AllowUnexported(addrs.MoveEndpoint{})) {
   169  				t.Fatalf("wrong result: %s", cmp.Diff(got, test.want))
   170  			}
   171  		})
   172  	}
   173  }
   174  
   175  func TestMovedBlock_inModule(t *testing.T) {
   176  	parser := NewParser(nil)
   177  	mod, diags := parser.LoadConfigDir("testdata/valid-modules/moved-blocks")
   178  	if diags.HasErrors() {
   179  		t.Errorf("unexpected error: %s", diags.Error())
   180  	}
   181  
   182  	var gotPairs [][2]string
   183  	for _, mc := range mod.Moved {
   184  		gotPairs = append(gotPairs, [2]string{mc.From.String(), mc.To.String()})
   185  	}
   186  	wantPairs := [][2]string{
   187  		{`test.foo`, `test.bar`},
   188  		{`test.foo`, `test.bar["bloop"]`},
   189  		{`module.a`, `module.b`},
   190  		{`module.a`, `module.a["foo"]`},
   191  		{`test.foo`, `module.a.test.foo`},
   192  		{`data.test.foo`, `data.test.bar`},
   193  	}
   194  	if diff := cmp.Diff(wantPairs, gotPairs); diff != "" {
   195  		t.Errorf("wrong addresses\n%s", diff)
   196  	}
   197  }
   198  
   199  func mustMoveEndpointFromExpr(expr hcl.Expression) *addrs.MoveEndpoint {
   200  	traversal, hcldiags := hcl.AbsTraversalForExpr(expr)
   201  	if hcldiags.HasErrors() {
   202  		panic(hcldiags.Errs())
   203  	}
   204  
   205  	ep, diags := addrs.ParseMoveEndpoint(traversal)
   206  	if diags.HasErrors() {
   207  		panic(diags.Err())
   208  	}
   209  
   210  	return ep
   211  }