lib/stabilizer/src/properties/intrinsics.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const hypothesis = @import("hypothesis");
 3 const stabilizer = @import("stabilizer");
 4 
 5 const Allocator = std.mem.Allocator;
 6 
 7 const powif = stabilizer.powif;
 8 const memset_i8 = stabilizer.memset_i8;
 9 const memset_i16 = stabilizer.memset_i16;
10 const memset_i32 = stabilizer.memset_i32;
11 const memset_i64 = stabilizer.memset_i64;
12 
13 fn settings() hypothesis.Settings {
14     return hypothesis.Settings.quick()
15         .withSeed(0x57ab_11e5)
16         .withDatabase("zig-out/hypothesis-failures/stabilizer");
17 }
18 
19 fn drawUsize(data: *hypothesis.ConjectureData, min: usize, max: usize, shrink_towards: usize) !usize {
20     return @intCast(try data.drawInteger(
21         @intCast(min),
22         @intCast(max),
23         @intCast(shrink_towards),
24     ));
25 }
26 
27 fn drawI32(data: *hypothesis.ConjectureData, min: i32, max: i32, shrink_towards: i32) !i32 {
28     return hypothesis.strategies.u64ToInt(i32, try data.drawInteger(
29         hypothesis.strategies.intToU64(i32, min),
30         hypothesis.strategies.intToU64(i32, max),
31         hypothesis.strategies.intToU64(i32, shrink_towards),
32     ));
33 }
34 
35 const IntrinsicPowProperty = struct {
36     pub fn property(data: *hypothesis.ConjectureData, allocator: Allocator) !void {
37         _ = allocator;
38         const base_i = try drawI32(data, -32, 32, 2);
39         const exponent = try drawI32(data, -8, 8, 0);
40         const base: f32 = @floatFromInt(base_i);
41         const expected = std.math.pow(f32, base, @floatFromInt(exponent));
42         const actual = powif(base, @intCast(exponent));
43         if (std.math.isNan(expected)) {
44             try std.testing.expect(std.math.isNan(actual));
45         } else {
46             try std.testing.expectEqual(expected, actual);
47         }
48     }
49 };
50 
51 test "pbt: powif matches upstream float exponent cast" {
52     try hypothesis.checkNamed(IntrinsicPowProperty, "stabilizer-powif", settings());
53 }
54 
55 const IntrinsicMemsetProperty = struct {
56     pub fn property(data: *hypothesis.ConjectureData, allocator: Allocator) !void {
57         const variant = try drawUsize(data, 0, 3, 0);
58         const len = try drawUsize(data, 0, if (variant == 0) 255 else 256, 0);
59         const prefix = try drawUsize(data, 0, 16, 0);
60         const suffix = try drawUsize(data, 0, 16, 0);
61         const value: u8 = @truncate(try drawUsize(data, 0, 255, 0));
62         const total = prefix + len + suffix;
63         const bytes = try allocator.alloc(u8, total);
64         defer allocator.free(bytes);
65         @memset(bytes, 0xa5);
66 
67         switch (variant) {
68             0 => memset_i8(bytes[prefix..].ptr, value, @intCast(len), 1, false),
69             1 => memset_i16(bytes[prefix..].ptr, value, @intCast(len), 1, false),
70             2 => memset_i32(bytes[prefix..].ptr, value, @intCast(len), 1, false),
71             else => memset_i64(bytes[prefix..].ptr, value, @intCast(len), 1, true),
72         }
73 
74         for (bytes[0..prefix]) |byte| try std.testing.expectEqual(@as(u8, 0xa5), byte);
75         for (bytes[prefix..][0..len]) |byte| try std.testing.expectEqual(value, byte);
76         for (bytes[prefix + len ..]) |byte| try std.testing.expectEqual(@as(u8, 0xa5), byte);
77     }
78 };
79 
80 test "pbt: memset intrinsics preserve exact byte ranges" {
81     try hypothesis.checkNamed(IntrinsicMemsetProperty, "stabilizer-memset-intrinsics", settings());
82 }