package editor import ( "testing" tea "github.com/charmbracelet/bubbletea" ) func altUp(e *Editor) { e.HandleKey(tea.KeyMsg{Type: tea.KeyUp, Alt: true}) } func altDown(e *Editor) { e.HandleKey(tea.KeyMsg{Type: tea.KeyDown, Alt: true}) } func TestMoveLineUpSwapsWithLineAbove(t *testing.T) { e := New() e.SetContent([]byte("a\nb\nc")) e.Cursor = Position{Row: 1, Col: 1} if !e.MoveLineUp() { t.Fatal("MoveLineUp returned false") } if e.Lines[0] != "b" || e.Lines[1] != "a" { t.Fatalf("lines = %q, want [b a c]", e.Lines) } if e.Cursor.Row != 0 || e.Cursor.Col != 1 { t.Fatalf("cursor = %+v, want row 0 col 1 (follows the moved line)", e.Cursor) } } func TestMoveLineDownSwapsWithLineBelow(t *testing.T) { e := New() e.SetContent([]byte("a\nb\nc")) e.Cursor = Position{Row: 1, Col: 1} if !e.MoveLineDown() { t.Fatal("MoveLineDown returned false") } if e.Lines[1] != "c" || e.Lines[2] != "b" { t.Fatalf("lines = %q, want [a c b]", e.Lines) } if e.Cursor.Row != 2 || e.Cursor.Col != 1 { t.Fatalf("cursor = %+v, want row 2 col 1", e.Cursor) } } func TestMoveLineUpNoOpAtTop(t *testing.T) { e := New() e.SetContent([]byte("a\nb")) e.Cursor = Position{Row: 0, Col: 0} if e.MoveLineUp() { t.Fatal("MoveLineUp at top should be a no-op") } if e.Lines[0] != "a" || e.Lines[1] != "b" { t.Fatalf("lines = %q, want unchanged", e.Lines) } } func TestMoveLineDownNoOpAtBottom(t *testing.T) { e := New() e.SetContent([]byte("a\nb")) e.Cursor = Position{Row: 1, Col: 0} if e.MoveLineDown() { t.Fatal("MoveLineDown at bottom should be a no-op") } if e.Lines[0] != "a" || e.Lines[1] != "b" { t.Fatalf("lines = %q, want unchanged", e.Lines) } } // Repeated presses walk a line several positions in one direction. func TestMoveLineUpRepeatsWalkUp(t *testing.T) { e := New() e.SetContent([]byte("a\nb\nc\nd")) e.Cursor = Position{Row: 3, Col: 0} // "d" altUp(e) altUp(e) altUp(e) if e.Lines[0] != "d" { t.Fatalf("lines = %q, want d walked to top", e.Lines) } if e.Cursor.Row != 0 { t.Fatalf("cursor row = %d, want 0", e.Cursor.Row) } } // Each move is one undo step that reverts exactly one swap. func TestMoveLineDownIsOneUndoStep(t *testing.T) { e := New() e.SetContent([]byte("a\nb\nc")) e.Cursor = Position{Row: 0, Col: 0} altDown(e) if e.Lines[0] != "b" || e.Lines[1] != "a" { t.Fatalf("after move lines = %q, want [b a c]", e.Lines) } e.Undo() if e.Lines[0] != "a" || e.Lines[1] != "b" || e.Lines[2] != "c" { t.Fatalf("after undo lines = %q, want [a b c]", e.Lines) } } // A move past the document edge records no undo checkpoint (no-op key). func TestMoveLineUpAtTopRecordsNoUndo(t *testing.T) { e := New() e.SetContent([]byte("a\nb")) e.Cursor = Position{Row: 0, Col: 0} altUp(e) if len(e.undo) != 0 { t.Fatalf("undo stack = %d, want 0 (no-op move records nothing)", len(e.undo)) } }