authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-08 18:24:52-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:08-08:00
log9e3bda5efffb12dd6491b4f7c92ccc89b9043c64
treeccb1af8488c729172ca9727ccbbf8dd04348b546
parenta91c6dc71d42ea59ec53ce4e0ae83e4970731313

tests: close() -> close(io)


21 files changed, 187 insertions(+), 139 deletions(-)

lib/std/Io/File/Writer.zig+4-2
...@@ -56,8 +56,9 @@ pub const WriteFileError = error{...@@ -56,8 +56,9 @@ pub const WriteFileError = error{
5656
57pub const SeekError = Io.File.SeekError;57pub const SeekError = Io.File.SeekError;
5858
59pub fn init(file: File, buffer: []u8) Writer {59pub fn init(file: File, io: Io, buffer: []u8) Writer {
60 return .{60 return .{
61 .io = io,
61 .file = file,62 .file = file,
62 .interface = initInterface(buffer),63 .interface = initInterface(buffer),
63 .mode = .positional,64 .mode = .positional,
...@@ -67,8 +68,9 @@ pub fn init(file: File, buffer: []u8) Writer {...@@ -67,8 +68,9 @@ pub fn init(file: File, buffer: []u8) Writer {
67/// Positional is more threadsafe, since the global seek position is not68/// Positional is more threadsafe, since the global seek position is not
68/// affected, but when such syscalls are not available, preemptively69/// affected, but when such syscalls are not available, preemptively
69/// initializing in streaming mode will skip a failed syscall.70/// initializing in streaming mode will skip a failed syscall.
70pub fn initStreaming(file: File, buffer: []u8) Writer {71pub fn initStreaming(file: File, io: Io, buffer: []u8) Writer {
71 return .{72 return .{
73 .io = io,
72 .file = file,74 .file = file,
73 .interface = initInterface(buffer),75 .interface = initInterface(buffer),
74 .mode = .streaming,76 .mode = .streaming,
lib/std/process/Child.zig+8-9
...@@ -435,8 +435,7 @@ pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix...@@ -435,8 +435,7 @@ pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix
435435
436/// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.436/// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
437/// If it succeeds, the caller owns result.stdout and result.stderr memory.437/// If it succeeds, the caller owns result.stdout and result.stderr memory.
438pub fn run(args: struct {438pub fn run(allocator: Allocator, io: Io, args: struct {
439 allocator: mem.Allocator,
440 argv: []const []const u8,439 argv: []const []const u8,
441 cwd: ?[]const u8 = null,440 cwd: ?[]const u8 = null,
442 cwd_dir: ?Io.Dir = null,441 cwd_dir: ?Io.Dir = null,
...@@ -447,7 +446,7 @@ pub fn run(args: struct {...@@ -447,7 +446,7 @@ pub fn run(args: struct {
447 expand_arg0: Arg0Expand = .no_expand,446 expand_arg0: Arg0Expand = .no_expand,
448 progress_node: std.Progress.Node = std.Progress.Node.none,447 progress_node: std.Progress.Node = std.Progress.Node.none,
449}) RunError!RunResult {448}) RunError!RunResult {
450 var child = ChildProcess.init(args.argv, args.allocator);449 var child = ChildProcess.init(args.argv, allocator);
451 child.stdin_behavior = .Ignore;450 child.stdin_behavior = .Ignore;
452 child.stdout_behavior = .Pipe;451 child.stdout_behavior = .Pipe;
453 child.stderr_behavior = .Pipe;452 child.stderr_behavior = .Pipe;
...@@ -458,19 +457,19 @@ pub fn run(args: struct {...@@ -458,19 +457,19 @@ pub fn run(args: struct {
458 child.progress_node = args.progress_node;457 child.progress_node = args.progress_node;
459458
460 var stdout: ArrayList(u8) = .empty;459 var stdout: ArrayList(u8) = .empty;
461 defer stdout.deinit(args.allocator);460 defer stdout.deinit(allocator);
462 var stderr: ArrayList(u8) = .empty;461 var stderr: ArrayList(u8) = .empty;
463 defer stderr.deinit(args.allocator);462 defer stderr.deinit(allocator);
464463
465 try child.spawn();464 try child.spawn();
466 errdefer {465 errdefer {
467 _ = child.kill() catch {};466 _ = child.kill(io) catch {};
468 }467 }
469 try child.collectOutput(args.allocator, &stdout, &stderr, args.max_output_bytes);468 try child.collectOutput(allocator, &stdout, &stderr, args.max_output_bytes);
470469
471 return .{470 return .{
472 .stdout = try stdout.toOwnedSlice(args.allocator),471 .stdout = try stdout.toOwnedSlice(allocator),
473 .stderr = try stderr.toOwnedSlice(args.allocator),472 .stderr = try stderr.toOwnedSlice(allocator),
474 .term = try child.wait(),473 .term = try child.wait(),
475 };474 };
476}475}
test/src/convert-stack-trace.zig+3-3
...@@ -41,13 +41,13 @@ pub fn main() !void {...@@ -41,13 +41,13 @@ pub fn main() !void {
41 var read_buf: [1024]u8 = undefined;41 var read_buf: [1024]u8 = undefined;
42 var write_buf: [1024]u8 = undefined;42 var write_buf: [1024]u8 = undefined;
4343
44 const in_file = try std.fs.cwd().openFile(args[1], .{});44 const in_file = try std.Io.Dir.cwd().openFile(io, args[1], .{});
45 defer in_file.close();45 defer in_file.close(io);
4646
47 const out_file: std.Io.File = .stdout();47 const out_file: std.Io.File = .stdout();
4848
49 var in_fr = in_file.reader(io, &read_buf);49 var in_fr = in_file.reader(io, &read_buf);
50 var out_fw = out_file.writer(&write_buf);50 var out_fw = out_file.writer(io, &write_buf);
5151
52 const w = &out_fw.interface;52 const w = &out_fw.interface;
5353
test/standalone/child_process/main.zig+8-7
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const Io = std.Io;
23
3pub fn main() !void {4pub fn main() !void {
4 // make sure safety checks are enabled even in release modes5 // make sure safety checks are enabled even in release modes
...@@ -20,7 +21,7 @@ pub fn main() !void {...@@ -20,7 +21,7 @@ pub fn main() !void {
20 };21 };
21 defer if (needs_free) gpa.free(child_path);22 defer if (needs_free) gpa.free(child_path);
2223
23 var threaded: std.Io.Threaded = .init(gpa);24 var threaded: Io.Threaded = .init(gpa);
24 defer threaded.deinit();25 defer threaded.deinit();
25 const io = threaded.io();26 const io = threaded.io();
2627
...@@ -31,7 +32,7 @@ pub fn main() !void {...@@ -31,7 +32,7 @@ pub fn main() !void {
31 try child.spawn();32 try child.spawn();
32 const child_stdin = child.stdin.?;33 const child_stdin = child.stdin.?;
33 try child_stdin.writeAll("hello from stdin"); // verified in child34 try child_stdin.writeAll("hello from stdin"); // verified in child
34 child_stdin.close();35 child_stdin.close(io);
35 child.stdin = null;36 child.stdin = null;
3637
37 const hello_stdout = "hello from stdout";38 const hello_stdout = "hello from stdout";
...@@ -39,17 +40,17 @@ pub fn main() !void {...@@ -39,17 +40,17 @@ pub fn main() !void {
39 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});40 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
40 const n = try stdout_reader.interface.readSliceShort(&buf);41 const n = try stdout_reader.interface.readSliceShort(&buf);
41 if (!std.mem.eql(u8, buf[0..n], hello_stdout)) {42 if (!std.mem.eql(u8, buf[0..n], hello_stdout)) {
42 testError("child stdout: '{s}'; want '{s}'", .{ buf[0..n], hello_stdout });43 testError(io, "child stdout: '{s}'; want '{s}'", .{ buf[0..n], hello_stdout });
43 }44 }
4445
45 switch (try child.wait()) {46 switch (try child.wait()) {
46 .Exited => |code| {47 .Exited => |code| {
47 const child_ok_code = 42; // set by child if no test errors48 const child_ok_code = 42; // set by child if no test errors
48 if (code != child_ok_code) {49 if (code != child_ok_code) {
49 testError("child exit code: {d}; want {d}", .{ code, child_ok_code });50 testError(io, "child exit code: {d}; want {d}", .{ code, child_ok_code });
50 }51 }
51 },52 },
52 else => |term| testError("abnormal child exit: {}", .{term}),53 else => |term| testError(io, "abnormal child exit: {}", .{term}),
53 }54 }
54 if (parent_test_error) return error.ParentTestError;55 if (parent_test_error) return error.ParentTestError;
5556
...@@ -61,8 +62,8 @@ pub fn main() !void {...@@ -61,8 +62,8 @@ pub fn main() !void {
6162
62var parent_test_error = false;63var parent_test_error = false;
6364
64fn testError(comptime fmt: []const u8, args: anytype) void {65fn testError(io: Io, comptime fmt: []const u8, args: anytype) void {
65 var stderr_writer = std.Io.File.stderr().writer(&.{});66 var stderr_writer = Io.File.stderr().writer(io, &.{});
66 const stderr = &stderr_writer.interface;67 const stderr = &stderr_writer.interface;
67 stderr.print("PARENT TEST ERROR: ", .{}) catch {};68 stderr.print("PARENT TEST ERROR: ", .{}) catch {};
68 stderr.print(fmt, args) catch {};69 stderr.print(fmt, args) catch {};
test/standalone/cmakedefine/check.zig+5-2
...@@ -9,8 +9,11 @@ pub fn main() !void {...@@ -9,8 +9,11 @@ pub fn main() !void {
9 const actual_path = args[1];9 const actual_path = args[1];
10 const expected_path = args[2];10 const expected_path = args[2];
1111
12 const actual = try std.fs.cwd().readFileAlloc(actual_path, arena, .limited(1024 * 1024));12 var threaded: std.Io.Threaded = .init_single_threaded;
13 const expected = try std.fs.cwd().readFileAlloc(expected_path, arena, .limited(1024 * 1024));13 const io = threaded.io();
14
15 const actual = try std.Io.Dir.cwd().readFileAlloc(io, actual_path, arena, .limited(1024 * 1024));
16 const expected = try std.Io.Dir.cwd().readFileAlloc(io, expected_path, arena, .limited(1024 * 1024));
1417
15 // The actual output starts with a comment which we should strip out before comparing.18 // The actual output starts with a comment which we should strip out before comparing.
16 const comment_str = "/* This file was generated by ConfigHeader using the Zig Build System. */\n";19 const comment_str = "/* This file was generated by ConfigHeader using the Zig Build System. */\n";
test/standalone/dirname/build.zig+6-4
...@@ -59,13 +59,15 @@ pub fn build(b: *std.Build) void {...@@ -59,13 +59,15 @@ pub fn build(b: *std.Build) void {
5959
60 // Absolute path:60 // Absolute path:
61 const abs_path = setup_abspath: {61 const abs_path = setup_abspath: {
62 // TODO this is a bad pattern, don't do this
63 const io = b.graph.io;
62 const temp_dir = b.makeTempPath();64 const temp_dir = b.makeTempPath();
6365
64 var dir = std.fs.cwd().openDir(temp_dir, .{}) catch @panic("failed to open temp dir");66 var dir = std.Io.Dir.cwd().openDir(io, temp_dir, .{}) catch @panic("failed to open temp dir");
65 defer dir.close();67 defer dir.close(io);
6668
67 var file = dir.createFile("foo.txt", .{}) catch @panic("failed to create file");69 var file = dir.createFile(io, "foo.txt", .{}) catch @panic("failed to create file");
68 file.close();70 file.close(io);
6971
70 break :setup_abspath std.Build.LazyPath{ .cwd_relative = temp_dir };72 break :setup_abspath std.Build.LazyPath{ .cwd_relative = temp_dir };
71 };73 };
test/standalone/dirname/exists_in.zig+6-3
...@@ -34,8 +34,11 @@ fn run(allocator: std.mem.Allocator) !void {...@@ -34,8 +34,11 @@ fn run(allocator: std.mem.Allocator) !void {
34 return error.BadUsage;34 return error.BadUsage;
35 };35 };
3636
37 var dir = try std.fs.cwd().openDir(dir_path, .{});37 var threaded: std.Io.Threaded = .init_single_threaded;
38 defer dir.close();38 const io = threaded.io();
3939
40 _ = try dir.statFile(relpath);40 var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
41 defer dir.close(io);
42
43 _ = try dir.statFile(io, relpath);
41}44}
test/standalone/dirname/touch.zig+10-7
...@@ -26,14 +26,17 @@ fn run(allocator: std.mem.Allocator) !void {...@@ -26,14 +26,17 @@ fn run(allocator: std.mem.Allocator) !void {
26 return error.BadUsage;26 return error.BadUsage;
27 };27 };
2828
29 const dir_path = std.fs.path.dirname(path) orelse unreachable;29 const dir_path = std.Io.Dir.path.dirname(path) orelse unreachable;
30 const basename = std.fs.path.basename(path);30 const basename = std.Io.Dir.path.basename(path);
3131
32 var dir = try std.fs.cwd().openDir(dir_path, .{});32 var threaded: std.Io.Threaded = .init_single_threaded;
33 defer dir.close();33 const io = threaded.io();
3434
35 _ = dir.statFile(basename) catch {35 var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
36 var file = try dir.createFile(basename, .{});36 defer dir.close(io);
37 file.close();37
38 _ = dir.statFile(io, basename) catch {
39 var file = try dir.createFile(io, basename, .{});
40 file.close(io);
38 };41 };
39}42}
test/standalone/entry_point/check_differ.zig+5-2
...@@ -6,8 +6,11 @@ pub fn main() !void {...@@ -6,8 +6,11 @@ pub fn main() !void {
6 const args = try std.process.argsAlloc(arena);6 const args = try std.process.argsAlloc(arena);
7 if (args.len != 3) return error.BadUsage; // usage: 'check_differ <path a> <path b>'7 if (args.len != 3) return error.BadUsage; // usage: 'check_differ <path a> <path b>'
88
9 const contents_1 = try std.fs.cwd().readFileAlloc(args[1], arena, .limited(1024 * 1024 * 64)); // 64 MiB ought to be plenty9 var threaded: std.Io.Threaded = .init_single_threaded;
10 const contents_2 = try std.fs.cwd().readFileAlloc(args[2], arena, .limited(1024 * 1024 * 64)); // 64 MiB ought to be plenty10 const io = threaded.io();
11
12 const contents_1 = try std.Io.Dir.cwd().readFileAlloc(io, args[1], arena, .limited(1024 * 1024 * 64)); // 64 MiB ought to be plenty
13 const contents_2 = try std.Io.Dir.cwd().readFileAlloc(io, args[2], arena, .limited(1024 * 1024 * 64)); // 64 MiB ought to be plenty
1114
12 if (std.mem.eql(u8, contents_1, contents_2)) {15 if (std.mem.eql(u8, contents_1, contents_2)) {
13 return error.FilesMatch;16 return error.FilesMatch;
test/standalone/glibc_compat/glibc_runtime_check.zig+2-2
...@@ -28,10 +28,10 @@ extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: [*]const u8) c_int;...@@ -28,10 +28,10 @@ extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: [*]const u8) c_int;
2828
29// PR #17034 - fstat moved between libc_nonshared and libc29// PR #17034 - fstat moved between libc_nonshared and libc
30fn checkStat() !void {30fn checkStat() !void {
31 const cwdFd = std.fs.cwd().fd;31 const cwd_fd = std.Io.Dir.cwd().handle;
3232
33 var buf: [256]u8 = @splat(0);33 var buf: [256]u8 = @splat(0);
34 var result = fstatat(cwdFd, "a_file_that_definitely_does_not_exist", &buf, 0);34 var result = fstatat(cwd_fd, "a_file_that_definitely_does_not_exist", &buf, 0);
35 assert(result == -1);35 assert(result == -1);
36 assert(std.posix.errno(result) == .NOENT);36 assert(std.posix.errno(result) == .NOENT);
3737
test/standalone/install_headers/check_exists.zig+7-4
...@@ -11,8 +11,11 @@ pub fn main() !void {...@@ -11,8 +11,11 @@ pub fn main() !void {
11 var arg_it = try std.process.argsWithAllocator(arena);11 var arg_it = try std.process.argsWithAllocator(arena);
12 _ = arg_it.next();12 _ = arg_it.next();
1313
14 const cwd = std.fs.cwd();14 var threaded: std.Io.Threaded = .init_single_threaded;
15 const cwd_realpath = try cwd.realpathAlloc(arena, ".");15 const io = threaded.io();
16
17 const cwd = std.Io.Dir.cwd();
18 const cwd_realpath = try cwd.realPathAlloc(io, arena, ".");
1619
17 while (arg_it.next()) |file_path| {20 while (arg_it.next()) |file_path| {
18 if (file_path.len > 0 and file_path[0] == '!') {21 if (file_path.len > 0 and file_path[0] == '!') {
...@@ -20,7 +23,7 @@ pub fn main() !void {...@@ -20,7 +23,7 @@ pub fn main() !void {
20 "exclusive file check '{s}{c}{s}' failed",23 "exclusive file check '{s}{c}{s}' failed",
21 .{ cwd_realpath, std.fs.path.sep, file_path[1..] },24 .{ cwd_realpath, std.fs.path.sep, file_path[1..] },
22 );25 );
23 if (std.fs.cwd().statFile(file_path[1..])) |_| {26 if (cwd.statFile(io, file_path[1..])) |_| {
24 return error.FileFound;27 return error.FileFound;
25 } else |err| switch (err) {28 } else |err| switch (err) {
26 error.FileNotFound => {},29 error.FileNotFound => {},
...@@ -31,7 +34,7 @@ pub fn main() !void {...@@ -31,7 +34,7 @@ pub fn main() !void {
31 "inclusive file check '{s}{c}{s}' failed",34 "inclusive file check '{s}{c}{s}' failed",
32 .{ cwd_realpath, std.fs.path.sep, file_path },35 .{ cwd_realpath, std.fs.path.sep, file_path },
33 );36 );
34 _ = try std.fs.cwd().statFile(file_path);37 _ = try cwd.statFile(io, file_path);
35 }38 }
36 }39 }
37}40}
test/standalone/libfuzzer/main.zig+5-5
...@@ -20,8 +20,8 @@ pub fn main() !void {...@@ -20,8 +20,8 @@ pub fn main() !void {
20 const io = threaded.io();20 const io = threaded.io();
2121
22 const cache_dir_path = args.next() orelse @panic("expected cache directory path argument");22 const cache_dir_path = args.next() orelse @panic("expected cache directory path argument");
23 var cache_dir = try std.fs.cwd().openDir(cache_dir_path, .{});23 var cache_dir = try std.Io.Dir.cwd().openDir(io, cache_dir_path, .{});
24 defer cache_dir.close();24 defer cache_dir.close(io);
2525
26 abi.fuzzer_init(.fromSlice(cache_dir_path));26 abi.fuzzer_init(.fromSlice(cache_dir_path));
27 abi.fuzzer_init_test(testOne, .fromSlice("test"));27 abi.fuzzer_init_test(testOne, .fromSlice("test"));
...@@ -30,8 +30,8 @@ pub fn main() !void {...@@ -30,8 +30,8 @@ pub fn main() !void {
3030
31 const pc_digest = abi.fuzzer_coverage().id;31 const pc_digest = abi.fuzzer_coverage().id;
32 const coverage_file_path = "v/" ++ std.fmt.hex(pc_digest);32 const coverage_file_path = "v/" ++ std.fmt.hex(pc_digest);
33 const coverage_file = try cache_dir.openFile(coverage_file_path, .{});33 const coverage_file = try cache_dir.openFile(io, coverage_file_path, .{});
34 defer coverage_file.close();34 defer coverage_file.close(io);
3535
36 var read_buf: [@sizeOf(abi.SeenPcsHeader)]u8 = undefined;36 var read_buf: [@sizeOf(abi.SeenPcsHeader)]u8 = undefined;
37 var r = coverage_file.reader(io, &read_buf);37 var r = coverage_file.reader(io, &read_buf);
...@@ -42,6 +42,6 @@ pub fn main() !void {...@@ -42,6 +42,6 @@ pub fn main() !void {
42 const expected_len = @sizeOf(abi.SeenPcsHeader) +42 const expected_len = @sizeOf(abi.SeenPcsHeader) +
43 try std.math.divCeil(usize, pcs_header.pcs_len, @bitSizeOf(usize)) * @sizeOf(usize) +43 try std.math.divCeil(usize, pcs_header.pcs_len, @bitSizeOf(usize)) * @sizeOf(usize) +
44 pcs_header.pcs_len * @sizeOf(usize);44 pcs_header.pcs_len * @sizeOf(usize);
45 if (try coverage_file.getEndPos() != expected_len)45 if (try coverage_file.length(io) != expected_len)
46 return error.WrongEnd;46 return error.WrongEnd;
47}47}
test/standalone/posix/relpaths.zig+15-8
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1// Test relative paths through POSIX APIS. These tests have to change the cwd, so1// Test relative paths through POSIX APIS. These tests have to change the cwd, so
2// they shouldn't be Zig unit tests.2// they shouldn't be Zig unit tests.
33
4const std = @import("std");
5const builtin = @import("builtin");4const builtin = @import("builtin");
65
6const std = @import("std");
7const Io = std.Io;
8
7pub fn main() !void {9pub fn main() !void {
8 if (builtin.target.os.tag == .wasi) return; // Can link, but can't change into tmpDir10 if (builtin.target.os.tag == .wasi) return; // Can link, but can't change into tmpDir
911
...@@ -11,6 +13,11 @@ pub fn main() !void {...@@ -11,6 +13,11 @@ pub fn main() !void {
11 const a = Allocator.allocator();13 const a = Allocator.allocator();
12 defer std.debug.assert(Allocator.deinit() == .ok);14 defer std.debug.assert(Allocator.deinit() == .ok);
1315
16 var threaded: std.Io.Threaded = .init_single_threaded;
17 const io = threaded.io();
18
19 // TODO this API isn't supposed to be used outside of unit testing. make it compilation error if used
20 // outside of unit testing.
14 var tmp = std.testing.tmpDir(.{});21 var tmp = std.testing.tmpDir(.{});
15 defer tmp.cleanup();22 defer tmp.cleanup();
1623
...@@ -18,7 +25,7 @@ pub fn main() !void {...@@ -18,7 +25,7 @@ pub fn main() !void {
18 try tmp.dir.setAsCwd();25 try tmp.dir.setAsCwd();
1926
20 try test_symlink(a, tmp);27 try test_symlink(a, tmp);
21 try test_link(tmp);28 try test_link(io, tmp);
22}29}
2330
24fn test_symlink(a: std.mem.Allocator, tmp: std.testing.TmpDir) !void {31fn 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...@@ -65,7 +72,7 @@ fn getLinkInfo(fd: std.posix.fd_t) !struct { std.posix.ino_t, std.posix.nlink_t
65 return .{ st.ino, st.nlink };72 return .{ st.ino, st.nlink };
66}73}
6774
68fn test_link(tmp: std.testing.TmpDir) !void {75fn test_link(io: Io, tmp: std.testing.TmpDir) !void {
69 switch (builtin.target.os.tag) {76 switch (builtin.target.os.tag) {
70 .linux, .illumos => {},77 .linux, .illumos => {},
71 else => return,78 else => return,
...@@ -74,17 +81,17 @@ fn test_link(tmp: std.testing.TmpDir) !void {...@@ -74,17 +81,17 @@ fn test_link(tmp: std.testing.TmpDir) !void {
74 const target_name = "link-target";81 const target_name = "link-target";
75 const link_name = "newlink";82 const link_name = "newlink";
7683
77 try tmp.dir.writeFile(.{ .sub_path = target_name, .data = "example" });84 try tmp.dir.writeFile(io, .{ .sub_path = target_name, .data = "example" });
7885
79 // Test 1: create the relative link from inside tmp86 // Test 1: create the relative link from inside tmp
80 try std.posix.link(target_name, link_name);87 try std.posix.link(target_name, link_name);
8188
82 // Verify89 // Verify
83 const efd = try tmp.dir.openFile(target_name, .{});90 const efd = try tmp.dir.openFile(io, target_name, .{});
84 defer efd.close();91 defer efd.close(io);
8592
86 const nfd = try tmp.dir.openFile(link_name, .{});93 const nfd = try tmp.dir.openFile(io, link_name, .{});
87 defer nfd.close();94 defer nfd.close(io);
8895
89 {96 {
90 const eino, _ = try getLinkInfo(efd.handle);97 const eino, _ = try getLinkInfo(efd.handle);
test/standalone/run_cwd/check_file_exists.zig+4-1
...@@ -8,7 +8,10 @@ pub fn main() !void {...@@ -8,7 +8,10 @@ pub fn main() !void {
8 if (args.len != 2) return error.BadUsage;8 if (args.len != 2) return error.BadUsage;
9 const path = args[1];9 const path = args[1];
1010
11 std.fs.cwd().access(path, .{}) catch return error.AccessFailed;11 var threaded: std.Io.Threaded = .init_single_threaded;
12 const io = threaded.io();
13
14 std.Io.Dir.cwd().access(io, path, .{}) catch return error.AccessFailed;
12}15}
1316
14const std = @import("std");17const std = @import("std");
test/standalone/run_output_caching/main.zig+5-3
...@@ -1,10 +1,12 @@...@@ -1,10 +1,12 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn main() !void {3pub fn main() !void {
4 var threaded: std.Io.Threaded = .init_single_threaded;
5 const io = threaded.io();
4 var args = try std.process.argsWithAllocator(std.heap.page_allocator);6 var args = try std.process.argsWithAllocator(std.heap.page_allocator);
5 _ = args.skip();7 _ = args.skip();
6 const filename = args.next().?;8 const filename = args.next().?;
7 const file = try std.fs.cwd().createFile(filename, .{});9 const file = try std.Io.Dir.cwd().createFile(io, filename, .{});
8 defer file.close();10 defer file.close(io);
9 try file.writeAll(filename);11 try file.writeAll(io, filename);
10}12}
test/standalone/run_output_paths/create_file.zig+3-1
...@@ -1,10 +1,12 @@...@@ -1,10 +1,12 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn main() !void {3pub fn main() !void {
4 var threaded: std.Io.Threaded = .init_single_threaded;
5 const io = threaded.io();
4 var args = try std.process.argsWithAllocator(std.heap.page_allocator);6 var args = try std.process.argsWithAllocator(std.heap.page_allocator);
5 _ = args.skip();7 _ = args.skip();
6 const dir_name = args.next().?;8 const dir_name = args.next().?;
7 const dir = try std.fs.cwd().openDir(if (std.mem.startsWith(u8, dir_name, "--dir="))9 const dir = try std.Io.Dir.cwd().openDir(io, if (std.mem.startsWith(u8, dir_name, "--dir="))
8 dir_name["--dir=".len..]10 dir_name["--dir=".len..]
9 else11 else
10 dir_name, .{});12 dir_name, .{});
test/standalone/self_exe_symlink/create-symlink.zig+5-1
...@@ -14,5 +14,9 @@ pub fn main() anyerror!void {...@@ -14,5 +14,9 @@ pub fn main() anyerror!void {
14 // If `exe_path` is relative to our cwd, we need to convert it to be relative to the dirname of `symlink_path`.14 // If `exe_path` is relative to our cwd, we need to convert it to be relative to the dirname of `symlink_path`.
15 const exe_rel_path = try std.fs.path.relative(allocator, std.fs.path.dirname(symlink_path) orelse ".", exe_path);15 const exe_rel_path = try std.fs.path.relative(allocator, std.fs.path.dirname(symlink_path) orelse ".", exe_path);
16 defer allocator.free(exe_rel_path);16 defer allocator.free(exe_rel_path);
17 try std.fs.cwd().symLink(exe_rel_path, symlink_path, .{});17
18 var threaded: std.Io.Threaded = .init_single_threaded;
19 const io = threaded.io();
20
21 try std.Io.Dir.cwd().symLink(io, exe_rel_path, symlink_path, .{});
18}22}
test/standalone/self_exe_symlink/main.zig+10-6
...@@ -1,15 +1,19 @@...@@ -1,15 +1,19 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn main() !void {3pub fn main() !void {
4 var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;4 var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
5 defer std.debug.assert(gpa.deinit() == .ok);5 defer if (debug_allocator.deinit() == .leak) @panic("found memory leaks");
6 const allocator = gpa.allocator();6 const gpa = debug_allocator.allocator();
77
8 const self_path = try std.fs.selfExePathAlloc(allocator);8 var threaded: std.Io.Threaded = .init(gpa);
9 defer allocator.free(self_path);9 defer threaded.deinit();
10 const io = threaded.io();
11
12 const self_path = try std.fs.selfExePathAlloc(gpa);
13 defer gpa.free(self_path);
1014
11 var self_exe = try std.fs.openSelfExe(.{});15 var self_exe = try std.fs.openSelfExe(.{});
12 defer self_exe.close();16 defer self_exe.close(io);
13 var buf: [std.fs.max_path_bytes]u8 = undefined;17 var buf: [std.fs.max_path_bytes]u8 = undefined;
14 const self_exe_path = try std.os.getFdPath(self_exe.handle, &buf);18 const self_exe_path = try std.os.getFdPath(self_exe.handle, &buf);
1519
test/standalone/simple/cat/main.zig+3-3
...@@ -18,7 +18,7 @@ pub fn main() !void {...@@ -18,7 +18,7 @@ pub fn main() !void {
18 const exe = args[0];18 const exe = args[0];
19 var catted_anything = false;19 var catted_anything = false;
20 var stdout_buffer: [4096]u8 = undefined;20 var stdout_buffer: [4096]u8 = undefined;
21 var stdout_writer = Io.File.stdout().writerStreaming(&stdout_buffer);21 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
22 const stdout = &stdout_writer.interface;22 const stdout = &stdout_writer.interface;
23 var stdin_reader = Io.File.stdin().readerStreaming(io, &.{});23 var stdin_reader = Io.File.stdin().readerStreaming(io, &.{});
2424
...@@ -32,8 +32,8 @@ pub fn main() !void {...@@ -32,8 +32,8 @@ pub fn main() !void {
32 } else if (mem.startsWith(u8, arg, "-")) {32 } else if (mem.startsWith(u8, arg, "-")) {
33 return usage(exe);33 return usage(exe);
34 } else {34 } else {
35 const file = cwd.openFile(arg, .{}) catch |err| fatal("unable to open file: {t}\n", .{err});35 const file = cwd.openFile(io, arg, .{}) catch |err| fatal("unable to open file: {t}\n", .{err});
36 defer file.close();36 defer file.close(io);
3737
38 catted_anything = true;38 catted_anything = true;
39 var file_reader = file.reader(io, &.{});39 var file_reader = file.reader(io, &.{});
test/standalone/windows_spawn/main.zig+62-58
...@@ -1,15 +1,20 @@...@@ -1,15 +1,20 @@
1const std = @import("std");1const std = @import("std");
2const Io = std.Io;2const Io = std.Io;
3const Allocator = std.mem.Allocator;
34
4const windows = std.os.windows;5const windows = std.os.windows;
5const utf16Literal = std.unicode.utf8ToUtf16LeStringLiteral;6const utf16Literal = std.unicode.utf8ToUtf16LeStringLiteral;
67
7pub fn main() anyerror!void {8pub fn main() anyerror!void {
8 var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;9 var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
9 defer if (gpa.deinit() == .leak) @panic("found memory leaks");10 defer if (debug_allocator.deinit() == .leak) @panic("found memory leaks");
10 const allocator = gpa.allocator();11 const gpa = debug_allocator.allocator();
1112
12 var it = try std.process.argsWithAllocator(allocator);13 var threaded: std.Io.Threaded = .init(gpa);
14 defer threaded.deinit();
15 const io = threaded.io();
16
17 var it = try std.process.argsWithAllocator(gpa);
13 defer it.deinit();18 defer it.deinit();
14 _ = it.next() orelse unreachable; // skip binary name19 _ = it.next() orelse unreachable; // skip binary name
15 const hello_exe_cache_path = it.next() orelse unreachable;20 const hello_exe_cache_path = it.next() orelse unreachable;
...@@ -17,14 +22,14 @@ pub fn main() anyerror!void {...@@ -17,14 +22,14 @@ pub fn main() anyerror!void {
17 var tmp = std.testing.tmpDir(.{});22 var tmp = std.testing.tmpDir(.{});
18 defer tmp.cleanup();23 defer tmp.cleanup();
1924
20 const tmp_absolute_path = try tmp.dir.realpathAlloc(allocator, ".");25 const tmp_absolute_path = try tmp.dir.realpathAlloc(gpa, ".");
21 defer allocator.free(tmp_absolute_path);26 defer gpa.free(tmp_absolute_path);
22 const tmp_absolute_path_w = try std.unicode.utf8ToUtf16LeAllocZ(allocator, tmp_absolute_path);27 const tmp_absolute_path_w = try std.unicode.utf8ToUtf16LeAllocZ(gpa, tmp_absolute_path);
23 defer allocator.free(tmp_absolute_path_w);28 defer gpa.free(tmp_absolute_path_w);
24 const cwd_absolute_path = try std.fs.cwd().realpathAlloc(allocator, ".");29 const cwd_absolute_path = try Io.Dir.cwd().realpathAlloc(gpa, ".");
25 defer allocator.free(cwd_absolute_path);30 defer gpa.free(cwd_absolute_path);
26 const tmp_relative_path = try std.fs.path.relative(allocator, cwd_absolute_path, tmp_absolute_path);31 const tmp_relative_path = try std.fs.path.relative(gpa, cwd_absolute_path, tmp_absolute_path);
27 defer allocator.free(tmp_relative_path);32 defer gpa.free(tmp_relative_path);
2833
29 // Clear PATH34 // Clear PATH
30 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(35 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
...@@ -39,10 +44,10 @@ pub fn main() anyerror!void {...@@ -39,10 +44,10 @@ pub fn main() anyerror!void {
39 ) == windows.TRUE);44 ) == windows.TRUE);
4045
41 // No PATH, so it should fail to find anything not in the cwd46 // No PATH, so it should fail to find anything not in the cwd
42 try testExecError(error.FileNotFound, allocator, "something_missing");47 try testExecError(error.FileNotFound, gpa, "something_missing");
4348
44 // make sure we don't get error.BadPath traversing out of cwd with a relative path49 // make sure we don't get error.BadPath traversing out of cwd with a relative path
45 try testExecError(error.FileNotFound, allocator, "..\\.\\.\\.\\\\..\\more_missing");50 try testExecError(error.FileNotFound, gpa, "..\\.\\.\\.\\\\..\\more_missing");
4651
47 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(52 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
48 utf16Literal("PATH"),53 utf16Literal("PATH"),
...@@ -50,14 +55,14 @@ pub fn main() anyerror!void {...@@ -50,14 +55,14 @@ pub fn main() anyerror!void {
50 ) == windows.TRUE);55 ) == windows.TRUE);
5156
52 // Move hello.exe into the tmp dir which is now added to the path57 // Move hello.exe into the tmp dir which is now added to the path
53 try std.fs.cwd().copyFile(hello_exe_cache_path, tmp.dir, "hello.exe", .{});58 try Io.Dir.cwd().copyFile(hello_exe_cache_path, tmp.dir, "hello.exe", .{});
5459
55 // with extension should find the .exe (case insensitive)60 // with extension should find the .exe (case insensitive)
56 try testExec(allocator, "HeLLo.exe", "hello from exe\n");61 try testExec(gpa, "HeLLo.exe", "hello from exe\n");
57 // without extension should find the .exe (case insensitive)62 // without extension should find the .exe (case insensitive)
58 try testExec(allocator, "heLLo", "hello from exe\n");63 try testExec(gpa, "heLLo", "hello from exe\n");
59 // with invalid cwd64 // with invalid cwd
60 try std.testing.expectError(error.FileNotFound, testExecWithCwd(allocator, "hello.exe", "missing_dir", ""));65 try std.testing.expectError(error.FileNotFound, testExecWithCwd(gpa, io, "hello.exe", "missing_dir", ""));
6166
62 // now add a .bat67 // now add a .bat
63 try tmp.dir.writeFile(.{ .sub_path = "hello.bat", .data = "@echo hello from bat" });68 try tmp.dir.writeFile(.{ .sub_path = "hello.bat", .data = "@echo hello from bat" });
...@@ -65,33 +70,33 @@ pub fn main() anyerror!void {...@@ -65,33 +70,33 @@ pub fn main() anyerror!void {
65 try tmp.dir.writeFile(.{ .sub_path = "hello.cmd", .data = "@echo hello from cmd" });70 try tmp.dir.writeFile(.{ .sub_path = "hello.cmd", .data = "@echo hello from cmd" });
6671
67 // with extension should find the .bat (case insensitive)72 // with extension should find the .bat (case insensitive)
68 try testExec(allocator, "heLLo.bat", "hello from bat\r\n");73 try testExec(gpa, "heLLo.bat", "hello from bat\r\n");
69 // with extension should find the .cmd (case insensitive)74 // with extension should find the .cmd (case insensitive)
70 try testExec(allocator, "heLLo.cmd", "hello from cmd\r\n");75 try testExec(gpa, "heLLo.cmd", "hello from cmd\r\n");
71 // without extension should find the .exe (since its first in PATHEXT)76 // without extension should find the .exe (since its first in PATHEXT)
72 try testExec(allocator, "heLLo", "hello from exe\n");77 try testExec(gpa, "heLLo", "hello from exe\n");
7378
74 // now rename the exe to not have an extension79 // now rename the exe to not have an extension
75 try renameExe(tmp.dir, "hello.exe", "hello");80 try renameExe(tmp.dir, "hello.exe", "hello");
7681
77 // with extension should now fail82 // with extension should now fail
78 try testExecError(error.FileNotFound, allocator, "hello.exe");83 try testExecError(error.FileNotFound, gpa, "hello.exe");
79 // without extension should succeed (case insensitive)84 // without extension should succeed (case insensitive)
80 try testExec(allocator, "heLLo", "hello from exe\n");85 try testExec(gpa, "heLLo", "hello from exe\n");
8186
82 try tmp.dir.makeDir("something");87 try tmp.dir.makeDir("something");
83 try renameExe(tmp.dir, "hello", "something/hello.exe");88 try renameExe(tmp.dir, "hello", "something/hello.exe");
8489
85 const relative_path_no_ext = try std.fs.path.join(allocator, &.{ tmp_relative_path, "something/hello" });90 const relative_path_no_ext = try std.fs.path.join(gpa, &.{ tmp_relative_path, "something/hello" });
86 defer allocator.free(relative_path_no_ext);91 defer gpa.free(relative_path_no_ext);
8792
88 // Giving a full relative path to something/hello should work93 // Giving a full relative path to something/hello should work
89 try testExec(allocator, relative_path_no_ext, "hello from exe\n");94 try testExec(gpa, relative_path_no_ext, "hello from exe\n");
90 // But commands with path separators get excluded from PATH searching, so this will fail95 // But commands with path separators get excluded from PATH searching, so this will fail
91 try testExecError(error.FileNotFound, allocator, "something/hello");96 try testExecError(error.FileNotFound, gpa, "something/hello");
9297
93 // Now that .BAT is the first PATHEXT that should be found, this should succeed98 // Now that .BAT is the first PATHEXT that should be found, this should succeed
94 try testExec(allocator, "heLLo", "hello from bat\r\n");99 try testExec(gpa, "heLLo", "hello from bat\r\n");
95100
96 // Add a hello.exe that is not a valid executable101 // Add a hello.exe that is not a valid executable
97 try tmp.dir.writeFile(.{ .sub_path = "hello.exe", .data = "invalid" });102 try tmp.dir.writeFile(.{ .sub_path = "hello.exe", .data = "invalid" });
...@@ -100,18 +105,18 @@ pub fn main() anyerror!void {...@@ -100,18 +105,18 @@ pub fn main() anyerror!void {
100 // case for .EXE extensions, where if they ever try to get executed but they are105 // case for .EXE extensions, where if they ever try to get executed but they are
101 // invalid, that gets treated as a fatal error wherever they are found and InvalidExe106 // invalid, that gets treated as a fatal error wherever they are found and InvalidExe
102 // is returned immediately.107 // is returned immediately.
103 try testExecError(error.InvalidExe, allocator, "hello.exe");108 try testExecError(error.InvalidExe, gpa, "hello.exe");
104 // Same thing applies to the command with no extension--even though there is a109 // Same thing applies to the command with no extension--even though there is a
105 // hello.bat that could be executed, it should stop after it tries executing110 // hello.bat that could be executed, it should stop after it tries executing
106 // hello.exe and getting InvalidExe.111 // hello.exe and getting InvalidExe.
107 try testExecError(error.InvalidExe, allocator, "hello");112 try testExecError(error.InvalidExe, gpa, "hello");
108113
109 // If we now rename hello.exe to have no extension, it will behave differently114 // If we now rename hello.exe to have no extension, it will behave differently
110 try renameExe(tmp.dir, "hello.exe", "hello");115 try renameExe(tmp.dir, "hello.exe", "hello");
111116
112 // Now, trying to execute it without an extension should treat InvalidExe as recoverable117 // Now, trying to execute it without an extension should treat InvalidExe as recoverable
113 // and skip over it and find hello.bat and execute that118 // and skip over it and find hello.bat and execute that
114 try testExec(allocator, "hello", "hello from bat\r\n");119 try testExec(gpa, "hello", "hello from bat\r\n");
115120
116 // If we rename the invalid exe to something else121 // If we rename the invalid exe to something else
117 try renameExe(tmp.dir, "hello", "goodbye");122 try renameExe(tmp.dir, "hello", "goodbye");
...@@ -119,13 +124,13 @@ pub fn main() anyerror!void {...@@ -119,13 +124,13 @@ pub fn main() anyerror!void {
119 // since that is what the original error will be after searching for 'goodbye'124 // since that is what the original error will be after searching for 'goodbye'
120 // in the cwd. It will try to execute 'goodbye' from the PATH but the InvalidExe error125 // in the cwd. It will try to execute 'goodbye' from the PATH but the InvalidExe error
121 // should be ignored in this case.126 // should be ignored in this case.
122 try testExecError(error.FileNotFound, allocator, "goodbye");127 try testExecError(error.FileNotFound, gpa, "goodbye");
123128
124 // Now let's set the tmp dir as the cwd and set the path only include the "something" sub dir129 // Now let's set the tmp dir as the cwd and set the path only include the "something" sub dir
125 try tmp.dir.setAsCwd();130 try tmp.dir.setAsCwd();
126 defer tmp.parent_dir.setAsCwd() catch {};131 defer tmp.parent_dir.setAsCwd() catch {};
127 const something_subdir_abs_path = try std.mem.concatWithSentinel(allocator, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);132 const something_subdir_abs_path = try std.mem.concatWithSentinel(gpa, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);
128 defer allocator.free(something_subdir_abs_path);133 defer gpa.free(something_subdir_abs_path);
129134
130 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(135 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
131 utf16Literal("PATH"),136 utf16Literal("PATH"),
...@@ -134,37 +139,37 @@ pub fn main() anyerror!void {...@@ -134,37 +139,37 @@ pub fn main() anyerror!void {
134139
135 // Now trying to execute goodbye should give error.InvalidExe since it's the original140 // Now trying to execute goodbye should give error.InvalidExe since it's the original
136 // error that we got when trying within the cwd141 // error that we got when trying within the cwd
137 try testExecError(error.InvalidExe, allocator, "goodbye");142 try testExecError(error.InvalidExe, gpa, "goodbye");
138143
139 // hello should still find the .bat144 // hello should still find the .bat
140 try testExec(allocator, "hello", "hello from bat\r\n");145 try testExec(gpa, "hello", "hello from bat\r\n");
141146
142 // If we rename something/hello.exe to something/goodbye.exe147 // If we rename something/hello.exe to something/goodbye.exe
143 try renameExe(tmp.dir, "something/hello.exe", "something/goodbye.exe");148 try renameExe(tmp.dir, "something/hello.exe", "something/goodbye.exe");
144 // And try to execute goodbye, then the one in something should be found149 // And try to execute goodbye, then the one in something should be found
145 // since the one in cwd is an invalid executable150 // since the one in cwd is an invalid executable
146 try testExec(allocator, "goodbye", "hello from exe\n");151 try testExec(gpa, "goodbye", "hello from exe\n");
147152
148 // If we use an absolute path to execute the invalid goodbye153 // If we use an absolute path to execute the invalid goodbye
149 const goodbye_abs_path = try std.mem.join(allocator, "\\", &.{ tmp_absolute_path, "goodbye" });154 const goodbye_abs_path = try std.mem.join(gpa, "\\", &.{ tmp_absolute_path, "goodbye" });
150 defer allocator.free(goodbye_abs_path);155 defer gpa.free(goodbye_abs_path);
151 // then the PATH should not be searched and we should get InvalidExe156 // then the PATH should not be searched and we should get InvalidExe
152 try testExecError(error.InvalidExe, allocator, goodbye_abs_path);157 try testExecError(error.InvalidExe, gpa, goodbye_abs_path);
153158
154 // If we try to exec but provide a cwd that is an absolute path, the PATH159 // If we try to exec but provide a cwd that is an absolute path, the PATH
155 // should still be searched and the goodbye.exe in something should be found.160 // should still be searched and the goodbye.exe in something should be found.
156 try testExecWithCwd(allocator, "goodbye", tmp_absolute_path, "hello from exe\n");161 try testExecWithCwd(gpa, "goodbye", tmp_absolute_path, "hello from exe\n");
157162
158 // introduce some extra path separators into the path which is dealt with inside the spawn call.163 // introduce some extra path separators into the path which is dealt with inside the spawn call.
159 const denormed_something_subdir_size = std.mem.replacementSize(u16, something_subdir_abs_path, utf16Literal("\\"), utf16Literal("\\\\\\\\"));164 const denormed_something_subdir_size = std.mem.replacementSize(u16, something_subdir_abs_path, utf16Literal("\\"), utf16Literal("\\\\\\\\"));
160165
161 const denormed_something_subdir_abs_path = try allocator.allocSentinel(u16, denormed_something_subdir_size, 0);166 const denormed_something_subdir_abs_path = try gpa.allocSentinel(u16, denormed_something_subdir_size, 0);
162 defer allocator.free(denormed_something_subdir_abs_path);167 defer gpa.free(denormed_something_subdir_abs_path);
163168
164 _ = std.mem.replace(u16, something_subdir_abs_path, utf16Literal("\\"), utf16Literal("\\\\\\\\"), denormed_something_subdir_abs_path);169 _ = std.mem.replace(u16, something_subdir_abs_path, utf16Literal("\\"), utf16Literal("\\\\\\\\"), denormed_something_subdir_abs_path);
165170
166 const denormed_something_subdir_wtf8 = try std.unicode.wtf16LeToWtf8Alloc(allocator, denormed_something_subdir_abs_path);171 const denormed_something_subdir_wtf8 = try std.unicode.wtf16LeToWtf8Alloc(gpa, denormed_something_subdir_abs_path);
167 defer allocator.free(denormed_something_subdir_wtf8);172 defer gpa.free(denormed_something_subdir_wtf8);
168173
169 // clear the path to ensure that the match comes from the cwd174 // clear the path to ensure that the match comes from the cwd
170 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(175 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
...@@ -172,18 +177,18 @@ pub fn main() anyerror!void {...@@ -172,18 +177,18 @@ pub fn main() anyerror!void {
172 null,177 null,
173 ) == windows.TRUE);178 ) == windows.TRUE);
174179
175 try testExecWithCwd(allocator, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n");180 try testExecWithCwd(gpa, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n");
176181
177 // normalization should also work if the non-normalized path is found in the PATH var.182 // normalization should also work if the non-normalized path is found in the PATH var.
178 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(183 std.debug.assert(windows.kernel32.SetEnvironmentVariableW(
179 utf16Literal("PATH"),184 utf16Literal("PATH"),
180 denormed_something_subdir_abs_path,185 denormed_something_subdir_abs_path,
181 ) == windows.TRUE);186 ) == windows.TRUE);
182 try testExec(allocator, "goodbye", "hello from exe\n");187 try testExec(gpa, "goodbye", "hello from exe\n");
183188
184 // now make sure we can launch executables "outside" of the cwd189 // now make sure we can launch executables "outside" of the cwd
185 var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{});190 var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{});
186 defer subdir_cwd.close();191 defer subdir_cwd.close(io);
187192
188 try renameExe(tmp.dir, "something/goodbye.exe", "hello.exe");193 try renameExe(tmp.dir, "something/goodbye.exe", "hello.exe");
189 try subdir_cwd.setAsCwd();194 try subdir_cwd.setAsCwd();
...@@ -195,25 +200,24 @@ pub fn main() anyerror!void {...@@ -195,25 +200,24 @@ pub fn main() anyerror!void {
195 ) == windows.TRUE);200 ) == windows.TRUE);
196201
197 // while we're at it make sure non-windows separators work fine202 // while we're at it make sure non-windows separators work fine
198 try testExec(allocator, "../hello", "hello from exe\n");203 try testExec(gpa, "../hello", "hello from exe\n");
199}204}
200205
201fn testExecError(err: anyerror, allocator: std.mem.Allocator, command: []const u8) !void {206fn testExecError(err: anyerror, gpa: Allocator, command: []const u8) !void {
202 return std.testing.expectError(err, testExec(allocator, command, ""));207 return std.testing.expectError(err, testExec(gpa, command, ""));
203}208}
204209
205fn testExec(allocator: std.mem.Allocator, command: []const u8, expected_stdout: []const u8) !void {210fn testExec(gpa: Allocator, command: []const u8, expected_stdout: []const u8) !void {
206 return testExecWithCwd(allocator, command, null, expected_stdout);211 return testExecWithCwd(gpa, command, null, expected_stdout);
207}212}
208213
209fn testExecWithCwd(allocator: std.mem.Allocator, command: []const u8, cwd: ?[]const u8, expected_stdout: []const u8) !void {214fn testExecWithCwd(gpa: Allocator, io: Io, command: []const u8, cwd: ?[]const u8, expected_stdout: []const u8) !void {
210 const result = try std.process.Child.run(.{215 const result = try std.process.Child.run(gpa, io, .{
211 .allocator = allocator,
212 .argv = &[_][]const u8{command},216 .argv = &[_][]const u8{command},
213 .cwd = cwd,217 .cwd = cwd,
214 });218 });
215 defer allocator.free(result.stdout);219 defer gpa.free(result.stdout);
216 defer allocator.free(result.stderr);220 defer gpa.free(result.stderr);
217221
218 try std.testing.expectEqualStrings("", result.stderr);222 try std.testing.expectEqualStrings("", result.stderr);
219 try std.testing.expectEqualStrings(expected_stdout, result.stdout);223 try std.testing.expectEqualStrings(expected_stdout, result.stdout);
test/tests.zig+11-8
...@@ -2024,6 +2024,7 @@ pub fn addLinkTests(...@@ -2024,6 +2024,7 @@ pub fn addLinkTests(
2024pub fn addCliTests(b: *std.Build) *Step {2024pub fn addCliTests(b: *std.Build) *Step {
2025 const step = b.step("test-cli", "Test the command line interface");2025 const step = b.step("test-cli", "Test the command line interface");
2026 const s = std.fs.path.sep_str;2026 const s = std.fs.path.sep_str;
2027 const io = b.graph.io;
20272028
2028 {2029 {
2029 // Test `zig init`.2030 // Test `zig init`.
...@@ -2132,13 +2133,13 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -2132,13 +2133,13 @@ pub fn addCliTests(b: *std.Build) *Step {
2132 const tmp_path = b.makeTempPath();2133 const tmp_path = b.makeTempPath();
2133 const unformatted_code = " // no reason for indent";2134 const unformatted_code = " // no reason for indent";
21342135
2135 var dir = std.fs.cwd().openDir(tmp_path, .{}) catch @panic("unhandled");2136 var dir = std.Io.Dir.cwd().openDir(io, tmp_path, .{}) catch @panic("unhandled");
2136 defer dir.close();2137 defer dir.close(io);
2137 dir.writeFile(.{ .sub_path = "fmt1.zig", .data = unformatted_code }) catch @panic("unhandled");2138 dir.writeFile(.{ .sub_path = "fmt1.zig", .data = unformatted_code }) catch @panic("unhandled");
2138 dir.writeFile(.{ .sub_path = "fmt2.zig", .data = unformatted_code }) catch @panic("unhandled");2139 dir.writeFile(.{ .sub_path = "fmt2.zig", .data = unformatted_code }) catch @panic("unhandled");
2139 dir.makeDir("subdir") catch @panic("unhandled");2140 dir.makeDir("subdir") catch @panic("unhandled");
2140 var subdir = dir.openDir("subdir", .{}) catch @panic("unhandled");2141 var subdir = dir.openDir(io, "subdir", .{}) catch @panic("unhandled");
2141 defer subdir.close();2142 defer subdir.close(io);
2142 subdir.writeFile(.{ .sub_path = "fmt3.zig", .data = unformatted_code }) catch @panic("unhandled");2143 subdir.writeFile(.{ .sub_path = "fmt3.zig", .data = unformatted_code }) catch @panic("unhandled");
21432144
2144 // Test zig fmt affecting only the appropriate files.2145 // Test zig fmt affecting only the appropriate files.
...@@ -2634,7 +2635,7 @@ pub fn addCases(...@@ -2634,7 +2635,7 @@ pub fn addCases(
2634 var cases = @import("src/Cases.zig").init(gpa, arena);2635 var cases = @import("src/Cases.zig").init(gpa, arena);
26352636
2636 var dir = try b.build_root.handle.openDir(io, "test/cases", .{ .iterate = true });2637 var dir = try b.build_root.handle.openDir(io, "test/cases", .{ .iterate = true });
2637 defer dir.close();2638 defer dir.close(io);
26382639
2639 cases.addFromDir(dir, b);2640 cases.addFromDir(dir, b);
2640 try @import("cases.zig").addCases(&cases, build_options, b);2641 try @import("cases.zig").addCases(&cases, build_options, b);
...@@ -2680,6 +2681,8 @@ pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step...@@ -2680,6 +2681,8 @@ pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step
2680}2681}
26812682
2682pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {2683pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {
2684 const io = b.graph.io;
2685
2683 const incr_check = b.addExecutable(.{2686 const incr_check = b.addExecutable(.{
2684 .name = "incr-check",2687 .name = "incr-check",
2685 .root_module = b.createModule(.{2688 .root_module = b.createModule(.{
...@@ -2689,11 +2692,11 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {...@@ -2689,11 +2692,11 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {
2689 }),2692 }),
2690 });2693 });
26912694
2692 var dir = try b.build_root.handle.openDir("test/incremental", .{ .iterate = true });2695 var dir = try b.build_root.handle.openDir(io, "test/incremental", .{ .iterate = true });
2693 defer dir.close();2696 defer dir.close(io);
26942697
2695 var it = try dir.walk(b.graph.arena);2698 var it = try dir.walk(b.graph.arena);
2696 while (try it.next()) |entry| {2699 while (try it.next(io)) |entry| {
2697 if (entry.kind != .file) continue;2700 if (entry.kind != .file) continue;
26982701
2699 const run = b.addRunArtifact(incr_check);2702 const run = b.addRunArtifact(incr_check);