|
|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
package tfdiags
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"reflect"
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
@ -33,109 +34,124 @@ baz "b" {
|
|
|
|
|
t.Fatal(parseDiags)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body := f.Body
|
|
|
|
|
var diags Diagnostics
|
|
|
|
|
diags = diags.Append(AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
"foo[0].bar",
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "foo"},
|
|
|
|
|
cty.IndexStep{Key: cty.NumberIntVal(0)},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
diags = diags.Append(AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
"foo[1].bar",
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "foo"},
|
|
|
|
|
cty.IndexStep{Key: cty.NumberIntVal(1)},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
diags = diags.Append(AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
"bar.bar",
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
diags = diags.Append(AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
`baz["a"].bar`,
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "baz"},
|
|
|
|
|
cty.IndexStep{Key: cty.StringVal("a")},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
diags = diags.Append(AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
`baz["b"].bar`,
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "baz"},
|
|
|
|
|
cty.IndexStep{Key: cty.StringVal("b")},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
testCases := []struct {
|
|
|
|
|
Diag Diagnostic
|
|
|
|
|
ExpectedRange *SourceRange
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
"foo[0].bar",
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "foo"},
|
|
|
|
|
cty.IndexStep{Key: cty.NumberIntVal(0)},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
&SourceRange{
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 3, Column: 9, Byte: 15},
|
|
|
|
|
End: SourcePos{Line: 3, Column: 13, Byte: 19},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
// Attribute value with subject already populated should not be disturbed.
|
|
|
|
|
// (in a real case, this might've been passed through from a deeper function
|
|
|
|
|
// in the call stack, for example.)
|
|
|
|
|
diags = diags.Append(&attributeDiagnostic{
|
|
|
|
|
diagnosticBase: diagnosticBase{
|
|
|
|
|
summary: "preexisting",
|
|
|
|
|
detail: "detail",
|
|
|
|
|
{
|
|
|
|
|
AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
"foo[1].bar",
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "foo"},
|
|
|
|
|
cty.IndexStep{Key: cty.NumberIntVal(1)},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
&SourceRange{
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 6, Column: 9, Byte: 36},
|
|
|
|
|
End: SourcePos{Line: 6, Column: 14, Byte: 41},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
subject: &SourceRange{
|
|
|
|
|
Filename: "somewhere_else.tf",
|
|
|
|
|
{
|
|
|
|
|
AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
"bar.bar",
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
&SourceRange{
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 9, Column: 9, Byte: 58},
|
|
|
|
|
End: SourcePos{Line: 9, Column: 15, Byte: 64},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
gotDiags := diags.InConfigBody(body)
|
|
|
|
|
|
|
|
|
|
wantRanges := map[string]*SourceRange{
|
|
|
|
|
`foo[0].bar`: {
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 3, Column: 9, Byte: 15},
|
|
|
|
|
End: SourcePos{Line: 3, Column: 13, Byte: 19},
|
|
|
|
|
{
|
|
|
|
|
AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
`baz["a"].bar`,
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "baz"},
|
|
|
|
|
cty.IndexStep{Key: cty.StringVal("a")},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
&SourceRange{
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 12, Column: 9, Byte: 85},
|
|
|
|
|
End: SourcePos{Line: 12, Column: 15, Byte: 91},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
`foo[1].bar`: {
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 6, Column: 9, Byte: 36},
|
|
|
|
|
End: SourcePos{Line: 6, Column: 14, Byte: 41},
|
|
|
|
|
{
|
|
|
|
|
AttributeValue(
|
|
|
|
|
Error,
|
|
|
|
|
`baz["b"].bar`,
|
|
|
|
|
"detail",
|
|
|
|
|
cty.Path{
|
|
|
|
|
cty.GetAttrStep{Name: "baz"},
|
|
|
|
|
cty.IndexStep{Key: cty.StringVal("b")},
|
|
|
|
|
cty.GetAttrStep{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
&SourceRange{
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 15, Column: 9, Byte: 112},
|
|
|
|
|
End: SourcePos{Line: 15, Column: 15, Byte: 118},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
`bar.bar`: {
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 9, Column: 9, Byte: 58},
|
|
|
|
|
End: SourcePos{Line: 9, Column: 15, Byte: 64},
|
|
|
|
|
},
|
|
|
|
|
`baz["a"].bar`: {
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 12, Column: 9, Byte: 85},
|
|
|
|
|
End: SourcePos{Line: 12, Column: 15, Byte: 91},
|
|
|
|
|
},
|
|
|
|
|
`baz["b"].bar`: {
|
|
|
|
|
Filename: "test.tf",
|
|
|
|
|
Start: SourcePos{Line: 15, Column: 9, Byte: 112},
|
|
|
|
|
End: SourcePos{Line: 15, Column: 15, Byte: 118},
|
|
|
|
|
},
|
|
|
|
|
`preexisting`: {
|
|
|
|
|
Filename: "somewhere_else.tf",
|
|
|
|
|
{
|
|
|
|
|
// Attribute value with subject already populated should not be disturbed.
|
|
|
|
|
// (in a real case, this might've been passed through from a deeper function
|
|
|
|
|
// in the call stack, for example.)
|
|
|
|
|
&attributeDiagnostic{
|
|
|
|
|
diagnosticBase: diagnosticBase{
|
|
|
|
|
summary: "preexisting",
|
|
|
|
|
detail: "detail",
|
|
|
|
|
},
|
|
|
|
|
subject: &SourceRange{
|
|
|
|
|
Filename: "somewhere_else.tf",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
&SourceRange{
|
|
|
|
|
Filename: "somewhere_else.tf",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
gotRanges := make(map[string]*SourceRange)
|
|
|
|
|
for _, diag := range gotDiags {
|
|
|
|
|
gotRanges[diag.Description().Summary] = diag.Source().Subject
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, problem := range deep.Equal(gotRanges, wantRanges) {
|
|
|
|
|
t.Error(problem)
|
|
|
|
|
for i, tc := range testCases {
|
|
|
|
|
t.Run(fmt.Sprintf("%d:%s", i, tc.Diag.Description()), func(t *testing.T) {
|
|
|
|
|
var diags Diagnostics
|
|
|
|
|
diags = diags.Append(tc.Diag)
|
|
|
|
|
gotDiags := diags.InConfigBody(f.Body)
|
|
|
|
|
gotRange := gotDiags[0].Source().Subject
|
|
|
|
|
|
|
|
|
|
for _, problem := range deep.Equal(gotRange, tc.ExpectedRange) {
|
|
|
|
|
t.Error(problem)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|