lib/machine/src/properties/generator.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const explore = @import("../explore/root.zig");
 2 const hypothesis = @import("hypothesis");
 3 const profile = @import("../profile/root.zig");
 4 const std = @import("std");
 5 
 6 const Input = explore.InputGenerator(.{ .steps = 8, .alternatives = 5 });
 7 
 8 pub const Replay = struct {
 9     pub fn property(
10         data: *hypothesis.ConjectureData,
11         _: std.mem.Allocator,
12     ) !void {
13         const raw_seed = try data.drawInteger(0, std.math.maxInt(u64), 0);
14         const step_count: u16 = @intCast(try data.drawInteger(1, 8, 1));
15         const seed = explore.Seed.fromU64(raw_seed);
16         const plan = explore.TemporalPlan{
17             .steps = step_count,
18             .start_tick = 0,
19             .end_tick = 1_000,
20         };
21         var first = try ready(try Input.init(
22             profile.interpretedContinuationTestV1(),
23             seed,
24             plan,
25         ));
26         var replay = try ready(try Input.init(
27             profile.interpretedContinuationTestV1(),
28             seed,
29             plan,
30         ));
31         for (0..step_count) |_| {
32             const first_site = try site(first.next());
33             const replay_site = try site(replay.next());
34             try expectSite(first_site, replay_site);
35             const index: u8 = @intCast(try data.drawInteger(
36                 0,
37                 first_site.count - 1,
38                 first_site.suggested,
39             ));
40             const first_value = try first.choose(first_site, index);
41             const replay_value = try replay.choose(replay_site, index);
42             try std.testing.expectEqualDeep(first_value, replay_value);
43             const declared = profile.determinism.entry(first_value.origin.source);
44             try std.testing.expectEqual(declared.version, first_value.origin.version);
45         }
46     }
47 };
48 
49 test "pbt: explore generators replay explicit choices per seed" {
50     const settings = hypothesis.Settings.quick()
51         .withSeed(0xb10c_7eed)
52         .withDatabase(null);
53     try hypothesis.checkNamed(Replay, "machine-explore-replay", settings);
54 }
55 
56 fn ready(result: Input.InitResult) !Input {
57     return switch (result) {
58         .item => |value| value,
59         .exhausted => error.TestUnexpectedExhaustion,
60         .incomplete => error.TestUnexpectedIncomplete,
61     };
62 }
63 
64 fn site(result: Input.NextResult) !Input.Site {
65     return switch (result) {
66         .item => |value| value,
67         .exhausted => error.TestUnexpectedExhaustion,
68         .incomplete => error.TestUnexpectedIncomplete,
69     };
70 }
71 
72 fn expectSite(first: Input.Site, second: Input.Site) !void {
73     try std.testing.expectEqualDeep(first.id, second.id);
74     try std.testing.expectEqual(first.count, second.count);
75     try std.testing.expectEqual(first.suggested, second.suggested);
76     try std.testing.expectEqualDeep(first.values(), second.values());
77 }