mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-28 19:47:08 +03:00
134 lines
4.4 KiB
Zig
134 lines
4.4 KiB
Zig
const builtin = @import("builtin");
|
|
|
|
const std = @import("std");
|
|
const Io = std.Io;
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
pub fn main(init: std.process.Init) !void {
|
|
const gpa = init.gpa;
|
|
const io = init.io;
|
|
|
|
var it = try init.minimal.args.iterateAllocator(gpa);
|
|
defer it.deinit();
|
|
_ = it.next() orelse unreachable; // skip binary name
|
|
|
|
const iterations: u64 = iterations: {
|
|
const arg = it.next() orelse "0";
|
|
break :iterations try std.fmt.parseUnsigned(u64, arg, 10);
|
|
};
|
|
|
|
var rand_seed = false;
|
|
const seed: u64 = seed: {
|
|
const seed_arg = it.next() orelse {
|
|
rand_seed = true;
|
|
var buf: [8]u8 = undefined;
|
|
try std.posix.getrandom(&buf);
|
|
break :seed std.mem.readInt(u64, &buf, builtin.cpu.arch.endian());
|
|
};
|
|
break :seed try std.fmt.parseUnsigned(u64, seed_arg, 10);
|
|
};
|
|
var random = std.Random.DefaultPrng.init(seed);
|
|
const rand = random.random();
|
|
|
|
// If the seed was not given via the CLI, then output the
|
|
// randomly chosen seed so that this run can be reproduced
|
|
if (rand_seed) {
|
|
std.debug.print("rand seed: {}\n", .{seed});
|
|
}
|
|
|
|
var i: u64 = 0;
|
|
while (iterations == 0 or i < iterations) {
|
|
const rand_arg = try randomArg(gpa, rand);
|
|
defer gpa.free(rand_arg);
|
|
|
|
try testExec(gpa, io, &.{rand_arg}, null);
|
|
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
fn testExec(gpa: Allocator, io: Io, args: []const []const u8, env: ?*std.process.Environ.Map) !void {
|
|
try testExecBat(gpa, io, "args1.bat", args, env);
|
|
try testExecBat(gpa, io, "args2.bat", args, env);
|
|
try testExecBat(gpa, io, "args3.bat", args, env);
|
|
}
|
|
|
|
fn testExecBat(gpa: Allocator, io: Io, bat: []const u8, args: []const []const u8, env: ?*std.process.Environ.Map) !void {
|
|
const argv = try gpa.alloc([]const u8, 1 + args.len);
|
|
defer gpa.free(argv);
|
|
argv[0] = bat;
|
|
@memcpy(argv[1..], args);
|
|
|
|
const can_have_trailing_empty_args = std.mem.eql(u8, bat, "args3.bat");
|
|
|
|
const result = try std.process.run(gpa, io, .{
|
|
.environ_map = env,
|
|
.argv = argv,
|
|
});
|
|
defer gpa.free(result.stdout);
|
|
defer gpa.free(result.stderr);
|
|
|
|
try std.testing.expectEqualStrings("", result.stderr);
|
|
var it = std.mem.splitScalar(u8, result.stdout, '\x00');
|
|
var i: usize = 0;
|
|
while (it.next()) |actual_arg| {
|
|
if (i >= args.len and can_have_trailing_empty_args) {
|
|
try std.testing.expectEqualStrings("", actual_arg);
|
|
continue;
|
|
}
|
|
const expected_arg = args[i];
|
|
try std.testing.expectEqualSlices(u8, expected_arg, actual_arg);
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
fn randomArg(gpa: Allocator, rand: std.Random) ![]const u8 {
|
|
const Choice = enum {
|
|
backslash,
|
|
quote,
|
|
space,
|
|
control,
|
|
printable,
|
|
surrogate_half,
|
|
non_ascii,
|
|
};
|
|
|
|
const choices = rand.uintAtMostBiased(u16, 256);
|
|
var buf: std.ArrayList(u8) = try .initCapacity(gpa, choices);
|
|
errdefer buf.deinit(gpa);
|
|
|
|
var last_codepoint: u21 = 0;
|
|
for (0..choices) |_| {
|
|
const choice = rand.enumValue(Choice);
|
|
const codepoint: u21 = switch (choice) {
|
|
.backslash => '\\',
|
|
.quote => '"',
|
|
.space => ' ',
|
|
.control => switch (rand.uintAtMostBiased(u8, 0x21)) {
|
|
// NUL/CR/LF can't roundtrip
|
|
'\x00', '\r', '\n' => ' ',
|
|
0x21 => '\x7F',
|
|
else => |b| b,
|
|
},
|
|
.printable => '!' + rand.uintAtMostBiased(u8, '~' - '!'),
|
|
.surrogate_half => rand.intRangeAtMostBiased(u16, 0xD800, 0xDFFF),
|
|
.non_ascii => rand.intRangeAtMostBiased(u21, 0x80, 0x10FFFF),
|
|
};
|
|
// Ensure that we always return well-formed WTF-8.
|
|
// Instead of concatenating to ensure well-formed WTF-8,
|
|
// we just skip encoding the low surrogate.
|
|
if (std.unicode.isSurrogateCodepoint(last_codepoint) and std.unicode.isSurrogateCodepoint(codepoint)) {
|
|
if (std.unicode.utf16IsHighSurrogate(@intCast(last_codepoint)) and std.unicode.utf16IsLowSurrogate(@intCast(codepoint))) {
|
|
continue;
|
|
}
|
|
}
|
|
try buf.ensureUnusedCapacity(gpa, 4);
|
|
const unused_slice = buf.unusedCapacitySlice();
|
|
const len = std.unicode.wtf8Encode(codepoint, unused_slice) catch unreachable;
|
|
buf.items.len += len;
|
|
last_codepoint = codepoint;
|
|
}
|
|
|
|
return buf.toOwnedSlice(gpa);
|
|
}
|