mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
standalone tests: Delete all ad hoc TmpDir instances, use the build system instead
This commit is contained in:
committed by
Andrew Kelley
parent
50422d5c37
commit
52141fe85f
@@ -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,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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user