▍ humdrum codex / glint v1.0.2
license AGPL-3.0
2.8 KB raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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))
	}
}