Skip to content

Commit f0a519d

Browse files
authored
fix: Handling situation when diagnostics contain nil range (#6729)
1 parent e76f6f1 commit f0a519d

2 files changed

Lines changed: 86 additions & 1 deletion

File tree

internal/view/diagnostic/diagnostic.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88

99
type Diagnostics []*Diagnostic
1010

11+
// Contains reports whether diags holds a diagnostic with the same source range as find.
12+
// A diagnostic without a range matches nothing, not even another one without a range.
1113
func (diags *Diagnostics) Contains(find *Diagnostic) bool {
1214
for _, diag := range *diags {
13-
if find.Range != nil && find.Range.String() == diag.Range.String() {
15+
if find.Range != nil && diag.Range != nil && find.Range.String() == diag.Range.String() {
1416
return true
1517
}
1618
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package diagnostic_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/gruntwork-io/terragrunt/internal/view/diagnostic"
7+
"github.com/hashicorp/hcl/v2"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func rangeOnLine(line int) *diagnostic.Range {
13+
return &diagnostic.Range{
14+
Filename: "terragrunt.hcl",
15+
Start: diagnostic.Pos{Line: line, Column: 1, Byte: 0},
16+
End: diagnostic.Pos{Line: line, Column: 5, Byte: 4},
17+
}
18+
}
19+
20+
func TestDiagnosticsContains(t *testing.T) {
21+
t.Parallel()
22+
23+
tc := []struct {
24+
find *diagnostic.Diagnostic
25+
name string
26+
stored diagnostic.Diagnostics
27+
expected bool
28+
}{
29+
{
30+
name: "same range",
31+
stored: diagnostic.Diagnostics{{Range: rangeOnLine(1)}},
32+
find: &diagnostic.Diagnostic{Range: rangeOnLine(1)},
33+
expected: true,
34+
},
35+
{
36+
name: "different range",
37+
stored: diagnostic.Diagnostics{{Range: rangeOnLine(1)}},
38+
find: &diagnostic.Diagnostic{Range: rangeOnLine(2)},
39+
expected: false,
40+
},
41+
{
42+
name: "stored diagnostic without a range is skipped",
43+
stored: diagnostic.Diagnostics{{Summary: "no subject"}, {Range: rangeOnLine(1)}},
44+
find: &diagnostic.Diagnostic{Range: rangeOnLine(1)},
45+
expected: true,
46+
},
47+
{
48+
name: "searched diagnostic without a range",
49+
stored: diagnostic.Diagnostics{{Range: rangeOnLine(1)}},
50+
find: &diagnostic.Diagnostic{Summary: "no subject"},
51+
expected: false,
52+
},
53+
{
54+
name: "neither has a range",
55+
stored: diagnostic.Diagnostics{{Summary: "no subject"}},
56+
find: &diagnostic.Diagnostic{Summary: "no subject"},
57+
expected: false,
58+
},
59+
}
60+
61+
for _, tt := range tc {
62+
t.Run(tt.name, func(t *testing.T) {
63+
t.Parallel()
64+
65+
assert.Equal(t, tt.expected, tt.stored.Contains(tt.find))
66+
})
67+
}
68+
}
69+
70+
func TestDiagnosticsContainsDiagnosticWithoutSubject(t *testing.T) {
71+
t.Parallel()
72+
73+
withoutSubject := diagnostic.NewDiagnostic(nil, &hcl.Diagnostic{
74+
Severity: hcl.DiagError,
75+
Summary: "Multiple terraform blocks",
76+
})
77+
require.Nil(t, withoutSubject.Range)
78+
79+
diags := diagnostic.Diagnostics{withoutSubject}
80+
81+
assert.False(t, diags.Contains(withoutSubject))
82+
assert.False(t, diags.Contains(&diagnostic.Diagnostic{Range: rangeOnLine(1)}))
83+
}

0 commit comments

Comments
 (0)