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 }