6c4344623b
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.
468 lines
12 KiB
Go
468 lines
12 KiB
Go
package hcl
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestRangeOver(t *testing.T) {
|
|
tests := []struct {
|
|
A Range
|
|
B Range
|
|
Want Range
|
|
}{
|
|
{
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // #####
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // #####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ###
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ###
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ##
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 2, Line: 1, Column: 3},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 4, Line: 1, Column: 5},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
Range{ // ######
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ##
|
|
Start: Pos{Byte: 4, Line: 1, Column: 5},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 2, Line: 1, Column: 3},
|
|
},
|
|
Range{ // ######
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("%s<=>%s", test.A, test.B), func(t *testing.T) {
|
|
got := RangeOver(test.A, test.B)
|
|
if !reflect.DeepEqual(got, test.Want) {
|
|
t.Errorf(
|
|
"wrong result\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s",
|
|
visRangeOffsets(test.A), test.A,
|
|
visRangeOffsets(test.B), test.B,
|
|
visRangeOffsets(got), got,
|
|
visRangeOffsets(test.Want), test.Want,
|
|
)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPosOverlap(t *testing.T) {
|
|
tests := []struct {
|
|
A Range
|
|
B Range
|
|
Want Range
|
|
}{
|
|
{
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ###
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ###
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ###
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ###
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ###
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ###
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ##
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 2, Line: 1, Column: 3},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 4, Line: 1, Column: 5},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
Range{ // (no overlap)
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 0, Line: 1, Column: 1},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ##
|
|
Start: Pos{Byte: 4, Line: 1, Column: 5},
|
|
End: Pos{Byte: 6, Line: 1, Column: 7},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 2, Line: 1, Column: 3},
|
|
},
|
|
Range{ // (no overlap)
|
|
Start: Pos{Byte: 4, Line: 1, Column: 5},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("%s<=>%s", test.A, test.B), func(t *testing.T) {
|
|
got := test.A.Overlap(test.B)
|
|
if !reflect.DeepEqual(got, test.Want) {
|
|
t.Errorf(
|
|
"wrong result\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s",
|
|
visRangeOffsets(test.A), test.A,
|
|
visRangeOffsets(test.B), test.B,
|
|
visRangeOffsets(got), got,
|
|
visRangeOffsets(test.Want), test.Want,
|
|
)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRangePartitionAround(t *testing.T) {
|
|
tests := []struct {
|
|
Outer Range
|
|
Inner Range
|
|
WantBefore Range
|
|
WantOverlap Range
|
|
WantAfter Range
|
|
}{
|
|
{
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // (empty)
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 2, Line: 1, Column: 3},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // (empty)
|
|
Start: Pos{Byte: 4, Line: 1, Column: 5},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // #
|
|
Start: Pos{Byte: 0, Line: 1, Column: 1},
|
|
End: Pos{Byte: 1, Line: 1, Column: 2},
|
|
},
|
|
Range{ // ###
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // (empty)
|
|
Start: Pos{Byte: 4, Line: 1, Column: 5},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // (empty)
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 2, Line: 1, Column: 3},
|
|
},
|
|
Range{ // ###
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // #
|
|
Start: Pos{Byte: 5, Line: 1, Column: 6},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
{
|
|
Range{ // ####
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // #
|
|
Start: Pos{Byte: 1, Line: 1, Column: 2},
|
|
End: Pos{Byte: 2, Line: 1, Column: 3},
|
|
},
|
|
Range{ // ##
|
|
Start: Pos{Byte: 2, Line: 1, Column: 3},
|
|
End: Pos{Byte: 4, Line: 1, Column: 5},
|
|
},
|
|
Range{ // #
|
|
Start: Pos{Byte: 4, Line: 1, Column: 5},
|
|
End: Pos{Byte: 5, Line: 1, Column: 6},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("%s around %s", test.Outer, test.Inner), func(t *testing.T) {
|
|
gotBefore, gotOverlap, gotAfter := test.Outer.PartitionAround(test.Inner)
|
|
if !reflect.DeepEqual(gotBefore, test.WantBefore) {
|
|
t.Errorf(
|
|
"wrong before\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s",
|
|
visRangeOffsets(test.Outer), test.Outer,
|
|
visRangeOffsets(test.Inner), test.Inner,
|
|
visRangeOffsets(gotBefore), gotBefore,
|
|
visRangeOffsets(test.WantBefore), test.WantBefore,
|
|
)
|
|
}
|
|
if !reflect.DeepEqual(gotOverlap, test.WantOverlap) {
|
|
t.Errorf(
|
|
"wrong overlap\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s",
|
|
visRangeOffsets(test.Outer), test.Outer,
|
|
visRangeOffsets(test.Inner), test.Inner,
|
|
visRangeOffsets(gotOverlap), gotOverlap,
|
|
visRangeOffsets(test.WantOverlap), test.WantOverlap,
|
|
)
|
|
}
|
|
if !reflect.DeepEqual(gotAfter, test.WantAfter) {
|
|
t.Errorf(
|
|
"wrong after\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s",
|
|
visRangeOffsets(test.Outer), test.Outer,
|
|
visRangeOffsets(test.Inner), test.Inner,
|
|
visRangeOffsets(gotAfter), gotAfter,
|
|
visRangeOffsets(test.WantAfter), test.WantAfter,
|
|
)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// visRangeOffsets is a helper that produces a visual representation of the
|
|
// start and end byte offsets of the given range, which can then be stacked
|
|
// with the same for other ranges to more easily see how the ranges relate
|
|
// to one another.
|
|
func visRangeOffsets(rng Range) string {
|
|
var buf bytes.Buffer
|
|
if rng.End.Byte < rng.Start.Byte {
|
|
// Should never happen, but we'll visualize it anyway so we can
|
|
// more easily debug failing tests.
|
|
for i := 0; i < rng.End.Byte; i++ {
|
|
buf.WriteByte(' ')
|
|
}
|
|
for i := rng.End.Byte; i < rng.Start.Byte; i++ {
|
|
buf.WriteByte('!')
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
for i := 0; i < rng.Start.Byte; i++ {
|
|
buf.WriteByte(' ')
|
|
}
|
|
for i := rng.Start.Byte; i < rng.End.Byte; i++ {
|
|
buf.WriteByte('#')
|
|
}
|
|
return buf.String()
|
|
}
|