Gim/internal/syntax/treesitter_internal_test.go
Hayden Hargreaves 64c448c639
All checks were successful
Run Test Suite / test (push) Successful in 37s
test: updated tests and pulled theme into EditorSettings.
2026-04-08 17:19:32 -07:00

284 lines
6.2 KiB
Go

package syntax
import "testing"
func TestMergeRanges(t *testing.T) {
tests := []struct {
name string
input []lineRange
expected []lineRange
wantErr bool
}{
{
name: "overlapping and unsorted ranges are merged",
input: []lineRange{{start: 5, end: 8}, {start: 1, end: 2}, {start: 2, end: 4}, {start: 10, end: 10}},
expected: []lineRange{{start: 1, end: 8}, {start: 10, end: 10}},
wantErr: false,
},
{
name: "adjacent ranges are merged",
input: []lineRange{{start: 0, end: 1}, {start: 2, end: 3}},
expected: []lineRange{{start: 0, end: 3}},
wantErr: false,
},
{
name: "empty input returns nil",
input: nil,
expected: nil,
wantErr: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := mergeRanges(tc.input)
if tc.wantErr {
t.Fatalf("unexpected wantErr=true for mergeRanges")
}
if len(got) != len(tc.expected) {
t.Fatalf("unexpected merged range count: got %d want %d", len(got), len(tc.expected))
}
for i := range got {
if got[i] != tc.expected[i] {
t.Fatalf("range %d mismatch: got %+v want %+v", i, got[i], tc.expected[i])
}
}
})
}
}
func TestNormalizedDirtyRanges(t *testing.T) {
tests := []struct {
name string
args struct {
ranges []lineRange
lineCount int
}
expected []lineRange
wantErr bool
}{
{
name: "clamps negative and overflowing ranges",
args: struct {
ranges []lineRange
lineCount int
}{
ranges: []lineRange{{start: -2, end: 1}, {start: 3, end: 99}},
lineCount: 5,
},
expected: []lineRange{{start: 0, end: 1}, {start: 3, end: 4}},
wantErr: false,
},
{
name: "drops invalid clamped ranges",
args: struct {
ranges []lineRange
lineCount int
}{
ranges: []lineRange{{start: 8, end: 9}},
lineCount: 5,
},
expected: nil,
wantErr: false,
},
{
name: "merges adjacent ranges after clamping",
args: struct {
ranges []lineRange
lineCount int
}{
ranges: []lineRange{{start: -3, end: 0}, {start: 1, end: 2}},
lineCount: 4,
},
expected: []lineRange{{start: 0, end: 2}},
wantErr: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := normalizedDirtyRanges(tc.args.ranges, tc.args.lineCount)
if tc.wantErr {
t.Fatalf("unexpected wantErr=true for normalizedDirtyRanges")
}
if len(got) != len(tc.expected) {
t.Fatalf("unexpected normalized range count: got %d want %d", len(got), len(tc.expected))
}
for i := range got {
if got[i] != tc.expected[i] {
t.Fatalf("range %d mismatch: got %+v want %+v", i, got[i], tc.expected[i])
}
}
})
}
}
func TestByteColToRuneIndexUTF8(t *testing.T) {
tests := []struct {
name string
args struct {
line []byte
col int
}
expected int
wantErr bool
}{
{
name: "zero column maps to first rune",
args: struct {
line []byte
col int
}{line: []byte("aéb"), col: 0},
expected: 0,
wantErr: false,
},
{
name: "middle byte offset on multibyte rune",
args: struct {
line []byte
col int
}{line: []byte("aéb"), col: 1},
expected: 1,
wantErr: false,
},
{
name: "end of multibyte rune maps after rune",
args: struct {
line []byte
col int
}{line: []byte("aéb"), col: 3},
expected: 2,
wantErr: false,
},
{
name: "column at line end maps to rune length",
args: struct {
line []byte
col int
}{line: []byte("aéb"), col: len([]byte("aéb"))},
expected: 3,
wantErr: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := byteColToRuneIndex(tc.args.line, tc.args.col)
if tc.wantErr {
t.Fatalf("unexpected wantErr=true for byteColToRuneIndex")
}
if got != tc.expected {
t.Fatalf("unexpected rune index: got %d want %d", got, tc.expected)
}
})
}
}
func TestAddDirtyRangeNormalizesAndMerges(t *testing.T) {
tests := []struct {
name string
args struct {
initial []lineRange
start int
end int
}
expected []lineRange
wantErr bool
}{
{
name: "swaps start and end when reversed",
args: struct {
initial []lineRange
start int
end int
}{initial: nil, start: 7, end: 3},
expected: []lineRange{{start: 3, end: 7}},
wantErr: false,
},
{
name: "clamps negative values",
args: struct {
initial []lineRange
start int
end int
}{initial: nil, start: -5, end: -1},
expected: []lineRange{{start: 0, end: 0}},
wantErr: false,
},
{
name: "merges with existing adjacent range",
args: struct {
initial []lineRange
start int
end int
}{initial: []lineRange{{start: 1, end: 2}}, start: 3, end: 4},
expected: []lineRange{{start: 1, end: 4}},
wantErr: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
bc := &bufferCache{dirty: append([]lineRange{}, tc.args.initial...)}
addDirtyRange(bc, tc.args.start, tc.args.end)
if tc.wantErr {
t.Fatalf("unexpected wantErr=true for addDirtyRange")
}
if len(bc.dirty) != len(tc.expected) {
t.Fatalf("unexpected dirty range count: got %d want %d", len(bc.dirty), len(tc.expected))
}
for i := range bc.dirty {
if bc.dirty[i] != tc.expected[i] {
t.Fatalf("dirty range %d mismatch: got %+v want %+v", i, bc.dirty[i], tc.expected[i])
}
}
})
}
}
func TestRowInRanges(t *testing.T) {
tests := []struct {
name string
input struct {
row int
ranges []lineRange
}
expected bool
wantErr bool
}{
{
name: "row inside range",
input: struct {
row int
ranges []lineRange
}{row: 3, ranges: []lineRange{{start: 1, end: 4}}},
expected: true,
wantErr: false,
},
{
name: "row outside all ranges",
input: struct {
row int
ranges []lineRange
}{row: 8, ranges: []lineRange{{start: 1, end: 4}, {start: 10, end: 12}}},
expected: false,
wantErr: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := rowInRanges(tc.input.row, tc.input.ranges)
if tc.wantErr {
t.Fatalf("unexpected wantErr=true for rowInRanges")
}
if got != tc.expected {
t.Fatalf("unexpected result: got %v want %v", got, tc.expected)
}
})
}
}