package editor import ( "testing" "pad/internal/ui" ) // TestCursorPositioning_Basic verifies cursor positioning via GlyphLayout. func TestCursorPositioning_Basic(t *testing.T) { TheState = NewState() TheState.Editor.Buffer = "hello\nworld" // Two lines: "hello\n" (bytes 0-5) and "world" (bytes 6-10) // Line 0 glyphs at Y=70, Line 1 glyphs at Y=140 TheState.Editor.GlyphLayout = ui.GlyphLayout{ ByteOffsets: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, X: []ui.Dp{10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 60}, Y: []ui.Dp{70, 70, 70, 70, 70, 70, 140, 140, 140, 140, 140}, Advance: []ui.Dp{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, } // Test tapping on first line near X=30 (glyph index 2, byteOffset 2) SetCursorFromPoint(25, 70) if TheState.Editor.CursorPosition < 0 || TheState.Editor.CursorPosition > len(TheState.Editor.Buffer) { t.Errorf("cursor position %d out of bounds after first tap", TheState.Editor.CursorPosition) } // Test tapping on second line SetCursorFromPoint(35, 140) if TheState.Editor.CursorPosition < 0 || TheState.Editor.CursorPosition > len(TheState.Editor.Buffer) { t.Errorf("cursor position %d out of bounds after second tap", TheState.Editor.CursorPosition) } } // TestCursorPositioning_EmptyDocument verifies cursor positioning handles empty documents. func TestCursorPositioning_EmptyDocument(t *testing.T) { TheState = NewState() TheState.Editor.Buffer = "" TheState.Editor.GlyphLayout = ui.GlyphLayout{} // Should not panic on empty layout SetCursorFromPoint(50, 50) if TheState.Editor.CursorPosition != 0 { t.Errorf("expected cursor at 0 for empty document, got %d", TheState.Editor.CursorPosition) } } // TestCursorPositioning_IncompleteLayout verifies cursor positioning handles missing layout slices. func TestCursorPositioning_IncompleteLayout(t *testing.T) { TheState = NewState() TheState.Editor.Buffer = "test" // GlyphLayout with ByteOffsets and X but no Advance (partial data) TheState.Editor.GlyphLayout = ui.GlyphLayout{ ByteOffsets: []int{0, 1, 2, 3}, X: []ui.Dp{10, 20, 30, 40}, Y: []ui.Dp{70, 70, 70, 70}, // Advance intentionally omitted } // Should not panic when Advance is missing SetCursorFromPoint(25, 70) } // TestHandleCursorMove_Bounds verifies cursor movement stays within buffer bounds. func TestHandleCursorMove_Bounds(t *testing.T) { TheState = NewState() TheState.Editor.Buffer = "hello" TheState.Editor.CursorPosition = 0 // Move right 3 times HandleCursorMove(1) HandleCursorMove(1) HandleCursorMove(1) if TheState.Editor.CursorPosition != 3 { t.Errorf("expected cursor at 3, got %d", TheState.Editor.CursorPosition) } // Move right past end — should clamp to buffer length HandleCursorMove(10) if TheState.Editor.CursorPosition != len(TheState.Editor.Buffer) { t.Errorf("expected cursor at %d (end of buffer), got %d", len(TheState.Editor.Buffer), TheState.Editor.CursorPosition) } // Move left past start — should clamp to 0 HandleCursorMove(-100) if TheState.Editor.CursorPosition != 0 { t.Errorf("expected cursor at 0, got %d", TheState.Editor.CursorPosition) } }