hcl/cmd/hclspecsuite/traversals.go
Martin Atkins 6c4344623b Unfold the "hcl" directory up into the root
The main HCL package is more visible this way, and so it's easier than
having to pick it out from dozens of other package directories.
2019-09-09 16:08:19 -07:00

118 lines
3.0 KiB
Go

package main
import (
"fmt"
"reflect"
"github.com/hashicorp/hcl/v2"
)
func findTraversalSpec(got hcl.Traversal, candidates []*TestFileExpectTraversal) *TestFileExpectTraversal {
for _, candidate := range candidates {
if traversalsAreEquivalent(candidate.Traversal, got) {
return candidate
}
}
return nil
}
func findTraversalForSpec(want *TestFileExpectTraversal, have []hcl.Traversal) hcl.Traversal {
for _, candidate := range have {
if traversalsAreEquivalent(candidate, want.Traversal) {
return candidate
}
}
return nil
}
func traversalsAreEquivalent(a, b hcl.Traversal) bool {
if len(a) != len(b) {
return false
}
for i := range a {
aStep := a[i]
bStep := b[i]
if reflect.TypeOf(aStep) != reflect.TypeOf(bStep) {
return false
}
// We can now assume that both are of the same type.
switch ts := aStep.(type) {
case hcl.TraverseRoot:
if bStep.(hcl.TraverseRoot).Name != ts.Name {
return false
}
case hcl.TraverseAttr:
if bStep.(hcl.TraverseAttr).Name != ts.Name {
return false
}
case hcl.TraverseIndex:
if !bStep.(hcl.TraverseIndex).Key.RawEquals(ts.Key) {
return false
}
default:
return false
}
}
return true
}
// checkTraversalsMatch determines if a given traversal matches the given
// expectation, which must've been produced by an earlier call to
// findTraversalSpec for the same traversal.
func checkTraversalsMatch(got hcl.Traversal, filename string, match *TestFileExpectTraversal) hcl.Diagnostics {
var diags hcl.Diagnostics
gotRng := got.SourceRange()
wantRng := match.Range
if got, want := gotRng.Filename, filename; got != want {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Incorrect filename in detected traversal",
Detail: fmt.Sprintf(
"Filename was reported as %q, but was expecting %q.",
got, want,
),
Subject: match.Traversal.SourceRange().Ptr(),
})
return diags
}
// If we have the expected filename then we'll use that to construct the
// full "want range" here so that we can use it to point to the appropriate
// location in the remaining diagnostics.
wantRng.Filename = filename
if got, want := gotRng.Start, wantRng.Start; got != want {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Incorrect start position in detected traversal",
Detail: fmt.Sprintf(
"Start position was reported as line %d column %d byte %d, but was expecting line %d column %d byte %d.",
got.Line, got.Column, got.Byte,
want.Line, want.Column, want.Byte,
),
Subject: &wantRng,
})
}
if got, want := gotRng.End, wantRng.End; got != want {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Incorrect end position in detected traversal",
Detail: fmt.Sprintf(
"End position was reported as line %d column %d byte %d, but was expecting line %d column %d byte %d.",
got.Line, got.Column, got.Byte,
want.Line, want.Column, want.Byte,
),
Subject: &wantRng,
})
}
return diags
}