authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-01-05 02:04:28-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-05 20:41:18+01:00
log52141fe85f1b7719cecb868520f40431fcfff2a1
tree69451db5e274bc1ba3cda27131e7f409270cc1a2
parent50422d5c37e85f08da7579cbffb4c0281a5cb2a8

standalone tests: Delete all ad hoc TmpDir instances, use the build system instead


8 files changed, 71 insertions(+), 296 deletions(-)

test/standalone/posix/build.zig+6
......@@ -4,11 +4,13 @@ const builtin = @import("builtin");
44const Case = struct {
55 src_path: []const u8,
66 set_env_vars: bool = false,
7 make_tmp_dir: bool = false,
78};
89
910const cases = [_]Case{
1011 .{
1112 .src_path = "cwd.zig",
13 .make_tmp_dir = true,
1214 },
1315 .{
1416 .src_path = "getenv.zig",
......@@ -19,6 +21,7 @@ const cases = [_]Case{
1921 },
2022 .{
2123 .src_path = "relpaths.zig",
24 .make_tmp_dir = true,
2225 },
2326};
2427
......@@ -69,6 +72,9 @@ fn run_exe(b: *std.Build, optimize: std.builtin.OptimizeMode, case: *const Case,
6972 });
7073
7174 const run_cmd = b.addRunArtifact(exe);
75 if (case.make_tmp_dir) {
76 run_cmd.addDirectoryArg(b.tmpPath());
77 }
7278
7379 if (case.set_env_vars) {
7480 run_cmd.setEnvironmentVariable("ZIG_TEST_POSIX_1EQ", "test=variable");
test/standalone/posix/cwd.zig+13-47
......@@ -13,10 +13,15 @@ pub fn main(init: std.process.Init) !void {
1313 .windows => return, // POSIX is not implemented by Windows
1414 else => {},
1515 }
16 const args = try init.minimal.args.toSlice(init.arena.allocator());
17 const tmp_dir_path = args[1];
18
19 var tmp_dir = try Io.Dir.cwd().openDir(init.io, tmp_dir_path, .{});
20 defer tmp_dir.close(init.io);
1621
1722 try test_chdir_self();
1823 try test_chdir_absolute();
19 try test_chdir_relative(init.gpa, init.io);
24 try test_chdir_relative(init.gpa, init.io, tmp_dir);
2025}
2126
2227// get current working directory and expect it to match given path
......@@ -47,23 +52,22 @@ fn test_chdir_absolute() !void {
4752 try expect_cwd(parent);
4853}
4954
50fn test_chdir_relative(gpa: Allocator, io: Io) !void {
51 var tmp = tmpDir(io, .{});
52 defer tmp.cleanup(io);
55fn test_chdir_relative(gpa: Allocator, io: Io, tmp_dir: Io.Dir) !void {
56 const subdir_path = "subdir";
57 try tmp_dir.createDir(io, "subdir", .default_dir);
5358
54 // Use the tmpDir parent_dir as the "base" for the test. Then cd into the child
55 try std.process.setCurrentDir(io, tmp.parent_dir);
59 // Use the tmp dir as the "base" for the test. Then cd into the child
60 try std.process.setCurrentDir(io, tmp_dir);
5661
5762 // Capture base working directory path, to build expected full path
5863 var base_cwd_buf: [path_max]u8 = undefined;
5964 const base_cwd = try std.posix.getcwd(base_cwd_buf[0..]);
6065
61 const relative_dir_name = &tmp.sub_path;
62 const expected_path = try std.fs.path.resolve(gpa, &.{ base_cwd, relative_dir_name });
66 const expected_path = try std.fs.path.resolve(gpa, &.{ base_cwd, subdir_path });
6367 defer gpa.free(expected_path);
6468
6569 // change current working directory to new test directory
66 try std.Io.Threaded.chdir(relative_dir_name);
70 try std.Io.Threaded.chdir(subdir_path);
6771
6872 var new_cwd_buf: [path_max]u8 = undefined;
6973 const new_cwd = try std.posix.getcwd(new_cwd_buf[0..]);
......@@ -74,41 +78,3 @@ fn test_chdir_relative(gpa: Allocator, io: Io) !void {
7478
7579 try std.testing.expectEqualStrings(expected_path, resolved_cwd);
7680}
77
78pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
79 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
80 std.crypto.random.bytes(&random_bytes);
81 var sub_path: [TmpDir.sub_path_len]u8 = undefined;
82 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
83
84 const cwd = Io.Dir.cwd();
85 var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
86 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
87 defer cache_dir.close(io);
88 const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
89 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
90 const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
91 @panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
92
93 return .{
94 .dir = dir,
95 .parent_dir = parent_dir,
96 .sub_path = sub_path,
97 };
98}
99
100pub const TmpDir = struct {
101 dir: Io.Dir,
102 parent_dir: Io.Dir,
103 sub_path: [sub_path_len]u8,
104
105 const random_bytes_count = 12;
106 const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
107
108 pub fn cleanup(self: *TmpDir, io: Io) void {
109 self.dir.close(io);
110 self.parent_dir.deleteTree(io, &self.sub_path) catch {};
111 self.parent_dir.close(io);
112 self.* = undefined;
113 }
114};
test/standalone/posix/relpaths.zig+12-47
......@@ -11,16 +11,19 @@ pub fn main(init: std.process.Init) !void {
1111
1212 const io = init.io;
1313
14 var tmp = tmpDir(io, .{});
15 defer tmp.cleanup(io);
14 const args = try init.minimal.args.toSlice(init.arena.allocator());
15 const tmp_dir_path = args[1];
16
17 var tmp_dir = try Io.Dir.cwd().openDir(io, tmp_dir_path, .{});
18 defer tmp_dir.close(io);
1619
1720 // Want to test relative paths, so cd into the tmpdir for these tests
18 try std.process.setCurrentDir(io, tmp.dir);
21 try std.process.setCurrentDir(io, tmp_dir);
1922
20 try test_link(io, tmp);
23 try test_link(io, tmp_dir);
2124}
2225
23fn test_link(io: Io, tmp: TmpDir) !void {
26fn test_link(io: Io, tmp_dir: Io.Dir) !void {
2427 switch (builtin.target.os.tag) {
2528 .linux, .illumos => {},
2629 else => return,
......@@ -29,16 +32,16 @@ fn test_link(io: Io, tmp: TmpDir) !void {
2932 const target_name = "link-target";
3033 const link_name = "newlink";
3134
32 try tmp.dir.writeFile(io, .{ .sub_path = target_name, .data = "example" });
35 try tmp_dir.writeFile(io, .{ .sub_path = target_name, .data = "example" });
3336
34 // Test 1: create the relative link from inside tmp
37 // Test 1: create the relative link from inside tmp_dir
3538 try Io.Dir.hardLink(.cwd(), target_name, .cwd(), link_name, io, .{});
3639
3740 // Verify
38 const efd = try tmp.dir.openFile(io, target_name, .{});
41 const efd = try tmp_dir.openFile(io, target_name, .{});
3942 defer efd.close(io);
4043
41 const nfd = try tmp.dir.openFile(io, link_name, .{});
44 const nfd = try tmp_dir.openFile(io, link_name, .{});
4245 defer nfd.close(io);
4346
4447 {
......@@ -55,41 +58,3 @@ fn test_link(io: Io, tmp: TmpDir) !void {
5558 try std.testing.expectEqual(1, e_stat.nlink);
5659 }
5760}
58
59pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
60 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
61 std.crypto.random.bytes(&random_bytes);
62 var sub_path: [TmpDir.sub_path_len]u8 = undefined;
63 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
64
65 const cwd = Io.Dir.cwd();
66 var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
67 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
68 defer cache_dir.close(io);
69 const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
70 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
71 const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
72 @panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
73
74 return .{
75 .dir = dir,
76 .parent_dir = parent_dir,
77 .sub_path = sub_path,
78 };
79}
80
81pub const TmpDir = struct {
82 dir: Io.Dir,
83 parent_dir: Io.Dir,
84 sub_path: [sub_path_len]u8,
85
86 const random_bytes_count = 12;
87 const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
88
89 pub fn cleanup(self: *TmpDir, io: Io) void {
90 self.dir.close(io);
91 self.parent_dir.deleteTree(io, &self.sub_path) catch {};
92 self.parent_dir.close(io);
93 self.* = undefined;
94 }
95};
test/standalone/windows_bat_args/build.zig+18-2
......@@ -19,6 +19,22 @@ pub fn build(b: *std.Build) !void {
1919 }),
2020 });
2121
22 const bat_files = b.addWriteFiles();
23 {
24 const echo_args_basename = "echo-args.exe";
25 const preamble = std.fmt.allocPrint(b.allocator,
26 \\@echo off
27 \\"{s}"
28 , .{echo_args_basename}) catch @panic("OOM");
29 // Trailing newline intentionally omitted above so we can add args.
30
31 _ = bat_files.add("args1.bat", std.mem.concat(b.allocator, u8, &.{ preamble, " %*" }) catch @panic("OOM"));
32 _ = bat_files.add("args2.bat", std.mem.concat(b.allocator, u8, &.{ preamble, " %1 %2 %3 %4 %5 %6 %7 %8 %9" }) catch @panic("OOM"));
33 _ = bat_files.add("args3.bat", std.mem.concat(b.allocator, u8, &.{ preamble, " \"%~1\" \"%~2\" \"%~3\" \"%~4\" \"%~5\" \"%~6\" \"%~7\" \"%~8\" \"%~9\"" }) catch @panic("OOM"));
34
35 _ = bat_files.addCopyFile(echo_args.getEmittedBin(), echo_args_basename);
36 }
37
2238 const test_exe = b.addExecutable(.{
2339 .name = "test",
2440 .root_module = b.createModule(.{
......@@ -29,7 +45,7 @@ pub fn build(b: *std.Build) !void {
2945 });
3046
3147 const run = b.addRunArtifact(test_exe);
32 run.addArtifactArg(echo_args);
48 run.setCwd(bat_files.getDirectory());
3349 run.expectExitCode(0);
3450 run.skip_foreign_checks = true;
3551
......@@ -55,7 +71,7 @@ pub fn build(b: *std.Build) !void {
5571 const fuzz_seed_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_seed}) catch @panic("oom");
5672
5773 const fuzz_run = b.addRunArtifact(fuzz);
58 fuzz_run.addArtifactArg(echo_args);
74 fuzz_run.setCwd(bat_files.getDirectory());
5975 fuzz_run.addArgs(&.{ fuzz_iterations_arg, fuzz_seed_arg });
6076 fuzz_run.expectExitCode(0);
6177 fuzz_run.skip_foreign_checks = true;
test/standalone/windows_bat_args/fuzz.zig-70
......@@ -11,7 +11,6 @@ pub fn main(init: std.process.Init) !void {
1111 var it = try init.minimal.args.iterateAllocator(gpa);
1212 defer it.deinit();
1313 _ = it.next() orelse unreachable; // skip binary name
14 const child_exe_path_orig = it.next() orelse unreachable;
1514
1615 const iterations: u64 = iterations: {
1716 const arg = it.next() orelse "0";
......@@ -37,37 +36,6 @@ pub fn main(init: std.process.Init) !void {
3736 std.debug.print("rand seed: {}\n", .{seed});
3837 }
3938
40 var tmp = tmpDir(io, .{});
41 defer tmp.cleanup(io);
42
43 try std.process.setCurrentDir(io, tmp.dir);
44 defer std.process.setCurrentDir(io, tmp.parent_dir) catch {};
45
46 // `child_exe_path_orig` might be relative; make it relative to our new cwd.
47 const child_exe_path = try std.fs.path.resolve(gpa, &.{ "..\\..\\..", child_exe_path_orig });
48 defer gpa.free(child_exe_path);
49
50 var buf: std.ArrayList(u8) = .empty;
51 defer buf.deinit(gpa);
52 try buf.print(gpa,
53 \\@echo off
54 \\"{s}"
55 , .{child_exe_path});
56 // Trailing newline intentionally omitted above so we can add args.
57 const preamble_len = buf.items.len;
58
59 try buf.appendSlice(gpa, " %*");
60 try tmp.dir.writeFile(io, .{ .sub_path = "args1.bat", .data = buf.items });
61 buf.shrinkRetainingCapacity(preamble_len);
62
63 try buf.appendSlice(gpa, " %1 %2 %3 %4 %5 %6 %7 %8 %9");
64 try tmp.dir.writeFile(io, .{ .sub_path = "args2.bat", .data = buf.items });
65 buf.shrinkRetainingCapacity(preamble_len);
66
67 try buf.appendSlice(gpa, " \"%~1\" \"%~2\" \"%~3\" \"%~4\" \"%~5\" \"%~6\" \"%~7\" \"%~8\" \"%~9\"");
68 try tmp.dir.writeFile(io, .{ .sub_path = "args3.bat", .data = buf.items });
69 buf.shrinkRetainingCapacity(preamble_len);
70
7139 var i: u64 = 0;
7240 while (iterations == 0 or i < iterations) {
7341 const rand_arg = try randomArg(gpa, rand);
......@@ -163,41 +131,3 @@ fn randomArg(gpa: Allocator, rand: std.Random) ![]const u8 {
163131
164132 return buf.toOwnedSlice(gpa);
165133}
166
167pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
168 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
169 std.crypto.random.bytes(&random_bytes);
170 var sub_path: [TmpDir.sub_path_len]u8 = undefined;
171 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
172
173 const cwd = Io.Dir.cwd();
174 var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
175 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
176 defer cache_dir.close(io);
177 const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
178 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
179 const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
180 @panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
181
182 return .{
183 .dir = dir,
184 .parent_dir = parent_dir,
185 .sub_path = sub_path,
186 };
187}
188
189pub const TmpDir = struct {
190 dir: Io.Dir,
191 parent_dir: Io.Dir,
192 sub_path: [sub_path_len]u8,
193
194 const random_bytes_count = 12;
195 const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
196
197 pub fn cleanup(self: *TmpDir, io: Io) void {
198 self.dir.close(io);
199 self.parent_dir.deleteTree(io, &self.sub_path) catch {};
200 self.parent_dir.close(io);
201 self.* = undefined;
202 }
203};
test/standalone/windows_bat_args/test.zig+1-75
......@@ -6,42 +6,6 @@ pub fn main(init: std.process.Init) !void {
66 const gpa = init.gpa;
77 const io = init.io;
88
9 var it = try init.minimal.args.iterateAllocator(gpa);
10 defer it.deinit();
11 _ = it.next() orelse unreachable; // skip binary name
12 const child_exe_path_orig = it.next() orelse unreachable;
13
14 var tmp = tmpDir(io, .{});
15 defer tmp.cleanup(io);
16
17 try std.process.setCurrentDir(io, tmp.dir);
18 defer std.process.setCurrentDir(io, tmp.parent_dir) catch {};
19
20 // `child_exe_path_orig` might be relative; make it relative to our new cwd.
21 const child_exe_path = try std.fs.path.resolve(gpa, &.{ "..\\..\\..", child_exe_path_orig });
22 defer gpa.free(child_exe_path);
23
24 var buf: std.ArrayList(u8) = .empty;
25 defer buf.deinit(gpa);
26 try buf.print(gpa,
27 \\@echo off
28 \\"{s}"
29 , .{child_exe_path});
30 // Trailing newline intentionally omitted above so we can add args.
31 const preamble_len = buf.items.len;
32
33 try buf.appendSlice(gpa, " %*");
34 try tmp.dir.writeFile(io, .{ .sub_path = "args1.bat", .data = buf.items });
35 buf.shrinkRetainingCapacity(preamble_len);
36
37 try buf.appendSlice(gpa, " %1 %2 %3 %4 %5 %6 %7 %8 %9");
38 try tmp.dir.writeFile(io, .{ .sub_path = "args2.bat", .data = buf.items });
39 buf.shrinkRetainingCapacity(preamble_len);
40
41 try buf.appendSlice(gpa, " \"%~1\" \"%~2\" \"%~3\" \"%~4\" \"%~5\" \"%~6\" \"%~7\" \"%~8\" \"%~9\"");
42 try tmp.dir.writeFile(io, .{ .sub_path = "args3.bat", .data = buf.items });
43 buf.shrinkRetainingCapacity(preamble_len);
44
459 // Test cases are from https://github.com/rust-lang/rust/blob/master/tests/ui/std/windows-bat-args.rs
4610 try testExecError(error.InvalidBatchScriptArg, gpa, io, &.{"\x00"});
4711 try testExecError(error.InvalidBatchScriptArg, gpa, io, &.{"\n"});
......@@ -119,7 +83,7 @@ pub fn main(init: std.process.Init) !void {
11983 try testExec(gpa, io, &.{"%FOO%"}, &env);
12084
12185 // Ensure that none of the `>file.txt`s have caused file.txt to be created
122 try std.testing.expectError(error.FileNotFound, tmp.dir.access(io, "file.txt", .{}));
86 try std.testing.expectError(error.FileNotFound, Io.Dir.cwd().access(io, "file.txt", .{}));
12387}
12488
12589fn testExecError(err: anyerror, gpa: Allocator, io: Io, args: []const []const u8) !void {
......@@ -160,41 +124,3 @@ fn testExecBat(gpa: Allocator, io: Io, bat: []const u8, args: []const []const u8
160124 i += 1;
161125 }
162126}
163
164pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
165 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
166 std.crypto.random.bytes(&random_bytes);
167 var sub_path: [TmpDir.sub_path_len]u8 = undefined;
168 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
169
170 const cwd = Io.Dir.cwd();
171 var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
172 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
173 defer cache_dir.close(io);
174 const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
175 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
176 const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
177 @panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
178
179 return .{
180 .dir = dir,
181 .parent_dir = parent_dir,
182 .sub_path = sub_path,
183 };
184}
185
186pub const TmpDir = struct {
187 dir: Io.Dir,
188 parent_dir: Io.Dir,
189 sub_path: [sub_path_len]u8,
190
191 const random_bytes_count = 12;
192 const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
193
194 pub fn cleanup(self: *TmpDir, io: Io) void {
195 self.dir.close(io);
196 self.parent_dir.deleteTree(io, &self.sub_path) catch {};
197 self.parent_dir.close(io);
198 self.* = undefined;
199 }
200};
test/standalone/windows_spawn/build.zig+1
......@@ -30,6 +30,7 @@ pub fn build(b: *std.Build) void {
3030
3131 const run = b.addRunArtifact(main);
3232 run.addArtifactArg(hello);
33 run.addDirectoryArg(b.tmpPath());
3334 run.expectExitCode(0);
3435 run.skip_foreign_checks = true;
3536
test/standalone/windows_spawn/main.zig+20-55
......@@ -9,16 +9,19 @@ pub fn main(init: std.process.Init) !void {
99 const gpa = init.gpa;
1010 const io = init.io;
1111 const process_cwd_path = try std.process.getCwdAlloc(init.arena.allocator());
12 var initial_process_cwd = try Io.Dir.cwd().openDir(io, ".", .{});
13 defer initial_process_cwd.close(io);
1214
1315 var it = try init.minimal.args.iterateAllocator(gpa);
1416 defer it.deinit();
1517 _ = it.next() orelse unreachable; // skip binary name
1618 const hello_exe_cache_path = it.next() orelse unreachable;
19 const tmp_dir_path = it.next() orelse unreachable;
1720
18 var tmp = tmpDir(io, .{});
19 defer tmp.cleanup(io);
21 var tmp_dir = try Io.Dir.cwd().openDir(io, tmp_dir_path, .{});
22 defer tmp_dir.close(io);
2023
21 const tmp_absolute_path = try tmp.dir.realPathFileAlloc(io, ".", gpa);
24 const tmp_absolute_path = try tmp_dir.realPathFileAlloc(io, ".", gpa);
2225 defer gpa.free(tmp_absolute_path);
2326 const tmp_absolute_path_w = try std.unicode.utf8ToUtf16LeAllocZ(gpa, tmp_absolute_path);
2427 defer gpa.free(tmp_absolute_path_w);
......@@ -51,7 +54,7 @@ pub fn main(init: std.process.Init) !void {
5154 ) == windows.TRUE);
5255
5356 // Move hello.exe into the tmp dir which is now added to the path
54 try Io.Dir.cwd().copyFile(hello_exe_cache_path, tmp.dir, "hello.exe", io, .{});
57 try Io.Dir.cwd().copyFile(hello_exe_cache_path, tmp_dir, "hello.exe", io, .{});
5558
5659 // with extension should find the .exe (case insensitive)
5760 try testExec(gpa, io, "HeLLo.exe", "hello from exe\n");
......@@ -61,9 +64,9 @@ pub fn main(init: std.process.Init) !void {
6164 try std.testing.expectError(error.FileNotFound, testExecWithCwd(gpa, io, "hello.exe", "missing_dir", ""));
6265
6366 // now add a .bat
64 try tmp.dir.writeFile(io, .{ .sub_path = "hello.bat", .data = "@echo hello from bat" });
67 try tmp_dir.writeFile(io, .{ .sub_path = "hello.bat", .data = "@echo hello from bat" });
6568 // and a .cmd
66 try tmp.dir.writeFile(io, .{ .sub_path = "hello.cmd", .data = "@echo hello from cmd" });
69 try tmp_dir.writeFile(io, .{ .sub_path = "hello.cmd", .data = "@echo hello from cmd" });
6770
6871 // with extension should find the .bat (case insensitive)
6972 try testExec(gpa, io, "heLLo.bat", "hello from bat\r\n");
......@@ -73,15 +76,15 @@ pub fn main(init: std.process.Init) !void {
7376 try testExec(gpa, io, "heLLo", "hello from exe\n");
7477
7578 // now rename the exe to not have an extension
76 try renameExe(tmp.dir, io, "hello.exe", "hello");
79 try renameExe(tmp_dir, io, "hello.exe", "hello");
7780
7881 // with extension should now fail
7982 try testExecError(error.FileNotFound, gpa, io, "hello.exe");
8083 // without extension should succeed (case insensitive)
8184 try testExec(gpa, io, "heLLo", "hello from exe\n");
8285
83 try tmp.dir.createDir(io, "something", .default_dir);
84 try renameExe(tmp.dir, io, "hello", "something/hello.exe");
86 try tmp_dir.createDir(io, "something", .default_dir);
87 try renameExe(tmp_dir, io, "hello", "something/hello.exe");
8588
8689 const relative_path_no_ext = try std.fs.path.join(gpa, &.{ tmp_relative_path, "something/hello" });
8790 defer gpa.free(relative_path_no_ext);
......@@ -95,7 +98,7 @@ pub fn main(init: std.process.Init) !void {
9598 try testExec(gpa, io, "heLLo", "hello from bat\r\n");
9699
97100 // Add a hello.exe that is not a valid executable
98 try tmp.dir.writeFile(io, .{ .sub_path = "hello.exe", .data = "invalid" });
101 try tmp_dir.writeFile(io, .{ .sub_path = "hello.exe", .data = "invalid" });
99102
100103 // Trying to execute it with extension will give InvalidExe. This is a special
101104 // case for .EXE extensions, where if they ever try to get executed but they are
......@@ -108,14 +111,14 @@ pub fn main(init: std.process.Init) !void {
108111 try testExecError(error.InvalidExe, gpa, io, "hello");
109112
110113 // If we now rename hello.exe to have no extension, it will behave differently
111 try renameExe(tmp.dir, io, "hello.exe", "hello");
114 try renameExe(tmp_dir, io, "hello.exe", "hello");
112115
113116 // Now, trying to execute it without an extension should treat InvalidExe as recoverable
114117 // and skip over it and find hello.bat and execute that
115118 try testExec(gpa, io, "hello", "hello from bat\r\n");
116119
117120 // If we rename the invalid exe to something else
118 try renameExe(tmp.dir, io, "hello", "goodbye");
121 try renameExe(tmp_dir, io, "hello", "goodbye");
119122 // Then we should now get FileNotFound when trying to execute 'goodbye',
120123 // since that is what the original error will be after searching for 'goodbye'
121124 // in the cwd. It will try to execute 'goodbye' from the PATH but the InvalidExe error
......@@ -123,8 +126,8 @@ pub fn main(init: std.process.Init) !void {
123126 try testExecError(error.FileNotFound, gpa, io, "goodbye");
124127
125128 // Now let's set the tmp dir as the cwd and set the path only include the "something" sub dir
126 try std.process.setCurrentDir(io, tmp.dir);
127 defer std.process.setCurrentDir(io, tmp.parent_dir) catch {};
129 try std.process.setCurrentDir(io, tmp_dir);
130 defer std.process.setCurrentDir(io, initial_process_cwd) catch {};
128131 const something_subdir_abs_path = try std.mem.concatWithSentinel(gpa, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);
129132 defer gpa.free(something_subdir_abs_path);
130133
......@@ -141,7 +144,7 @@ pub fn main(init: std.process.Init) !void {
141144 try testExec(gpa, io, "hello", "hello from bat\r\n");
142145
143146 // If we rename something/hello.exe to something/goodbye.exe
144 try renameExe(tmp.dir, io, "something/hello.exe", "something/goodbye.exe");
147 try renameExe(tmp_dir, io, "something/hello.exe", "something/goodbye.exe");
145148 // And try to execute goodbye, then the one in something should be found
146149 // since the one in cwd is an invalid executable
147150 try testExec(gpa, io, "goodbye", "hello from exe\n");
......@@ -183,10 +186,10 @@ pub fn main(init: std.process.Init) !void {
183186 try testExec(gpa, io, "goodbye", "hello from exe\n");
184187
185188 // now make sure we can launch executables "outside" of the cwd
186 var subdir_cwd = try tmp.dir.openDir(io, denormed_something_subdir_wtf8, .{});
189 var subdir_cwd = try tmp_dir.openDir(io, denormed_something_subdir_wtf8, .{});
187190 defer subdir_cwd.close(io);
188191
189 try renameExe(tmp.dir, io, "something/goodbye.exe", "hello.exe");
192 try renameExe(tmp_dir, io, "something/goodbye.exe", "hello.exe");
190193 try std.process.setCurrentDir(io, subdir_cwd);
191194
192195 // clear the PATH again
......@@ -232,41 +235,3 @@ fn renameExe(dir: Io.Dir, io: Io, old_sub_path: []const u8, new_sub_path: []cons
232235 else => |e| return e,
233236 };
234237}
235
236pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
237 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
238 std.crypto.random.bytes(&random_bytes);
239 var sub_path: [TmpDir.sub_path_len]u8 = undefined;
240 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
241
242 const cwd = Io.Dir.cwd();
243 var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
244 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
245 defer cache_dir.close(io);
246 const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
247 @panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
248 const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
249 @panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
250
251 return .{
252 .dir = dir,
253 .parent_dir = parent_dir,
254 .sub_path = sub_path,
255 };
256}
257
258pub const TmpDir = struct {
259 dir: Io.Dir,
260 parent_dir: Io.Dir,
261 sub_path: [sub_path_len]u8,
262
263 const random_bytes_count = 12;
264 const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
265
266 pub fn cleanup(self: *TmpDir, io: Io) void {
267 self.dir.close(io);
268 self.parent_dir.deleteTree(io, &self.sub_path) catch {};
269 self.parent_dir.close(io);
270 self.* = undefined;
271 }
272};