authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-11 22:35:55-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:09-08:00
loge1cf753db72425fd944f6fe9f2a991fb1de3f942
tree4b9c33aa2cd4e0da5ad7e5fec9f0de45c6747507
parent68621afd2e203d82b6f53bf4ede951827fa98db8

std: update fchmodat tests


5 files changed, 243 insertions(+), 313 deletions(-)

lib/std/Build.zig+1-1
......@@ -1698,7 +1698,7 @@ pub fn addCheckFile(
16981698 return Step.CheckFile.create(b, file_source, options);
16991699}
17001700
1701pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.MakeError || Io.Dir.StatPathError)!void {
1701pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.MakeError || Io.Dir.StatFileError)!void {
17021702 const io = b.graph.io;
17031703 if (b.verbose) log.info("truncate {s}", .{dest_path});
17041704 const cwd = Io.Dir.cwd();
lib/std/Io/Dir.zig+1-1
......@@ -1710,7 +1710,7 @@ pub const SetFilePermissionsOptions = struct {
17101710 follow_symlinks: bool = true,
17111711};
17121712
1713/// Also known as "chmodat".
1713/// Also known as "fchmodat".
17141714pub fn setFilePermissions(
17151715 dir: Dir,
17161716 io: Io,
lib/std/Io/Kqueue.zig+2-2
......@@ -873,7 +873,7 @@ pub fn io(k: *Kqueue) Io {
873873 .dirMakePath = dirMakePath,
874874 .dirMakeOpenPath = dirMakeOpenPath,
875875 .dirStat = dirStat,
876 .dirStatPath = dirStatPath,
876 .dirStatFile = dirStatFile,
877877
878878 .fileStat = fileStat,
879879 .dirAccess = dirAccess,
......@@ -1144,7 +1144,7 @@ fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat {
11441144 _ = dir;
11451145 @panic("TODO");
11461146}
1147fn dirStatPath(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.StatPathOptions) Dir.StatPathError!File.Stat {
1147fn dirStatFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.StatPathOptions) Dir.StatFileError!File.Stat {
11481148 const k: *Kqueue = @ptrCast(@alignCast(userdata));
11491149 _ = k;
11501150 _ = dir;
lib/std/fs/test.zig+239-248
......@@ -3,19 +3,23 @@ const native_os = builtin.os.tag;
33
44const std = @import("../std.zig");
55const Io = std.Io;
6const testing = std.testing;
7const expect = std.testing.expect;
86const fs = std.fs;
97const mem = std.mem;
108const wasi = std.os.wasi;
119const windows = std.os.windows;
12const posix = std.posix;
1310const ArenaAllocator = std.heap.ArenaAllocator;
1411const Dir = std.Io.Dir;
1512const File = std.Io.File;
16const tmpDir = std.testing.tmpDir;
1713const SymLinkFlags = std.Io.Dir.SymLinkFlags;
1814
15const testing = std.testing;
16const expect = std.testing.expect;
17const expectError = std.testing.expectError;
18const expectEqual = std.testing.expectEqual;
19const tmpDir = std.testing.tmpDir;
20const expectEqualStrings = std.testing.expectEqualStrings;
21const expectEqualSlices = std.testing.expectEqualSlices;
22
1923const PathType = enum {
2024 relative,
2125 absolute,
......@@ -29,7 +33,7 @@ const PathType = enum {
2933 };
3034 }
3135
32 pub const TransformError = posix.RealPathError || error{OutOfMemory};
36 pub const TransformError = Io.Dir.RealPathError || error{OutOfMemory};
3337 pub const TransformFn = fn (allocator: mem.Allocator, dir: Dir, relative_path: [:0]const u8) TransformError![:0]const u8;
3438
3539 pub fn getTransformFn(comptime path_type: PathType) TransformFn {
......@@ -249,7 +253,7 @@ test "Dir.readLink on non-symlinks" {
249253fn testReadLink(io: Io, dir: Dir, target_path: []const u8, symlink_path: []const u8) !void {
250254 var buffer: [fs.max_path_bytes]u8 = undefined;
251255 const actual = try dir.readLink(io, symlink_path, &buffer);
252 try testing.expectEqualStrings(target_path, actual);
256 try expectEqualStrings(target_path, actual);
253257}
254258
255259fn testReadLinkW(allocator: mem.Allocator, dir: Dir, target_path: []const u8, symlink_path: []const u8) !void {
......@@ -260,13 +264,13 @@ fn testReadLinkW(allocator: mem.Allocator, dir: Dir, target_path: []const u8, sy
260264 const wtf16_buffer = try allocator.alloc(u16, target_path_w.len);
261265 defer allocator.free(wtf16_buffer);
262266 const actual = try dir.readLinkW(symlink_path_w.span(), wtf16_buffer);
263 try testing.expectEqualSlices(u16, target_path_w, actual);
267 try expectEqualSlices(u16, target_path_w, actual);
264268}
265269
266270fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void {
267271 var buffer: [fs.max_path_bytes]u8 = undefined;
268272 const given = try fs.readLinkAbsolute(symlink_path, buffer[0..]);
269 try testing.expectEqualStrings(target_path, given);
273 try expectEqualStrings(target_path, given);
270274}
271275
272276test "File.stat on a File that is a symlink returns Kind.sym_link" {
......@@ -286,72 +290,11 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
286290
287291 try setupSymlink(io, ctx.dir, dir_target_path, "symlink", .{ .is_directory = true });
288292
289 var symlink: Dir = switch (builtin.target.os.tag) {
290 .windows => windows_symlink: {
291 const sub_path_w = try windows.cStrToPrefixedFileW(ctx.dir.handle, "symlink");
292
293 var result: Dir = .{
294 .handle = undefined,
295 };
296
297 const path_len_bytes = @as(u16, @intCast(sub_path_w.span().len * 2));
298 var nt_name = windows.UNICODE_STRING{
299 .Length = path_len_bytes,
300 .MaximumLength = path_len_bytes,
301 .Buffer = @constCast(&sub_path_w.data),
302 };
303 var attr: windows.OBJECT_ATTRIBUTES = .{
304 .Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
305 .RootDirectory = if (fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else ctx.dir.handle,
306 .Attributes = 0,
307 .ObjectName = &nt_name,
308 .SecurityDescriptor = null,
309 .SecurityQualityOfService = null,
310 };
311 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
312 const rc = windows.ntdll.NtCreateFile(
313 &result.handle,
314 windows.STANDARD_RIGHTS_READ | windows.FILE_READ_ATTRIBUTES | windows.FILE_READ_EA | windows.SYNCHRONIZE | windows.FILE_TRAVERSE,
315 &attr,
316 &io_status_block,
317 null,
318 .{ .NORMAL = true },
319 .VALID_FLAGS,
320 .OPEN,
321 .{
322 .DIRECTORY_FILE = true,
323 .IO = .SYNCHRONOUS_NONALERT,
324 .OPEN_FOR_BACKUP_INTENT = true,
325 .OPEN_REPARSE_POINT = true, // the important thing here
326 },
327 null,
328 0,
329 );
330
331 switch (rc) {
332 .SUCCESS => break :windows_symlink .{ .fd = result.handle },
333 else => return windows.unexpectedStatus(rc),
334 }
335 },
336 .linux => linux_symlink: {
337 const sub_path_c = try posix.toPosixPath("symlink");
338 // the O_NOFOLLOW | O_PATH combination can obtain a fd to a symlink
339 // note that if O_DIRECTORY is set, then this will error with ENOTDIR
340 const flags: posix.O = .{
341 .NOFOLLOW = true,
342 .PATH = true,
343 .ACCMODE = .RDONLY,
344 .CLOEXEC = true,
345 };
346 const fd = try posix.openatZ(ctx.dir.handle, &sub_path_c, flags, 0);
347 break :linux_symlink .{ .handle = fd };
348 },
349 else => unreachable,
350 };
293 var symlink: Dir = try ctx.dir.openDir("symlink", .{ .follow_symlinks = false });
351294 defer symlink.close(io);
352295
353296 const stat = try symlink.stat(io);
354 try testing.expectEqual(File.Kind.sym_link, stat.kind);
297 try expectEqual(File.Kind.sym_link, stat.kind);
355298 }
356299 }.impl);
357300}
......@@ -417,7 +360,7 @@ test "openDirAbsolute" {
417360 defer dir.close(io);
418361
419362 const ino = (try dir.stat(io)).inode;
420 try testing.expectEqual(tmp_ino, ino);
363 try expectEqual(tmp_ino, ino);
421364 }
422365
423366 {
......@@ -429,7 +372,7 @@ test "openDirAbsolute" {
429372 defer dir.close(io);
430373
431374 const ino = (try dir.stat(io)).inode;
432 try testing.expectEqual(sub_ino, ino);
375 try expectEqual(sub_ino, ino);
433376 }
434377
435378 {
......@@ -441,7 +384,7 @@ test "openDirAbsolute" {
441384 defer dir.close(io);
442385
443386 const ino = (try dir.stat(io)).inode;
444 try testing.expectEqual(tmp_ino, ino);
387 try expectEqual(tmp_ino, ino);
445388 }
446389}
447390
......@@ -480,7 +423,7 @@ test "openDir non-cwd parent '..'" {
480423 const actual_path = try dir.realpathAlloc(testing.allocator, ".");
481424 defer testing.allocator.free(actual_path);
482425
483 try testing.expectEqualStrings(expected_path, actual_path);
426 try expectEqualStrings(expected_path, actual_path);
484427}
485428
486429test "readLinkAbsolute" {
......@@ -548,7 +491,7 @@ test "Dir.Iterator" {
548491 try entries.append(Dir.Entry{ .name = name, .kind = entry.kind });
549492 }
550493
551 try testing.expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
494 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
552495 try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
553496 try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
554497}
......@@ -619,7 +562,7 @@ test "Dir.Iterator twice" {
619562 try entries.append(Dir.Entry{ .name = name, .kind = entry.kind });
620563 }
621564
622 try testing.expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
565 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
623566 try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
624567 try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
625568 }
......@@ -655,7 +598,7 @@ test "Dir.Iterator reset" {
655598 try entries.append(.{ .name = name, .kind = entry.kind });
656599 }
657600
658 try testing.expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
601 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
659602 try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
660603 try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
661604
......@@ -690,7 +633,7 @@ test "Dir.Iterator but dir is deleted during iteration" {
690633
691634 // On Linux, we can opt-in to receiving a more specific error by calling `nextLinux`
692635 if (native_os == .linux) {
693 try std.testing.expectError(error.DirNotFound, iterator.nextLinux());
636 try expectError(error.DirNotFound, iterator.nextLinux());
694637 }
695638}
696639
......@@ -717,10 +660,10 @@ test "Dir.realpath smoke test" {
717660 var buf: [fs.max_path_bytes]u8 = undefined;
718661
719662 // FileNotFound if the path doesn't exist
720 try testing.expectError(error.FileNotFound, ctx.dir.realpathAlloc(allocator, test_file_path));
721 try testing.expectError(error.FileNotFound, ctx.dir.realpath(test_file_path, &buf));
722 try testing.expectError(error.FileNotFound, ctx.dir.realpathAlloc(allocator, test_dir_path));
723 try testing.expectError(error.FileNotFound, ctx.dir.realpath(test_dir_path, &buf));
663 try expectError(error.FileNotFound, ctx.dir.realpathAlloc(allocator, test_file_path));
664 try expectError(error.FileNotFound, ctx.dir.realpath(test_file_path, &buf));
665 try expectError(error.FileNotFound, ctx.dir.realpathAlloc(allocator, test_dir_path));
666 try expectError(error.FileNotFound, ctx.dir.realpath(test_dir_path, &buf));
724667
725668 // Now create the file and dir
726669 try ctx.dir.writeFile(io, .{ .sub_path = test_file_path, .data = "" });
......@@ -740,19 +683,19 @@ test "Dir.realpath smoke test" {
740683 // First, test non-alloc version
741684 {
742685 const file_path = try ctx.dir.realpath(test_file_path, &buf);
743 try testing.expectEqualStrings(expected_file_path, file_path);
686 try expectEqualStrings(expected_file_path, file_path);
744687
745688 const dir_path = try ctx.dir.realpath(test_dir_path, &buf);
746 try testing.expectEqualStrings(expected_dir_path, dir_path);
689 try expectEqualStrings(expected_dir_path, dir_path);
747690 }
748691
749692 // Next, test alloc version
750693 {
751694 const file_path = try ctx.dir.realpathAlloc(allocator, test_file_path);
752 try testing.expectEqualStrings(expected_file_path, file_path);
695 try expectEqualStrings(expected_file_path, file_path);
753696
754697 const dir_path = try ctx.dir.realpathAlloc(allocator, test_dir_path);
755 try testing.expectEqualStrings(expected_dir_path, dir_path);
698 try expectEqualStrings(expected_dir_path, dir_path);
756699 }
757700 }
758701 }.impl);
......@@ -769,7 +712,7 @@ test "readFileAlloc" {
769712
770713 const buf1 = try tmp_dir.dir.readFileAlloc(io, "test_file", testing.allocator, .limited(1024));
771714 defer testing.allocator.free(buf1);
772 try testing.expectEqualStrings("", buf1);
715 try expectEqualStrings("", buf1);
773716
774717 const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n";
775718 try file.writeAll(write_buf);
......@@ -778,12 +721,12 @@ test "readFileAlloc" {
778721 // max_bytes > file_size
779722 const buf2 = try tmp_dir.dir.readFileAlloc(io, "test_file", testing.allocator, .limited(1024));
780723 defer testing.allocator.free(buf2);
781 try testing.expectEqualStrings(write_buf, buf2);
724 try expectEqualStrings(write_buf, buf2);
782725 }
783726
784727 {
785728 // max_bytes == file_size
786 try testing.expectError(
729 try expectError(
787730 error.StreamTooLong,
788731 tmp_dir.dir.readFileAlloc(io, "test_file", testing.allocator, .limited(write_buf.len)),
789732 );
......@@ -793,11 +736,11 @@ test "readFileAlloc" {
793736 // max_bytes == file_size + 1
794737 const buf2 = try tmp_dir.dir.readFileAlloc(io, "test_file", testing.allocator, .limited(write_buf.len + 1));
795738 defer testing.allocator.free(buf2);
796 try testing.expectEqualStrings(write_buf, buf2);
739 try expectEqualStrings(write_buf, buf2);
797740 }
798741
799742 // max_bytes < file_size
800 try testing.expectError(
743 try expectError(
801744 error.StreamTooLong,
802745 tmp_dir.dir.readFileAlloc(io, "test_file", testing.allocator, .limited(write_buf.len - 1)),
803746 );
......@@ -809,12 +752,12 @@ test "Dir.statFile" {
809752 const io = ctx.io;
810753 const test_file_name = try ctx.transformPath("test_file");
811754
812 try testing.expectError(error.FileNotFound, ctx.dir.statFile(io, test_file_name, .{}));
755 try expectError(error.FileNotFound, ctx.dir.statFile(io, test_file_name, .{}));
813756
814757 try ctx.dir.writeFile(io, .{ .sub_path = test_file_name, .data = "" });
815758
816759 const stat = try ctx.dir.statFile(io, test_file_name, .{});
817 try testing.expectEqual(File.Kind.file, stat.kind);
760 try expectEqual(File.Kind.file, stat.kind);
818761 }
819762 }.impl);
820763}
......@@ -828,7 +771,7 @@ test "statFile on dangling symlink" {
828771
829772 try setupSymlink(io, ctx.dir, symlink_target, symlink_name, .{});
830773
831 try std.testing.expectError(error.FileNotFound, ctx.dir.statFile(io, symlink_name, .{}));
774 try expectError(error.FileNotFound, ctx.dir.statFile(io, symlink_name, .{}));
832775 }
833776 }.impl);
834777}
......@@ -843,19 +786,19 @@ test "directory operations on files" {
843786 var file = try ctx.dir.createFile(io, test_file_name, .{ .read = true });
844787 file.close(io);
845788
846 try testing.expectError(error.PathAlreadyExists, ctx.dir.makeDir(io, test_file_name, .default_dir));
847 try testing.expectError(error.NotDir, ctx.dir.openDir(io, test_file_name, .{}));
848 try testing.expectError(error.NotDir, ctx.dir.deleteDir(io, test_file_name));
789 try expectError(error.PathAlreadyExists, ctx.dir.makeDir(io, test_file_name, .default_dir));
790 try expectError(error.NotDir, ctx.dir.openDir(io, test_file_name, .{}));
791 try expectError(error.NotDir, ctx.dir.deleteDir(io, test_file_name));
849792
850793 if (ctx.path_type == .absolute and comptime PathType.absolute.isSupported(builtin.os)) {
851 try testing.expectError(error.PathAlreadyExists, fs.makeDirAbsolute(test_file_name));
852 try testing.expectError(error.NotDir, fs.deleteDirAbsolute(test_file_name));
794 try expectError(error.PathAlreadyExists, fs.makeDirAbsolute(test_file_name));
795 try expectError(error.NotDir, fs.deleteDirAbsolute(test_file_name));
853796 }
854797
855798 // ensure the file still exists and is a file as a sanity check
856799 file = try ctx.dir.openFile(io, test_file_name, .{});
857800 const stat = try file.stat(io);
858 try testing.expectEqual(File.Kind.file, stat.kind);
801 try expectEqual(File.Kind.file, stat.kind);
859802 file.close(io);
860803 }
861804 }.impl);
......@@ -873,8 +816,8 @@ test "file operations on directories" {
873816
874817 try ctx.dir.makeDir(io, test_dir_name, .default_dir);
875818
876 try testing.expectError(error.IsDir, ctx.dir.createFile(io, test_dir_name, .{}));
877 try testing.expectError(error.IsDir, ctx.dir.deleteFile(io, test_dir_name));
819 try expectError(error.IsDir, ctx.dir.createFile(io, test_dir_name, .{}));
820 try expectError(error.IsDir, ctx.dir.deleteFile(io, test_dir_name));
878821 switch (native_os) {
879822 .dragonfly, .netbsd => {
880823 // no error when reading a directory. See https://github.com/ziglang/zig/issues/5732
......@@ -884,10 +827,10 @@ test "file operations on directories" {
884827 .wasi => {
885828 // WASI return EBADF, which gets mapped to NotOpenForReading.
886829 // See https://github.com/bytecodealliance/wasmtime/issues/1935
887 try testing.expectError(error.NotOpenForReading, ctx.dir.readFileAlloc(io, test_dir_name, testing.allocator, .unlimited));
830 try expectError(error.NotOpenForReading, ctx.dir.readFileAlloc(io, test_dir_name, testing.allocator, .unlimited));
888831 },
889832 else => {
890 try testing.expectError(error.IsDir, ctx.dir.readFileAlloc(io, test_dir_name, testing.allocator, .unlimited));
833 try expectError(error.IsDir, ctx.dir.readFileAlloc(io, test_dir_name, testing.allocator, .unlimited));
891834 },
892835 }
893836
......@@ -898,12 +841,12 @@ test "file operations on directories" {
898841 } else {
899842 // Note: The `.mode = .read_write` is necessary to ensure the error occurs on all platforms.
900843 // TODO: Add a read-only test as well, see https://github.com/ziglang/zig/issues/5732
901 try testing.expectError(error.IsDir, ctx.dir.openFile(io, test_dir_name, .{ .mode = .read_write }));
844 try expectError(error.IsDir, ctx.dir.openFile(io, test_dir_name, .{ .mode = .read_write }));
902845 }
903846
904847 if (ctx.path_type == .absolute and comptime PathType.absolute.isSupported(builtin.os)) {
905 try testing.expectError(error.IsDir, fs.createFileAbsolute(test_dir_name, .{}));
906 try testing.expectError(error.IsDir, fs.deleteFileAbsolute(test_dir_name));
848 try expectError(error.IsDir, fs.createFileAbsolute(test_dir_name, .{}));
849 try expectError(error.IsDir, fs.deleteFileAbsolute(test_dir_name));
907850 }
908851
909852 // ensure the directory still exists as a sanity check
......@@ -935,12 +878,12 @@ test "deleteDir" {
935878 const test_file_path = try ctx.transformPath("test_dir" ++ fs.path.sep_str ++ "test_file");
936879
937880 // deleting a non-existent directory
938 try testing.expectError(error.FileNotFound, ctx.dir.deleteDir(io, test_dir_path));
881 try expectError(error.FileNotFound, ctx.dir.deleteDir(io, test_dir_path));
939882
940883 // deleting a non-empty directory
941884 try ctx.dir.makeDir(io, test_dir_path, .default_dir);
942885 try ctx.dir.writeFile(io, .{ .sub_path = test_file_path, .data = "" });
943 try testing.expectError(error.DirNotEmpty, ctx.dir.deleteDir(io, test_dir_path));
886 try expectError(error.DirNotEmpty, ctx.dir.deleteDir(io, test_dir_path));
944887
945888 // deleting an empty directory
946889 try ctx.dir.deleteFile(io, test_file_path);
......@@ -962,7 +905,7 @@ test "Dir.rename files" {
962905 const missing_file_path = try ctx.transformPath("missing_file_name");
963906 const something_else_path = try ctx.transformPath("something_else");
964907
965 try testing.expectError(error.FileNotFound, ctx.dir.rename(missing_file_path, ctx.dir, something_else_path, io));
908 try expectError(error.FileNotFound, ctx.dir.rename(missing_file_path, ctx.dir, something_else_path, io));
966909
967910 // Renaming files
968911 const test_file_name = try ctx.transformPath("test_file");
......@@ -972,7 +915,7 @@ test "Dir.rename files" {
972915 try ctx.dir.rename(test_file_name, ctx.dir, renamed_test_file_name, io);
973916
974917 // Ensure the file was renamed
975 try testing.expectError(error.FileNotFound, ctx.dir.openFile(io, test_file_name, .{}));
918 try expectError(error.FileNotFound, ctx.dir.openFile(io, test_file_name, .{}));
976919 file = try ctx.dir.openFile(io, renamed_test_file_name, .{});
977920 file.close(io);
978921
......@@ -985,7 +928,7 @@ test "Dir.rename files" {
985928 existing_file.close(io);
986929 try ctx.dir.rename(renamed_test_file_name, ctx.dir, existing_file_path, io);
987930
988 try testing.expectError(error.FileNotFound, ctx.dir.openFile(io, renamed_test_file_name, .{}));
931 try expectError(error.FileNotFound, ctx.dir.openFile(io, renamed_test_file_name, .{}));
989932 file = try ctx.dir.openFile(io, existing_file_path, .{});
990933 file.close(io);
991934 }
......@@ -1011,7 +954,7 @@ test "Dir.rename directories" {
1011954 try ctx.dir.rename(test_dir_path, ctx.dir, test_dir_renamed_path, io);
1012955
1013956 // Ensure the directory was renamed
1014 try testing.expectError(error.FileNotFound, ctx.dir.openDir(io, test_dir_path, .{}));
957 try expectError(error.FileNotFound, ctx.dir.openDir(io, test_dir_path, .{}));
1015958 var dir = try ctx.dir.openDir(io, test_dir_renamed_path, .{});
1016959
1017960 // Put a file in the directory
......@@ -1023,7 +966,7 @@ test "Dir.rename directories" {
1023966 try ctx.dir.rename(test_dir_renamed_path, ctx.dir, test_dir_renamed_again_path, io);
1024967
1025968 // Ensure the directory was renamed and the file still exists in it
1026 try testing.expectError(error.FileNotFound, ctx.dir.openDir(io, test_dir_renamed_path, .{}));
969 try expectError(error.FileNotFound, ctx.dir.openDir(io, test_dir_renamed_path, .{}));
1027970 dir = try ctx.dir.openDir(io, test_dir_renamed_again_path, .{});
1028971 file = try dir.openFile(io, "test_file", .{});
1029972 file.close(io);
......@@ -1048,7 +991,7 @@ test "Dir.rename directory onto empty dir" {
1048991 try ctx.dir.rename(test_dir_path, ctx.dir, target_dir_path, io);
1049992
1050993 // Ensure the directory was renamed
1051 try testing.expectError(error.FileNotFound, ctx.dir.openDir(io, test_dir_path, .{}));
994 try expectError(error.FileNotFound, ctx.dir.openDir(io, test_dir_path, .{}));
1052995 var dir = try ctx.dir.openDir(io, target_dir_path, .{});
1053996 dir.close(io);
1054997 }
......@@ -1073,7 +1016,7 @@ test "Dir.rename directory onto non-empty dir" {
10731016 target_dir.close(io);
10741017
10751018 // Rename should fail with PathAlreadyExists if target_dir is non-empty
1076 try testing.expectError(error.PathAlreadyExists, ctx.dir.rename(test_dir_path, ctx.dir, target_dir_path, io));
1019 try expectError(error.PathAlreadyExists, ctx.dir.rename(test_dir_path, ctx.dir, target_dir_path, io));
10771020
10781021 // Ensure the directory was not renamed
10791022 var dir = try ctx.dir.openDir(io, test_dir_path, .{});
......@@ -1095,8 +1038,8 @@ test "Dir.rename file <-> dir" {
10951038 var file = try ctx.dir.createFile(io, test_file_path, .{ .read = true });
10961039 file.close(io);
10971040 try ctx.dir.makeDir(io, test_dir_path, .default_dir);
1098 try testing.expectError(error.IsDir, ctx.dir.rename(test_file_path, ctx.dir, test_dir_path, io));
1099 try testing.expectError(error.NotDir, ctx.dir.rename(test_dir_path, ctx.dir, test_file_path, io));
1041 try expectError(error.IsDir, ctx.dir.rename(test_file_path, ctx.dir, test_dir_path, io));
1042 try expectError(error.NotDir, ctx.dir.rename(test_dir_path, ctx.dir, test_file_path, io));
11001043 }
11011044 }.impl);
11021045}
......@@ -1118,7 +1061,7 @@ test "rename" {
11181061 try Dir.rename(tmp_dir1.dir, test_file_name, tmp_dir2.dir, renamed_test_file_name, io);
11191062
11201063 // ensure the file was renamed
1121 try testing.expectError(error.FileNotFound, tmp_dir1.dir.openFile(io, test_file_name, .{}));
1064 try expectError(error.FileNotFound, tmp_dir1.dir.openFile(io, test_file_name, .{}));
11221065 file = try tmp_dir2.dir.openFile(io, renamed_test_file_name, .{});
11231066 file.close(io);
11241067}
......@@ -1139,7 +1082,7 @@ test "renameAbsolute" {
11391082
11401083 const base_path = try tmp_dir.dir.realpathAlloc(allocator, ".");
11411084
1142 try testing.expectError(error.FileNotFound, fs.renameAbsolute(
1085 try expectError(error.FileNotFound, fs.renameAbsolute(
11431086 try fs.path.join(allocator, &.{ base_path, "missing_file_name" }),
11441087 try fs.path.join(allocator, &.{ base_path, "something_else" }),
11451088 ));
......@@ -1155,10 +1098,10 @@ test "renameAbsolute" {
11551098 );
11561099
11571100 // ensure the file was renamed
1158 try testing.expectError(error.FileNotFound, tmp_dir.dir.openFile(io, test_file_name, .{}));
1101 try expectError(error.FileNotFound, tmp_dir.dir.openFile(io, test_file_name, .{}));
11591102 file = try tmp_dir.dir.openFile(io, renamed_test_file_name, .{});
11601103 const stat = try file.stat(io);
1161 try testing.expectEqual(File.Kind.file, stat.kind);
1104 try expectEqual(File.Kind.file, stat.kind);
11621105 file.close(io);
11631106
11641107 // Renaming directories
......@@ -1171,7 +1114,7 @@ test "renameAbsolute" {
11711114 );
11721115
11731116 // ensure the directory was renamed
1174 try testing.expectError(error.FileNotFound, tmp_dir.dir.openDir(io, test_dir_name, .{}));
1117 try expectError(error.FileNotFound, tmp_dir.dir.openDir(io, test_dir_name, .{}));
11751118 var dir = try tmp_dir.dir.openDir(io, renamed_test_dir_name, .{});
11761119 dir.close(io);
11771120}
......@@ -1193,7 +1136,7 @@ test "executablePath" {
11931136 const buf_self_exe_path = try std.process.executablePath(io, &buf);
11941137 const alloc_self_exe_path = try std.process.executablePathAlloc(io, testing.allocator);
11951138 defer testing.allocator.free(alloc_self_exe_path);
1196 try testing.expectEqualSlices(u8, buf_self_exe_path, alloc_self_exe_path);
1139 try expectEqualSlices(u8, buf_self_exe_path, alloc_self_exe_path);
11971140}
11981141
11991142test "deleteTree does not follow symlinks" {
......@@ -1212,7 +1155,7 @@ test "deleteTree does not follow symlinks" {
12121155
12131156 try tmp.dir.deleteTree(io, "a");
12141157
1215 try testing.expectError(error.FileNotFound, tmp.dir.access(io, "a", .{}));
1158 try expectError(error.FileNotFound, tmp.dir.access(io, "a", .{}));
12161159 try tmp.dir.access(io, "b", .{});
12171160}
12181161
......@@ -1227,7 +1170,7 @@ test "deleteTree on a symlink" {
12271170 try setupSymlink(io, tmp.dir, "file", "filelink", .{});
12281171
12291172 try tmp.dir.deleteTree(io, "filelink");
1230 try testing.expectError(error.FileNotFound, tmp.dir.access(io, "filelink", .{}));
1173 try expectError(error.FileNotFound, tmp.dir.access(io, "filelink", .{}));
12311174 try tmp.dir.access(io, "file", .{});
12321175
12331176 // Symlink to a directory
......@@ -1235,7 +1178,7 @@ test "deleteTree on a symlink" {
12351178 try setupSymlink(io, tmp.dir, "dir", "dirlink", .{ .is_directory = true });
12361179
12371180 try tmp.dir.deleteTree(io, "dirlink");
1238 try testing.expectError(error.FileNotFound, tmp.dir.access(io, "dirlink", .{}));
1181 try expectError(error.FileNotFound, tmp.dir.access(io, "dirlink", .{}));
12391182 try tmp.dir.access(io, "dir", .{});
12401183}
12411184
......@@ -1257,7 +1200,7 @@ test "makePath, put some files in it, deleteTree" {
12571200 });
12581201
12591202 try ctx.dir.deleteTree(io, dir_path);
1260 try testing.expectError(error.FileNotFound, ctx.dir.openDir(io, dir_path, .{}));
1203 try expectError(error.FileNotFound, ctx.dir.openDir(io, dir_path, .{}));
12611204 }
12621205 }.impl);
12631206}
......@@ -1280,7 +1223,7 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {
12801223 });
12811224
12821225 try ctx.dir.deleteTreeMinStackSize(dir_path);
1283 try testing.expectError(error.FileNotFound, ctx.dir.openDir(io, dir_path, .{}));
1226 try expectError(error.FileNotFound, ctx.dir.openDir(io, dir_path, .{}));
12841227 }
12851228 }.impl);
12861229}
......@@ -1294,7 +1237,7 @@ test "makePath in a directory that no longer exists" {
12941237 defer tmp.cleanup();
12951238 try tmp.parent_dir.deleteTree(io, &tmp.sub_path);
12961239
1297 try testing.expectError(error.FileNotFound, tmp.dir.makePath(io, "sub-path"));
1240 try expectError(error.FileNotFound, tmp.dir.makePath(io, "sub-path"));
12981241}
12991242
13001243test "makePath but sub_path contains pre-existing file" {
......@@ -1306,7 +1249,7 @@ test "makePath but sub_path contains pre-existing file" {
13061249 try tmp.dir.makeDir(io, "foo", .default_dir);
13071250 try tmp.dir.writeFile(io, .{ .sub_path = "foo/bar", .data = "" });
13081251
1309 try testing.expectError(error.NotDir, tmp.dir.makePath(io, "foo/bar/baz"));
1252 try expectError(error.NotDir, tmp.dir.makePath(io, "foo/bar/baz"));
13101253}
13111254
13121255fn expectDir(io: Io, dir: Dir, path: []const u8) !void {
......@@ -1364,8 +1307,8 @@ test "makepath relative walks" {
13641307 // On Windows, .. is resolved before passing the path to NtCreateFile,
13651308 // meaning everything except `first/C` drops out.
13661309 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "C");
1367 try testing.expectError(error.FileNotFound, tmp.dir.access(io, "second", .{}));
1368 try testing.expectError(error.FileNotFound, tmp.dir.access(io, "third", .{}));
1310 try expectError(error.FileNotFound, tmp.dir.access(io, "second", .{}));
1311 try expectError(error.FileNotFound, tmp.dir.access(io, "third", .{}));
13691312 },
13701313 else => {
13711314 try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "A");
......@@ -1413,10 +1356,10 @@ fn testFilenameLimits(io: Io, iterable_dir: Dir, maxed_filename: []const u8) !vo
14131356
14141357 var count: usize = 0;
14151358 while (try walker.next()) |entry| {
1416 try testing.expectEqualStrings(maxed_filename, entry.basename);
1359 try expectEqualStrings(maxed_filename, entry.basename);
14171360 count += 1;
14181361 }
1419 try testing.expectEqual(@as(usize, 2), count);
1362 try expectEqual(@as(usize, 2), count);
14201363 }
14211364
14221365 // ensure that we can delete the tree
......@@ -1467,14 +1410,14 @@ test "writev, readv" {
14671410
14681411 try writer.interface.writeVecAll(&write_vecs);
14691412 try writer.interface.flush();
1470 try testing.expectEqual(@as(u64, line1.len + line2.len), try src_file.length(io));
1413 try expectEqual(@as(u64, line1.len + line2.len), try src_file.length(io));
14711414
14721415 var reader = writer.moveToReader(io);
14731416 try reader.seekTo(0);
14741417 try reader.interface.readVecAll(&read_vecs);
1475 try testing.expectEqualStrings(&buf1, "line2\n");
1476 try testing.expectEqualStrings(&buf2, "line1\n");
1477 try testing.expectError(error.EndOfStream, reader.interface.readSliceAll(&buf1));
1418 try expectEqualStrings(&buf1, "line2\n");
1419 try expectEqualStrings(&buf2, "line1\n");
1420 try expectError(error.EndOfStream, reader.interface.readSliceAll(&buf1));
14781421}
14791422
14801423test "pwritev, preadv" {
......@@ -1498,14 +1441,14 @@ test "pwritev, preadv" {
14981441 try writer.seekTo(16);
14991442 try writer.interface.writeVecAll(&lines);
15001443 try writer.interface.flush();
1501 try testing.expectEqual(@as(u64, 16 + line1.len + line2.len), try src_file.length(io));
1444 try expectEqual(@as(u64, 16 + line1.len + line2.len), try src_file.length(io));
15021445
15031446 var reader = writer.moveToReader(io);
15041447 try reader.seekTo(16);
15051448 try reader.interface.readVecAll(&read_vecs);
1506 try testing.expectEqualStrings(&buf1, "line2\n");
1507 try testing.expectEqualStrings(&buf2, "line1\n");
1508 try testing.expectError(error.EndOfStream, reader.interface.readSliceAll(&buf1));
1449 try expectEqualStrings(&buf1, "line2\n");
1450 try expectEqualStrings(&buf2, "line1\n");
1451 try expectError(error.EndOfStream, reader.interface.readSliceAll(&buf1));
15091452}
15101453
15111454test "setEndPos" {
......@@ -1529,34 +1472,34 @@ test "setEndPos" {
15291472
15301473 {
15311474 try f.setEndPos(initial_size);
1532 try testing.expectEqual(initial_size, try f.length(io));
1475 try expectEqual(initial_size, try f.length(io));
15331476 try reader.seekTo(0);
1534 try testing.expectEqual(initial_size, try reader.interface.readSliceShort(&buffer));
1535 try testing.expectEqualStrings("ninebytes", buffer[0..@intCast(initial_size)]);
1477 try expectEqual(initial_size, try reader.interface.readSliceShort(&buffer));
1478 try expectEqualStrings("ninebytes", buffer[0..@intCast(initial_size)]);
15361479 }
15371480
15381481 {
15391482 const larger = initial_size + 4;
15401483 try f.setEndPos(larger);
1541 try testing.expectEqual(larger, try f.length(io));
1484 try expectEqual(larger, try f.length(io));
15421485 try reader.seekTo(0);
1543 try testing.expectEqual(larger, try reader.interface.readSliceShort(&buffer));
1544 try testing.expectEqualStrings("ninebytes\x00\x00\x00\x00", buffer[0..@intCast(larger)]);
1486 try expectEqual(larger, try reader.interface.readSliceShort(&buffer));
1487 try expectEqualStrings("ninebytes\x00\x00\x00\x00", buffer[0..@intCast(larger)]);
15451488 }
15461489
15471490 {
15481491 const smaller = initial_size - 5;
15491492 try f.setEndPos(smaller);
1550 try testing.expectEqual(smaller, try f.length(io));
1493 try expectEqual(smaller, try f.length(io));
15511494 try reader.seekTo(0);
1552 try testing.expectEqual(smaller, try reader.interface.readSliceShort(&buffer));
1553 try testing.expectEqualStrings("nine", buffer[0..@intCast(smaller)]);
1495 try expectEqual(smaller, try reader.interface.readSliceShort(&buffer));
1496 try expectEqualStrings("nine", buffer[0..@intCast(smaller)]);
15541497 }
15551498
15561499 try f.setEndPos(0);
1557 try testing.expectEqual(0, try f.length(io));
1500 try expectEqual(0, try f.length(io));
15581501 try reader.seekTo(0);
1559 try testing.expectEqual(0, try reader.interface.readSliceShort(&buffer));
1502 try expectEqual(0, try reader.interface.readSliceShort(&buffer));
15601503}
15611504
15621505test "access file" {
......@@ -1567,7 +1510,7 @@ test "access file" {
15671510 const file_path = try ctx.transformPath("os_test_tmp" ++ fs.path.sep_str ++ "file.txt");
15681511
15691512 try ctx.dir.makePath(io, dir_path);
1570 try testing.expectError(error.FileNotFound, ctx.dir.access(io, file_path, .{}));
1513 try expectError(error.FileNotFound, ctx.dir.access(io, file_path, .{}));
15711514
15721515 try ctx.dir.writeFile(io, .{ .sub_path = file_path, .data = "" });
15731516 try ctx.dir.access(io, file_path, .{});
......@@ -1614,13 +1557,13 @@ test "sendfile" {
16141557 var file_writer = dest_file.writer(io, &fallback_buffer);
16151558 try file_writer.interface.writeVecAll(&headers);
16161559 try file_reader.seekTo(1);
1617 try testing.expectEqual(10, try file_writer.interface.sendFileAll(&file_reader, .limited(10)));
1560 try expectEqual(10, try file_writer.interface.sendFileAll(&file_reader, .limited(10)));
16181561 try file_writer.interface.writeVecAll(&trailers);
16191562 try file_writer.interface.flush();
16201563 var fr = file_writer.moveToReader(io);
16211564 try fr.seekTo(0);
16221565 const amt = try fr.interface.readSliceShort(&written_buf);
1623 try testing.expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]);
1566 try expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]);
16241567}
16251568
16261569test "sendfile with buffered data" {
......@@ -1651,15 +1594,15 @@ test "sendfile with buffered data" {
16511594 var fallback_buffer: [32]u8 = undefined;
16521595 var file_writer = dest_file.writer(io, &fallback_buffer);
16531596
1654 try std.testing.expectEqual(4, try file_writer.interface.sendFileAll(&file_reader, .limited(4)));
1597 try expectEqual(4, try file_writer.interface.sendFileAll(&file_reader, .limited(4)));
16551598
16561599 var written_buf: [8]u8 = undefined;
16571600 var fr = file_writer.moveToReader(io);
16581601 try fr.seekTo(0);
16591602 const amt = try fr.interface.readSliceShort(&written_buf);
16601603
1661 try std.testing.expectEqual(4, amt);
1662 try std.testing.expectEqualSlices(u8, "AAAA", written_buf[0..amt]);
1604 try expectEqual(4, amt);
1605 try expectEqualSlices(u8, "AAAA", written_buf[0..amt]);
16631606}
16641607
16651608test "copyFile" {
......@@ -1690,7 +1633,7 @@ fn expectFileContents(io: Io, dir: Dir, file_path: []const u8, data: []const u8)
16901633 const contents = try dir.readFileAlloc(io, file_path, testing.allocator, .limited(1000));
16911634 defer testing.allocator.free(contents);
16921635
1693 try testing.expectEqualSlices(u8, data, contents);
1636 try expectEqualSlices(u8, data, contents);
16941637}
16951638
16961639test "AtomicFile" {
......@@ -1712,7 +1655,7 @@ test "AtomicFile" {
17121655 try af.finish();
17131656 }
17141657 const content = try ctx.dir.readFileAlloc(io, test_out_file, allocator, .limited(9999));
1715 try testing.expectEqualStrings(test_content, content);
1658 try expectEqualStrings(test_content, content);
17161659
17171660 try ctx.dir.deleteFile(io, test_out_file);
17181661 }
......@@ -1731,7 +1674,7 @@ test "open file with exclusive nonblocking lock twice" {
17311674 defer file1.close(io);
17321675
17331676 const file2 = ctx.dir.createFile(io, filename, .{ .lock = .exclusive, .lock_nonblocking = true });
1734 try testing.expectError(error.WouldBlock, file2);
1677 try expectError(error.WouldBlock, file2);
17351678 }
17361679 }.impl);
17371680}
......@@ -1748,7 +1691,7 @@ test "open file with shared and exclusive nonblocking lock" {
17481691 defer file1.close(io);
17491692
17501693 const file2 = ctx.dir.createFile(io, filename, .{ .lock = .exclusive, .lock_nonblocking = true });
1751 try testing.expectError(error.WouldBlock, file2);
1694 try expectError(error.WouldBlock, file2);
17521695 }
17531696 }.impl);
17541697}
......@@ -1765,7 +1708,7 @@ test "open file with exclusive and shared nonblocking lock" {
17651708 defer file1.close(io);
17661709
17671710 const file2 = ctx.dir.createFile(io, filename, .{ .lock = .shared, .lock_nonblocking = true });
1768 try testing.expectError(error.WouldBlock, file2);
1711 try expectError(error.WouldBlock, file2);
17691712 }
17701713 }.impl);
17711714}
......@@ -1805,7 +1748,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
18051748 // Wait for the spawned thread to start trying to acquire the exclusive file lock.
18061749 // Then wait a bit to make sure that can't acquire it since we currently hold the file lock.
18071750 started.wait();
1808 try testing.expectError(error.Timeout, locked.timedWait(10 * std.time.ns_per_ms));
1751 try expectError(error.Timeout, locked.timedWait(10 * std.time.ns_per_ms));
18091752
18101753 // Release the file lock which should unlock the thread to lock it and set the locked event.
18111754 file.close(io);
......@@ -1846,7 +1789,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
18461789 .lock_nonblocking = true,
18471790 });
18481791 file1.close(io);
1849 try testing.expectError(error.WouldBlock, file2);
1792 try expectError(error.WouldBlock, file2);
18501793}
18511794
18521795test "read from locked file" {
......@@ -1871,9 +1814,9 @@ test "read from locked file" {
18711814 defer f2.close(io);
18721815 var buffer: [1]u8 = undefined;
18731816 if (builtin.os.tag == .windows) {
1874 try std.testing.expectError(error.LockViolation, f2.read(&buffer));
1817 try expectError(error.LockViolation, f2.read(&buffer));
18751818 } else {
1876 try std.testing.expectEqual(0, f2.read(&buffer));
1819 try expectEqual(0, f2.read(&buffer));
18771820 }
18781821 }
18791822 }
......@@ -1925,7 +1868,7 @@ test "walker" {
19251868 std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
19261869 return err;
19271870 };
1928 testing.expectEqual(expected_paths.get(entry.path).?, entry.depth()) catch |err| {
1871 expectEqual(expected_paths.get(entry.path).?, entry.depth()) catch |err| {
19291872 std.debug.print("path reported unexpected depth: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
19301873 return err;
19311874 };
......@@ -1934,7 +1877,7 @@ test "walker" {
19341877 defer entry_dir.close(io);
19351878 num_walked += 1;
19361879 }
1937 try testing.expectEqual(expected_paths.kvs.len, num_walked);
1880 try expectEqual(expected_paths.kvs.len, num_walked);
19381881}
19391882
19401883test "selective walker, skip entries that start with ." {
......@@ -1992,7 +1935,7 @@ test "selective walker, skip entries that start with ." {
19921935 std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
19931936 return err;
19941937 };
1995 testing.expectEqual(expected_paths.get(entry.path).?, entry.depth()) catch |err| {
1938 expectEqual(expected_paths.get(entry.path).?, entry.depth()) catch |err| {
19961939 std.debug.print("path reported unexpected depth: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
19971940 return err;
19981941 };
......@@ -2002,7 +1945,7 @@ test "selective walker, skip entries that start with ." {
20021945 defer entry_dir.close(io);
20031946 num_walked += 1;
20041947 }
2005 try testing.expectEqual(expected_paths.kvs.len, num_walked);
1948 try expectEqual(expected_paths.kvs.len, num_walked);
20061949}
20071950
20081951test "walker without fully iterating" {
......@@ -2025,7 +1968,7 @@ test "walker without fully iterating" {
20251968 num_walked += 1;
20261969 break;
20271970 }
2028 try testing.expectEqual(@as(usize, 1), num_walked);
1971 try expectEqual(@as(usize, 1), num_walked);
20291972}
20301973
20311974test "'.' and '..' in Io.Dir functions" {
......@@ -2061,7 +2004,7 @@ test "'.' and '..' in Io.Dir functions" {
20612004 try ctx.dir.writeFile(io, .{ .sub_path = update_path, .data = "something" });
20622005 var dir = ctx.dir;
20632006 const prev_status = try dir.updateFile(io, file_path, dir, update_path, .{});
2064 try testing.expectEqual(Io.Dir.PrevStatus.stale, prev_status);
2007 try expectEqual(Io.Dir.PrevStatus.stale, prev_status);
20652008
20662009 try ctx.dir.deleteDir(io, subdir_path);
20672010 }
......@@ -2106,8 +2049,7 @@ test "'.' and '..' in absolute functions" {
21062049}
21072050
21082051test "chmod" {
2109 if (native_os == .windows or native_os == .wasi)
2110 return error.SkipZigTest;
2052 if (native_os == .windows or native_os == .wasi) return;
21112053
21122054 const io = testing.io;
21132055
......@@ -2116,17 +2058,17 @@ test "chmod" {
21162058
21172059 const file = try tmp.dir.createFile(io, "test_file", .{ .permissions = .fromMode(0o600) });
21182060 defer file.close(io);
2119 try testing.expectEqual(@as(posix.mode_t, 0o600), (try file.stat(io)).permissions.toMode() & 0o7777);
2061 try expectEqual(0o600, (try file.stat(io)).permissions.toMode() & 0o7777);
21202062
21212063 try file.setPermissions(io, .fromMode(0o644));
2122 try testing.expectEqual(@as(posix.mode_t, 0o644), (try file.stat(io)).permissions.toMode() & 0o7777);
2064 try expectEqual(0o644, (try file.stat(io)).permissions.toMode() & 0o7777);
21232065
21242066 try tmp.dir.makeDir(io, "test_dir", .default_dir);
21252067 var dir = try tmp.dir.openDir(io, "test_dir", .{ .iterate = true });
21262068 defer dir.close(io);
21272069
21282070 try dir.setPermissions(io, .fromMode(0o700));
2129 try testing.expectEqual(@as(posix.mode_t, 0o700), (try dir.stat(io)).permissions.toMode() & 0o7777);
2071 try expectEqual(0o700, (try dir.stat(io)).permissions.toMode() & 0o7777);
21302072}
21312073
21322074test "chown" {
......@@ -2162,70 +2104,70 @@ test "invalid UTF-8/WTF-8 paths" {
21622104 // This is both invalid UTF-8 and WTF-8, since \xFF is an invalid start byte
21632105 const invalid_path = try ctx.transformPath("\xFF");
21642106
2165 try testing.expectError(expected_err, ctx.dir.openFile(invalid_path, .{}));
2107 try expectError(expected_err, ctx.dir.openFile(invalid_path, .{}));
21662108
2167 try testing.expectError(expected_err, ctx.dir.createFile(invalid_path, .{}));
2109 try expectError(expected_err, ctx.dir.createFile(invalid_path, .{}));
21682110
2169 try testing.expectError(expected_err, ctx.dir.makeDir(invalid_path, .default_dir));
2111 try expectError(expected_err, ctx.dir.makeDir(invalid_path, .default_dir));
21702112
2171 try testing.expectError(expected_err, ctx.dir.makePath(invalid_path));
2172 try testing.expectError(expected_err, ctx.dir.makeOpenPath(invalid_path, .{}));
2113 try expectError(expected_err, ctx.dir.makePath(invalid_path));
2114 try expectError(expected_err, ctx.dir.makeOpenPath(invalid_path, .{}));
21732115
2174 try testing.expectError(expected_err, ctx.dir.openDir(invalid_path, .{}));
2116 try expectError(expected_err, ctx.dir.openDir(invalid_path, .{}));
21752117
2176 try testing.expectError(expected_err, ctx.dir.deleteFile(invalid_path));
2118 try expectError(expected_err, ctx.dir.deleteFile(invalid_path));
21772119
2178 try testing.expectError(expected_err, ctx.dir.deleteDir(io, invalid_path));
2120 try expectError(expected_err, ctx.dir.deleteDir(io, invalid_path));
21792121
2180 try testing.expectError(expected_err, ctx.dir.rename(invalid_path, ctx.dir, invalid_path, io));
2122 try expectError(expected_err, ctx.dir.rename(invalid_path, ctx.dir, invalid_path, io));
21812123
2182 try testing.expectError(expected_err, ctx.dir.symLink(io, invalid_path, invalid_path, .{}));
2124 try expectError(expected_err, ctx.dir.symLink(io, invalid_path, invalid_path, .{}));
21832125 if (native_os == .wasi) {
2184 try testing.expectError(expected_err, ctx.dir.symLinkWasi(invalid_path, invalid_path, .{}));
2126 try expectError(expected_err, ctx.dir.symLinkWasi(invalid_path, invalid_path, .{}));
21852127 }
21862128
2187 try testing.expectError(expected_err, ctx.dir.readLink(io, invalid_path, &[_]u8{}));
2129 try expectError(expected_err, ctx.dir.readLink(io, invalid_path, &[_]u8{}));
21882130 if (native_os == .wasi) {
2189 try testing.expectError(expected_err, ctx.dir.readLinkWasi(invalid_path, &[_]u8{}));
2131 try expectError(expected_err, ctx.dir.readLinkWasi(invalid_path, &[_]u8{}));
21902132 }
21912133
2192 try testing.expectError(expected_err, ctx.dir.readFile(invalid_path, &[_]u8{}));
2193 try testing.expectError(expected_err, ctx.dir.readFileAlloc(invalid_path, testing.allocator, .limited(0)));
2134 try expectError(expected_err, ctx.dir.readFile(invalid_path, &[_]u8{}));
2135 try expectError(expected_err, ctx.dir.readFileAlloc(invalid_path, testing.allocator, .limited(0)));
21942136
2195 try testing.expectError(expected_err, ctx.dir.deleteTree(io, invalid_path));
2196 try testing.expectError(expected_err, ctx.dir.deleteTreeMinStackSize(invalid_path));
2137 try expectError(expected_err, ctx.dir.deleteTree(io, invalid_path));
2138 try expectError(expected_err, ctx.dir.deleteTreeMinStackSize(invalid_path));
21972139
2198 try testing.expectError(expected_err, ctx.dir.writeFile(io, .{ .sub_path = invalid_path, .data = "" }));
2140 try expectError(expected_err, ctx.dir.writeFile(io, .{ .sub_path = invalid_path, .data = "" }));
21992141
2200 try testing.expectError(expected_err, ctx.dir.access(invalid_path, .{}));
2142 try expectError(expected_err, ctx.dir.access(invalid_path, .{}));
22012143
22022144 var dir = ctx.dir;
2203 try testing.expectError(expected_err, dir.updateFile(io, invalid_path, dir, invalid_path, .{}));
2204 try testing.expectError(expected_err, ctx.dir.copyFile(invalid_path, ctx.dir, invalid_path, .{}));
2145 try expectError(expected_err, dir.updateFile(io, invalid_path, dir, invalid_path, .{}));
2146 try expectError(expected_err, ctx.dir.copyFile(invalid_path, ctx.dir, invalid_path, .{}));
22052147
2206 try testing.expectError(expected_err, ctx.dir.statFile(invalid_path));
2148 try expectError(expected_err, ctx.dir.statFile(invalid_path));
22072149
22082150 if (native_os != .wasi) {
2209 try testing.expectError(expected_err, ctx.dir.realpath(invalid_path, &[_]u8{}));
2210 try testing.expectError(expected_err, ctx.dir.realpathAlloc(testing.allocator, invalid_path));
2151 try expectError(expected_err, ctx.dir.realpath(invalid_path, &[_]u8{}));
2152 try expectError(expected_err, ctx.dir.realpathAlloc(testing.allocator, invalid_path));
22112153 }
22122154
2213 try testing.expectError(expected_err, Dir.rename(ctx.dir, invalid_path, ctx.dir, invalid_path, io));
2155 try expectError(expected_err, Dir.rename(ctx.dir, invalid_path, ctx.dir, invalid_path, io));
22142156
22152157 if (native_os != .wasi and ctx.path_type != .relative) {
2216 try testing.expectError(expected_err, Dir.copyFileAbsolute(invalid_path, invalid_path, .{}));
2217 try testing.expectError(expected_err, Dir.makeDirAbsolute(invalid_path));
2218 try testing.expectError(expected_err, Dir.deleteDirAbsolute(invalid_path));
2219 try testing.expectError(expected_err, Dir.renameAbsolute(invalid_path, invalid_path));
2220 try testing.expectError(expected_err, Dir.openDirAbsolute(invalid_path, .{}));
2221 try testing.expectError(expected_err, Dir.openFileAbsolute(invalid_path, .{}));
2222 try testing.expectError(expected_err, Dir.accessAbsolute(invalid_path, .{}));
2223 try testing.expectError(expected_err, Dir.createFileAbsolute(invalid_path, .{}));
2224 try testing.expectError(expected_err, Dir.deleteFileAbsolute(invalid_path));
2158 try expectError(expected_err, Dir.copyFileAbsolute(invalid_path, invalid_path, .{}));
2159 try expectError(expected_err, Dir.makeDirAbsolute(invalid_path));
2160 try expectError(expected_err, Dir.deleteDirAbsolute(invalid_path));
2161 try expectError(expected_err, Dir.renameAbsolute(invalid_path, invalid_path));
2162 try expectError(expected_err, Dir.openDirAbsolute(invalid_path, .{}));
2163 try expectError(expected_err, Dir.openFileAbsolute(invalid_path, .{}));
2164 try expectError(expected_err, Dir.accessAbsolute(invalid_path, .{}));
2165 try expectError(expected_err, Dir.createFileAbsolute(invalid_path, .{}));
2166 try expectError(expected_err, Dir.deleteFileAbsolute(invalid_path));
22252167 var readlink_buf: [Dir.max_path_bytes]u8 = undefined;
2226 try testing.expectError(expected_err, Dir.readLinkAbsolute(invalid_path, &readlink_buf));
2227 try testing.expectError(expected_err, Dir.symLinkAbsolute(invalid_path, invalid_path, .{}));
2228 try testing.expectError(expected_err, Dir.realpathAlloc(testing.allocator, invalid_path));
2168 try expectError(expected_err, Dir.readLinkAbsolute(invalid_path, &readlink_buf));
2169 try expectError(expected_err, Dir.symLinkAbsolute(invalid_path, invalid_path, .{}));
2170 try expectError(expected_err, Dir.realpathAlloc(testing.allocator, invalid_path));
22292171 }
22302172 }
22312173 }.impl);
......@@ -2259,8 +2201,8 @@ test "read file non vectored" {
22592201 else => |e| return e,
22602202 };
22612203 }
2262 try testing.expectEqualStrings(contents, w.buffered());
2263 try testing.expectEqual(contents.len, i);
2204 try expectEqualStrings(contents, w.buffered());
2205 try expectEqual(contents.len, i);
22642206}
22652207
22662208test "seek keeping partial buffer" {
......@@ -2282,7 +2224,7 @@ test "seek keeping partial buffer" {
22822224 var read_buffer: [3]u8 = undefined;
22832225 var file_reader: Io.File.Reader = .init(file, io, &read_buffer);
22842226
2285 try testing.expectEqual(0, file_reader.logicalPos());
2227 try expectEqual(0, file_reader.logicalPos());
22862228
22872229 var buf: [4]u8 = undefined;
22882230 try file_reader.interface.readSliceAll(&buf);
......@@ -2292,18 +2234,18 @@ test "seek keeping partial buffer" {
22922234 return;
22932235 }
22942236
2295 try testing.expectEqual(4, file_reader.logicalPos());
2296 try testing.expectEqual(7, file_reader.pos);
2237 try expectEqual(4, file_reader.logicalPos());
2238 try expectEqual(7, file_reader.pos);
22972239 try file_reader.seekTo(6);
2298 try testing.expectEqual(6, file_reader.logicalPos());
2299 try testing.expectEqual(7, file_reader.pos);
2240 try expectEqual(6, file_reader.logicalPos());
2241 try expectEqual(7, file_reader.pos);
23002242
2301 try testing.expectEqualStrings("0123", &buf);
2243 try expectEqualStrings("0123", &buf);
23022244
23032245 const n = try file_reader.interface.readSliceShort(&buf);
2304 try testing.expectEqual(4, n);
2246 try expectEqual(4, n);
23052247
2306 try testing.expectEqualStrings("6789", &buf);
2248 try expectEqualStrings("6789", &buf);
23072249}
23082250
23092251test "seekBy" {
......@@ -2320,8 +2262,8 @@ test "seekBy" {
23202262
23212263 var buffer: [20]u8 = undefined;
23222264 const n = try reader.interface.readSliceShort(&buffer);
2323 try testing.expectEqual(15, n);
2324 try testing.expectEqualStrings("t's test seekBy", buffer[0..15]);
2265 try expectEqual(15, n);
2266 try expectEqualStrings("t's test seekBy", buffer[0..15]);
23252267}
23262268
23272269test "seekTo flushes buffered data" {
......@@ -2348,7 +2290,7 @@ test "seekTo flushes buffered data" {
23482290
23492291 var buf: [4]u8 = undefined;
23502292 try file_reader.interface.readSliceAll(&buf);
2351 try std.testing.expectEqualStrings(contents, &buf);
2293 try expectEqualStrings(contents, &buf);
23522294}
23532295
23542296test "File.Writer sendfile with buffered contents" {
......@@ -2372,7 +2314,7 @@ test "File.Writer sendfile with buffered contents" {
23722314 var out_buf: [1]u8 = undefined;
23732315 var out_w = out.writerStreaming(&out_buf);
23742316 try out_w.interface.writeByte('a');
2375 try testing.expectEqual(3, try out_w.interface.sendFileAll(&in_r, .unlimited));
2317 try expectEqual(3, try out_w.interface.sendFileAll(&in_r, .unlimited));
23762318 try out_w.interface.flush();
23772319 }
23782320
......@@ -2380,8 +2322,8 @@ test "File.Writer sendfile with buffered contents" {
23802322 defer check.close(io);
23812323 var check_buf: [4]u8 = undefined;
23822324 var check_r = check.reader(io, &check_buf);
2383 try testing.expectEqualStrings("abcd", try check_r.interface.take(4));
2384 try testing.expectError(error.EndOfStream, check_r.interface.takeByte());
2325 try expectEqualStrings("abcd", try check_r.interface.take(4));
2326 try expectError(error.EndOfStream, check_r.interface.takeByte());
23852327}
23862328
23872329test "readlink on Windows" {
......@@ -2410,23 +2352,72 @@ test "readlinkat" {
24102352 try tmp.dir.writeFile(io, .{ .sub_path = "file.txt", .data = "nonsense" });
24112353
24122354 // create a symbolic link
2413 if (native_os == .windows) {
2414 std.os.windows.CreateSymbolicLink(
2415 tmp.dir.handle,
2416 &[_]u16{ 'l', 'i', 'n', 'k' },
2417 &[_:0]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
2418 false,
2419 ) catch |err| switch (err) {
2355 tmp.dir.symLink("file.txt", "link", .{}) catch |err| switch (err) {
2356 error.AccessDenied => {
24202357 // Symlink requires admin privileges on windows, so this test can legitimately fail.
2421 error.AccessDenied => return error.SkipZigTest,
2422 else => return err,
2423 };
2424 } else {
2425 try posix.symlinkat("file.txt", tmp.dir.handle, "link");
2426 }
2358 if (native_os == .windows) return error.SkipZigTest;
2359 },
2360 };
24272361
24282362 // read the link
24292363 var buffer: [fs.max_path_bytes]u8 = undefined;
24302364 const read_link = try tmp.dir.readLink(io, "link", &buffer);
2431 try expect(mem.eql(u8, "file.txt", read_link));
2365 try expectEqualStrings("file.txt", read_link);
2366}
2367
2368test "fchmodat smoke test" {
2369 if (!Io.File.Permissions.has_executable_bit) return error.SkipZigTest;
2370
2371 if (builtin.cpu.arch.isMIPS64() and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32)) {
2372 // https://github.com/ziglang/zig/issues/23808
2373 return error.SkipZigTest;
2374 }
2375
2376 const io = testing.io;
2377
2378 var tmp = tmpDir(.{});
2379 defer tmp.cleanup();
2380
2381 try expectError(error.FileNotFound, tmp.dir.setPermissions(io, "regfile", 0o666, .{}));
2382 const file = try tmp.dir.createFile(io, "regfile", .{
2383 .exclusive = true,
2384 .permissions = .fromMode(0o644),
2385 });
2386 file.close(io);
2387
2388 if ((builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) and
2389 builtin.os.tag == .linux and !builtin.link_libc)
2390 {
2391 return error.SkipZigTest; // No `fstatat()`.
2392 }
2393
2394 try tmp.dir.symLink(io, "regfile", "symlink", .{});
2395 const sym_mode = blk: {
2396 const st = try tmp.dir.statFile(io, "symlink", .{ .follow_symlinks = false });
2397 break :blk st.permissions.toMode() & 0b111_111_111;
2398 };
2399
2400 try tmp.dir.setFilePermissions(io, "regfile", .fromMode(0o640), .{});
2401 try expectMode(io, tmp.dir, "regfile", .fromMode(0o640));
2402 try tmp.dir.setFilePermissions(io, "regfile", .fromMode(0o600), .{ .follow_symlinks = false });
2403 try expectMode(io, tmp.dir, "regfile", .fromMode(0o600));
2404
2405 try tmp.dir.setFilePermissions(io, "symlink", .fromMode(0o640), .{});
2406 try expectMode(io, tmp.dir, "regfile", .fromMode(0o640));
2407 try expectMode(io, tmp.dir, "symlink", .fromMode(sym_mode));
2408
2409 var test_link = true;
2410 tmp.dir.setFilePermissions(io, "symlink", .fromMode(0o600), .{ .follow_symlinks = false }) catch |err| switch (err) {
2411 error.OperationNotSupported => test_link = false,
2412 else => |e| return e,
2413 };
2414 if (test_link)
2415 try expectMode(tmp.dir.handle, "symlink", 0o600);
2416 try expectMode(tmp.dir.handle, "regfile", 0o640);
2417}
2418
2419fn expectMode(io: Io, dir: Dir, file: []const u8, permissions: File.Permissions) !void {
2420 const mode = permissions.toMode();
2421 const st = try dir.statFile(io, file, .{ .follow_symlinks = false });
2422 try expectEqual(mode, st.mode & 0b111_111_111);
24322423}
lib/std/posix/test.zig-61
......@@ -870,67 +870,6 @@ test "pwrite with empty buffer" {
870870 try expectEqual(rc, 0);
871871}
872872
873fn getFileMode(dir: posix.fd_t, path: []const u8) !posix.mode_t {
874 const path_z = try posix.toPosixPath(path);
875 const mode: posix.mode_t = if (native_os == .linux) blk: {
876 const stx = try linux.wrapped.statx(
877 dir,
878 &path_z,
879 posix.AT.SYMLINK_NOFOLLOW,
880 .{ .MODE = true },
881 );
882 std.debug.assert(stx.mask.MODE);
883 break :blk stx.mode;
884 } else blk: {
885 const st = try posix.fstatatZ(dir, &path_z, posix.AT.SYMLINK_NOFOLLOW);
886 break :blk st.mode;
887 };
888
889 return mode & 0b111_111_111;
890}
891
892fn expectMode(dir: posix.fd_t, file: []const u8, mode: posix.mode_t) !void {
893 const actual = try getFileMode(dir, file);
894 try expectEqual(mode, actual & 0b111_111_111);
895}
896
897test "fchmodat smoke test" {
898 if (!Io.File.Permissions.has_executable_bit) return error.SkipZigTest;
899
900 var tmp = tmpDir(.{});
901 defer tmp.cleanup();
902
903 try expectError(error.FileNotFound, posix.fchmodat(tmp.dir.handle, "regfile", 0o666, 0));
904 const fd = try posix.openat(
905 tmp.dir.handle,
906 "regfile",
907 .{ .ACCMODE = .WRONLY, .CREAT = true, .EXCL = true, .TRUNC = true },
908 0o644,
909 );
910 posix.close(fd);
911
912 try posix.symlinkat("regfile", tmp.dir.handle, "symlink");
913 const sym_mode = try getFileMode(tmp.dir.handle, "symlink");
914
915 try posix.fchmodat(tmp.dir.handle, "regfile", 0o640, 0);
916 try expectMode(tmp.dir.handle, "regfile", 0o640);
917 try posix.fchmodat(tmp.dir.handle, "regfile", 0o600, posix.AT.SYMLINK_NOFOLLOW);
918 try expectMode(tmp.dir.handle, "regfile", 0o600);
919
920 try posix.fchmodat(tmp.dir.handle, "symlink", 0o640, 0);
921 try expectMode(tmp.dir.handle, "regfile", 0o640);
922 try expectMode(tmp.dir.handle, "symlink", sym_mode);
923
924 var test_link = true;
925 posix.fchmodat(tmp.dir.handle, "symlink", 0o600, posix.AT.SYMLINK_NOFOLLOW) catch |err| switch (err) {
926 error.OperationNotSupported => test_link = false,
927 else => |e| return e,
928 };
929 if (test_link)
930 try expectMode(tmp.dir.handle, "symlink", 0o600);
931 try expectMode(tmp.dir.handle, "regfile", 0o640);
932}
933
934873const CommonOpenFlags = packed struct {
935874 ACCMODE: posix.ACCMODE = .RDONLY,
936875 CREAT: bool = false,