ReviewOS

also looking at this

zig-utils/zig-test-framework

Add reproducible randomized test order

#29
Merged glennmichael123 wants to merge codex/issue-14-random-order into main
18 files +487 -42
src/reporter.zigmodified+25-6
Changes to src/reporter.zig
@@ -31,6 +31,7 @@ pub const Reporter = struct {
3131 vtable: *const VTable,
3232 allocator: std.mem.Allocator,
3333 use_colors: bool = true,
34 random_seed: ?u64 = null,
3435
3536 const Self = @This();
3637
@@ -76,6 +77,7 @@ pub const TestResults = struct {
7677 failed: usize = 0,
7778 skipped: usize = 0,
7879 total_time_ns: u64 = 0,
80 random_seed: ?u64 = null,
7981 failed_tests: std.ArrayList(suite.TestCase),
8082 flaky_tests: std.ArrayList(suite.TestCase),
8183 allocator: std.mem.Allocator,
@@ -163,6 +165,9 @@ pub const SpecReporter = struct {
163165 } else {
164166 try s.output().print("Running {d} test(s)...\n\n", .{total_tests});
165167 }
168 if (reporter.random_seed) |seed| {
169 try s.output().print("Random seed: {d}\n\n", .{seed});
170 }
166171 }
167172
168173 fn onRunEnd(reporter: *Reporter, results: *TestResults) !void {
@@ -188,6 +193,9 @@ pub const SpecReporter = struct {
188193 }
189194 }
190195 try s.output().print("\n", .{});
196 if (results.random_seed) |seed| {
197 try s.output().print("Reproduce with: --seed {d}\n\n", .{seed});
198 }
191199 }
192200
193201 // Print summary
@@ -377,6 +385,7 @@ pub const DotReporter = struct {
377385 fn onRunStart(reporter: *Reporter, total_tests: usize) !void {
378386 const s = self(reporter);
379387 try s.output().print("\nRunning {d} tests:\n", .{total_tests});
388 if (reporter.random_seed) |seed| try s.output().print("Random seed: {d}\n", .{seed});
380389 }
381390
382391 fn onRunEnd(reporter: *Reporter, results: *TestResults) !void {
@@ -399,6 +408,9 @@ pub const DotReporter = struct {
399408 total_time_ms,
400409 });
401410 }
411 if (results.failed > 0) {
412 if (results.random_seed) |seed| try s.output().print("Reproduce with: --seed {d}\n", .{seed});
413 }
402414 }
403415
404416 fn onSuiteStart(reporter: *Reporter, suite_name: []const u8) !void {
@@ -512,7 +524,7 @@ pub const JsonReporter = struct {
512524 s.emitted_events = false;
513525 s.suites.clearRetainingCapacity();
514526 try s.output().writeAll("[\n");
515 try s.emit(.{ .run_start = .{ .total = total_tests } });
527 try s.emit(.{ .run_start = .{ .total = total_tests, .random_seed = reporter.random_seed } });
516528 }
517529
518530 fn onRunEnd(reporter: *Reporter, results: *TestResults) !void {
@@ -524,6 +536,7 @@ pub const JsonReporter = struct {
524536 .failed = results.failed,
525537 .skipped = results.skipped,
526538 .duration_ns = results.total_time_ns,
539 .random_seed = results.random_seed,
527540 } });
528541 try s.output().writeAll("\n]\n");
529542 }
@@ -618,11 +631,14 @@ pub const TAPReporter = struct {
618631 fn onRunStart(reporter: *Reporter, total: usize) !void {
619632 const self: *Self = @fieldParentPtr("reporter", reporter);
620633 try self.output().print("TAP version 14\n1..{d}\n", .{total});
634 if (reporter.random_seed) |seed| try self.output().print("# random-seed {d}\n", .{seed});
621635 }
622636
623637 fn onRunEnd(reporter: *Reporter, results: *TestResults) !void {
624 _ = reporter;
625 _ = results;
638 const self: *Self = @fieldParentPtr("reporter", reporter);
639 if (results.failed > 0) {
640 if (results.random_seed) |seed| try self.output().print("# reproduce --seed {d}\n", .{seed});
641 }
626642 }
627643
628644 fn onSuiteStart(reporter: *Reporter, suite_name: []const u8) !void {
@@ -753,14 +769,13 @@ pub const JUnitReporter = struct {
753769 fn onSuiteStart(reporter: *Reporter, suite_name: []const u8) !void {
754770 const self: *Self = @fieldParentPtr("reporter", reporter);
755771
756 const suite_result = try self.allocator.create(TestSuiteResult);
757 suite_result.* = .{
772 const suite_result = TestSuiteResult{
758773 .name = try self.allocator.dupe(u8, suite_name),
759774 .tests = .empty,
760775 .timestamp = compat.milliTimestamp(),
761776 };
762777
763 try self.suites.append(self.allocator, suite_result.*);
778 try self.suites.append(self.allocator, suite_result);
764779 self.current_suite = &self.suites.items[self.suites.items.len - 1];
765780 }
766781
@@ -843,6 +858,10 @@ pub const JUnitReporter = struct {
843858 suite_time,
844859 });
845860
861 if (results.random_seed) |seed| {
862 try buffer.print(self.allocator, " <properties><property name=\"random_seed\" value=\"{d}\"/></properties>\n", .{seed});
863 }
864
846865 for (suite_result.tests.items) |test_result| {
847866 try buffer.print(self.allocator, " <testcase name=\"{s}\" time=\"{d:.6}\"", .{
848867 test_result.name,