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

This commit is contained in:
Ryan Liptak
2026-01-05 02:04:28 -08:00
committed by Andrew Kelley
parent 50422d5c37
commit 52141fe85f
8 changed files with 71 additions and 296 deletions
+6
View File
@@ -4,11 +4,13 @@ const builtin = @import("builtin");
const Case = struct {
src_path: []const u8,
set_env_vars: bool = false,
make_tmp_dir: bool = false,
};
const cases = [_]Case{
.{
.src_path = "cwd.zig",
.make_tmp_dir = true,
},
.{
.src_path = "getenv.zig",
@@ -19,6 +21,7 @@ const cases = [_]Case{
},
.{
.src_path = "relpaths.zig",
.make_tmp_dir = true,
},
};
@@ -69,6 +72,9 @@ fn run_exe(b: *std.Build, optimize: std.builtin.OptimizeMode, case: *const Case,
});
const run_cmd = b.addRunArtifact(exe);
if (case.make_tmp_dir) {
run_cmd.addDirectoryArg(b.tmpPath());
}
if (case.set_env_vars) {
run_cmd.setEnvironmentVariable("ZIG_TEST_POSIX_1EQ", "test=variable");
+13 -47
View File
@@ -13,10 +13,15 @@ pub fn main(init: std.process.Init) !void {
.windows => return, // POSIX is not implemented by Windows
else => {},
}
const args = try init.minimal.args.toSlice(init.arena.allocator());
const tmp_dir_path = args[1];
var tmp_dir = try Io.Dir.cwd().openDir(init.io, tmp_dir_path, .{});
defer tmp_dir.close(init.io);
try test_chdir_self();
try test_chdir_absolute();
try test_chdir_relative(init.gpa, init.io);
try test_chdir_relative(init.gpa, init.io, tmp_dir);
}
// get current working directory and expect it to match given path
@@ -47,23 +52,22 @@ fn test_chdir_absolute() !void {
try expect_cwd(parent);
}
fn test_chdir_relative(gpa: Allocator, io: Io) !void {
var tmp = tmpDir(io, .{});
defer tmp.cleanup(io);
fn test_chdir_relative(gpa: Allocator, io: Io, tmp_dir: Io.Dir) !void {
const subdir_path = "subdir";
try tmp_dir.createDir(io, "subdir", .default_dir);
// Use the tmpDir parent_dir as the "base" for the test. Then cd into the child
try std.process.setCurrentDir(io, tmp.parent_dir);
// Use the tmp dir as the "base" for the test. Then cd into the child
try std.process.setCurrentDir(io, tmp_dir);
// Capture base working directory path, to build expected full path
var base_cwd_buf: [path_max]u8 = undefined;
const base_cwd = try std.posix.getcwd(base_cwd_buf[0..]);
const relative_dir_name = &tmp.sub_path;
const expected_path = try std.fs.path.resolve(gpa, &.{ base_cwd, relative_dir_name });
const expected_path = try std.fs.path.resolve(gpa, &.{ base_cwd, subdir_path });
defer gpa.free(expected_path);
// change current working directory to new test directory
try std.Io.Threaded.chdir(relative_dir_name);
try std.Io.Threaded.chdir(subdir_path);
var new_cwd_buf: [path_max]u8 = undefined;
const new_cwd = try std.posix.getcwd(new_cwd_buf[0..]);
@@ -74,41 +78,3 @@ fn test_chdir_relative(gpa: Allocator, io: Io) !void {
try std.testing.expectEqualStrings(expected_path, resolved_cwd);
}
pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
std.crypto.random.bytes(&random_bytes);
var sub_path: [TmpDir.sub_path_len]u8 = undefined;
_ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
const cwd = Io.Dir.cwd();
var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
defer cache_dir.close(io);
const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
@panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
return .{
.dir = dir,
.parent_dir = parent_dir,
.sub_path = sub_path,
};
}
pub const TmpDir = struct {
dir: Io.Dir,
parent_dir: Io.Dir,
sub_path: [sub_path_len]u8,
const random_bytes_count = 12;
const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
pub fn cleanup(self: *TmpDir, io: Io) void {
self.dir.close(io);
self.parent_dir.deleteTree(io, &self.sub_path) catch {};
self.parent_dir.close(io);
self.* = undefined;
}
};
+12 -47
View File
@@ -11,16 +11,19 @@ pub fn main(init: std.process.Init) !void {
const io = init.io;
var tmp = tmpDir(io, .{});
defer tmp.cleanup(io);
const args = try init.minimal.args.toSlice(init.arena.allocator());
const tmp_dir_path = args[1];
var tmp_dir = try Io.Dir.cwd().openDir(io, tmp_dir_path, .{});
defer tmp_dir.close(io);
// Want to test relative paths, so cd into the tmpdir for these tests
try std.process.setCurrentDir(io, tmp.dir);
try std.process.setCurrentDir(io, tmp_dir);
try test_link(io, tmp);
try test_link(io, tmp_dir);
}
fn test_link(io: Io, tmp: TmpDir) !void {
fn test_link(io: Io, tmp_dir: Io.Dir) !void {
switch (builtin.target.os.tag) {
.linux, .illumos => {},
else => return,
@@ -29,16 +32,16 @@ fn test_link(io: Io, tmp: TmpDir) !void {
const target_name = "link-target";
const link_name = "newlink";
try tmp.dir.writeFile(io, .{ .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
// Test 1: create the relative link from inside tmp_dir
try Io.Dir.hardLink(.cwd(), target_name, .cwd(), link_name, io, .{});
// Verify
const efd = try tmp.dir.openFile(io, target_name, .{});
const efd = try tmp_dir.openFile(io, target_name, .{});
defer efd.close(io);
const nfd = try tmp.dir.openFile(io, link_name, .{});
const nfd = try tmp_dir.openFile(io, link_name, .{});
defer nfd.close(io);
{
@@ -55,41 +58,3 @@ fn test_link(io: Io, tmp: TmpDir) !void {
try std.testing.expectEqual(1, e_stat.nlink);
}
}
pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
std.crypto.random.bytes(&random_bytes);
var sub_path: [TmpDir.sub_path_len]u8 = undefined;
_ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
const cwd = Io.Dir.cwd();
var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
defer cache_dir.close(io);
const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
@panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
return .{
.dir = dir,
.parent_dir = parent_dir,
.sub_path = sub_path,
};
}
pub const TmpDir = struct {
dir: Io.Dir,
parent_dir: Io.Dir,
sub_path: [sub_path_len]u8,
const random_bytes_count = 12;
const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
pub fn cleanup(self: *TmpDir, io: Io) void {
self.dir.close(io);
self.parent_dir.deleteTree(io, &self.sub_path) catch {};
self.parent_dir.close(io);
self.* = undefined;
}
};
+18 -2
View File
@@ -19,6 +19,22 @@ pub fn build(b: *std.Build) !void {
}),
});
const bat_files = b.addWriteFiles();
{
const echo_args_basename = "echo-args.exe";
const preamble = std.fmt.allocPrint(b.allocator,
\\@echo off
\\"{s}"
, .{echo_args_basename}) catch @panic("OOM");
// Trailing newline intentionally omitted above so we can add args.
_ = bat_files.add("args1.bat", std.mem.concat(b.allocator, u8, &.{ preamble, " %*" }) catch @panic("OOM"));
_ = bat_files.add("args2.bat", std.mem.concat(b.allocator, u8, &.{ preamble, " %1 %2 %3 %4 %5 %6 %7 %8 %9" }) catch @panic("OOM"));
_ = bat_files.add("args3.bat", std.mem.concat(b.allocator, u8, &.{ preamble, " \"%~1\" \"%~2\" \"%~3\" \"%~4\" \"%~5\" \"%~6\" \"%~7\" \"%~8\" \"%~9\"" }) catch @panic("OOM"));
_ = bat_files.addCopyFile(echo_args.getEmittedBin(), echo_args_basename);
}
const test_exe = b.addExecutable(.{
.name = "test",
.root_module = b.createModule(.{
@@ -29,7 +45,7 @@ pub fn build(b: *std.Build) !void {
});
const run = b.addRunArtifact(test_exe);
run.addArtifactArg(echo_args);
run.setCwd(bat_files.getDirectory());
run.expectExitCode(0);
run.skip_foreign_checks = true;
@@ -55,7 +71,7 @@ pub fn build(b: *std.Build) !void {
const fuzz_seed_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_seed}) catch @panic("oom");
const fuzz_run = b.addRunArtifact(fuzz);
fuzz_run.addArtifactArg(echo_args);
fuzz_run.setCwd(bat_files.getDirectory());
fuzz_run.addArgs(&.{ fuzz_iterations_arg, fuzz_seed_arg });
fuzz_run.expectExitCode(0);
fuzz_run.skip_foreign_checks = true;
-70
View File
@@ -11,7 +11,6 @@ pub fn main(init: std.process.Init) !void {
var it = try init.minimal.args.iterateAllocator(gpa);
defer it.deinit();
_ = it.next() orelse unreachable; // skip binary name
const child_exe_path_orig = it.next() orelse unreachable;
const iterations: u64 = iterations: {
const arg = it.next() orelse "0";
@@ -37,37 +36,6 @@ pub fn main(init: std.process.Init) !void {
std.debug.print("rand seed: {}\n", .{seed});
}
var tmp = tmpDir(io, .{});
defer tmp.cleanup(io);
try std.process.setCurrentDir(io, tmp.dir);
defer std.process.setCurrentDir(io, tmp.parent_dir) catch {};
// `child_exe_path_orig` might be relative; make it relative to our new cwd.
const child_exe_path = try std.fs.path.resolve(gpa, &.{ "..\\..\\..", child_exe_path_orig });
defer gpa.free(child_exe_path);
var buf: std.ArrayList(u8) = .empty;
defer buf.deinit(gpa);
try buf.print(gpa,
\\@echo off
\\"{s}"
, .{child_exe_path});
// Trailing newline intentionally omitted above so we can add args.
const preamble_len = buf.items.len;
try buf.appendSlice(gpa, " %*");
try tmp.dir.writeFile(io, .{ .sub_path = "args1.bat", .data = buf.items });
buf.shrinkRetainingCapacity(preamble_len);
try buf.appendSlice(gpa, " %1 %2 %3 %4 %5 %6 %7 %8 %9");
try tmp.dir.writeFile(io, .{ .sub_path = "args2.bat", .data = buf.items });
buf.shrinkRetainingCapacity(preamble_len);
try buf.appendSlice(gpa, " \"%~1\" \"%~2\" \"%~3\" \"%~4\" \"%~5\" \"%~6\" \"%~7\" \"%~8\" \"%~9\"");
try tmp.dir.writeFile(io, .{ .sub_path = "args3.bat", .data = buf.items });
buf.shrinkRetainingCapacity(preamble_len);
var i: u64 = 0;
while (iterations == 0 or i < iterations) {
const rand_arg = try randomArg(gpa, rand);
@@ -163,41 +131,3 @@ fn randomArg(gpa: Allocator, rand: std.Random) ![]const u8 {
return buf.toOwnedSlice(gpa);
}
pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
std.crypto.random.bytes(&random_bytes);
var sub_path: [TmpDir.sub_path_len]u8 = undefined;
_ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
const cwd = Io.Dir.cwd();
var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
defer cache_dir.close(io);
const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
@panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
return .{
.dir = dir,
.parent_dir = parent_dir,
.sub_path = sub_path,
};
}
pub const TmpDir = struct {
dir: Io.Dir,
parent_dir: Io.Dir,
sub_path: [sub_path_len]u8,
const random_bytes_count = 12;
const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
pub fn cleanup(self: *TmpDir, io: Io) void {
self.dir.close(io);
self.parent_dir.deleteTree(io, &self.sub_path) catch {};
self.parent_dir.close(io);
self.* = undefined;
}
};
+1 -75
View File
@@ -6,42 +6,6 @@ pub fn main(init: std.process.Init) !void {
const gpa = init.gpa;
const io = init.io;
var it = try init.minimal.args.iterateAllocator(gpa);
defer it.deinit();
_ = it.next() orelse unreachable; // skip binary name
const child_exe_path_orig = it.next() orelse unreachable;
var tmp = tmpDir(io, .{});
defer tmp.cleanup(io);
try std.process.setCurrentDir(io, tmp.dir);
defer std.process.setCurrentDir(io, tmp.parent_dir) catch {};
// `child_exe_path_orig` might be relative; make it relative to our new cwd.
const child_exe_path = try std.fs.path.resolve(gpa, &.{ "..\\..\\..", child_exe_path_orig });
defer gpa.free(child_exe_path);
var buf: std.ArrayList(u8) = .empty;
defer buf.deinit(gpa);
try buf.print(gpa,
\\@echo off
\\"{s}"
, .{child_exe_path});
// Trailing newline intentionally omitted above so we can add args.
const preamble_len = buf.items.len;
try buf.appendSlice(gpa, " %*");
try tmp.dir.writeFile(io, .{ .sub_path = "args1.bat", .data = buf.items });
buf.shrinkRetainingCapacity(preamble_len);
try buf.appendSlice(gpa, " %1 %2 %3 %4 %5 %6 %7 %8 %9");
try tmp.dir.writeFile(io, .{ .sub_path = "args2.bat", .data = buf.items });
buf.shrinkRetainingCapacity(preamble_len);
try buf.appendSlice(gpa, " \"%~1\" \"%~2\" \"%~3\" \"%~4\" \"%~5\" \"%~6\" \"%~7\" \"%~8\" \"%~9\"");
try tmp.dir.writeFile(io, .{ .sub_path = "args3.bat", .data = buf.items });
buf.shrinkRetainingCapacity(preamble_len);
// Test cases are from https://github.com/rust-lang/rust/blob/master/tests/ui/std/windows-bat-args.rs
try testExecError(error.InvalidBatchScriptArg, gpa, io, &.{"\x00"});
try testExecError(error.InvalidBatchScriptArg, gpa, io, &.{"\n"});
@@ -119,7 +83,7 @@ pub fn main(init: std.process.Init) !void {
try testExec(gpa, io, &.{"%FOO%"}, &env);
// Ensure that none of the `>file.txt`s have caused file.txt to be created
try std.testing.expectError(error.FileNotFound, tmp.dir.access(io, "file.txt", .{}));
try std.testing.expectError(error.FileNotFound, Io.Dir.cwd().access(io, "file.txt", .{}));
}
fn 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
i += 1;
}
}
pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
std.crypto.random.bytes(&random_bytes);
var sub_path: [TmpDir.sub_path_len]u8 = undefined;
_ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
const cwd = Io.Dir.cwd();
var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
defer cache_dir.close(io);
const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
@panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
return .{
.dir = dir,
.parent_dir = parent_dir,
.sub_path = sub_path,
};
}
pub const TmpDir = struct {
dir: Io.Dir,
parent_dir: Io.Dir,
sub_path: [sub_path_len]u8,
const random_bytes_count = 12;
const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
pub fn cleanup(self: *TmpDir, io: Io) void {
self.dir.close(io);
self.parent_dir.deleteTree(io, &self.sub_path) catch {};
self.parent_dir.close(io);
self.* = undefined;
}
};
+1
View File
@@ -30,6 +30,7 @@ pub fn build(b: *std.Build) void {
const run = b.addRunArtifact(main);
run.addArtifactArg(hello);
run.addDirectoryArg(b.tmpPath());
run.expectExitCode(0);
run.skip_foreign_checks = true;
+20 -55
View File
@@ -9,16 +9,19 @@ pub fn main(init: std.process.Init) !void {
const gpa = init.gpa;
const io = init.io;
const process_cwd_path = try std.process.getCwdAlloc(init.arena.allocator());
var initial_process_cwd = try Io.Dir.cwd().openDir(io, ".", .{});
defer initial_process_cwd.close(io);
var it = try init.minimal.args.iterateAllocator(gpa);
defer it.deinit();
_ = it.next() orelse unreachable; // skip binary name
const hello_exe_cache_path = it.next() orelse unreachable;
const tmp_dir_path = it.next() orelse unreachable;
var tmp = tmpDir(io, .{});
defer tmp.cleanup(io);
var tmp_dir = try Io.Dir.cwd().openDir(io, tmp_dir_path, .{});
defer tmp_dir.close(io);
const tmp_absolute_path = try tmp.dir.realPathFileAlloc(io, ".", gpa);
const tmp_absolute_path = try tmp_dir.realPathFileAlloc(io, ".", 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);
@@ -51,7 +54,7 @@ pub fn main(init: std.process.Init) !void {
) == windows.TRUE);
// Move hello.exe into the tmp dir which is now added to the path
try Io.Dir.cwd().copyFile(hello_exe_cache_path, tmp.dir, "hello.exe", io, .{});
try Io.Dir.cwd().copyFile(hello_exe_cache_path, tmp_dir, "hello.exe", io, .{});
// with extension should find the .exe (case insensitive)
try testExec(gpa, io, "HeLLo.exe", "hello from exe\n");
@@ -61,9 +64,9 @@ pub fn main(init: std.process.Init) !void {
try std.testing.expectError(error.FileNotFound, testExecWithCwd(gpa, io, "hello.exe", "missing_dir", ""));
// now add a .bat
try tmp.dir.writeFile(io, .{ .sub_path = "hello.bat", .data = "@echo hello from bat" });
try tmp_dir.writeFile(io, .{ .sub_path = "hello.bat", .data = "@echo hello from bat" });
// and a .cmd
try tmp.dir.writeFile(io, .{ .sub_path = "hello.cmd", .data = "@echo hello from cmd" });
try tmp_dir.writeFile(io, .{ .sub_path = "hello.cmd", .data = "@echo hello from cmd" });
// with extension should find the .bat (case insensitive)
try testExec(gpa, io, "heLLo.bat", "hello from bat\r\n");
@@ -73,15 +76,15 @@ pub fn main(init: std.process.Init) !void {
try testExec(gpa, io, "heLLo", "hello from exe\n");
// now rename the exe to not have an extension
try renameExe(tmp.dir, io, "hello.exe", "hello");
try renameExe(tmp_dir, io, "hello.exe", "hello");
// with extension should now fail
try testExecError(error.FileNotFound, gpa, io, "hello.exe");
// without extension should succeed (case insensitive)
try testExec(gpa, io, "heLLo", "hello from exe\n");
try tmp.dir.createDir(io, "something", .default_dir);
try renameExe(tmp.dir, io, "hello", "something/hello.exe");
try tmp_dir.createDir(io, "something", .default_dir);
try renameExe(tmp_dir, io, "hello", "something/hello.exe");
const relative_path_no_ext = try std.fs.path.join(gpa, &.{ tmp_relative_path, "something/hello" });
defer gpa.free(relative_path_no_ext);
@@ -95,7 +98,7 @@ pub fn main(init: std.process.Init) !void {
try testExec(gpa, io, "heLLo", "hello from bat\r\n");
// Add a hello.exe that is not a valid executable
try tmp.dir.writeFile(io, .{ .sub_path = "hello.exe", .data = "invalid" });
try tmp_dir.writeFile(io, .{ .sub_path = "hello.exe", .data = "invalid" });
// Trying to execute it with extension will give InvalidExe. This is a special
// 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 {
try testExecError(error.InvalidExe, gpa, io, "hello");
// If we now rename hello.exe to have no extension, it will behave differently
try renameExe(tmp.dir, io, "hello.exe", "hello");
try renameExe(tmp_dir, io, "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(gpa, io, "hello", "hello from bat\r\n");
// If we rename the invalid exe to something else
try renameExe(tmp.dir, io, "hello", "goodbye");
try renameExe(tmp_dir, io, "hello", "goodbye");
// Then we should now get FileNotFound when trying to execute 'goodbye',
// 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
@@ -123,8 +126,8 @@ pub fn main(init: std.process.Init) !void {
try testExecError(error.FileNotFound, gpa, io, "goodbye");
// Now let's set the tmp dir as the cwd and set the path only include the "something" sub dir
try std.process.setCurrentDir(io, tmp.dir);
defer std.process.setCurrentDir(io, tmp.parent_dir) catch {};
try std.process.setCurrentDir(io, tmp_dir);
defer std.process.setCurrentDir(io, initial_process_cwd) catch {};
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);
@@ -141,7 +144,7 @@ pub fn main(init: std.process.Init) !void {
try testExec(gpa, io, "hello", "hello from bat\r\n");
// If we rename something/hello.exe to something/goodbye.exe
try renameExe(tmp.dir, io, "something/hello.exe", "something/goodbye.exe");
try renameExe(tmp_dir, io, "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(gpa, io, "goodbye", "hello from exe\n");
@@ -183,10 +186,10 @@ pub fn main(init: std.process.Init) !void {
try testExec(gpa, io, "goodbye", "hello from exe\n");
// now make sure we can launch executables "outside" of the cwd
var subdir_cwd = try tmp.dir.openDir(io, denormed_something_subdir_wtf8, .{});
var subdir_cwd = try tmp_dir.openDir(io, denormed_something_subdir_wtf8, .{});
defer subdir_cwd.close(io);
try renameExe(tmp.dir, io, "something/goodbye.exe", "hello.exe");
try renameExe(tmp_dir, io, "something/goodbye.exe", "hello.exe");
try std.process.setCurrentDir(io, subdir_cwd);
// clear the PATH again
@@ -232,41 +235,3 @@ fn renameExe(dir: Io.Dir, io: Io, old_sub_path: []const u8, new_sub_path: []cons
else => |e| return e,
};
}
pub fn tmpDir(io: Io, opts: Io.Dir.OpenOptions) TmpDir {
var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
std.crypto.random.bytes(&random_bytes);
var sub_path: [TmpDir.sub_path_len]u8 = undefined;
_ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
const cwd = Io.Dir.cwd();
var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache dir");
defer cache_dir.close(io);
const parent_dir = cache_dir.createDirPathOpen(io, "tmp", .{}) catch
@panic("unable to make tmp dir for testing: unable to make and open .zig-cache/tmp dir");
const dir = parent_dir.createDirPathOpen(io, &sub_path, .{ .open_options = opts }) catch
@panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
return .{
.dir = dir,
.parent_dir = parent_dir,
.sub_path = sub_path,
};
}
pub const TmpDir = struct {
dir: Io.Dir,
parent_dir: Io.Dir,
sub_path: [sub_path_len]u8,
const random_bytes_count = 12;
const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
pub fn cleanup(self: *TmpDir, io: Io) void {
self.dir.close(io);
self.parent_dir.deleteTree(io, &self.sub_path) catch {};
self.parent_dir.close(io);
self.* = undefined;
}
};