1const builtin = @import("builtin");
2
3const std = @import("std");
4const Io = std.Io;
5const Allocator = std.mem.Allocator;
6const assert = std.debug.assert;
7
8const path_max = std.fs.max_path_bytes;
9
10pub 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
29fn 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
35fn 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
44fn 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
56fn 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}