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/random_order.zigadded+42-0
Changes to src/random_order.zig
@@ -0,0 +1,42 @@
1const std = ;
2const compat = ;
3
4/// Return the seed that should control this run. Supplying a seed enables
5/// shuffling even when `shuffle` is false; otherwise random order is opt-in.
6pub fn resolveSeed(shuffle: bool, configured: ?u64) ?u64 {
7 if (configured) |seed| return seed;
8 if (!shuffle) return null;
9 return @truncate(@as(u128, @bitCast(compat.nanoTimestamp())));
10}
11
12pub const Shuffler = struct {
13 prng: std.Random.DefaultPrng,
14
15 pub fn init(seed: u64) Shuffler {
16 return .{ .prng = std.Random.DefaultPrng.init(seed) };
17 }
18
19 pub fn shuffle(self: *Shuffler, comptime T: type, items: []T) void {
20 self.prng.random().shuffleWithIndex(T, items, u64);
21 }
22};
23
24test "random order is opt-in and an explicit seed enables it" {
25 try std.testing.expect(resolveSeed(false, null) == null);
26 try std.testing.expect(resolveSeed(true, null) != null);
27 try std.testing.expectEqual(@as(?u64, 0), resolveSeed(false, 0));
28 try std.testing.expectEqual(@as(?u64, 42), resolveSeed(true, 42));
29}
30
31test "the same seed produces the same order" {
32 var first = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
33 var second = first;
34 var first_shuffler = Shuffler.init(123456789);
35 var second_shuffler = Shuffler.init(123456789);
36
37 first_shuffler.shuffle(u8, &first);
38 second_shuffler.shuffle(u8, &second);
39
40 try std.testing.expectEqualSlices(u8, &first, &second);
41 try std.testing.expect(!std.mem.eql(u8, &first, &[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }));
42}