package app import ( "fmt" "strings" "testing" "github.com/hjbdev/patterm/internal/vt" ) func TestRenderScreenSnapshotClipsRowsToViewport(t *testing.T) { // hostRows=8 leaves three rows of viewport once the 3-row tab bar // and 1-row status line are reserved. layout := newTerminalLayout(20, 8) mainTop := int(layout.mainTop) got := string(renderScreenSnapshot("abcdefghijklmnopqrstuvwxy\nsecond", vt.CursorState{}, layout)) if strings.Contains(got, "uvwxy") { t.Fatalf("line leaked past viewport width: %q", got) } first := fmt.Sprintf("\x1b[%d;1Habcdefghijklmnopqrst", mainTop) if !strings.Contains(got, first) { t.Fatalf("first row not drawn at viewport top: %q", got) } second := fmt.Sprintf("\x1b[%d;1Hsecond ", mainTop+1) if !strings.Contains(got, second) { t.Fatalf("second row not padded in viewport: %q", got) } blank := fmt.Sprintf("\x1b[%d;1H ", mainTop+2) if !strings.Contains(got, blank) { t.Fatalf("blank viewport row not cleared: %q", got) } } func TestRenderScreenSnapshotPlacesCursorInsideViewport(t *testing.T) { layout := newTerminalLayout(20, 8) got := string(renderScreenSnapshot("abc", vt.CursorState{Col: 2, Row: 1, Visible: true}, layout)) want := fmt.Sprintf("\x1b[?25h\x1b[%d;3H", int(layout.mainTop)+1) if !strings.HasSuffix(got, want) { t.Fatalf("cursor not placed inside viewport: %q (want suffix %q)", got, want) } }