github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/addrs/parse_target_test.go (about)

     1  package addrs
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/go-test/deep"
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/hashicorp/hcl/v2/hclsyntax"
     9  	"github.com/hashicorp/terraform-plugin-sdk/internal/tfdiags"
    10  )
    11  
    12  func TestParseTarget(t *testing.T) {
    13  	tests := []struct {
    14  		Input   string
    15  		Want    *Target
    16  		WantErr string
    17  	}{
    18  		{
    19  			`module.foo`,
    20  			&Target{
    21  				Subject: ModuleInstance{
    22  					{
    23  						Name: "foo",
    24  					},
    25  				},
    26  				SourceRange: tfdiags.SourceRange{
    27  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
    28  					End:   tfdiags.SourcePos{Line: 1, Column: 11, Byte: 10},
    29  				},
    30  			},
    31  			``,
    32  		},
    33  		{
    34  			`module.foo[2]`,
    35  			&Target{
    36  				Subject: ModuleInstance{
    37  					{
    38  						Name:        "foo",
    39  						InstanceKey: IntKey(2),
    40  					},
    41  				},
    42  				SourceRange: tfdiags.SourceRange{
    43  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
    44  					End:   tfdiags.SourcePos{Line: 1, Column: 14, Byte: 13},
    45  				},
    46  			},
    47  			``,
    48  		},
    49  		{
    50  			`module.foo[2].module.bar`,
    51  			&Target{
    52  				Subject: ModuleInstance{
    53  					{
    54  						Name:        "foo",
    55  						InstanceKey: IntKey(2),
    56  					},
    57  					{
    58  						Name: "bar",
    59  					},
    60  				},
    61  				SourceRange: tfdiags.SourceRange{
    62  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
    63  					End:   tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
    64  				},
    65  			},
    66  			``,
    67  		},
    68  		{
    69  			`aws_instance.foo`,
    70  			&Target{
    71  				Subject: AbsResource{
    72  					Resource: Resource{
    73  						Mode: ManagedResourceMode,
    74  						Type: "aws_instance",
    75  						Name: "foo",
    76  					},
    77  					Module: RootModuleInstance,
    78  				},
    79  				SourceRange: tfdiags.SourceRange{
    80  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
    81  					End:   tfdiags.SourcePos{Line: 1, Column: 17, Byte: 16},
    82  				},
    83  			},
    84  			``,
    85  		},
    86  		{
    87  			`aws_instance.foo[1]`,
    88  			&Target{
    89  				Subject: AbsResourceInstance{
    90  					Resource: ResourceInstance{
    91  						Resource: Resource{
    92  							Mode: ManagedResourceMode,
    93  							Type: "aws_instance",
    94  							Name: "foo",
    95  						},
    96  						Key: IntKey(1),
    97  					},
    98  					Module: RootModuleInstance,
    99  				},
   100  				SourceRange: tfdiags.SourceRange{
   101  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   102  					End:   tfdiags.SourcePos{Line: 1, Column: 20, Byte: 19},
   103  				},
   104  			},
   105  			``,
   106  		},
   107  		{
   108  			`data.aws_instance.foo`,
   109  			&Target{
   110  				Subject: AbsResource{
   111  					Resource: Resource{
   112  						Mode: DataResourceMode,
   113  						Type: "aws_instance",
   114  						Name: "foo",
   115  					},
   116  					Module: RootModuleInstance,
   117  				},
   118  				SourceRange: tfdiags.SourceRange{
   119  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   120  					End:   tfdiags.SourcePos{Line: 1, Column: 22, Byte: 21},
   121  				},
   122  			},
   123  			``,
   124  		},
   125  		{
   126  			`data.aws_instance.foo[1]`,
   127  			&Target{
   128  				Subject: AbsResourceInstance{
   129  					Resource: ResourceInstance{
   130  						Resource: Resource{
   131  							Mode: DataResourceMode,
   132  							Type: "aws_instance",
   133  							Name: "foo",
   134  						},
   135  						Key: IntKey(1),
   136  					},
   137  					Module: RootModuleInstance,
   138  				},
   139  				SourceRange: tfdiags.SourceRange{
   140  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   141  					End:   tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24},
   142  				},
   143  			},
   144  			``,
   145  		},
   146  		{
   147  			`module.foo.aws_instance.bar`,
   148  			&Target{
   149  				Subject: AbsResource{
   150  					Resource: Resource{
   151  						Mode: ManagedResourceMode,
   152  						Type: "aws_instance",
   153  						Name: "bar",
   154  					},
   155  					Module: ModuleInstance{
   156  						{Name: "foo"},
   157  					},
   158  				},
   159  				SourceRange: tfdiags.SourceRange{
   160  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   161  					End:   tfdiags.SourcePos{Line: 1, Column: 28, Byte: 27},
   162  				},
   163  			},
   164  			``,
   165  		},
   166  		{
   167  			`module.foo.module.bar.aws_instance.baz`,
   168  			&Target{
   169  				Subject: AbsResource{
   170  					Resource: Resource{
   171  						Mode: ManagedResourceMode,
   172  						Type: "aws_instance",
   173  						Name: "baz",
   174  					},
   175  					Module: ModuleInstance{
   176  						{Name: "foo"},
   177  						{Name: "bar"},
   178  					},
   179  				},
   180  				SourceRange: tfdiags.SourceRange{
   181  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   182  					End:   tfdiags.SourcePos{Line: 1, Column: 39, Byte: 38},
   183  				},
   184  			},
   185  			``,
   186  		},
   187  		{
   188  			`module.foo.module.bar.aws_instance.baz["hello"]`,
   189  			&Target{
   190  				Subject: AbsResourceInstance{
   191  					Resource: ResourceInstance{
   192  						Resource: Resource{
   193  							Mode: ManagedResourceMode,
   194  							Type: "aws_instance",
   195  							Name: "baz",
   196  						},
   197  						Key: StringKey("hello"),
   198  					},
   199  					Module: ModuleInstance{
   200  						{Name: "foo"},
   201  						{Name: "bar"},
   202  					},
   203  				},
   204  				SourceRange: tfdiags.SourceRange{
   205  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   206  					End:   tfdiags.SourcePos{Line: 1, Column: 48, Byte: 47},
   207  				},
   208  			},
   209  			``,
   210  		},
   211  		{
   212  			`module.foo.data.aws_instance.bar`,
   213  			&Target{
   214  				Subject: AbsResource{
   215  					Resource: Resource{
   216  						Mode: DataResourceMode,
   217  						Type: "aws_instance",
   218  						Name: "bar",
   219  					},
   220  					Module: ModuleInstance{
   221  						{Name: "foo"},
   222  					},
   223  				},
   224  				SourceRange: tfdiags.SourceRange{
   225  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   226  					End:   tfdiags.SourcePos{Line: 1, Column: 33, Byte: 32},
   227  				},
   228  			},
   229  			``,
   230  		},
   231  		{
   232  			`module.foo.module.bar.data.aws_instance.baz`,
   233  			&Target{
   234  				Subject: AbsResource{
   235  					Resource: Resource{
   236  						Mode: DataResourceMode,
   237  						Type: "aws_instance",
   238  						Name: "baz",
   239  					},
   240  					Module: ModuleInstance{
   241  						{Name: "foo"},
   242  						{Name: "bar"},
   243  					},
   244  				},
   245  				SourceRange: tfdiags.SourceRange{
   246  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   247  					End:   tfdiags.SourcePos{Line: 1, Column: 44, Byte: 43},
   248  				},
   249  			},
   250  			``,
   251  		},
   252  		{
   253  			`module.foo.module.bar.data.aws_instance.baz["hello"]`,
   254  			&Target{
   255  				Subject: AbsResourceInstance{
   256  					Resource: ResourceInstance{
   257  						Resource: Resource{
   258  							Mode: DataResourceMode,
   259  							Type: "aws_instance",
   260  							Name: "baz",
   261  						},
   262  						Key: StringKey("hello"),
   263  					},
   264  					Module: ModuleInstance{
   265  						{Name: "foo"},
   266  						{Name: "bar"},
   267  					},
   268  				},
   269  				SourceRange: tfdiags.SourceRange{
   270  					Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   271  					End:   tfdiags.SourcePos{Line: 1, Column: 53, Byte: 52},
   272  				},
   273  			},
   274  			``,
   275  		},
   276  
   277  		{
   278  			`aws_instance`,
   279  			nil,
   280  			`Resource specification must include a resource type and name.`,
   281  		},
   282  		{
   283  			`module`,
   284  			nil,
   285  			`Prefix "module." must be followed by a module name.`,
   286  		},
   287  		{
   288  			`module["baz"]`,
   289  			nil,
   290  			`Prefix "module." must be followed by a module name.`,
   291  		},
   292  		{
   293  			`module.baz.bar`,
   294  			nil,
   295  			`Resource specification must include a resource type and name.`,
   296  		},
   297  		{
   298  			`aws_instance.foo.bar`,
   299  			nil,
   300  			`Resource instance key must be given in square brackets.`,
   301  		},
   302  		{
   303  			`aws_instance.foo[1].baz`,
   304  			nil,
   305  			`Unexpected extra operators after address.`,
   306  		},
   307  	}
   308  
   309  	for _, test := range tests {
   310  		t.Run(test.Input, func(t *testing.T) {
   311  			traversal, travDiags := hclsyntax.ParseTraversalAbs([]byte(test.Input), "", hcl.Pos{Line: 1, Column: 1})
   312  			if travDiags.HasErrors() {
   313  				t.Fatal(travDiags.Error())
   314  			}
   315  
   316  			got, diags := ParseTarget(traversal)
   317  
   318  			switch len(diags) {
   319  			case 0:
   320  				if test.WantErr != "" {
   321  					t.Fatalf("succeeded; want error: %s", test.WantErr)
   322  				}
   323  			case 1:
   324  				if test.WantErr == "" {
   325  					t.Fatalf("unexpected diagnostics: %s", diags.Err())
   326  				}
   327  				if got, want := diags[0].Description().Detail, test.WantErr; got != want {
   328  					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
   329  				}
   330  			default:
   331  				t.Fatalf("too many diagnostics: %s", diags.Err())
   332  			}
   333  
   334  			if diags.HasErrors() {
   335  				return
   336  			}
   337  
   338  			for _, problem := range deep.Equal(got, test.Want) {
   339  				t.Errorf(problem)
   340  			}
   341  		})
   342  	}
   343  }