| 1 | const builtin = @import("builtin"); |
| 2 | |
| 3 | const std = @import("std"); |
| 4 | const Io = std.Io; |
| 5 | const Allocator = std.mem.Allocator; |
| 6 | const assert = std.debug.assert; |
| 7 | |
| 8 | const path_max = std.fs.max_path_bytes; |
| 9 | |
| 10 | pub fn main(init: std.process.Init) !void { |
| 11 | switch (builtin.target.os.tag) { |
| 12 | .wasi => return, // WASI doesn't support changing the working directory at all. |
| 13 | .windows => return, // POSIX is not implemented by Windows |
| 14 | else => {}, |
| 15 | } |
| 16 | const io = init.io; |
| 17 | const args = try init.minimal.args.toSlice(init.arena.allocator()); |
| 18 | const tmp_dir_path = args[1]; |
| 19 | |
| 20 | var tmp_dir = try Io.Dir.cwd().openDir(init.io, tmp_dir_path, .{}); |
| 21 | defer tmp_dir.close(init.io); |
| 22 | |
| 23 | try test_chdir_self(io); |
| 24 | try test_chdir_absolute(io); |
| 25 | try test_chdir_relative(init.gpa, io, tmp_dir); |
| 26 | } |
| 27 | |
| 28 | // get current working directory and expect it to match given path |
| 29 | fn expect_cwd(io: Io, expected_cwd: []const u8) !void { |
| 30 | var cwd_buf: [path_max]u8 = undefined; |
| 31 | const actual_cwd = cwd_buf[0..try std.process.currentPath(io, &cwd_buf)]; |
| 32 | try std.testing.expectEqualStrings(actual_cwd, expected_cwd); |
| 33 | } |
| 34 | |
| 35 | fn test_chdir_self(io: Io) !void { |
| 36 | var old_cwd_buf: [path_max]u8 = undefined; |
| 37 | const old_cwd = old_cwd_buf[0..try std.process.currentPath(io, &old_cwd_buf)]; |
| 38 | |
| 39 | // Try changing to the current directory |
| 40 | try std.process.setCurrentPath(io, old_cwd); |
| 41 | try expect_cwd(io, old_cwd); |
| 42 | } |
| 43 | |
| 44 | fn test_chdir_absolute(io: Io) !void { |
| 45 | var old_cwd_buf: [path_max]u8 = undefined; |
| 46 | const old_cwd = old_cwd_buf[0..try std.process.currentPath(io, &old_cwd_buf)]; |
| 47 | |
| 48 | const parent = std.fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute |
| 49 | |
| 50 | // Try changing to the parent via a full path |
| 51 | try std.process.setCurrentPath(io, parent); |
| 52 | |
| 53 | try expect_cwd(io, parent); |
| 54 | } |
| 55 | |
| 56 | fn test_chdir_relative(gpa: Allocator, io: Io, tmp_dir: Io.Dir) !void { |
| 57 | const subdir_path = "subdir"; |
| 58 | try tmp_dir.createDir(io, "subdir", .default_dir); |
| 59 | |
| 60 | // Use the tmp dir as the "base" for the test. Then cd into the child |
| 61 | try std.process.setCurrentDir(io, tmp_dir); |
| 62 | |
| 63 | // Capture base working directory path, to build expected full path |
| 64 | var base_cwd_buf: [path_max]u8 = undefined; |
| 65 | const base_cwd = base_cwd_buf[0..try std.process.currentPath(io, &base_cwd_buf)]; |
| 66 | |
| 67 | const expected_path = try std.fs.path.resolve(gpa, &.{ base_cwd, subdir_path }); |
| 68 | defer gpa.free(expected_path); |
| 69 | |
| 70 | // change current working directory to new test directory |
| 71 | try std.process.setCurrentPath(io, subdir_path); |
| 72 | |
| 73 | var new_cwd_buf: [path_max]u8 = undefined; |
| 74 | const new_cwd = new_cwd_buf[0..try std.process.currentPath(io, &new_cwd_buf)]; |
| 75 | |
| 76 | // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase |
| 77 | const resolved_cwd = try std.fs.path.resolve(gpa, &.{new_cwd}); |
| 78 | defer gpa.free(resolved_cwd); |
| 79 | |
| 80 | try std.testing.expectEqualStrings(expected_path, resolved_cwd); |
| 81 | } |