35c92e24
Add synthetic hidden-freeze regression test
a73x 2026-04-16 11:21
Exercises the hide → pty-flood → show sequence through the FrameLoop state machine. Verifies no canRender() call returns true while hidden, and that normal pacing resumes on show.
diff --git a/src/frame_loop.zig b/src/frame_loop.zig index 66e5bdf..46a2c21 100644 --- a/src/frame_loop.zig +++ b/src/frame_loop.zig @@ -369,3 +369,44 @@ test "deinit destroys any pending callback" { try std.testing.expectEqual(@as(usize, 1), mock.callbacks_destroyed); } test "hidden-freeze regression: pty flood while hidden never blocks" { var mock = try Mock.init(); defer mock.deinit(); var ts = try TestState.init(std.testing.allocator); defer ts.deinit(); var loop = FrameLoop.init(mock.ops(), ts.view()); defer loop.deinit(); // Initial render. try loop.commitRender(); const first_tok = loop.pending_token.?; loop.onFrameCallbackDone(first_tok); // Hide the surface: tracker leaves all outputs. ts.tracker.leaveOutput(1); loop.onSurfaceHidden(); try std.testing.expect(!loop.canRender()); // Simulate 100 iterations of "pty wrote more data, we want to render". // Under the gate, canRender is false every iteration and we never call // commitRender — so no Vulkan work, no blocking. var i: usize = 0; while (i < 100) : (i += 1) { try std.testing.expect(!loop.canRender()); } // Show again: tracker re-enters an output. try ts.tracker.enterOutput(1); loop.onSurfaceShown(); try std.testing.expect(loop.canRender()); // Normal render resumes. try loop.commitRender(); try std.testing.expect(loop.pending_token != null); const tok = loop.pending_token.?; loop.onFrameCallbackDone(tok); try std.testing.expect(loop.armed); }