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 }