summaryrefslogtreecommitdiff
path: root/tests.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-06-21 13:35:37 -0300
committerGabriel Schneider <[email protected]>2026-06-25 11:23:20 -0300
commit8c0bce4983915b8fa079cc218fae93a2adcf4b0e (patch)
tree3f7499e16b88068247c3121c51a58dd0b7bf3fe1 /tests.zig
parentc528d9f3e90c6e7a2c3d349ec8e46feb0719d2aa (diff)
downloadpardes-8c0bce4983915b8fa079cc218fae93a2adcf4b0e.tar.gz
pardes-8c0bce4983915b8fa079cc218fae93a2adcf4b0e.zip
working in realtime better than expected lol
Diffstat (limited to 'tests.zig')
-rw-r--r--tests.zig120
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;
+ }
+}