fn testPropertiesUpheld(_: void, smith: *std.testing.Smith) !void {
@disableInstrumentation();
var source_buf: [512]u8 = undefined;
const len = smith.sliceWeightedBytes(source_buf[0 .. source_buf.len - 1], &.{
.rangeAtMost(u8, 0x00, 0xff, 1),
.rangeAtMost(u8, 0x20, 0x7e, 4),
.rangeAtMost(u8, 0x00, 0x1f, 1),
.value(u8, 0, 6),
.value(u8, ' ', 6),
.rangeAtMost(u8, '\t', '\n', 6), // \t, \n
.value(u8, '\r', 3),
});
source_buf[len] = 0;
const source = source_buf[0..len :0];
var tokenizer = Tokenizer.init(source);
var tokenization_failed = false;
while (true) {
const token = tokenizer.next();
// Property: token end location after start location (or equal)
try std.testing.expect(token.loc.end >= token.loc.start);
switch (token.tag) {
.invalid => {
tokenization_failed = true;
// Property: invalid token always ends at newline or eof
try std.testing.expect(source[token.loc.end] == '\n' or source[token.loc.end] == 0);
},
.eof => {
// Property: EOF token is always 0-length at end of source.
try std.testing.expectEqual(source.len, token.loc.start);
try std.testing.expectEqual(source.len, token.loc.end);
break;
},
else => continue,
}
}
if (tokenization_failed) return;
for (source) |cur| {
// Property: No null byte allowed except at end.
if (cur == 0) {
return error.TestUnexpectedResult;
}
// Property: No ASCII control characters other than \n, \t, and \r are allowed.
if (std.ascii.isControl(cur) and cur != '\n' and cur != '\t' and cur != '\r') {
return error.TestUnexpectedResult;
}
}
}