diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index 5b83a4ac8d..10649e9c0c 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -17,6 +17,9 @@ const AtomicOrder = std.builtin.AtomicOrder; const native_os = builtin.target.os.tag; const tmpDir = std.testing.tmpDir; +// NOTE: several additional tests are in test/standalone/posix/. Any tests that mutate +// process-wide POSIX state (cwd, signals, etc) cannot be Zig unit tests and should be over there. + // https://github.com/ziglang/zig/issues/20288 test "WTF-8 to WTF-16 conversion buffer overflows" { if (native_os != .windows) return error.SkipZigTest; @@ -39,68 +42,6 @@ test "check WASI CWD" { } } -test "chdir absolute parent" { - if (native_os == .wasi) return error.SkipZigTest; - - // Restore default CWD at end of test. - const orig_cwd = try fs.cwd().openDir(".", .{}); - defer orig_cwd.setAsCwd() catch unreachable; - - // Get current working directory path - var old_cwd_buf: [fs.max_path_bytes]u8 = undefined; - const old_cwd = try posix.getcwd(old_cwd_buf[0..]); - - { - // Firstly, changing to itself should have no effect - try posix.chdir(old_cwd); - var new_cwd_buf: [fs.max_path_bytes]u8 = undefined; - const new_cwd = try posix.getcwd(new_cwd_buf[0..]); - try expect(mem.eql(u8, old_cwd, new_cwd)); - } - - // Next, change current working directory to one level above - const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute - try posix.chdir(parent); - - var new_cwd_buf: [fs.max_path_bytes]u8 = undefined; - const new_cwd = try posix.getcwd(new_cwd_buf[0..]); - try expect(mem.eql(u8, parent, new_cwd)); -} - -test "chdir relative" { - if (native_os == .wasi) return error.SkipZigTest; - - var tmp = tmpDir(.{}); - defer tmp.cleanup(); - - // Restore default CWD at end of test. - const orig_cwd = try fs.cwd().openDir(".", .{}); - defer orig_cwd.setAsCwd() catch unreachable; - - // Use the tmpDir parent_dir as the "base" for the test. Then cd into the child - try tmp.parent_dir.setAsCwd(); - - // Capture base working directory path, to build expected full path - var base_cwd_buf: [fs.max_path_bytes]u8 = undefined; - const base_cwd = try posix.getcwd(base_cwd_buf[0..]); - - const dir_name = &tmp.sub_path; - const expected_path = try fs.path.resolve(a, &.{ base_cwd, dir_name }); - defer a.free(expected_path); - - // change current working directory to new directory - try posix.chdir(dir_name); - - var new_cwd_buf: [fs.max_path_bytes]u8 = undefined; - const new_cwd = try posix.getcwd(new_cwd_buf[0..]); - - // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase - const resolved_cwd = try fs.path.resolve(a, &.{new_cwd}); - defer a.free(resolved_cwd); - - try expect(mem.eql(u8, expected_path, resolved_cwd)); -} - test "open smoke test" { if (native_os == .wasi) return error.SkipZigTest; if (native_os == .windows) return error.SkipZigTest; @@ -455,12 +396,6 @@ test "getrandom" { try expect(!mem.eql(u8, &buf_a, &buf_b)); } -test "getcwd" { - // at least call it so it gets compiled - var buf: [std.fs.max_path_bytes]u8 = undefined; - _ = posix.getcwd(&buf) catch undefined; -} - test "getuid" { if (native_os == .windows or native_os == .wasi) return error.SkipZigTest; _ = posix.getuid(); diff --git a/test/standalone/posix/cwd.zig b/test/standalone/posix/cwd.zig index bbb7b6ed70..43dcc63bfe 100644 --- a/test/standalone/posix/cwd.zig +++ b/test/standalone/posix/cwd.zig @@ -1 +1,75 @@ -pub fn main() !void {} +const std = @import("std"); +const builtin = @import("builtin"); + +const path_max = std.fs.max_path_bytes; + +pub fn main() !void { + if (builtin.target.os.tag == .wasi) { + // WASI doesn't support changing the working directory at all. + return; + } + + var Allocator = std.heap.DebugAllocator(.{}){}; + const a = Allocator.allocator(); + defer std.debug.assert(Allocator.deinit() == .ok); + + try test_chdir_self(); + try test_chdir_absolute(); + try test_chdir_relative(a); +} + +// get current working directory and expect it to match given path +fn expect_cwd(expected_cwd: []const u8) !void { + var cwd_buf: [path_max]u8 = undefined; + const actual_cwd = try std.posix.getcwd(cwd_buf[0..]); + try std.testing.expectEqualStrings(actual_cwd, expected_cwd); +} + +fn test_chdir_self() !void { + var old_cwd_buf: [path_max]u8 = undefined; + const old_cwd = try std.posix.getcwd(old_cwd_buf[0..]); + + // Try changing to the current directory + try std.posix.chdir(old_cwd); + try expect_cwd(old_cwd); +} + +fn test_chdir_absolute() !void { + var old_cwd_buf: [path_max]u8 = undefined; + const old_cwd = try std.posix.getcwd(old_cwd_buf[0..]); + + const parent = std.fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute + + // Try changing to the parent via a full path + try std.posix.chdir(parent); + + try expect_cwd(parent); +} + +fn test_chdir_relative(a: std.mem.Allocator) !void { + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + + // Use the tmpDir parent_dir as the "base" for the test. Then cd into the child + try tmp.parent_dir.setAsCwd(); + + // 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(a, &.{ base_cwd, relative_dir_name }); + defer a.free(expected_path); + + // change current working directory to new test directory + try std.posix.chdir(relative_dir_name); + + var new_cwd_buf: [path_max]u8 = undefined; + const new_cwd = try std.posix.getcwd(new_cwd_buf[0..]); + + // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase + const resolved_cwd = try std.fs.path.resolve(a, &.{new_cwd}); + defer a.free(resolved_cwd); + + try std.testing.expectEqualStrings(expected_path, resolved_cwd); +}