lib/hypothesis/src/coverage.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 pub const Bucket = enum {
 4     valid,
 5     invalid,
 6     boundary,
 7     large_state,
 8 };
 9 
10 pub const Counts = struct {
11     valid: u64 = 0,
12     invalid: u64 = 0,
13     boundary: u64 = 0,
14     large_state: u64 = 0,
15 
16     pub fn get(self: Counts, bucket: Bucket) u64 {
17         return switch (bucket) {
18             .valid => self.valid,
19             .invalid => self.invalid,
20             .boundary => self.boundary,
21             .large_state => self.large_state,
22         };
23     }
24 };
25 
26 pub const Counters = struct {
27     counts: Counts = .{},
28 
29     pub fn record(self: *Counters, bucket: Bucket) void {
30         const counter = switch (bucket) {
31             .valid => &self.counts.valid,
32             .invalid => &self.counts.invalid,
33             .boundary => &self.counts.boundary,
34             .large_state => &self.counts.large_state,
35         };
36         std.debug.assert(counter.* < std.math.maxInt(u64));
37         counter.* += 1;
38     }
39 
40     pub fn snapshot(self: *const Counters) Counts {
41         return self.counts;
42     }
43 
44     pub fn meets(self: *const Counters, minimum: Counts) bool {
45         for (std.meta.tags(Bucket)) |bucket| {
46             if (self.counts.get(bucket) < minimum.get(bucket)) return false;
47         }
48         return true;
49     }
50 
51     pub fn require(self: *const Counters, minimum: Counts) error{InsufficientCoverage}!void {
52         if (!self.meets(minimum)) return error.InsufficientCoverage;
53     }
54 };
55 
56 test "coverage: independent generators retain reachability buckets" {
57     var plans = Counters{};
58     var values = Counters{};
59     plans.record(.valid);
60     plans.record(.boundary);
61     values.record(.invalid);
62     values.record(.large_state);
63 
64     try std.testing.expect(plans.meets(.{ .valid = 1, .boundary = 1 }));
65     try std.testing.expect(values.meets(.{ .invalid = 1, .large_state = 1 }));
66     try std.testing.expect(!plans.meets(.{ .large_state = 1 }));
67     try std.testing.expectError(
68         error.InsufficientCoverage,
69         plans.require(.{ .large_state = 1 }),
70     );
71     try values.require(.{ .invalid = 1, .large_state = 1 });
72     try std.testing.expectEqual(@as(u64, 0), values.snapshot().valid);
73 }