package app import ( "strings" "testing" ) func TestViewportRendererShiftsCursor(t *testing.T) { vr := newViewportRenderer(newTerminalLayout(120, 40)) got := string(vr.Render([]byte("\x1b[H"))) if got != "\x1b[2;1H" { t.Fatalf("CUP home: got %q", got) } } func TestViewportRendererSwallowsAltScreenToggles(t *testing.T) { vr := newViewportRenderer(newTerminalLayout(120, 40)) got := string(vr.Render([]byte("a\x1b[?1049hb\x1b[?1049lc"))) if got != "abc" { t.Fatalf("alt-screen toggles: got %q", got) } } func TestViewportRendererClearScreenIsViewportOnly(t *testing.T) { vr := newViewportRenderer(newTerminalLayout(20, 5)) got := string(vr.Render([]byte("\x1b[2J"))) if strings.Contains(got, "\x1b[2J") { t.Fatalf("host clear-screen leaked through: %q", got) } if strings.Count(got, " ") != 3 { t.Fatalf("clear rows: got %q", got) } if !strings.Contains(got, "\x1b[2;1H") || !strings.Contains(got, "\x1b[4;1H") { t.Fatalf("clear did not target viewport rows: %q", got) } } func TestViewportRendererClearLineUsesEraseChars(t *testing.T) { vr := newViewportRenderer(newTerminalLayout(20, 5)) got := string(vr.Render([]byte("\x1b[K"))) if strings.Contains(got, "\x1b[K") { t.Fatalf("host clear-line leaked through: %q", got) } if got != "\x1b[20X" { t.Fatalf("clear-line: got %q want ECH", got) } } func TestViewportRendererClearLineStopsAtViewportRight(t *testing.T) { vr := newViewportRenderer(newTerminalLayout(20, 5)) got := string(vr.Render([]byte("\x1b[10G\x1b[K"))) if !strings.HasSuffix(got, "\x1b[11X") { t.Fatalf("clear-line from col 10 should erase 11 cells: %q", got) } } func TestViewportRendererTracksPrintableCursor(t *testing.T) { vr := newViewportRenderer(newTerminalLayout(20, 5)) got := string(vr.Render([]byte("hello\x1b[K"))) if !strings.HasSuffix(got, "\x1b[15X") { t.Fatalf("clear-line after five chars should erase 15 cells: %q", got) } }