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) } }) } }