diff options
Diffstat (limited to 'tests.zig')
| -rw-r--r-- | tests.zig | 110 |
1 files changed, 110 insertions, 0 deletions
@@ -26,6 +26,16 @@ fn rowOf(text: []const u8, needle: []const u8) ?usize { return null; } +// Column (0-based byte offset within its line) of the first `needle` on screen. +// The grid is monospace ASCII here, so the byte offset is the screen column. +fn colOf(text: []const u8, needle: []const u8) ?usize { + var it = std.mem.splitScalar(u8, text, '\n'); + while (it.next()) |line| { + if (std.mem.indexOf(u8, line, needle)) |off| return off; + } + return null; +} + pub fn main(init: std.process.Init) !void { const gpa = init.gpa; const args = try init.minimal.args.toSlice(init.arena.allocator()); @@ -479,4 +489,104 @@ pub fn main(init: std.process.Init) !void { // grapheme slice into a stack-local cell). try hs5.expectContains("█", "petscii image body is blank — no block glyphs rendered"); } + + // 16. Opening a SECOND file SPLITS the existing file pane (acme-style minimal + // reflow) instead of stacking at the top of the column: the new file lands + // directly BELOW the source file, so A is above B. The OLD stack-at-top + // behavior would put B ABOVE A — so asserting rowOf(A) < rowOf(B) is a + // regression test for the split. + { + var hs6 = try Harness.init(gpa, exe.ptr, 24, 80); + defer hs6.deinit(); + try hs6.expectWaitFor("build.zig", 8000, "fresh terminal never auto-ls'd"); + try h.writeFile("/tmp/pardesE2Efa.txt", "ZZFILEA\nfa1\nfa2\nfa3\nfa4\nfa5\nfa6\nfa7\nfa8\nfa9\n"); + try h.writeFile("/tmp/pardesE2Efb.txt", "ZZFILEB\nfb1\nfb2\nfb3\nfb4\nfb5\nfb6\nfb7\nfb8\nfb9\n"); + try hs6.resize(30, 100); // clean geometry: right column starts ~col 51 + try hs6.pump(700); + // open file A from the right-column terminal: the FIRST doc pane, so it + // takes the stack-at-top fallback (no existing doc pane to split). + try hs6.send("\x1b[<0;60;20M\x1b[<0;60;20m"); // pin a blank row, right column -> normal + try hs6.pump(400); + try hs6.send("i"); + try hs6.pump(300); + try hs6.send("/tmp/pardesE2Efa.txt"); + try hs6.pump(500); + try hs6.send("\x1b"); // -> normal + try hs6.pump(400); + try hs6.send("\x1b[<2;70;20M\x1b[<2;70;20m"); // right-click the path -> open file A + try hs6.expectWaitFor("ZZFILEA", 12000, "right-click did not open file A"); + // open file B likewise: a doc pane now exists, so B SPLITS it (lands below A). + try hs6.send("\x1b[<0;60;22M\x1b[<0;60;22m"); // pin another blank row, right column + try hs6.pump(400); + try hs6.send("i"); + try hs6.pump(300); + try hs6.send("/tmp/pardesE2Efb.txt"); + try hs6.pump(500); + try hs6.send("\x1b"); + try hs6.pump(400); + try hs6.send("\x1b[<2;70;22M\x1b[<2;70;22m"); // right-click the path -> open file B + try hs6.expectWaitFor("ZZFILEB", 12000, "right-click did not open file B"); + // both markers sit on each file's TOP line (scroll 0). The split puts B + // under A -> A's row < B's row. Stack-at-top would invert this. + const text = try hs6.screenText(); + defer gpa.free(text); + const ra = rowOf(text, "ZZFILEA") orelse return error.NoFileAOnScreen; + const rb = rowOf(text, "ZZFILEB") orelse return error.NoFileBOnScreen; + if (!(ra < rb)) { + hs6.dump("second file did not split BELOW the first (B not under A)"); + return error.FileSplitOrderWrong; + } + } + + // 17. Deleting a pane that EMPTIES its column hands the column's width to a + // neighbor, so the OTHER columns keep their widths (only the neighbor + // grows). Regression for the extra horizontal movement: without the + // col-weight handoff, wsum drops and every surviving column reflows + // sideways. Build 3 columns, put a marker in the rightmost, delete the + // MIDDLE column's shell (exit), and assert the marker's screen column is + // unchanged (the middle column's width flowed LEFT, not to the right one). + { + var hs7 = try Harness.init(gpa, exe.ptr, 24, 80); + defer hs7.deinit(); + try hs7.expectWaitFor("build.zig", 8000, "fresh terminal never auto-ls'd"); + try hs7.resize(30, 120); // 3 columns of ~40 each + try hs7.pump(700); + // add a 3rd column via the global-tagbar "Newcol" (cols 5-10, 0-based). + try hs7.send("\x1b[<1;8;1M\x1b[<1;8;1m"); // middle-click "Newcol" + try hs7.pump(1600); // let the new shell come up + // mark the rightmost column (now the active pane) with a unique token. + try hs7.send("\x02"); // normal -> tty + try hs7.pump(500); + try hs7.send("clear\r"); + try hs7.pump(800); + // split the token so it appears ONLY in the OUTPUT (at the pane's left edge), + // never in the command text — else colOf would match the prompt-relative echo. + try hs7.send("echo ZZFAR''COL\r"); + try hs7.expectWaitFor("ZZFARCOL", 8000, "new column's shell did not echo the marker"); + const before = try hs7.screenText(); + const x1 = colOf(before, "ZZFARCOL") orelse { + gpa.free(before); + return error.NoFarColBefore; + }; + gpa.free(before); + // focus the MIDDLE column (x 40..80) and exit its shell -> the column + // empties and collapses. pty_eof deletes the pane and reflows. + try hs7.send("\x1b[<0;58;12M\x1b[<0;58;12m"); // left-click inside the middle column + try hs7.pump(500); + try hs7.send("\x02"); // -> tty + try hs7.pump(400); + try hs7.send("exit\r"); // shell EOF -> pane removed -> middle column collapses + try hs7.pump(2000); // let pty_eof + the reflow settle + try hs7.expectContains("ZZFARCOL", "marker vanished after collapsing the middle column"); + const after = try hs7.screenText(); + defer gpa.free(after); + const x2 = colOf(after, "ZZFARCOL") orelse return error.NoFarColAfter; + // with the width handoff the rightmost column stays put (x2 ~= x1); without + // it, every column reflows and x2 shrinks by ~one column width. + if (x2 + 2 < x1) { + hs7.dump("rightmost column moved when the middle column collapsed (no width handoff)"); + std.debug.print("ZZFARCOL col: before={d} after={d}\n", .{ x1, x2 }); + return error.ColumnCollapseReflow; + } + } } |
