mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 01:24:49 +01:00
tests: close() -> close(io)
This commit is contained in:
parent
a91c6dc71d
commit
9e3bda5eff
21 changed files with 187 additions and 139 deletions
|
|
@ -56,8 +56,9 @@ pub const WriteFileError = error{
|
|||
|
||||
pub const SeekError = Io.File.SeekError;
|
||||
|
||||
pub fn init(file: File, buffer: []u8) Writer {
|
||||
pub fn init(file: File, io: Io, buffer: []u8) Writer {
|
||||
return .{
|
||||
.io = io,
|
||||
.file = file,
|
||||
.interface = initInterface(buffer),
|
||||
.mode = .positional,
|
||||
|
|
@ -67,8 +68,9 @@ pub fn init(file: File, buffer: []u8) Writer {
|
|||
/// Positional is more threadsafe, since the global seek position is not
|
||||
/// affected, but when such syscalls are not available, preemptively
|
||||
/// initializing in streaming mode will skip a failed syscall.
|
||||
pub fn initStreaming(file: File, buffer: []u8) Writer {
|
||||
pub fn initStreaming(file: File, io: Io, buffer: []u8) Writer {
|
||||
return .{
|
||||
.io = io,
|
||||
.file = file,
|
||||
.interface = initInterface(buffer),
|
||||
.mode = .streaming,
|
||||
|
|
|
|||
|
|
@ -435,8 +435,7 @@ pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix
|
|||
|
||||
/// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
|
||||
/// If it succeeds, the caller owns result.stdout and result.stderr memory.
|
||||
pub fn run(args: struct {
|
||||
allocator: mem.Allocator,
|
||||
pub fn run(allocator: Allocator, io: Io, args: struct {
|
||||
argv: []const []const u8,
|
||||
cwd: ?[]const u8 = null,
|
||||
cwd_dir: ?Io.Dir = null,
|
||||
|
|
@ -447,7 +446,7 @@ pub fn run(args: struct {
|
|||
expand_arg0: Arg0Expand = .no_expand,
|
||||
progress_node: std.Progress.Node = std.Progress.Node.none,
|
||||
}) RunError!RunResult {
|
||||
var child = ChildProcess.init(args.argv, args.allocator);
|
||||
var child = ChildProcess.init(args.argv, allocator);
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
|
@ -458,19 +457,19 @@ pub fn run(args: struct {
|
|||
child.progress_node = args.progress_node;
|
||||
|
||||
var stdout: ArrayList(u8) = .empty;
|
||||
defer stdout.deinit(args.allocator);
|
||||
defer stdout.deinit(allocator);
|
||||
var stderr: ArrayList(u8) = .empty;
|
||||
defer stderr.deinit(args.allocator);
|
||||
defer stderr.deinit(allocator);
|
||||
|
||||
try child.spawn();
|
||||
errdefer {
|
||||
_ = child.kill() catch {};
|
||||
_ = child.kill(io) catch {};
|
||||
}
|
||||
try child.collectOutput(args.allocator, &stdout, &stderr, args.max_output_bytes);
|
||||
try child.collectOutput(allocator, &stdout, &stderr, args.max_output_bytes);
|
||||
|
||||
return .{
|
||||
.stdout = try stdout.toOwnedSlice(args.allocator),
|
||||
.stderr = try stderr.toOwnedSlice(args.allocator),
|
||||
.stdout = try stdout.toOwnedSlice(allocator),
|
||||
.stderr = try stderr.toOwnedSlice(allocator),
|
||||
.term = try child.wait(),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@ pub fn main() !void {
|
|||
var read_buf: [1024]u8 = undefined;
|
||||
var write_buf: [1024]u8 = undefined;
|
||||
|
||||
const in_file = try std.fs.cwd().openFile(args[1], .{});
|
||||
defer in_file.close();
|
||||
const in_file = try std.Io.Dir.cwd().openFile(io, args[1], .{});
|
||||
defer in_file.close(io);
|
||||
|
||||
const out_file: std.Io.File = .stdout();
|
||||
|
||||
var in_fr = in_file.reader(io, &read_buf);
|
||||
var out_fw = out_file.writer(&write_buf);
|
||||
var out_fw = out_file.writer(io, &write_buf);
|
||||
|
||||
const w = &out_fw.interface;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const std = @import("std");
|
||||
const Io = std.Io;
|
||||
|
||||
pub fn main() !void {
|
||||
// make sure safety checks are enabled even in release modes
|
||||
|
|
@ -20,7 +21,7 @@ pub fn main() !void {
|
|||
};
|
||||
defer if (needs_free) gpa.free(child_path);
|
||||
|
||||
var threaded: std.Io.Threaded = .init(gpa);
|
||||
var threaded: Io.Threaded = .init(gpa);
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
|
|
@ -31,7 +32,7 @@ pub fn main() !void {
|
|||
try child.spawn();
|
||||
const child_stdin = child.stdin.?;
|
||||
try child_stdin.writeAll("hello from stdin"); // verified in child
|
||||
child_stdin.close();
|
||||
child_stdin.close(io);
|
||||
child.stdin = null;
|
||||
|
||||
const hello_stdout = "hello from stdout";
|
||||
|
|
@ -39,17 +40,17 @@ pub fn main() !void {
|
|||
var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
|
||||
const n = try stdout_reader.interface.readSliceShort(&buf);
|
||||
if (!std.mem.eql(u8, buf[0..n], hello_stdout)) {
|
||||
testError("child stdout: '{s}'; want '{s}'", .{ buf[0..n], hello_stdout });
|
||||
testError(io, "child stdout: '{s}'; want '{s}'", .{ buf[0..n], hello_stdout });
|
||||
}
|
||||
|
||||
switch (try child.wait()) {
|
||||
.Exited => |code| {
|
||||
const child_ok_code = 42; // set by child if no test errors
|
||||
if (code != child_ok_code) {
|
||||
testError("child exit code: {d}; want {d}", .{ code, child_ok_code });
|
||||
testError(io, "child exit code: {d}; want {d}", .{ code, child_ok_code });
|
||||
}
|
||||
},
|
||||
else => |term| testError("abnormal child exit: {}", .{term}),
|
||||
else => |term| testError(io, "abnormal child exit: {}", .{term}),
|
||||
}
|
||||
if (parent_test_error) return error.ParentTestError;
|
||||
|
||||
|
|
@ -61,8 +62,8 @@ pub fn main() !void {
|
|||
|
||||
var parent_test_error = false;
|
||||
|
||||
fn testError(comptime fmt: []const u8, args: anytype) void {
|
||||
var stderr_writer = std.Io.File.stderr().writer(&.{});
|
||||
fn testError(io: Io, comptime fmt: []const u8, args: anytype) void {
|
||||
var stderr_writer = Io.File.stderr().writer(io, &.{});
|
||||
const stderr = &stderr_writer.interface;
|
||||
stderr.print("PARENT TEST ERROR: ", .{}) catch {};
|
||||
stderr.print(fmt, args) catch {};
|
||||
|
|
|
|||
|
|
@ -9,8 +9,11 @@ pub fn main() !void {
|
|||
const actual_path = args[1];
|
||||
const expected_path = args[2];
|
||||
|
||||
const actual = try std.fs.cwd().readFileAlloc(actual_path, arena, .limited(1024 * 1024));
|
||||
const expected = try std.fs.cwd().readFileAlloc(expected_path, arena, .limited(1024 * 1024));
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
|
||||
const actual = try std.Io.Dir.cwd().readFileAlloc(io, actual_path, arena, .limited(1024 * 1024));
|
||||
const expected = try std.Io.Dir.cwd().readFileAlloc(io, expected_path, arena, .limited(1024 * 1024));
|
||||
|
||||
// The actual output starts with a comment which we should strip out before comparing.
|
||||
const comment_str = "/* This file was generated by ConfigHeader using the Zig Build System. */\n";
|
||||
|
|
|
|||
|
|
@ -59,13 +59,15 @@ pub fn build(b: *std.Build) void {
|
|||
|
||||
// Absolute path:
|
||||
const abs_path = setup_abspath: {
|
||||
// TODO this is a bad pattern, don't do this
|
||||
const io = b.graph.io;
|
||||
const temp_dir = b.makeTempPath();
|
||||
|
||||
var dir = std.fs.cwd().openDir(temp_dir, .{}) catch @panic("failed to open temp dir");
|
||||
defer dir.close();
|
||||
var dir = std.Io.Dir.cwd().openDir(io, temp_dir, .{}) catch @panic("failed to open temp dir");
|
||||
defer dir.close(io);
|
||||
|
||||
var file = dir.createFile("foo.txt", .{}) catch @panic("failed to create file");
|
||||
file.close();
|
||||
var file = dir.createFile(io, "foo.txt", .{}) catch @panic("failed to create file");
|
||||
file.close(io);
|
||||
|
||||
break :setup_abspath std.Build.LazyPath{ .cwd_relative = temp_dir };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,8 +34,11 @@ fn run(allocator: std.mem.Allocator) !void {
|
|||
return error.BadUsage;
|
||||
};
|
||||
|
||||
var dir = try std.fs.cwd().openDir(dir_path, .{});
|
||||
defer dir.close();
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
|
||||
_ = try dir.statFile(relpath);
|
||||
var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
|
||||
defer dir.close(io);
|
||||
|
||||
_ = try dir.statFile(io, relpath);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,14 +26,17 @@ fn run(allocator: std.mem.Allocator) !void {
|
|||
return error.BadUsage;
|
||||
};
|
||||
|
||||
const dir_path = std.fs.path.dirname(path) orelse unreachable;
|
||||
const basename = std.fs.path.basename(path);
|
||||
const dir_path = std.Io.Dir.path.dirname(path) orelse unreachable;
|
||||
const basename = std.Io.Dir.path.basename(path);
|
||||
|
||||
var dir = try std.fs.cwd().openDir(dir_path, .{});
|
||||
defer dir.close();
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
|
||||
_ = dir.statFile(basename) catch {
|
||||
var file = try dir.createFile(basename, .{});
|
||||
file.close();
|
||||
var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
|
||||
defer dir.close(io);
|
||||
|
||||
_ = dir.statFile(io, basename) catch {
|
||||
var file = try dir.createFile(io, basename, .{});
|
||||
file.close(io);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,11 @@ pub fn main() !void {
|
|||
const args = try std.process.argsAlloc(arena);
|
||||
if (args.len != 3) return error.BadUsage; // usage: 'check_differ <path a> <path b>'
|
||||
|
||||
const contents_1 = try std.fs.cwd().readFileAlloc(args[1], arena, .limited(1024 * 1024 * 64)); // 64 MiB ought to be plenty
|
||||
const contents_2 = try std.fs.cwd().readFileAlloc(args[2], arena, .limited(1024 * 1024 * 64)); // 64 MiB ought to be plenty
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
|
||||
const contents_1 = try std.Io.Dir.cwd().readFileAlloc(io, args[1], arena, .limited(1024 * 1024 * 64)); // 64 MiB ought to be plenty
|
||||
const contents_2 = try std.Io.Dir.cwd().readFileAlloc(io, args[2], arena, .limited(1024 * 1024 * 64)); // 64 MiB ought to be plenty
|
||||
|
||||
if (std.mem.eql(u8, contents_1, contents_2)) {
|
||||
return error.FilesMatch;
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: [*]const u8) c_int;
|
|||
|
||||
// PR #17034 - fstat moved between libc_nonshared and libc
|
||||
fn checkStat() !void {
|
||||
const cwdFd = std.fs.cwd().fd;
|
||||
const cwd_fd = std.Io.Dir.cwd().handle;
|
||||
|
||||
var buf: [256]u8 = @splat(0);
|
||||
var result = fstatat(cwdFd, "a_file_that_definitely_does_not_exist", &buf, 0);
|
||||
var result = fstatat(cwd_fd, "a_file_that_definitely_does_not_exist", &buf, 0);
|
||||
assert(result == -1);
|
||||
assert(std.posix.errno(result) == .NOENT);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,11 @@ pub fn main() !void {
|
|||
var arg_it = try std.process.argsWithAllocator(arena);
|
||||
_ = arg_it.next();
|
||||
|
||||
const cwd = std.fs.cwd();
|
||||
const cwd_realpath = try cwd.realpathAlloc(arena, ".");
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
|
||||
const cwd = std.Io.Dir.cwd();
|
||||
const cwd_realpath = try cwd.realPathAlloc(io, arena, ".");
|
||||
|
||||
while (arg_it.next()) |file_path| {
|
||||
if (file_path.len > 0 and file_path[0] == '!') {
|
||||
|
|
@ -20,7 +23,7 @@ pub fn main() !void {
|
|||
"exclusive file check '{s}{c}{s}' failed",
|
||||
.{ cwd_realpath, std.fs.path.sep, file_path[1..] },
|
||||
);
|
||||
if (std.fs.cwd().statFile(file_path[1..])) |_| {
|
||||
if (cwd.statFile(io, file_path[1..])) |_| {
|
||||
return error.FileFound;
|
||||
} else |err| switch (err) {
|
||||
error.FileNotFound => {},
|
||||
|
|
@ -31,7 +34,7 @@ pub fn main() !void {
|
|||
"inclusive file check '{s}{c}{s}' failed",
|
||||
.{ cwd_realpath, std.fs.path.sep, file_path },
|
||||
);
|
||||
_ = try std.fs.cwd().statFile(file_path);
|
||||
_ = try cwd.statFile(io, file_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ pub fn main() !void {
|
|||
const io = threaded.io();
|
||||
|
||||
const cache_dir_path = args.next() orelse @panic("expected cache directory path argument");
|
||||
var cache_dir = try std.fs.cwd().openDir(cache_dir_path, .{});
|
||||
defer cache_dir.close();
|
||||
var cache_dir = try std.Io.Dir.cwd().openDir(io, cache_dir_path, .{});
|
||||
defer cache_dir.close(io);
|
||||
|
||||
abi.fuzzer_init(.fromSlice(cache_dir_path));
|
||||
abi.fuzzer_init_test(testOne, .fromSlice("test"));
|
||||
|
|
@ -30,8 +30,8 @@ pub fn main() !void {
|
|||
|
||||
const pc_digest = abi.fuzzer_coverage().id;
|
||||
const coverage_file_path = "v/" ++ std.fmt.hex(pc_digest);
|
||||
const coverage_file = try cache_dir.openFile(coverage_file_path, .{});
|
||||
defer coverage_file.close();
|
||||
const coverage_file = try cache_dir.openFile(io, coverage_file_path, .{});
|
||||
defer coverage_file.close(io);
|
||||
|
||||
var read_buf: [@sizeOf(abi.SeenPcsHeader)]u8 = undefined;
|
||||
var r = coverage_file.reader(io, &read_buf);
|
||||
|
|
@ -42,6 +42,6 @@ pub fn main() !void {
|
|||
const expected_len = @sizeOf(abi.SeenPcsHeader) +
|
||||
try std.math.divCeil(usize, pcs_header.pcs_len, @bitSizeOf(usize)) * @sizeOf(usize) +
|
||||
pcs_header.pcs_len * @sizeOf(usize);
|
||||
if (try coverage_file.getEndPos() != expected_len)
|
||||
if (try coverage_file.length(io) != expected_len)
|
||||
return error.WrongEnd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
// Test relative paths through POSIX APIS. These tests have to change the cwd, so
|
||||
// they shouldn't be Zig unit tests.
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const std = @import("std");
|
||||
const Io = std.Io;
|
||||
|
||||
pub fn main() !void {
|
||||
if (builtin.target.os.tag == .wasi) return; // Can link, but can't change into tmpDir
|
||||
|
||||
|
|
@ -11,6 +13,11 @@ pub fn main() !void {
|
|||
const a = Allocator.allocator();
|
||||
defer std.debug.assert(Allocator.deinit() == .ok);
|
||||
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
|
||||
// TODO this API isn't supposed to be used outside of unit testing. make it compilation error if used
|
||||
// outside of unit testing.
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
|
|
@ -18,7 +25,7 @@ pub fn main() !void {
|
|||
try tmp.dir.setAsCwd();
|
||||
|
||||
try test_symlink(a, tmp);
|
||||
try test_link(tmp);
|
||||
try test_link(io, tmp);
|
||||
}
|
||||
|
||||
fn test_symlink(a: std.mem.Allocator, tmp: std.testing.TmpDir) !void {
|
||||
|
|
@ -65,7 +72,7 @@ fn getLinkInfo(fd: std.posix.fd_t) !struct { std.posix.ino_t, std.posix.nlink_t
|
|||
return .{ st.ino, st.nlink };
|
||||
}
|
||||
|
||||
fn test_link(tmp: std.testing.TmpDir) !void {
|
||||
fn test_link(io: Io, tmp: std.testing.TmpDir) !void {
|
||||
switch (builtin.target.os.tag) {
|
||||
.linux, .illumos => {},
|
||||
else => return,
|
||||
|
|
@ -74,17 +81,17 @@ fn test_link(tmp: std.testing.TmpDir) !void {
|
|||
const target_name = "link-target";
|
||||
const link_name = "newlink";
|
||||
|
||||
try tmp.dir.writeFile(.{ .sub_path = target_name, .data = "example" });
|
||||
try tmp.dir.writeFile(io, .{ .sub_path = target_name, .data = "example" });
|
||||
|
||||
// Test 1: create the relative link from inside tmp
|
||||
try std.posix.link(target_name, link_name);
|
||||
|
||||
// Verify
|
||||
const efd = try tmp.dir.openFile(target_name, .{});
|
||||
defer efd.close();
|
||||
const efd = try tmp.dir.openFile(io, target_name, .{});
|
||||
defer efd.close(io);
|
||||
|
||||
const nfd = try tmp.dir.openFile(link_name, .{});
|
||||
defer nfd.close();
|
||||
const nfd = try tmp.dir.openFile(io, link_name, .{});
|
||||
defer nfd.close(io);
|
||||
|
||||
{
|
||||
const eino, _ = try getLinkInfo(efd.handle);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ pub fn main() !void {
|
|||
if (args.len != 2) return error.BadUsage;
|
||||
const path = args[1];
|
||||
|
||||
std.fs.cwd().access(path, .{}) catch return error.AccessFailed;
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
|
||||
std.Io.Dir.cwd().access(io, path, .{}) catch return error.AccessFailed;
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
var args = try std.process.argsWithAllocator(std.heap.page_allocator);
|
||||
_ = args.skip();
|
||||
const filename = args.next().?;
|
||||
const file = try std.fs.cwd().createFile(filename, .{});
|
||||
defer file.close();
|
||||
try file.writeAll(filename);
|
||||
const file = try std.Io.Dir.cwd().createFile(io, filename, .{});
|
||||
defer file.close(io);
|
||||
try file.writeAll(io, filename);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
var args = try std.process.argsWithAllocator(std.heap.page_allocator);
|
||||
_ = args.skip();
|
||||
const dir_name = args.next().?;
|
||||
const dir = try std.fs.cwd().openDir(if (std.mem.startsWith(u8, dir_name, "--dir="))
|
||||
const dir = try std.Io.Dir.cwd().openDir(io, if (std.mem.startsWith(u8, dir_name, "--dir="))
|
||||
dir_name["--dir=".len..]
|
||||
else
|
||||
dir_name, .{});
|
||||
|
|
|
|||
|
|
@ -14,5 +14,9 @@ pub fn main() anyerror!void {
|
|||
// If `exe_path` is relative to our cwd, we need to convert it to be relative to the dirname of `symlink_path`.
|
||||
const exe_rel_path = try std.fs.path.relative(allocator, std.fs.path.dirname(symlink_path) orelse ".", exe_path);
|
||||
defer allocator.free(exe_rel_path);
|
||||
try std.fs.cwd().symLink(exe_rel_path, symlink_path, .{});
|
||||
|
||||
var threaded: std.Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
|
||||
try std.Io.Dir.cwd().symLink(io, exe_rel_path, symlink_path, .{});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
||||
defer std.debug.assert(gpa.deinit() == .ok);
|
||||
const allocator = gpa.allocator();
|
||||
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
||||
defer if (debug_allocator.deinit() == .leak) @panic("found memory leaks");
|
||||
const gpa = debug_allocator.allocator();
|
||||
|
||||
const self_path = try std.fs.selfExePathAlloc(allocator);
|
||||
defer allocator.free(self_path);
|
||||
var threaded: std.Io.Threaded = .init(gpa);
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
const self_path = try std.fs.selfExePathAlloc(gpa);
|
||||
defer gpa.free(self_path);
|
||||
|
||||
var self_exe = try std.fs.openSelfExe(.{});
|
||||
defer self_exe.close();
|
||||
defer self_exe.close(io);
|
||||
var buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
const self_exe_path = try std.os.getFdPath(self_exe.handle, &buf);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub fn main() !void {
|
|||
const exe = args[0];
|
||||
var catted_anything = false;
|
||||
var stdout_buffer: [4096]u8 = undefined;
|
||||
var stdout_writer = Io.File.stdout().writerStreaming(&stdout_buffer);
|
||||
var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
|
||||
const stdout = &stdout_writer.interface;
|
||||
var stdin_reader = Io.File.stdin().readerStreaming(io, &.{});
|
||||
|
||||
|
|
@ -32,8 +32,8 @@ pub fn main() !void {
|
|||
} else if (mem.startsWith(u8, arg, "-")) {
|
||||
return usage(exe);
|
||||
} else {
|
||||
const file = cwd.openFile(arg, .{}) catch |err| fatal("unable to open file: {t}\n", .{err});
|
||||
defer file.close();
|
||||
const file = cwd.openFile(io, arg, .{}) catch |err| fatal("unable to open file: {t}\n", .{err});
|
||||
defer file.close(io);
|
||||
|
||||
catted_anything = true;
|
||||
var file_reader = file.reader(io, &.{});
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
const std = @import("std");
|
||||
const Io = std.Io;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const windows = std.os.windows;
|
||||
const utf16Literal = std.unicode.utf8ToUtf16LeStringLiteral;
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
||||
defer if (gpa.deinit() == .leak) @panic("found memory leaks");
|
||||
const allocator = gpa.allocator();
|
||||
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
||||
defer if (debug_allocator.deinit() == .leak) @panic("found memory leaks");
|
||||
const gpa = debug_allocator.allocator();
|
||||
|
||||
var it = try std.process.argsWithAllocator(allocator);
|
||||
var threaded: std.Io.Threaded = .init(gpa);
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
var it = try std.process.argsWithAllocator(gpa);
|
||||
defer it.deinit();
|
||||
_ = it.next() orelse unreachable; // skip binary name
|
||||
const hello_exe_cache_path = it.next() orelse unreachable;
|
||||
|
|
@ -17,14 +22,14 @@ pub fn main() anyerror!void {
|
|||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
const tmp_absolute_path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(tmp_absolute_path);
|
||||
const tmp_absolute_path_w = try std.unicode.utf8ToUtf16LeAllocZ(allocator, tmp_absolute_path);
|
||||
defer allocator.free(tmp_absolute_path_w);
|
||||
const cwd_absolute_path = try std.fs.cwd().realpathAlloc(allocator, ".");
|
||||
defer allocator.free(cwd_absolute_path);
|
||||
const tmp_relative_path = try std.fs.path.relative(allocator, cwd_absolute_path, tmp_absolute_path);
|
||||
defer allocator.free(tmp_relative_path);
|
||||
const tmp_absolute_path = try tmp.dir.realpathAlloc(gpa, ".");
|
||||
defer gpa.free(tmp_absolute_path);
|
||||
const tmp_absolute_path_w = try std.unicode.utf8ToUtf16LeAllocZ(gpa, tmp_absolute_path);
|
||||
defer gpa.free(tmp_absolute_path_w);
|
||||
const cwd_absolute_path = try Io.Dir.cwd().realpathAlloc(gpa, ".");
|
||||
defer gpa.free(cwd_absolute_path);
|
||||
const tmp_relative_path = try std.fs.path.relative(gpa, cwd_absolute_path, tmp_absolute_path);
|
||||
defer gpa.free(tmp_relative_path);
|
||||
|
||||
// Clear PATH
|
||||
std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
|
||||
|
|
@ -39,10 +44,10 @@ pub fn main() anyerror!void {
|
|||
) == windows.TRUE);
|
||||
|
||||
// No PATH, so it should fail to find anything not in the cwd
|
||||
try testExecError(error.FileNotFound, allocator, "something_missing");
|
||||
try testExecError(error.FileNotFound, gpa, "something_missing");
|
||||
|
||||
// make sure we don't get error.BadPath traversing out of cwd with a relative path
|
||||
try testExecError(error.FileNotFound, allocator, "..\\.\\.\\.\\\\..\\more_missing");
|
||||
try testExecError(error.FileNotFound, gpa, "..\\.\\.\\.\\\\..\\more_missing");
|
||||
|
||||
std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
|
||||
utf16Literal("PATH"),
|
||||
|
|
@ -50,14 +55,14 @@ pub fn main() anyerror!void {
|
|||
) == windows.TRUE);
|
||||
|
||||
// Move hello.exe into the tmp dir which is now added to the path
|
||||
try std.fs.cwd().copyFile(hello_exe_cache_path, tmp.dir, "hello.exe", .{});
|
||||
try Io.Dir.cwd().copyFile(hello_exe_cache_path, tmp.dir, "hello.exe", .{});
|
||||
|
||||
// with extension should find the .exe (case insensitive)
|
||||
try testExec(allocator, "HeLLo.exe", "hello from exe\n");
|
||||
try testExec(gpa, "HeLLo.exe", "hello from exe\n");
|
||||
// without extension should find the .exe (case insensitive)
|
||||
try testExec(allocator, "heLLo", "hello from exe\n");
|
||||
try testExec(gpa, "heLLo", "hello from exe\n");
|
||||
// with invalid cwd
|
||||
try std.testing.expectError(error.FileNotFound, testExecWithCwd(allocator, "hello.exe", "missing_dir", ""));
|
||||
try std.testing.expectError(error.FileNotFound, testExecWithCwd(gpa, io, "hello.exe", "missing_dir", ""));
|
||||
|
||||
// now add a .bat
|
||||
try tmp.dir.writeFile(.{ .sub_path = "hello.bat", .data = "@echo hello from bat" });
|
||||
|
|
@ -65,33 +70,33 @@ pub fn main() anyerror!void {
|
|||
try tmp.dir.writeFile(.{ .sub_path = "hello.cmd", .data = "@echo hello from cmd" });
|
||||
|
||||
// with extension should find the .bat (case insensitive)
|
||||
try testExec(allocator, "heLLo.bat", "hello from bat\r\n");
|
||||
try testExec(gpa, "heLLo.bat", "hello from bat\r\n");
|
||||
// with extension should find the .cmd (case insensitive)
|
||||
try testExec(allocator, "heLLo.cmd", "hello from cmd\r\n");
|
||||
try testExec(gpa, "heLLo.cmd", "hello from cmd\r\n");
|
||||
// without extension should find the .exe (since its first in PATHEXT)
|
||||
try testExec(allocator, "heLLo", "hello from exe\n");
|
||||
try testExec(gpa, "heLLo", "hello from exe\n");
|
||||
|
||||
// now rename the exe to not have an extension
|
||||
try renameExe(tmp.dir, "hello.exe", "hello");
|
||||
|
||||
// with extension should now fail
|
||||
try testExecError(error.FileNotFound, allocator, "hello.exe");
|
||||
try testExecError(error.FileNotFound, gpa, "hello.exe");
|
||||
// without extension should succeed (case insensitive)
|
||||
try testExec(allocator, "heLLo", "hello from exe\n");
|
||||
try testExec(gpa, "heLLo", "hello from exe\n");
|
||||
|
||||
try tmp.dir.makeDir("something");
|
||||
try renameExe(tmp.dir, "hello", "something/hello.exe");
|
||||
|
||||
const relative_path_no_ext = try std.fs.path.join(allocator, &.{ tmp_relative_path, "something/hello" });
|
||||
defer allocator.free(relative_path_no_ext);
|
||||
const relative_path_no_ext = try std.fs.path.join(gpa, &.{ tmp_relative_path, "something/hello" });
|
||||
defer gpa.free(relative_path_no_ext);
|
||||
|
||||
// Giving a full relative path to something/hello should work
|
||||
try testExec(allocator, relative_path_no_ext, "hello from exe\n");
|
||||
try testExec(gpa, relative_path_no_ext, "hello from exe\n");
|
||||
// But commands with path separators get excluded from PATH searching, so this will fail
|
||||
try testExecError(error.FileNotFound, allocator, "something/hello");
|
||||
try testExecError(error.FileNotFound, gpa, "something/hello");
|
||||
|
||||
// Now that .BAT is the first PATHEXT that should be found, this should succeed
|
||||
try testExec(allocator, "heLLo", "hello from bat\r\n");
|
||||
try testExec(gpa, "heLLo", "hello from bat\r\n");
|
||||
|
||||
// Add a hello.exe that is not a valid executable
|
||||
try tmp.dir.writeFile(.{ .sub_path = "hello.exe", .data = "invalid" });
|
||||
|
|
@ -100,18 +105,18 @@ pub fn main() anyerror!void {
|
|||
// case for .EXE extensions, where if they ever try to get executed but they are
|
||||
// invalid, that gets treated as a fatal error wherever they are found and InvalidExe
|
||||
// is returned immediately.
|
||||
try testExecError(error.InvalidExe, allocator, "hello.exe");
|
||||
try testExecError(error.InvalidExe, gpa, "hello.exe");
|
||||
// Same thing applies to the command with no extension--even though there is a
|
||||
// hello.bat that could be executed, it should stop after it tries executing
|
||||
// hello.exe and getting InvalidExe.
|
||||
try testExecError(error.InvalidExe, allocator, "hello");
|
||||
try testExecError(error.InvalidExe, gpa, "hello");
|
||||
|
||||
// If we now rename hello.exe to have no extension, it will behave differently
|
||||
try renameExe(tmp.dir, "hello.exe", "hello");
|
||||
|
||||
// Now, trying to execute it without an extension should treat InvalidExe as recoverable
|
||||
// and skip over it and find hello.bat and execute that
|
||||
try testExec(allocator, "hello", "hello from bat\r\n");
|
||||
try testExec(gpa, "hello", "hello from bat\r\n");
|
||||
|
||||
// If we rename the invalid exe to something else
|
||||
try renameExe(tmp.dir, "hello", "goodbye");
|
||||
|
|
@ -119,13 +124,13 @@ pub fn main() anyerror!void {
|
|||
// since that is what the original error will be after searching for 'goodbye'
|
||||
// in the cwd. It will try to execute 'goodbye' from the PATH but the InvalidExe error
|
||||
// should be ignored in this case.
|
||||
try testExecError(error.FileNotFound, allocator, "goodbye");
|
||||
try testExecError(error.FileNotFound, gpa, "goodbye");
|
||||
|
||||
// Now let's set the tmp dir as the cwd and set the path only include the "something" sub dir
|
||||
try tmp.dir.setAsCwd();
|
||||
defer tmp.parent_dir.setAsCwd() catch {};
|
||||
const something_subdir_abs_path = try std.mem.concatWithSentinel(allocator, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);
|
||||
defer allocator.free(something_subdir_abs_path);
|
||||
const something_subdir_abs_path = try std.mem.concatWithSentinel(gpa, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);
|
||||
defer gpa.free(something_subdir_abs_path);
|
||||
|
||||
std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
|
||||
utf16Literal("PATH"),
|
||||
|
|
@ -134,37 +139,37 @@ pub fn main() anyerror!void {
|
|||
|
||||
// Now trying to execute goodbye should give error.InvalidExe since it's the original
|
||||
// error that we got when trying within the cwd
|
||||
try testExecError(error.InvalidExe, allocator, "goodbye");
|
||||
try testExecError(error.InvalidExe, gpa, "goodbye");
|
||||
|
||||
// hello should still find the .bat
|
||||
try testExec(allocator, "hello", "hello from bat\r\n");
|
||||
try testExec(gpa, "hello", "hello from bat\r\n");
|
||||
|
||||
// If we rename something/hello.exe to something/goodbye.exe
|
||||
try renameExe(tmp.dir, "something/hello.exe", "something/goodbye.exe");
|
||||
// And try to execute goodbye, then the one in something should be found
|
||||
// since the one in cwd is an invalid executable
|
||||
try testExec(allocator, "goodbye", "hello from exe\n");
|
||||
try testExec(gpa, "goodbye", "hello from exe\n");
|
||||
|
||||
// If we use an absolute path to execute the invalid goodbye
|
||||
const goodbye_abs_path = try std.mem.join(allocator, "\\", &.{ tmp_absolute_path, "goodbye" });
|
||||
defer allocator.free(goodbye_abs_path);
|
||||
const goodbye_abs_path = try std.mem.join(gpa, "\\", &.{ tmp_absolute_path, "goodbye" });
|
||||
defer gpa.free(goodbye_abs_path);
|
||||
// then the PATH should not be searched and we should get InvalidExe
|
||||
try testExecError(error.InvalidExe, allocator, goodbye_abs_path);
|
||||
try testExecError(error.InvalidExe, gpa, goodbye_abs_path);
|
||||
|
||||
// If we try to exec but provide a cwd that is an absolute path, the PATH
|
||||
// should still be searched and the goodbye.exe in something should be found.
|
||||
try testExecWithCwd(allocator, "goodbye", tmp_absolute_path, "hello from exe\n");
|
||||
try testExecWithCwd(gpa, "goodbye", tmp_absolute_path, "hello from exe\n");
|
||||
|
||||
// introduce some extra path separators into the path which is dealt with inside the spawn call.
|
||||
const denormed_something_subdir_size = std.mem.replacementSize(u16, something_subdir_abs_path, utf16Literal("\\"), utf16Literal("\\\\\\\\"));
|
||||
|
||||
const denormed_something_subdir_abs_path = try allocator.allocSentinel(u16, denormed_something_subdir_size, 0);
|
||||
defer allocator.free(denormed_something_subdir_abs_path);
|
||||
const denormed_something_subdir_abs_path = try gpa.allocSentinel(u16, denormed_something_subdir_size, 0);
|
||||
defer gpa.free(denormed_something_subdir_abs_path);
|
||||
|
||||
_ = std.mem.replace(u16, something_subdir_abs_path, utf16Literal("\\"), utf16Literal("\\\\\\\\"), denormed_something_subdir_abs_path);
|
||||
|
||||
const denormed_something_subdir_wtf8 = try std.unicode.wtf16LeToWtf8Alloc(allocator, denormed_something_subdir_abs_path);
|
||||
defer allocator.free(denormed_something_subdir_wtf8);
|
||||
const denormed_something_subdir_wtf8 = try std.unicode.wtf16LeToWtf8Alloc(gpa, denormed_something_subdir_abs_path);
|
||||
defer gpa.free(denormed_something_subdir_wtf8);
|
||||
|
||||
// clear the path to ensure that the match comes from the cwd
|
||||
std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
|
||||
|
|
@ -172,18 +177,18 @@ pub fn main() anyerror!void {
|
|||
null,
|
||||
) == windows.TRUE);
|
||||
|
||||
try testExecWithCwd(allocator, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n");
|
||||
try testExecWithCwd(gpa, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n");
|
||||
|
||||
// normalization should also work if the non-normalized path is found in the PATH var.
|
||||
std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
|
||||
utf16Literal("PATH"),
|
||||
denormed_something_subdir_abs_path,
|
||||
) == windows.TRUE);
|
||||
try testExec(allocator, "goodbye", "hello from exe\n");
|
||||
try testExec(gpa, "goodbye", "hello from exe\n");
|
||||
|
||||
// now make sure we can launch executables "outside" of the cwd
|
||||
var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{});
|
||||
defer subdir_cwd.close();
|
||||
defer subdir_cwd.close(io);
|
||||
|
||||
try renameExe(tmp.dir, "something/goodbye.exe", "hello.exe");
|
||||
try subdir_cwd.setAsCwd();
|
||||
|
|
@ -195,25 +200,24 @@ pub fn main() anyerror!void {
|
|||
) == windows.TRUE);
|
||||
|
||||
// while we're at it make sure non-windows separators work fine
|
||||
try testExec(allocator, "../hello", "hello from exe\n");
|
||||
try testExec(gpa, "../hello", "hello from exe\n");
|
||||
}
|
||||
|
||||
fn testExecError(err: anyerror, allocator: std.mem.Allocator, command: []const u8) !void {
|
||||
return std.testing.expectError(err, testExec(allocator, command, ""));
|
||||
fn testExecError(err: anyerror, gpa: Allocator, command: []const u8) !void {
|
||||
return std.testing.expectError(err, testExec(gpa, command, ""));
|
||||
}
|
||||
|
||||
fn testExec(allocator: std.mem.Allocator, command: []const u8, expected_stdout: []const u8) !void {
|
||||
return testExecWithCwd(allocator, command, null, expected_stdout);
|
||||
fn testExec(gpa: Allocator, command: []const u8, expected_stdout: []const u8) !void {
|
||||
return testExecWithCwd(gpa, command, null, expected_stdout);
|
||||
}
|
||||
|
||||
fn testExecWithCwd(allocator: std.mem.Allocator, command: []const u8, cwd: ?[]const u8, expected_stdout: []const u8) !void {
|
||||
const result = try std.process.Child.run(.{
|
||||
.allocator = allocator,
|
||||
fn testExecWithCwd(gpa: Allocator, io: Io, command: []const u8, cwd: ?[]const u8, expected_stdout: []const u8) !void {
|
||||
const result = try std.process.Child.run(gpa, io, .{
|
||||
.argv = &[_][]const u8{command},
|
||||
.cwd = cwd,
|
||||
});
|
||||
defer allocator.free(result.stdout);
|
||||
defer allocator.free(result.stderr);
|
||||
defer gpa.free(result.stdout);
|
||||
defer gpa.free(result.stderr);
|
||||
|
||||
try std.testing.expectEqualStrings("", result.stderr);
|
||||
try std.testing.expectEqualStrings(expected_stdout, result.stdout);
|
||||
|
|
|
|||
|
|
@ -2024,6 +2024,7 @@ pub fn addLinkTests(
|
|||
pub fn addCliTests(b: *std.Build) *Step {
|
||||
const step = b.step("test-cli", "Test the command line interface");
|
||||
const s = std.fs.path.sep_str;
|
||||
const io = b.graph.io;
|
||||
|
||||
{
|
||||
// Test `zig init`.
|
||||
|
|
@ -2132,13 +2133,13 @@ pub fn addCliTests(b: *std.Build) *Step {
|
|||
const tmp_path = b.makeTempPath();
|
||||
const unformatted_code = " // no reason for indent";
|
||||
|
||||
var dir = std.fs.cwd().openDir(tmp_path, .{}) catch @panic("unhandled");
|
||||
defer dir.close();
|
||||
var dir = std.Io.Dir.cwd().openDir(io, tmp_path, .{}) catch @panic("unhandled");
|
||||
defer dir.close(io);
|
||||
dir.writeFile(.{ .sub_path = "fmt1.zig", .data = unformatted_code }) catch @panic("unhandled");
|
||||
dir.writeFile(.{ .sub_path = "fmt2.zig", .data = unformatted_code }) catch @panic("unhandled");
|
||||
dir.makeDir("subdir") catch @panic("unhandled");
|
||||
var subdir = dir.openDir("subdir", .{}) catch @panic("unhandled");
|
||||
defer subdir.close();
|
||||
var subdir = dir.openDir(io, "subdir", .{}) catch @panic("unhandled");
|
||||
defer subdir.close(io);
|
||||
subdir.writeFile(.{ .sub_path = "fmt3.zig", .data = unformatted_code }) catch @panic("unhandled");
|
||||
|
||||
// Test zig fmt affecting only the appropriate files.
|
||||
|
|
@ -2634,7 +2635,7 @@ pub fn addCases(
|
|||
var cases = @import("src/Cases.zig").init(gpa, arena);
|
||||
|
||||
var dir = try b.build_root.handle.openDir(io, "test/cases", .{ .iterate = true });
|
||||
defer dir.close();
|
||||
defer dir.close(io);
|
||||
|
||||
cases.addFromDir(dir, b);
|
||||
try @import("cases.zig").addCases(&cases, build_options, b);
|
||||
|
|
@ -2680,6 +2681,8 @@ pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step
|
|||
}
|
||||
|
||||
pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {
|
||||
const io = b.graph.io;
|
||||
|
||||
const incr_check = b.addExecutable(.{
|
||||
.name = "incr-check",
|
||||
.root_module = b.createModule(.{
|
||||
|
|
@ -2689,11 +2692,11 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {
|
|||
}),
|
||||
});
|
||||
|
||||
var dir = try b.build_root.handle.openDir("test/incremental", .{ .iterate = true });
|
||||
defer dir.close();
|
||||
var dir = try b.build_root.handle.openDir(io, "test/incremental", .{ .iterate = true });
|
||||
defer dir.close(io);
|
||||
|
||||
var it = try dir.walk(b.graph.arena);
|
||||
while (try it.next()) |entry| {
|
||||
while (try it.next(io)) |entry| {
|
||||
if (entry.kind != .file) continue;
|
||||
|
||||
const run = b.addRunArtifact(incr_check);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue