diff options
| author | Gabriel Schneider <[email protected]> | 2026-06-21 13:35:37 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-06-25 11:23:20 -0300 |
| commit | 8c0bce4983915b8fa079cc218fae93a2adcf4b0e (patch) | |
| tree | 3f7499e16b88068247c3121c51a58dd0b7bf3fe1 /tests.zig | |
| parent | c528d9f3e90c6e7a2c3d349ec8e46feb0719d2aa (diff) | |
| download | pardes-8c0bce4983915b8fa079cc218fae93a2adcf4b0e.tar.gz pardes-8c0bce4983915b8fa079cc218fae93a2adcf4b0e.zip | |
working in realtime better than expected lol
Diffstat (limited to 'tests.zig')
| -rw-r--r-- | tests.zig | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/tests.zig b/tests.zig new file mode 100644 index 00000000..4cae1c26 --- /dev/null +++ b/tests.zig @@ -0,0 +1,120 @@ +const std = @import("std"); +const posix = std.posix; +const linux = std.os.linux; + +extern "c" fn forkpty( + amaster: *c_int, + name: ?[*:0]u8, + termp: ?*const anyopaque, + winp: ?*const posix.winsize, +) c_int; +extern "c" fn execvp(file: [*:0]const u8, argv: [*:null]const ?[*:0]const u8) c_int; +extern "c" fn _exit(status: c_int) noreturn; + +fn writeAll(fd: c_int, bytes: []const u8) !void { + var off: usize = 0; + while (off < bytes.len) { + const rc = linux.write(fd, bytes[off..].ptr, bytes.len - off); + switch (posix.errno(rc)) { + .SUCCESS => off += @intCast(rc), + .INTR => {}, + else => |err| { + std.debug.print("write failed: {}\n", .{err}); + return error.WriteFailed; + }, + } + } +} + +fn waitNoHang(pid: c_int) bool { + var status: u32 = 0; + const rc = linux.waitpid(pid, &status, linux.W.NOHANG); + return posix.errno(rc) == .SUCCESS and rc == @as(usize, @intCast(pid)); +} + +pub fn main(init: std.process.Init) !void { + const gpa = init.gpa; + const args = try init.minimal.args.toSlice(init.arena.allocator()); + if (args.len != 2) { + std.debug.print("usage: {s} <pardes-exe>\n", .{args[0]}); + return error.BadArgs; + } + + const exe = args[1]; + const marker = "PARDES_E2E"; + const command = "echo " ++ marker ++ "\r"; + + var master: c_int = undefined; + const ws = posix.winsize{ .row = 24, .col = 80, .xpixel = 0, .ypixel = 0 }; + const pid = forkpty(&master, null, null, &ws); + if (pid == 0) { + const child_argv = [_:null]?[*:0]const u8{ exe.ptr, null }; + _ = execvp(exe.ptr, &child_argv); + _exit(127); + } + defer _ = linux.close(master); + defer posix.kill(pid, posix.SIG.KILL) catch {}; + + var output: std.ArrayList(u8) = .empty; + defer output.deinit(gpa); + + var buf: [4096]u8 = undefined; + for (0..20) |_| { + var fds = [_]posix.pollfd{.{ + .fd = master, + .events = posix.POLL.IN, + .revents = 0, + }}; + _ = try posix.poll(&fds, 100); + if ((fds[0].revents & posix.POLL.IN) != 0) { + const n = posix.read(master, &buf) catch break; + if (n == 0) break; + try output.appendSlice(gpa, buf[0..n]); + break; + } + } + + try writeAll(master, command); + + var saw_marker = false; + for (0..80) |_| { + var fds = [_]posix.pollfd{.{ + .fd = master, + .events = posix.POLL.IN, + .revents = 0, + }}; + _ = try posix.poll(&fds, 100); + if ((fds[0].revents & (posix.POLL.IN | posix.POLL.HUP | posix.POLL.ERR)) != 0) { + const n = posix.read(master, &buf) catch break; + if (n == 0) break; + try output.appendSlice(gpa, buf[0..n]); + if (std.mem.containsAtLeast(u8, output.items, 1, marker)) { + saw_marker = true; + break; + } + } + if (waitNoHang(pid)) break; + } + + try writeAll(master, "\x03"); + for (0..20) |_| { + if (waitNoHang(pid)) break; + var fds = [_]posix.pollfd{.{ + .fd = master, + .events = posix.POLL.IN, + .revents = 0, + }}; + _ = posix.poll(&fds, 50) catch {}; + if ((fds[0].revents & posix.POLL.IN) != 0) { + _ = posix.read(master, &buf) catch 0; + } + } + + if (!saw_marker) { + std.debug.print("app did not render marker; captured {d} bytes:\n{s}\n", .{ + output.items.len, + output.items[0..@min(output.items.len, 4096)], + }); + return error.MarkerNotRendered; + } +} |
