| author | |
| committer | |
| log | 52141fe85f1b7719cecb868520f40431fcfff2a1 |
| tree | 69451db5e274bc1ba3cda27131e7f409270cc1a2 |
| parent | 50422d5c37e85f08da7579cbffb4c0281a5cb2a8 |
8 files changed, 71 insertions(+), 296 deletions(-)
test/standalone/posix/build.zig+6| ... | ... | @@ -4,11 +4,13 @@ const builtin = @import("builtin"); |
| 4 | 4 | const Case = struct { |
| 5 | 5 | src_path: []const u8, |
| 6 | 6 | set_env_vars: bool = false, |
| 7 | make_tmp_dir: bool = false, | |
| 7 | 8 | }; |
| 8 | 9 | |
| 9 | 10 | const cases = [_]Case{ |
| 10 | 11 | .{ |
| 11 | 12 | .src_path = "cwd.zig", |
| 13 | .make_tmp_dir = true, | |
| 12 | 14 | }, |
| 13 | 15 | .{ |
| 14 | 16 | .src_path = "getenv.zig", |
| ... | ... | @@ -19,6 +21,7 @@ const cases = [_]Case{ |
| 19 | 21 | }, |
| 20 | 22 | .{ |
| 21 | 23 | .src_path = "relpaths.zig", |
| 24 | .make_tmp_dir = true, | |
| 22 | 25 | }, |
| 23 | 26 | }; |
| 24 | 27 | |
| ... | ... | @@ -69,6 +72,9 @@ fn run_exe(b: *std.Build, optimize: std.builtin.OptimizeMode, case: *const Case, |
| 69 | 72 | }); |
| 70 | 73 | |
| 71 | 74 | const run_cmd = b.addRunArtifact(exe); |
| 75 | if (case.make_tmp_dir) { | |
| 76 | run_cmd.addDirectoryArg(b.tmpPath()); | |
| 77 | } | |
| 72 | 78 | |
| 73 | 79 | if (case.set_env_vars) { |
| 74 | 80 | 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 { |
| 13 | 13 | .windows => return, // POSIX is not implemented by Windows |
| 14 | 14 | else => {}, |
| 15 | 15 | } |
| 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); | |
| 16 | 21 | |
| 17 | 22 | try test_chdir_self(); |
| 18 | 23 | try test_chdir_absolute(); |
| 19 | try test_chdir_relative(init.gpa, init.io); | |
| 24 | try test_chdir_relative(init.gpa, init.io, tmp_dir); | |
| 20 | 25 | } |
| 21 | 26 | |
| 22 | 27 | // get current working directory and expect it to match given path |
| ... | ... | @@ -47,23 +52,22 @@ fn test_chdir_absolute() !void { |
| 47 | 52 | try expect_cwd(parent); |
| 48 | 53 | } |
| 49 | 54 | |
| 50 | fn test_chdir_relative(gpa: Allocator, io: Io) !void { | |
| 51 | var tmp = tmpDir(io, .{}); | |
| 52 | defer tmp.cleanup(io); | |
| 55 | fn 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); | |
| 53 | 58 | |
| 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); | |
| 56 | 61 | |
| 57 | 62 | // Capture base working directory path, to build expected full path |
| 58 | 63 | var base_cwd_buf: [path_max]u8 = undefined; |
| 59 | 64 | const base_cwd = try std.posix.getcwd(base_cwd_buf[0..]); |
| 60 | 65 | |
| 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 }); | |
| 63 | 67 | defer gpa.free(expected_path); |
| 64 | 68 | |
| 65 | 69 | // 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); | |
| 67 | 71 | |
| 68 | 72 | var new_cwd_buf: [path_max]u8 = undefined; |
| 69 | 73 | const new_cwd = try std.posix.getcwd(new_cwd_buf[0..]); |
| ... | ... | @@ -74,41 +78,3 @@ fn test_chdir_relative(gpa: Allocator, io: Io) !void { |
| 74 | 78 | |
| 75 | 79 | try std.testing.expectEqualStrings(expected_path, resolved_cwd); |
| 76 | 80 | } |
| 77 | ||
| 78 | pub 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 | ||
| 100 | pub 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 { |
| 11 | 11 | |
| 12 | 12 | const io = init.io; |
| 13 | 13 | |
| 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); | |
| 16 | 19 | |
| 17 | 20 | // 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); | |
| 19 | 22 | |
| 20 | try test_link(io, tmp); | |
| 23 | try test_link(io, tmp_dir); | |
| 21 | 24 | } |
| 22 | 25 | |
| 23 | fn test_link(io: Io, tmp: TmpDir) !void { | |
| 26 | fn test_link(io: Io, tmp_dir: Io.Dir) !void { | |
| 24 | 27 | switch (builtin.target.os.tag) { |
| 25 | 28 | .linux, .illumos => {}, |
| 26 | 29 | else => return, |
| ... | ... | @@ -29,16 +32,16 @@ fn test_link(io: Io, tmp: TmpDir) !void { |
| 29 | 32 | const target_name = "link-target"; |
| 30 | 33 | const link_name = "newlink"; |
| 31 | 34 | |
| 32 | try tmp.dir.writeFile(io, .{ .sub_path = target_name, .data = "example" }); | |
| 35 | try tmp_dir.writeFile(io, .{ .sub_path = target_name, .data = "example" }); | |
| 33 | 36 | |
| 34 | // Test 1: create the relative link from inside tmp | |
| 37 | // Test 1: create the relative link from inside tmp_dir | |
| 35 | 38 | try Io.Dir.hardLink(.cwd(), target_name, .cwd(), link_name, io, .{}); |
| 36 | 39 | |
| 37 | 40 | // Verify |
| 38 | const efd = try tmp.dir.openFile(io, target_name, .{}); | |
| 41 | const efd = try tmp_dir.openFile(io, target_name, .{}); | |
| 39 | 42 | defer efd.close(io); |
| 40 | 43 | |
| 41 | const nfd = try tmp.dir.openFile(io, link_name, .{}); | |
| 44 | const nfd = try tmp_dir.openFile(io, link_name, .{}); | |
| 42 | 45 | defer nfd.close(io); |
| 43 | 46 | |
| 44 | 47 | { |
| ... | ... | @@ -55,41 +58,3 @@ fn test_link(io: Io, tmp: TmpDir) !void { |
| 55 | 58 | try std.testing.expectEqual(1, e_stat.nlink); |
| 56 | 59 | } |
| 57 | 60 | } |
| 58 | ||
| 59 | pub 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 | ||
| 81 | pub 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 { |
| 19 | 19 | }), |
| 20 | 20 | }); |
| 21 | 21 | |
| 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 | ||
| 22 | 38 | const test_exe = b.addExecutable(.{ |
| 23 | 39 | .name = "test", |
| 24 | 40 | .root_module = b.createModule(.{ |
| ... | ... | @@ -29,7 +45,7 @@ pub fn build(b: *std.Build) !void { |
| 29 | 45 | }); |
| 30 | 46 | |
| 31 | 47 | const run = b.addRunArtifact(test_exe); |
| 32 | run.addArtifactArg(echo_args); | |
| 48 | run.setCwd(bat_files.getDirectory()); | |
| 33 | 49 | run.expectExitCode(0); |
| 34 | 50 | run.skip_foreign_checks = true; |
| 35 | 51 | |
| ... | ... | @@ -55,7 +71,7 @@ pub fn build(b: *std.Build) !void { |
| 55 | 71 | const fuzz_seed_arg = std.fmt.allocPrint(b.allocator, "{}", .{fuzz_seed}) catch @panic("oom"); |
| 56 | 72 | |
| 57 | 73 | const fuzz_run = b.addRunArtifact(fuzz); |
| 58 | fuzz_run.addArtifactArg(echo_args); | |
| 74 | fuzz_run.setCwd(bat_files.getDirectory()); | |
| 59 | 75 | fuzz_run.addArgs(&.{ fuzz_iterations_arg, fuzz_seed_arg }); |
| 60 | 76 | fuzz_run.expectExitCode(0); |
| 61 | 77 | 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 { |
| 11 | 11 | var it = try init.minimal.args.iterateAllocator(gpa); |
| 12 | 12 | defer it.deinit(); |
| 13 | 13 | _ = it.next() orelse unreachable; // skip binary name |
| 14 | const child_exe_path_orig = it.next() orelse unreachable; | |
| 15 | 14 | |
| 16 | 15 | const iterations: u64 = iterations: { |
| 17 | 16 | const arg = it.next() orelse "0"; |
| ... | ... | @@ -37,37 +36,6 @@ pub fn main(init: std.process.Init) !void { |
| 37 | 36 | std.debug.print("rand seed: {}\n", .{seed}); |
| 38 | 37 | } |
| 39 | 38 | |
| 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 | ||
| 71 | 39 | var i: u64 = 0; |
| 72 | 40 | while (iterations == 0 or i < iterations) { |
| 73 | 41 | const rand_arg = try randomArg(gpa, rand); |
| ... | ... | @@ -163,41 +131,3 @@ fn randomArg(gpa: Allocator, rand: std.Random) ![]const u8 { |
| 163 | 131 | |
| 164 | 132 | return buf.toOwnedSlice(gpa); |
| 165 | 133 | } |
| 166 | ||
| 167 | pub 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 | ||
| 189 | pub 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 { |
| 6 | 6 | const gpa = init.gpa; |
| 7 | 7 | const io = init.io; |
| 8 | 8 | |
| 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 | ||
| 45 | 9 | // Test cases are from https://github.com/rust-lang/rust/blob/master/tests/ui/std/windows-bat-args.rs |
| 46 | 10 | try testExecError(error.InvalidBatchScriptArg, gpa, io, &.{"\x00"}); |
| 47 | 11 | try testExecError(error.InvalidBatchScriptArg, gpa, io, &.{"\n"}); |
| ... | ... | @@ -119,7 +83,7 @@ pub fn main(init: std.process.Init) !void { |
| 119 | 83 | try testExec(gpa, io, &.{"%FOO%"}, &env); |
| 120 | 84 | |
| 121 | 85 | // 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", .{})); | |
| 123 | 87 | } |
| 124 | 88 | |
| 125 | 89 | 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 |
| 160 | 124 | i += 1; |
| 161 | 125 | } |
| 162 | 126 | } |
| 163 | ||
| 164 | pub 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 | ||
| 186 | pub 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 { |
| 30 | 30 | |
| 31 | 31 | const run = b.addRunArtifact(main); |
| 32 | 32 | run.addArtifactArg(hello); |
| 33 | run.addDirectoryArg(b.tmpPath()); | |
| 33 | 34 | run.expectExitCode(0); |
| 34 | 35 | run.skip_foreign_checks = true; |
| 35 | 36 |
test/standalone/windows_spawn/main.zig+20-55| ... | ... | @@ -9,16 +9,19 @@ pub fn main(init: std.process.Init) !void { |
| 9 | 9 | const gpa = init.gpa; |
| 10 | 10 | const io = init.io; |
| 11 | 11 | 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); | |
| 12 | 14 | |
| 13 | 15 | var it = try init.minimal.args.iterateAllocator(gpa); |
| 14 | 16 | defer it.deinit(); |
| 15 | 17 | _ = it.next() orelse unreachable; // skip binary name |
| 16 | 18 | const hello_exe_cache_path = it.next() orelse unreachable; |
| 19 | const tmp_dir_path = it.next() orelse unreachable; | |
| 17 | 20 | |
| 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); | |
| 20 | 23 | |
| 21 | const tmp_absolute_path = try tmp.dir.realPathFileAlloc(io, ".", gpa); | |
| 24 | const tmp_absolute_path = try tmp_dir.realPathFileAlloc(io, ".", gpa); | |
| 22 | 25 | defer gpa.free(tmp_absolute_path); |
| 23 | 26 | const tmp_absolute_path_w = try std.unicode.utf8ToUtf16LeAllocZ(gpa, tmp_absolute_path); |
| 24 | 27 | defer gpa.free(tmp_absolute_path_w); |
| ... | ... | @@ -51,7 +54,7 @@ pub fn main(init: std.process.Init) !void { |
| 51 | 54 | ) == windows.TRUE); |
| 52 | 55 | |
| 53 | 56 | // 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, .{}); | |
| 55 | 58 | |
| 56 | 59 | // with extension should find the .exe (case insensitive) |
| 57 | 60 | try testExec(gpa, io, "HeLLo.exe", "hello from exe\n"); |
| ... | ... | @@ -61,9 +64,9 @@ pub fn main(init: std.process.Init) !void { |
| 61 | 64 | try std.testing.expectError(error.FileNotFound, testExecWithCwd(gpa, io, "hello.exe", "missing_dir", "")); |
| 62 | 65 | |
| 63 | 66 | // 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" }); | |
| 65 | 68 | // 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" }); | |
| 67 | 70 | |
| 68 | 71 | // with extension should find the .bat (case insensitive) |
| 69 | 72 | try testExec(gpa, io, "heLLo.bat", "hello from bat\r\n"); |
| ... | ... | @@ -73,15 +76,15 @@ pub fn main(init: std.process.Init) !void { |
| 73 | 76 | try testExec(gpa, io, "heLLo", "hello from exe\n"); |
| 74 | 77 | |
| 75 | 78 | // 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"); | |
| 77 | 80 | |
| 78 | 81 | // with extension should now fail |
| 79 | 82 | try testExecError(error.FileNotFound, gpa, io, "hello.exe"); |
| 80 | 83 | // without extension should succeed (case insensitive) |
| 81 | 84 | try testExec(gpa, io, "heLLo", "hello from exe\n"); |
| 82 | 85 | |
| 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"); | |
| 85 | 88 | |
| 86 | 89 | const relative_path_no_ext = try std.fs.path.join(gpa, &.{ tmp_relative_path, "something/hello" }); |
| 87 | 90 | defer gpa.free(relative_path_no_ext); |
| ... | ... | @@ -95,7 +98,7 @@ pub fn main(init: std.process.Init) !void { |
| 95 | 98 | try testExec(gpa, io, "heLLo", "hello from bat\r\n"); |
| 96 | 99 | |
| 97 | 100 | // 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" }); | |
| 99 | 102 | |
| 100 | 103 | // Trying to execute it with extension will give InvalidExe. This is a special |
| 101 | 104 | // 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 { |
| 108 | 111 | try testExecError(error.InvalidExe, gpa, io, "hello"); |
| 109 | 112 | |
| 110 | 113 | // 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"); | |
| 112 | 115 | |
| 113 | 116 | // Now, trying to execute it without an extension should treat InvalidExe as recoverable |
| 114 | 117 | // and skip over it and find hello.bat and execute that |
| 115 | 118 | try testExec(gpa, io, "hello", "hello from bat\r\n"); |
| 116 | 119 | |
| 117 | 120 | // 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"); | |
| 119 | 122 | // Then we should now get FileNotFound when trying to execute 'goodbye', |
| 120 | 123 | // since that is what the original error will be after searching for 'goodbye' |
| 121 | 124 | // 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 { |
| 123 | 126 | try testExecError(error.FileNotFound, gpa, io, "goodbye"); |
| 124 | 127 | |
| 125 | 128 | // 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 {}; | |
| 128 | 131 | const something_subdir_abs_path = try std.mem.concatWithSentinel(gpa, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0); |
| 129 | 132 | defer gpa.free(something_subdir_abs_path); |
| 130 | 133 | |
| ... | ... | @@ -141,7 +144,7 @@ pub fn main(init: std.process.Init) !void { |
| 141 | 144 | try testExec(gpa, io, "hello", "hello from bat\r\n"); |
| 142 | 145 | |
| 143 | 146 | // 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"); | |
| 145 | 148 | // And try to execute goodbye, then the one in something should be found |
| 146 | 149 | // since the one in cwd is an invalid executable |
| 147 | 150 | try testExec(gpa, io, "goodbye", "hello from exe\n"); |
| ... | ... | @@ -183,10 +186,10 @@ pub fn main(init: std.process.Init) !void { |
| 183 | 186 | try testExec(gpa, io, "goodbye", "hello from exe\n"); |
| 184 | 187 | |
| 185 | 188 | // 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, .{}); | |
| 187 | 190 | defer subdir_cwd.close(io); |
| 188 | 191 | |
| 189 | try renameExe(tmp.dir, io, "something/goodbye.exe", "hello.exe"); | |
| 192 | try renameExe(tmp_dir, io, "something/goodbye.exe", "hello.exe"); | |
| 190 | 193 | try std.process.setCurrentDir(io, subdir_cwd); |
| 191 | 194 | |
| 192 | 195 | // clear the PATH again |
| ... | ... | @@ -232,41 +235,3 @@ fn renameExe(dir: Io.Dir, io: Io, old_sub_path: []const u8, new_sub_path: []cons |
| 232 | 235 | else => |e| return e, |
| 233 | 236 | }; |
| 234 | 237 | } |
| 235 | ||
| 236 | pub 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 | ||
| 258 | pub 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 | }; |