hcl: RangeOver function

This is a generalization of RangeBetween that finds a single range that
covers the full extent of both given ranges, possibly also including some
additional content between the ranges if they do not overlap.
This commit is contained in:
Martin Atkins 2018-01-14 11:33:23 -08:00
parent d34d4686fb
commit 1365a2cfe5
2 changed files with 184 additions and 0 deletions

View File

@ -60,6 +60,40 @@ func RangeBetween(start, end Range) Range {
}
}
// RangeOver returns a new range that covers both of the given ranges and
// possibly additional content between them if the two ranges do not overlap.
//
// If either range is empty then it is ignored. The result is empty if both
// given ranges are empty.
//
// The result is meaningless if the two ranges to not belong to the same
// source file.
func RangeOver(a, b Range) Range {
if a.Empty() {
return b
}
if b.Empty() {
return a
}
var start, end Pos
if a.Start.Byte < b.Start.Byte {
start = a.Start
} else {
start = b.Start
}
if a.End.Byte > b.End.Byte {
end = a.End
} else {
end = b.End
}
return Range{
Filename: a.Filename,
Start: start,
End: end,
}
}
// ContainsOffset returns true if and only if the given byte offset is within
// the receiving Range.
func (r Range) ContainsOffset(offset int) bool {

View File

@ -7,6 +7,156 @@ import (
"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