ReviewOS

also looking at this

zig-utils/zig-test-framework

Add retries, repeated runs, and flaky-test reporting

#25
Merged glennmichael123 wants to merge codex/issue-7-retries-repeat-flaky into main
15 files +719 -53
src/config.zigmodified+14-0
Changes to src/config.zig
@@ -29,6 +29,9 @@ pub const TestOptions = struct {
2929 recursive: bool = true,
3030 filter: ?[]const u8 = null,
3131 timeout: ?u64 = null,
32 retries: usize = 0,
33 repeat: usize = 1,
34 fail_on_flaky: bool = false,
3235};
3336
3437pub const ParallelOptions = struct {
@@ -86,6 +89,7 @@ pub const ConfigError = error{
8689 InvalidJobs,
8790 InvalidPort,
8891 InvalidTimeout,
92 InvalidRepeat,
8993 InvalidDebounce,
9094 InvalidShard,
9195};
@@ -183,6 +187,7 @@ fn validate(config: TestConfig) !void {
183187 if (config.test_options.timeout) |timeout| {
184188 if (timeout == 0) return ConfigError.InvalidTimeout;
185189 }
190 if (config.test_options.repeat == 0) return ConfigError.InvalidRepeat;
186191 if (config.watch.debounce_ms == 0) return ConfigError.InvalidDebounce;
187192 const has_shard_index = config.sharding.index != null;
188193 const has_shard_count = config.sharding.count != null;
@@ -199,6 +204,9 @@ test "TestConfig defaults match CLI discovery defaults" {
199204 try std.testing.expectEqualStrings(".", config.test_options.test_dir);
200205 try std.testing.expect(config.test_options.recursive);
201206 try std.testing.expect(config.test_options.timeout == null);
207 try std.testing.expectEqual(@as(usize, 0), config.test_options.retries);
208 try std.testing.expectEqual(@as(usize, 1), config.test_options.repeat);
209 try std.testing.expect(!config.test_options.fail_on_flaky);
202210 try std.testing.expect(config.sharding.index == null);
203211 try std.testing.expect(config.sharding.count == null);
204212 try std.testing.expect(!config.parallel.enabled);
@@ -219,6 +227,9 @@ test "configuration validation rejects invalid runtime values" {
219227 invalid.parallel.jobs = 0;
220228 try std.testing.expectError(ConfigError.InvalidJobs, validate(invalid));
221229 invalid.parallel.jobs = null;
230 invalid.test_options.repeat = 0;
231 try std.testing.expectError(ConfigError.InvalidRepeat, validate(invalid));
232 invalid.test_options.repeat = 1;
222233 invalid.sharding.index = 2;
223234 try std.testing.expectError(ConfigError.InvalidShard, validate(invalid));
224235 invalid.sharding.count = 1;
@@ -233,6 +244,9 @@ test "ConfigLoader loads supported JSON and rejects unknown keys" {
233244 try std.testing.expectEqualStrings("tests/fixtures", config.test_options.test_dir);
234245 try std.testing.expectEqualStrings("selected test passes", config.test_options.filter.?);
235246 try std.testing.expect(!config.test_options.recursive);
247 try std.testing.expectEqual(@as(usize, 1), config.test_options.retries);
248 try std.testing.expectEqual(@as(usize, 2), config.test_options.repeat);
249 try std.testing.expect(!config.test_options.fail_on_flaky);
236250 try std.testing.expectEqual(@as(?usize, 1), config.sharding.index);
237251 try std.testing.expectEqual(@as(?usize, 1), config.sharding.count);
238252