package editor import ( "strings" "testing" "codeberg.org/turbo-editors/turbo-core/buffer" ) // viewOn returns a view on a buffer holding text, with the cursor placed. func viewOn(t *testing.T, text string, line, col int) *View { t.Helper() buf := buffer.New() buf.SetText(text) v := NewView(buf, &Clipboard{}) buf.SetCursor(buffer.Position{Line: line, Col: col}) return v } func TestInsertSnippetPutsASingleLineAtTheCursor(t *testing.T) { v := viewOn(t, "abcd\n", 0, 2) v.InsertSnippet("XY") if got := v.Buffer().Text(); got != "abXYcd\n" { t.Errorf("the buffer holds %q", got) } } func TestInsertSnippetIndentsTheLinesAfterTheFirst(t *testing.T) { // The case that decides the whole feature: a multi-line snippet dropped // into indented code restarts at column zero without this. v := viewOn(t, "func f() {\n\t\n}\n", 1, 1) v.InsertSnippet("if err != nil {\n\treturn err\n}") want := "func f() {\n\tif err != nil {\n\t\treturn err\n\t}\n}\n" if got := v.Buffer().Text(); got != want { t.Errorf("the buffer holds\n%q\nwant\n%q", got, want) } } func TestInsertSnippetUsesSpacesWhenTheLineDoes(t *testing.T) { v := viewOn(t, "x = [\n \n]\n", 1, 4) v.InsertSnippet("a,\nb,") want := "x = [\n a,\n b,\n]\n" if got := v.Buffer().Text(); got != want { t.Errorf("the buffer holds\n%q\nwant\n%q", got, want) } } func TestInsertSnippetAtColumnZeroAddsNoIndent(t *testing.T) { v := viewOn(t, "\n", 0, 0) v.InsertSnippet("a\nb\nc") if got := v.Buffer().Text(); got != "a\nb\nc\n" { t.Errorf("the buffer holds %q", got) } } func TestInsertSnippetLeavesBlankLinesBlank(t *testing.T) { // Trailing whitespace on an empty line is something every formatter then // removes, so putting it there is noise in the next diff. v := viewOn(t, "func f() {\n\t\n}\n", 1, 1) v.InsertSnippet("a\n\nb") want := "func f() {\n\ta\n\n\tb\n}\n" if got := v.Buffer().Text(); got != want { t.Errorf("the buffer holds\n%q\nwant\n%q", got, want) } } func TestInsertSnippetIsOneUndoStep(t *testing.T) { v := viewOn(t, "func f() {\n\t\n}\n", 1, 1) before := v.Buffer().Text() v.InsertSnippet("if err != nil {\n\treturn err\n}") v.Buffer().Undo() if got := v.Buffer().Text(); got != before { t.Errorf("one undo left\n%q\nwant\n%q", got, before) } } func TestInsertSnippetLeavesTheCursorAfterTheText(t *testing.T) { v := viewOn(t, "func f() {\n\t\n}\n", 1, 1) v.InsertSnippet("a\nb") cursor := v.Buffer().Cursor() if cursor.Line != 2 { t.Errorf("the cursor is on line %d, want the last line of the snippet", cursor.Line) } if got := v.Buffer().Line(cursor.Line); cursor.Col != len([]rune(got)) { t.Errorf("the cursor is at column %d of %q, want the end", cursor.Col, got) } } func TestInsertSnippetCountsAsAChange(t *testing.T) { v := viewOn(t, "x\n", 0, 0) before := v.Buffer().Revision() v.InsertSnippet("y") if v.Buffer().Revision() == before { t.Error("inserting a snippet did not move the revision, so nothing will re-colour") } if !v.Buffer().Modified() { t.Error("inserting a snippet left the buffer unmodified") } } func TestInsertingAnEmptySnippetChangesNothing(t *testing.T) { // The revision is what says nothing happened; Modified() cannot, because // putting the text into the buffer in the first place already set it. v := viewOn(t, "x\n", 0, 0) before := v.Buffer().Revision() v.InsertSnippet("") if got := v.Buffer().Text(); got != "x\n" { t.Errorf("the buffer holds %q", got) } if v.Buffer().Revision() != before { t.Error("an empty snippet moved the revision") } } func TestInsertSnippetHandlesAccentsInTheCurrentLine(t *testing.T) { // The indent is taken as a byte prefix of the line, so a line whose text // has accents must still give back only its whitespace. if got := leadingWhitespace("\t évidemment"); got != "\t " { t.Errorf("leadingWhitespace() = %q, want the tab and two spaces", got) } } func TestLeadingWhitespaceOfABlankLineIsTheWholeLine(t *testing.T) { if got := leadingWhitespace("\t\t"); got != "\t\t" { t.Errorf("leadingWhitespace() = %q", got) } if got := leadingWhitespace(""); got != "" { t.Errorf("leadingWhitespace() = %q", got) } } func TestIndentContinuationLinesLeavesASingleLineAlone(t *testing.T) { if got := indentContinuationLines("only", "\t"); got != "only" { t.Errorf("got %q, want the text unchanged", got) } if strings.Contains(indentContinuationLines("only", "\t"), "\t") { t.Error("a single-line snippet was indented") } }