a9c14dfd
Add test-render orchestrator
a73x 2026-04-17 15:55
Iterates tests/golden/scripts/*.vt, runs waystty --capture on each, compares via imgdiff against reference PNGs. Continues on failure. WAYSTTY_GOLDEN_UPDATE=1 copies output to reference instead of diffing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
diff --git a/build.zig b/build.zig index 56314ea..42f3089 100644 --- a/build.zig +++ b/build.zig @@ -353,4 +353,21 @@ pub fn build(b: *std.Build) void { imgdiff_test_mod.addImport("png", png_mod); const imgdiff_tests = b.addTest(.{ .root_module = imgdiff_test_mod }); test_step.dependOn(&b.addRunArtifact(imgdiff_tests).step); const test_render_mod = b.createModule(.{ .root_source_file = b.path("src/tools/test_render.zig"), .target = target, .optimize = optimize, }); const test_render_exe = b.addExecutable(.{ .name = "test-render", .root_module = test_render_mod, }); b.installArtifact(test_render_exe); const test_render_step = b.step("test-render", "Run all golden VT scripts and diff against references"); test_render_step.dependOn(b.getInstallStep()); const test_render_run = b.addRunArtifact(test_render_exe); test_render_run.step.dependOn(b.getInstallStep()); test_render_step.dependOn(&test_render_run.step); } diff --git a/src/tools/test_render.zig b/src/tools/test_render.zig new file mode 100644 index 0000000..144e7aa --- /dev/null +++ b/src/tools/test_render.zig @@ -0,0 +1,75 @@ const std = @import("std"); pub fn main() !void { var gpa: std.heap.DebugAllocator(.{}) = .init; defer _ = gpa.deinit(); const alloc = gpa.allocator(); const mode_update = blk: { const m = std.posix.getenv("WAYSTTY_GOLDEN_UPDATE") orelse break :blk false; break :blk std.mem.eql(u8, m, "1"); }; try std.fs.cwd().makePath("tests/golden/output"); var scripts_dir = try std.fs.cwd().openDir("tests/golden/scripts", .{ .iterate = true }); defer scripts_dir.close(); var it = scripts_dir.iterate(); var passed: usize = 0; var failed: usize = 0; while (try it.next()) |entry| { if (entry.kind != .file) continue; if (!std.mem.endsWith(u8, entry.name, ".vt")) continue; const base = entry.name[0 .. entry.name.len - 3]; const script_path = try std.fmt.allocPrint(alloc, "tests/golden/scripts/{s}.vt", .{base}); defer alloc.free(script_path); const output_path = try std.fmt.allocPrint(alloc, "tests/golden/output/{s}.png", .{base}); defer alloc.free(output_path); const reference_path = try std.fmt.allocPrint(alloc, "tests/golden/reference/{s}.png", .{base}); defer alloc.free(reference_path); const diff_path = try std.fmt.allocPrint(alloc, "tests/golden/output/{s}.diff.png", .{base}); defer alloc.free(diff_path); // Run waystty --capture const cap = try std.process.Child.run(.{ .allocator = alloc, .argv = &.{ "zig-out/bin/waystty", "--capture", script_path, output_path }, }); defer alloc.free(cap.stdout); defer alloc.free(cap.stderr); if (cap.term != .Exited or cap.term.Exited != 0) { std.debug.print("FAIL: {s}: capture exited with {}\n stderr: {s}\n", .{ base, cap.term, cap.stderr }); failed += 1; continue; } if (mode_update) { try std.fs.cwd().makePath("tests/golden/reference"); try std.fs.cwd().copyFile(output_path, std.fs.cwd(), reference_path, .{}); std.debug.print("UPDATED: {s}\n", .{base}); passed += 1; continue; } // Run imgdiff const dif = try std.process.Child.run(.{ .allocator = alloc, .argv = &.{ "zig-out/bin/imgdiff", output_path, reference_path, diff_path }, }); defer alloc.free(dif.stdout); defer alloc.free(dif.stderr); std.debug.print("{s}", .{dif.stdout}); if (dif.term == .Exited and dif.term.Exited == 0) { passed += 1; } else { failed += 1; } } std.debug.print("\n=== test-render: {} passed, {} failed ===\n", .{ passed, failed }); if (failed > 0) std.process.exit(1); }