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/test_loader.zigmodified+18-2
Changes to src/test_loader.zig
@@ -8,6 +8,7 @@ const coverage = ;
88const ui_server = ;
99const compat = ;
1010const protocol = ;
11const random_order = ;
1112
1213/// Options for running discovered tests
1314pub const LoaderOptions = struct {
@@ -33,6 +34,10 @@ pub const LoaderOptions = struct {
3334 repeat: usize = 1,
3435 /// Treat recovered failures as an unsuccessful run.
3536 fail_on_flaky: bool = false,
37 /// Shuffle selected files. A generated seed is printed for replay.
38 shuffle: bool = false,
39 /// Reproduce a shuffled file order. Supplying a seed enables shuffle.
40 seed: ?u64 = null,
3641 /// Optional output supplied by a CLI host. Embedded/test callers default
3742 /// to stderr so they do not interfere with Zig's stdout test protocol.
3843 reporter_writer: ?*std.Io.Writer = null,
@@ -55,6 +60,11 @@ pub fn runDiscoveredTests(
5560
5661 var plan = try discoveryPlan(allocator, discovered, options.shard);
5762 defer plan.deinit();
63 const random_seed = random_order.resolveSeed(options.shuffle, options.seed);
64 if (random_seed) |seed| {
65 var shuffler = random_order.Shuffler.init(seed);
66 shuffler.shuffle(pipeline.PlanItem, plan.items.items);
67 }
5868 const selected_files = plan.items.items.len;
5969 if (options.shard) |shard| {
6070 std.debug.print(
@@ -84,7 +94,9 @@ pub fn runDiscoveredTests(
8494 options.use_colors,
8595 );
8696 defer reporters.deinit();
87 const events = pipeline.EventStream{ .rep = reporters.selected() };
97 const selected_reporter = reporters.selected();
98 selected_reporter.random_seed = random_seed;
99 const events = pipeline.EventStream{ .rep = selected_reporter };
88100 const policy = pipeline.ExecutionPolicy{
89101 .bail = options.bail,
90102 .filter = options.filter,
@@ -92,6 +104,7 @@ pub fn runDiscoveredTests(
92104 };
93105 var results = reporter.TestResults.init(allocator);
94106 defer results.deinit();
107 results.random_seed = random_seed;
95108 var executed_cases: std.ArrayList(suite.TestCase) = .empty;
96109 defer {
97110 for (executed_cases.items) |*test_case| test_case.deinit(allocator);
@@ -102,7 +115,7 @@ pub fn runDiscoveredTests(
102115
103116 // Notify UI of run start
104117 if (options.ui_server) |server| {
105 try server.broadcastEvent(allocator, .{ .run_start = .{ .total = selected_files } });
118 try server.broadcastEvent(allocator, .{ .run_start = .{ .total = selected_files, .random_seed = random_seed } });
106119 }
107120
108121 var files_run: usize = 0;
@@ -241,6 +254,7 @@ pub fn runDiscoveredTests(
241254 .failed = results.failed,
242255 .skipped = results.skipped,
243256 .duration_ns = results.total_time_ns,
257 .random_seed = results.random_seed,
244258 } });
245259 }
246260
@@ -355,6 +369,8 @@ test "LoaderOptions default values" {
355369 try std.testing.expectEqual(@as(?sharding.ShardOptions, null), options.shard);
356370 try std.testing.expectEqual(reporter.ReporterType.spec, options.reporter_type);
357371 try std.testing.expectEqualStrings("test-results.xml", options.junit_output);
372 try std.testing.expect(!options.shuffle);
373 try std.testing.expect(options.seed == null);
358374 try std.testing.expectEqual(@as(?u64, null), options.timeout_ms);
359375 try std.testing.expectEqual(@as(usize, 0), options.retries);
360376 try std.testing.expectEqual(@as(usize, 1), options.repeat);