@@ -290,6 +290,175 @@ func TestProviderValidate(t *testing.T) {
290290 }
291291}
292292
293+ func TestProviderValidate_attributePath (t * testing.T ) {
294+ cases := []struct {
295+ P * Provider
296+ Config map [string ]interface {}
297+ ExpectedDiags diag.Diagnostics
298+ }{
299+ { // validate path automatically built across list
300+ P : & Provider {
301+ Schema : map [string ]* Schema {
302+ "foo" : {
303+ Type : TypeList ,
304+ Required : true ,
305+ Elem : & Resource {
306+ Schema : map [string ]* Schema {
307+ "bar" : {
308+ Type : TypeString ,
309+ Required : true ,
310+ ValidateFunc : func (v interface {}, k string ) ([]string , []error ) {
311+ return []string {"warn" }, []error {fmt .Errorf ("error" )}
312+ },
313+ },
314+ },
315+ },
316+ },
317+ },
318+ },
319+ Config : map [string ]interface {}{
320+ "foo" : []interface {}{
321+ map [string ]interface {}{
322+ "bar" : "baz" ,
323+ },
324+ },
325+ },
326+ ExpectedDiags : diag.Diagnostics {
327+ {
328+ Severity : diag .Warning ,
329+ AttributePath : cty.Path {cty.GetAttrStep {Name : "foo" }, cty.IndexStep {Key : cty .NumberIntVal (0 )}, cty.GetAttrStep {Name : "bar" }},
330+ },
331+ {
332+ Severity : diag .Error ,
333+ AttributePath : cty.Path {cty.GetAttrStep {Name : "foo" }, cty.IndexStep {Key : cty .NumberIntVal (0 )}, cty.GetAttrStep {Name : "bar" }},
334+ },
335+ },
336+ },
337+ { // path is truncated at typeset
338+ P : & Provider {
339+ Schema : map [string ]* Schema {
340+ "foo" : {
341+ Type : TypeSet ,
342+ Required : true ,
343+ Elem : & Resource {
344+ Schema : map [string ]* Schema {
345+ "bar" : {
346+ Type : TypeString ,
347+ Required : true ,
348+ ValidateDiagFunc : func (v interface {}, path cty.Path ) diag.Diagnostics {
349+ return diag.Diagnostics {{Severity : diag .Error , AttributePath : cty.Path {cty.GetAttrStep {Name : "doesnotmatter" }}}}
350+ },
351+ },
352+ },
353+ },
354+ },
355+ },
356+ },
357+ Config : map [string ]interface {}{
358+ "foo" : []interface {}{
359+ map [string ]interface {}{
360+ "bar" : "baz" ,
361+ },
362+ },
363+ },
364+ ExpectedDiags : diag.Diagnostics {
365+ {
366+ Severity : diag .Error ,
367+ AttributePath : cty.Path {cty.GetAttrStep {Name : "foo" }},
368+ },
369+ },
370+ },
371+ { // relative path is appended
372+ P : & Provider {
373+ Schema : map [string ]* Schema {
374+ "foo" : {
375+ Type : TypeList ,
376+ Required : true ,
377+ Elem : & Resource {
378+ Schema : map [string ]* Schema {
379+ "bar" : {
380+ Type : TypeMap ,
381+ Required : true ,
382+ ValidateDiagFunc : func (v interface {}, path cty.Path ) diag.Diagnostics {
383+ return diag.Diagnostics {{Severity : diag .Error , AttributePath : cty.Path {cty.IndexStep {Key : cty .StringVal ("mapkey" )}}}}
384+ },
385+ },
386+ },
387+ },
388+ },
389+ },
390+ },
391+ Config : map [string ]interface {}{
392+ "foo" : []interface {}{
393+ map [string ]interface {}{
394+ "bar" : map [string ]interface {}{
395+ "mapkey" : "val" ,
396+ },
397+ },
398+ },
399+ },
400+ ExpectedDiags : diag.Diagnostics {
401+ {
402+ Severity : diag .Error ,
403+ AttributePath : cty.Path {cty.GetAttrStep {Name : "foo" }, cty.IndexStep {Key : cty .NumberIntVal (0 )}, cty.GetAttrStep {Name : "bar" }, cty.IndexStep {Key : cty .StringVal ("mapkey" )}},
404+ },
405+ },
406+ },
407+ { // absolute path is not altered
408+ P : & Provider {
409+ Schema : map [string ]* Schema {
410+ "foo" : {
411+ Type : TypeList ,
412+ Required : true ,
413+ Elem : & Resource {
414+ Schema : map [string ]* Schema {
415+ "bar" : {
416+ Type : TypeMap ,
417+ Required : true ,
418+ ValidateDiagFunc : func (v interface {}, path cty.Path ) diag.Diagnostics {
419+ return diag.Diagnostics {{Severity : diag .Error , AttributePath : append (path , cty.IndexStep {Key : cty .StringVal ("mapkey" )})}}
420+ },
421+ },
422+ },
423+ },
424+ },
425+ },
426+ },
427+ Config : map [string ]interface {}{
428+ "foo" : []interface {}{
429+ map [string ]interface {}{
430+ "bar" : map [string ]interface {}{
431+ "mapkey" : "val" ,
432+ },
433+ },
434+ },
435+ },
436+ ExpectedDiags : diag.Diagnostics {
437+ {
438+ Severity : diag .Error ,
439+ AttributePath : cty.Path {cty.GetAttrStep {Name : "foo" }, cty.IndexStep {Key : cty .NumberIntVal (0 )}, cty.GetAttrStep {Name : "bar" }, cty.IndexStep {Key : cty .StringVal ("mapkey" )}},
440+ },
441+ },
442+ },
443+ }
444+
445+ for i , tc := range cases {
446+ c := terraform .NewResourceConfigRaw (tc .Config )
447+ diags := tc .P .Validate (c )
448+ if len (diags ) != len (tc .ExpectedDiags ) {
449+ t .Fatalf ("%d: wrong number of diags, expected %d, got %d" , i , len (tc .ExpectedDiags ), len (diags ))
450+ }
451+ for j := range diags {
452+ if diags [j ].Severity != tc .ExpectedDiags [j ].Severity {
453+ t .Fatalf ("%d: expected severity %v, got %v" , i , tc .ExpectedDiags [j ].Severity , diags [j ].Severity )
454+ }
455+ if ! diags [j ].AttributePath .Equals (tc .ExpectedDiags [j ].AttributePath ) {
456+ t .Fatalf ("%d: attribute paths do not match expected: %v, got %v" , i , tc .ExpectedDiags [j ].AttributePath , diags [j ].AttributePath )
457+ }
458+ }
459+ }
460+ }
461+
293462func TestProviderDiff_legacyTimeoutType (t * testing.T ) {
294463 p := & Provider {
295464 ResourcesMap : map [string ]* Resource {
0 commit comments