libghostty: fix kitty graphics test failures

Fix three categories of test bugs in the kitty graphics C API tests:

The placement iterator reset in getTyped was clobbering the
layer_filter field when reinitializing the iterator struct,
causing the layer filter test to see unfiltered placements.
Preserve layer_filter across resets.

The viewport position tests were not accounting for the default
cursor_movement=after behavior of the kitty display command,
which calls index() for each row of the placement before the
test scroll sequence. Add C=1 to suppress cursor movement so
the scroll math in the tests is correct.

The source_rect tests used an 88-character all-A base64 payload
which decodes to 66 bytes, but a 4x4 RGBA image requires exactly
64 bytes. Fix the payload to use proper base64 padding (AA==).
This commit is contained in:
Mitchell Hashimoto
2026-04-06 12:49:12 -07:00
parent d712beff5b
commit 65e3265e3c
2 changed files with 13 additions and 7 deletions

View File

@@ -20,6 +20,8 @@ A file for [guiding coding agents](https://agents.md/).
- Build: `zig build -Demit-lib-vt`
- Build WASM: `zig build -Demit-lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall`
- Test: `zig build test-lib-vt -Dtest-filter=<filter>`
- Prefer this when the change is in a libghostty-vt file
## Directory Structure

View File

@@ -125,6 +125,7 @@ fn getTyped(
it.* = .{
.alloc = it.alloc,
.inner = storage.placements.iterator(),
.layer_filter = it.layer_filter,
};
},
}
@@ -1108,8 +1109,9 @@ test "placement_viewport_pos top off-screen" {
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 5, 10, 20));
// Transmit image, display at cursor (0,0) spanning 4 rows.
// C=1 prevents cursor movement after display.
const transmit = "\x1b_Ga=t,t=d,f=24,i=1,s=1,v=2;////////\x1b\\";
const display = "\x1b_Ga=p,i=1,p=1,c=1,r=4;\x1b\\";
const display = "\x1b_Ga=p,i=1,p=1,c=1,r=4,C=1;\x1b\\";
terminal_c.vt_write(t, transmit.ptr, transmit.len);
terminal_c.vt_write(t, display.ptr, display.len);
@@ -1150,10 +1152,11 @@ test "placement_viewport_pos bottom off-screen" {
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 5, 10, 20));
// Transmit image, move cursor to row 3 (1-based: row 4), display spanning 4 rows.
// C=1 prevents cursor movement after display.
// Image occupies rows 3-6 but viewport only has rows 0-4, so bottom is clipped.
const transmit = "\x1b_Ga=t,t=d,f=24,i=1,s=1,v=2;////////\x1b\\";
const cursor = "\x1b[4;1H";
const display = "\x1b_Ga=p,i=1,p=1,c=1,r=4;\x1b\\";
const display = "\x1b_Ga=p,i=1,p=1,c=1,r=4,C=1;\x1b\\";
terminal_c.vt_write(t, transmit.ptr, transmit.len);
terminal_c.vt_write(t, cursor.ptr, cursor.len);
terminal_c.vt_write(t, display.ptr, display.len);
@@ -1189,10 +1192,11 @@ test "placement_viewport_pos top and bottom off-screen" {
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 5, 10, 20));
// Transmit image, display at cursor (0,0) spanning 10 rows.
// C=1 prevents cursor movement after display.
// After scrolling by 3, image occupies vp rows -3..6, viewport is 0..4,
// so both top and bottom are clipped but center is visible.
const transmit = "\x1b_Ga=t,t=d,f=24,i=1,s=1,v=2;////////\x1b\\";
const display = "\x1b_Ga=p,i=1,p=1,c=1,r=10;\x1b\\";
const display = "\x1b_Ga=p,i=1,p=1,c=1,r=10,C=1;\x1b\\";
terminal_c.vt_write(t, transmit.ptr, transmit.len);
terminal_c.vt_write(t, display.ptr, display.len);
@@ -1278,9 +1282,9 @@ test "placement_source_rect with explicit source rect" {
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 24, 10, 20));
// Transmit a 4x4 RGBA image (64 bytes = 4*4*4).
// Base64 of 64 zero bytes: 86 chars.
// Base64 of 64 zero bytes: 88 chars (21 full groups + AA== padding).
const transmit = "\x1b_Ga=t,t=d,f=32,i=1,s=4,v=4;" ++
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ++
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" ++
"\x1b\\";
// Display with explicit source rect: x=1, y=1, w=2, h=2.
const display = "\x1b_Ga=p,i=1,p=1,x=1,y=1,w=2,h=2;\x1b\\";
@@ -1321,9 +1325,9 @@ test "placement_source_rect clamps to image bounds" {
defer terminal_c.free(t);
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 24, 10, 20));
// Transmit a 4x4 RGBA image.
// Transmit a 4x4 RGBA image (64 bytes = 4*4*4).
const transmit = "\x1b_Ga=t,t=d,f=32,i=1,s=4,v=4;" ++
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ++
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" ++
"\x1b\\";
// Display with source rect that exceeds image bounds: x=3, y=3, w=10, h=10.
// Should clamp to x=3, y=3, w=1, h=1.