@@ -44,13 +44,12 @@ test "check WASI CWD" {
4444 }
4545}
4646
47- test "chdir smoke test " {
47+ test "chdir absolute parent " {
4848 if (native_os == .wasi ) return error .SkipZigTest ;
4949
50- if (true ) {
51- // https://github.com/ziglang/zig/issues/14968
52- return error .SkipZigTest ;
53- }
50+ // Restore default CWD at end of test.
51+ const orig_cwd = try fs .cwd ().openDir ("." , .{});
52+ defer orig_cwd .setAsCwd () catch unreachable ;
5453
5554 // Get current working directory path
5655 var old_cwd_buf : [fs .max_path_bytes ]u8 = undefined ;
@@ -65,47 +64,46 @@ test "chdir smoke test" {
6564 }
6665
6766 // Next, change current working directory to one level above
68- if (native_os != .wasi ) { // WASI does not support navigating outside of Preopens
69- const parent = fs .path .dirname (old_cwd ) orelse unreachable ; // old_cwd should be absolute
70- try posix .chdir (parent );
67+ const parent = fs .path .dirname (old_cwd ) orelse unreachable ; // old_cwd should be absolute
68+ try posix .chdir (parent );
7169
72- // Restore cwd because process may have other tests that do not tolerate chdir.
73- defer posix .chdir (old_cwd ) catch unreachable ;
70+ var new_cwd_buf : [fs .max_path_bytes ]u8 = undefined ;
71+ const new_cwd = try posix .getcwd (new_cwd_buf [0.. ]);
72+ try expect (mem .eql (u8 , parent , new_cwd ));
73+ }
7474
75- var new_cwd_buf : [fs .max_path_bytes ]u8 = undefined ;
76- const new_cwd = try posix .getcwd (new_cwd_buf [0.. ]);
77- try expect (mem .eql (u8 , parent , new_cwd ));
78- }
75+ test "chdir relative" {
76+ if (native_os == .wasi ) return error .SkipZigTest ;
7977
80- // Next, change current working directory to a temp directory one level below
81- {
82- // Create a tmp directory
83- var tmp_dir_buf : [fs .max_path_bytes ]u8 = undefined ;
84- const tmp_dir_path = path : {
85- var allocator = std .heap .FixedBufferAllocator .init (& tmp_dir_buf );
86- break :path try fs .path .resolve (allocator .allocator (), &[_ ][]const u8 { old_cwd , "zig-test-tmp" });
87- };
88- var tmp_dir = try fs .cwd ().makeOpenPath ("zig-test-tmp" , .{});
78+ var tmp = tmpDir (.{});
79+ defer tmp .cleanup ();
8980
90- // Change current working directory to tmp directory
91- try posix .chdir ("zig-test-tmp" );
81+ // Restore default CWD at end of test.
82+ const orig_cwd = try fs .cwd ().openDir ("." , .{});
83+ defer orig_cwd .setAsCwd () catch unreachable ;
9284
93- var new_cwd_buf : [ fs . max_path_bytes ] u8 = undefined ;
94- const new_cwd = try posix . getcwd ( new_cwd_buf [0 .. ] );
85+ // Use the tmpDir parent_dir as the "base" for the test. Then cd into the child
86+ try tmp . parent_dir . setAsCwd ( );
9587
96- // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
97- var resolved_cwd_buf : [fs .max_path_bytes ]u8 = undefined ;
98- const resolved_cwd = path : {
99- var allocator = std .heap .FixedBufferAllocator .init (& resolved_cwd_buf );
100- break :path try fs .path .resolve (allocator .allocator (), &[_ ][]const u8 {new_cwd });
101- };
102- try expect (mem .eql (u8 , tmp_dir_path , resolved_cwd ));
88+ // Capture base working directory path, to build expected full path
89+ var base_cwd_buf : [fs .max_path_bytes ]u8 = undefined ;
90+ const base_cwd = try posix .getcwd (base_cwd_buf [0.. ]);
10391
104- // Restore cwd because process may have other tests that do not tolerate chdir.
105- tmp_dir .close ();
106- posix .chdir (old_cwd ) catch unreachable ;
107- try fs .cwd ().deleteDir ("zig-test-tmp" );
108- }
92+ const dir_name = & tmp .sub_path ;
93+ const expected_path = try fs .path .resolve (a , &.{ base_cwd , dir_name });
94+ defer a .free (expected_path );
95+
96+ // change current working directory to new directory
97+ try posix .chdir (dir_name );
98+
99+ var new_cwd_buf : [fs .max_path_bytes ]u8 = undefined ;
100+ const new_cwd = try posix .getcwd (new_cwd_buf [0.. ]);
101+
102+ // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
103+ const resolved_cwd = try fs .path .resolve (a , &.{new_cwd });
104+ defer a .free (resolved_cwd );
105+
106+ try expect (mem .eql (u8 , expected_path , resolved_cwd ));
109107}
110108
111109test "open smoke test" {
@@ -222,44 +220,42 @@ test "openat smoke test" {
222220}
223221
224222test "symlink with relative paths" {
225- if (native_os == .wasi and builtin . link_libc ) return error .SkipZigTest ;
223+ if (native_os == .wasi ) return error .SkipZigTest ; // Can symlink, but can't change into tmpDir
226224
227- if (true ) {
228- // https://github.com/ziglang/zig/issues/14968
229- return error .SkipZigTest ;
230- }
231- const cwd = fs .cwd ();
232- cwd .deleteFile ("file.txt" ) catch {};
233- cwd .deleteFile ("symlinked" ) catch {};
225+ var tmp = tmpDir (.{});
226+ defer tmp .cleanup ();
227+
228+ const target_name = "symlink-target" ;
229+ const symlink_name = "symlinker" ;
234230
235- // First, try relative paths in cwd
236- try cwd .writeFile (.{ .sub_path = "file.txt" , .data = "nonsense" });
231+ // Restore default CWD at end of test.
232+ const orig_cwd = try fs .cwd ().openDir ("." , .{});
233+ defer orig_cwd .setAsCwd () catch unreachable ;
234+
235+ // Create the target file
236+ try tmp .dir .writeFile (.{ .sub_path = target_name , .data = "nonsense" });
237+
238+ // Want to test relative paths, so cd into the tmpdir for this test
239+ try tmp .dir .setAsCwd ();
237240
238241 if (native_os == .windows ) {
239- std .os . windows . CreateSymbolicLink (
240- cwd . fd ,
241- &[ _ ] u16 { 's' , 'y' , 'm' , 'l' , 'i' , 'n' , 'k' , 'e' , 'd' },
242- &[ _ : 0 ] u16 { 'f' , 'i' , 'l' , 'e' , '.' , 't' , 'x' , 't' },
243- false ,
244- ) catch | err | switch (err ) {
242+ const wtarget_name = try std .unicode . wtf8ToWtf16LeAllocZ ( a , target_name );
243+ const wsymlink_name = try std . unicode . wtf8ToWtf16LeAllocZ ( a , symlink_name );
244+ defer a . free ( wtarget_name );
245+ defer a . free ( wsymlink_name );
246+
247+ std . os . windows . CreateSymbolicLink ( tmp . dir . fd , wsymlink_name , wtarget_name , false ) catch | err | switch (err ) {
245248 // Symlink requires admin privileges on windows, so this test can legitimately fail.
246- error .AccessDenied = > {
247- try cwd .deleteFile ("file.txt" );
248- try cwd .deleteFile ("symlinked" );
249- return error .SkipZigTest ;
250- },
249+ error .AccessDenied = > return error .SkipZigTest ,
251250 else = > return err ,
252251 };
253252 } else {
254- try posix .symlink ("file.txt" , "symlinked" );
253+ try posix .symlink (target_name , symlink_name );
255254 }
256255
257256 var buffer : [fs .max_path_bytes ]u8 = undefined ;
258- const given = try posix .readlink ("symlinked" , buffer [0.. ]);
259- try expect (mem .eql (u8 , "file.txt" , given ));
260-
261- try cwd .deleteFile ("file.txt" );
262- try cwd .deleteFile ("symlinked" );
257+ const given = try posix .readlink (symlink_name , buffer [0.. ]);
258+ try expect (mem .eql (u8 , target_name , given ));
263259}
264260
265261test "readlink on Windows" {
@@ -277,90 +273,95 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
277273}
278274
279275test "link with relative paths" {
280- if (native_os == .wasi and builtin .link_libc ) return error .SkipZigTest ;
276+ if (native_os == .wasi ) return error .SkipZigTest ; // Can link, but can't change into tmpDir
277+ if (builtin .cpu .arch == .riscv32 and builtin .os .tag == .linux and ! builtin .link_libc ) return error .SkipZigTest ; // No `fstat()`.
281278
282279 switch (native_os ) {
283280 .wasi , .linux , .solaris , .illumos = > {},
284281 else = > return error .SkipZigTest ,
285282 }
286- if (true ) {
287- // https://github.com/ziglang/zig/issues/14968
288- return error .SkipZigTest ;
289- }
290- var cwd = fs .cwd ();
291283
292- cwd .deleteFile ("example.txt" ) catch {};
293- cwd .deleteFile ("new.txt" ) catch {};
284+ var tmp = tmpDir (.{});
285+ defer tmp .cleanup ();
286+
287+ // Restore default CWD at end of test.
288+ const orig_cwd = try fs .cwd ().openDir ("." , .{});
289+ defer orig_cwd .setAsCwd () catch unreachable ;
290+
291+ const target_name = "link-target" ;
292+ const link_name = "newlink" ;
293+
294+ try tmp .dir .writeFile (.{ .sub_path = target_name , .data = "example" });
294295
295- try cwd .writeFile (.{ .sub_path = "example.txt" , .data = "example" });
296- try posix .link ("example.txt" , "new.txt" );
296+ // Test 1: create the relative link from inside tmp
297+ try tmp .dir .setAsCwd ();
298+ try posix .link (target_name , link_name );
297299
298- const efd = try cwd .openFile ("example.txt" , .{});
300+ // Verify
301+ const efd = try tmp .dir .openFile (target_name , .{});
299302 defer efd .close ();
300303
301- const nfd = try cwd . openFile ("new.txt" , .{});
304+ const nfd = try tmp . dir . openFile (link_name , .{});
302305 defer nfd .close ();
303306
304307 {
305308 const estat = try posix .fstat (efd .handle );
306309 const nstat = try posix .fstat (nfd .handle );
307-
308310 try testing .expectEqual (estat .ino , nstat .ino );
309311 try testing .expectEqual (@as (@TypeOf (nstat .nlink ), 2 ), nstat .nlink );
310312 }
311313
312- try posix .unlink ("new.txt" );
314+ // Test 2: Remove the link and see the stats update
315+ try posix .unlink (link_name );
313316
314317 {
315318 const estat = try posix .fstat (efd .handle );
316319 try testing .expectEqual (@as (@TypeOf (estat .nlink ), 1 ), estat .nlink );
317320 }
318-
319- try cwd .deleteFile ("example.txt" );
320321}
321322
322323test "linkat with different directories" {
323- if (native_os == .wasi and builtin .link_libc ) return error .SkipZigTest ;
324+ if (builtin . cpu . arch == .riscv32 and builtin .os . tag == .linux and ! builtin . link_libc ) return error .SkipZigTest ; // No `fstatat()`.
324325
325326 switch (native_os ) {
326327 .wasi , .linux , .solaris , .illumos = > {},
327328 else = > return error .SkipZigTest ,
328329 }
329- if (true ) {
330- // https://github.com/ziglang/zig/issues/14968
331- return error .SkipZigTest ;
332- }
333- var cwd = fs .cwd ();
330+
334331 var tmp = tmpDir (.{});
332+ defer tmp .cleanup ();
333+
334+ const target_name = "link-target" ;
335+ const link_name = "newlink" ;
335336
336- cwd .deleteFile ("example.txt" ) catch {};
337- tmp .dir .deleteFile ("new.txt" ) catch {};
337+ const subdir = try tmp .dir .makeOpenPath ("subdir" , .{});
338338
339- try cwd . writeFile (.{ . sub_path = "example.txt" , . data = "example" }) ;
340- try posix . linkat ( cwd . fd , "example.txt" , tmp . dir . fd , "new.txt" , 0 );
339+ defer tmp . dir . deleteFile ( target_name ) catch {} ;
340+ try tmp . dir . writeFile (.{ . sub_path = target_name , . data = "example" } );
341341
342- const efd = try cwd .openFile ("example.txt" , .{});
342+ // Test 1: link from file in subdir back up to target in parent directory
343+ try posix .linkat (tmp .dir .fd , target_name , subdir .fd , link_name , 0 );
344+
345+ const efd = try tmp .dir .openFile (target_name , .{});
343346 defer efd .close ();
344347
345- const nfd = try tmp .dir .openFile ("new.txt" , .{});
348+ const nfd = try subdir .openFile (link_name , .{});
349+ defer nfd .close ();
346350
347351 {
348- defer nfd .close ();
349352 const estat = try posix .fstat (efd .handle );
350353 const nstat = try posix .fstat (nfd .handle );
351-
352354 try testing .expectEqual (estat .ino , nstat .ino );
353355 try testing .expectEqual (@as (@TypeOf (nstat .nlink ), 2 ), nstat .nlink );
354356 }
355357
356- try posix .unlinkat (tmp .dir .fd , "new.txt" , 0 );
358+ // Test 2: remove link
359+ try posix .unlinkat (subdir .fd , link_name , 0 );
357360
358361 {
359362 const estat = try posix .fstat (efd .handle );
360363 try testing .expectEqual (@as (@TypeOf (estat .nlink ), 1 ), estat .nlink );
361364 }
362-
363- try cwd .deleteFile ("example.txt" );
364365}
365366
366367test "fstatat" {
@@ -979,7 +980,7 @@ test "POSIX file locking with fcntl" {
979980 return error .SkipZigTest ;
980981 }
981982
982- var tmp = std . testing . tmpDir (.{});
983+ var tmp = tmpDir (.{});
983984 defer tmp .cleanup ();
984985
985986 // Create a temporary lock file
0 commit comments