package buffer import "testing" func TestNewBufferHoldsOneEmptyLine(t *testing.T) { b := New() if got := b.LineCount(); got != 1 { t.Fatalf("LineCount() = %d, want 1", got) } if got := b.Line(0); got != "" { t.Errorf("Line(0) = %q, want empty", got) } if b.Modified() { t.Error("a fresh buffer must not be marked modified") } } func TestNewFromStringSplitsOnLineFeeds(t *testing.T) { b := NewFromString("package main\n\nfunc main() {}\n") if got := b.LineCount(); got != 3 { t.Fatalf("LineCount() = %d, want 3 (the trailing newline is not a line)", got) } for i, want := range []string{"package main", "", "func main() {}"} { if got := b.Line(i); got != want { t.Errorf("Line(%d) = %q, want %q", i, got, want) } } if b.Modified() { t.Error("loading text must not mark the buffer modified") } } func TestTextRoundTripsTheTrailingNewline(t *testing.T) { tests := []struct { name string text string }{ {"with trailing newline", "a\nb\n"}, {"without trailing newline", "a\nb"}, {"empty", ""}, {"only a newline", "\n"}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { if got := NewFromString(tc.text).Text(); got != tc.text { t.Errorf("Text() = %q, want %q", got, tc.text) } }) } } func TestTextPreservesWindowsLineEndings(t *testing.T) { b := NewFromString("a\r\nb\r\n") if got := b.LineCount(); got != 2 { t.Fatalf("LineCount() = %d, want 2", got) } if got := b.Line(0); got != "a" { t.Errorf("Line(0) = %q, want %q — the carriage return must be stripped", got, "a") } if got := b.Text(); got != "a\r\nb\r\n" { t.Errorf("Text() = %q, want the original CRLF endings back", got) } } func TestLineAccessorsToleratateOutOfRangeIndexes(t *testing.T) { b := NewFromString("only") for _, i := range []int{-1, 1, 99} { if got := b.Line(i); got != "" { t.Errorf("Line(%d) = %q, want empty", i, got) } if got := b.LineLen(i); got != 0 { t.Errorf("LineLen(%d) = %d, want 0", i, got) } if got := b.LineRunes(i); got != nil { t.Errorf("LineRunes(%d) = %v, want nil", i, got) } } } func TestLineRunesReturnsAnIndependentCopy(t *testing.T) { b := NewFromString("abc") runes := b.LineRunes(0) runes[0] = 'X' if got := b.Line(0); got != "abc" { t.Errorf("Line(0) = %q after mutating the returned slice, want %q", got, "abc") } } func TestSetTabWidthIgnoresNonPositiveValues(t *testing.T) { b := New() b.SetTabWidth(4) if got := b.TabWidth(); got != 4 { t.Fatalf("TabWidth() = %d, want 4", got) } b.SetTabWidth(0) b.SetTabWidth(-2) if got := b.TabWidth(); got != 4 { t.Errorf("TabWidth() = %d, want the previous 4 to be kept", got) } } func TestPositionOrdering(t *testing.T) { first := Position{Line: 1, Col: 5} sameLineLater := Position{Line: 1, Col: 6} nextLine := Position{Line: 2, Col: 0} if !first.Before(sameLineLater) { t.Error("a smaller column on the same line must come first") } if !first.Before(nextLine) { t.Error("a smaller line must come first whatever the columns") } if first.Before(first) { t.Error("a position must not come before itself") } if !sameLineLater.After(first) { t.Error("After must be the mirror of Before") } } func TestNewRangeOrdersItsBounds(t *testing.T) { low := Position{Line: 0, Col: 1} high := Position{Line: 3, Col: 2} if got := NewRange(high, low); got.Start != low || got.End != high { t.Errorf("NewRange(high, low) = %+v, want the bounds swapped", got) } if got := NewRange(low, high); got.Start != low || got.End != high { t.Errorf("NewRange(low, high) = %+v, want the bounds kept", got) } } func TestRangeContainsExcludesItsEnd(t *testing.T) { r := Range{Start: Position{Line: 1}, End: Position{Line: 1, Col: 3}} if !r.Contains(Position{Line: 1}) { t.Error("the start of a range is inside it") } if r.Contains(Position{Line: 1, Col: 3}) { t.Error("the end of a range is outside it") } if empty := (Range{}); empty.Contains(Position{}) { t.Error("an empty range contains nothing, not even its own position") } } func TestAnEmptyBufferHoldsAnEmptyString(t *testing.T) { // Not "\n": a buffer holds what was put into it, and nothing was. if got := New().Text(); got != "" { t.Errorf("New().Text() = %q, want empty", got) } if got := NewFromString("").Text(); got != "" { t.Errorf("NewFromString(\"\").Text() = %q, want empty", got) } } func TestPressingEnterGivesAFileItsTrailingNewline(t *testing.T) { b := New() b.Insert("package main") b.InsertNewlineAndIndent() if got := b.Text(); got != "package main\n" { t.Errorf("Text() = %q, want %q", got, "package main\n") } }