commit b4bfd501aedb4abe4257b7f54a225a9654c4e08e (tree)
parent f3723b42e1f05d14479d6f5507943cd1905e0fcf
Author: Andrew Kelley <andrew@ziglang.org>
Date: Thu, 18 Dec 2025 13:50:39 -0800
std: move some tests from posix to fs
Diffstat:
4 files changed, 443 insertions(+), 670 deletions(-)
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
@@ -3,7 +3,6 @@ const native_os = builtin.os.tag;
const std = @import("../std.zig");
const Io = std.Io;
-const fs = std.fs;
const mem = std.mem;
const wasi = std.os.wasi;
const windows = std.os.windows;
@@ -14,11 +13,11 @@ const SymLinkFlags = std.Io.Dir.SymLinkFlags;
const testing = std.testing;
const expect = std.testing.expect;
-const expectError = std.testing.expectError;
const expectEqual = std.testing.expectEqual;
-const tmpDir = std.testing.tmpDir;
-const expectEqualStrings = std.testing.expectEqualStrings;
const expectEqualSlices = std.testing.expectEqualSlices;
+const expectEqualStrings = std.testing.expectEqualStrings;
+const expectError = std.testing.expectError;
+const tmpDir = std.testing.tmpDir;
const PathType = enum {
relative,
@@ -33,7 +32,7 @@ const PathType = enum {
};
}
- pub const TransformError = Io.Dir.RealPathError || error{OutOfMemory};
+ pub const TransformError = Dir.RealPathError || error{OutOfMemory};
pub const TransformFn = fn (allocator: mem.Allocator, dir: Dir, relative_path: [:0]const u8) TransformError![:0]const u8;
pub fn getTransformFn(comptime path_type: PathType) TransformFn {
@@ -49,24 +48,24 @@ const PathType = enum {
fn transform(allocator: mem.Allocator, dir: Dir, relative_path: [:0]const u8) TransformError![:0]const u8 {
// The final path may not actually exist which would cause realpath to fail.
// So instead, we get the path of the dir and join it with the relative path.
- var fd_path_buf: [fs.max_path_bytes]u8 = undefined;
+ var fd_path_buf: [Dir.max_path_bytes]u8 = undefined;
const dir_path = try std.os.getFdPath(dir.handle, &fd_path_buf);
- return fs.path.joinZ(allocator, &.{ dir_path, relative_path });
+ return Dir.path.joinZ(allocator, &.{ dir_path, relative_path });
}
}.transform,
.unc => return struct {
fn transform(allocator: mem.Allocator, dir: Dir, relative_path: [:0]const u8) TransformError![:0]const u8 {
// Any drive absolute path (C:\foo) can be converted into a UNC path by
// using '127.0.0.1' as the server name and '<drive letter>$' as the share name.
- var fd_path_buf: [fs.max_path_bytes]u8 = undefined;
+ var fd_path_buf: [Dir.max_path_bytes]u8 = undefined;
const dir_path = try std.os.getFdPath(dir.handle, &fd_path_buf);
const windows_path_type = windows.getWin32PathType(u8, dir_path);
switch (windows_path_type) {
- .unc_absolute => return fs.path.joinZ(allocator, &.{ dir_path, relative_path }),
+ .unc_absolute => return Dir.path.joinZ(allocator, &.{ dir_path, relative_path }),
.drive_absolute => {
// `C:\<...>` -> `\\127.0.0.1\C$\<...>`
const prepended = "\\\\127.0.0.1\\";
- var path = try fs.path.joinZ(allocator, &.{ prepended, dir_path, relative_path });
+ var path = try Dir.path.joinZ(allocator, &.{ prepended, dir_path, relative_path });
path[prepended.len + 1] = '$';
return path;
},
@@ -84,7 +83,7 @@ const TestContext = struct {
path_sep: u8,
arena: ArenaAllocator,
tmp: testing.TmpDir,
- dir: Io.Dir,
+ dir: Dir,
transform_fn: *const PathType.TransformFn,
pub fn init(path_type: PathType, path_sep: u8, allocator: mem.Allocator, transform_fn: *const PathType.TransformFn) TestContext {
@@ -154,7 +153,7 @@ fn testWithAllSupportedPathTypes(test_func: anytype) !void {
fn testWithPathTypeIfSupported(comptime path_type: PathType, comptime path_sep: u8, test_func: anytype) !void {
if (!(comptime path_type.isSupported(builtin.os))) return;
- if (!(comptime fs.path.isSep(path_sep))) return;
+ if (!(comptime Dir.path.isSep(path_sep))) return;
var ctx = TestContext.init(path_type, path_sep, testing.allocator, path_type.getTransformFn());
defer ctx.deinit();
@@ -174,8 +173,8 @@ fn setupSymlink(io: Io, dir: Dir, target: []const u8, link: []const u8, flags: S
// For use in test setup. If the symlink creation fails on Windows with
// AccessDenied, then make the test failure silent (it is not a Zig failure).
-fn setupSymlinkAbsolute(target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
- return fs.symLinkAbsolute(target, link, flags) catch |err| switch (err) {
+fn setupSymlinkAbsolute(io: Io, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
+ return Dir.symLinkAbsolute(io, target, link, flags) catch |err| switch (err) {
error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err,
else => return err,
};
@@ -211,7 +210,7 @@ test "Dir.readLink" {
}
// test 3: relative path symlink
- const parent_file = ".." ++ fs.path.sep_str ++ "target.txt";
+ const parent_file = ".." ++ Dir.path.sep_str ++ "target.txt";
const canonical_parent_file = try ctx.toCanonicalPathSep(parent_file);
var subdir = try ctx.dir.makeOpenPath(io, "subdir", .{});
defer subdir.close(io);
@@ -251,7 +250,7 @@ test "Dir.readLink on non-symlinks" {
}
fn testReadLink(io: Io, dir: Dir, target_path: []const u8, symlink_path: []const u8) !void {
- var buffer: [fs.max_path_bytes]u8 = undefined;
+ var buffer: [Dir.max_path_bytes]u8 = undefined;
const actual = try dir.readLink(io, symlink_path, &buffer);
try expectEqualStrings(target_path, actual);
}
@@ -267,9 +266,9 @@ fn testReadLinkW(allocator: mem.Allocator, dir: Dir, target_path: []const u8, sy
try expectEqualSlices(u16, target_path_w, actual);
}
-fn testReadLinkAbsolute(target_path: []const u8, symlink_path: []const u8) !void {
- var buffer: [fs.max_path_bytes]u8 = undefined;
- const given = try fs.readLinkAbsolute(symlink_path, buffer[0..]);
+fn testReadLinkAbsolute(io: Io, target_path: []const u8, symlink_path: []const u8) !void {
+ var buffer: [Dir.max_path_bytes]u8 = undefined;
+ const given = try Dir.readLinkAbsolute(io, symlink_path, buffer[0..]);
try expectEqualStrings(target_path, given);
}
@@ -309,7 +308,7 @@ test "openDir" {
try ctx.dir.makeDir(io, subdir_path, .default_dir);
for ([_][]const u8{ "", ".", ".." }) |sub_path| {
- const dir_path = try fs.path.join(allocator, &.{ subdir_path, sub_path });
+ const dir_path = try Dir.path.join(allocator, &.{ subdir_path, sub_path });
var dir = try ctx.dir.openDir(io, dir_path, .{});
defer dir.close(io);
}
@@ -321,13 +320,16 @@ test "accessAbsolute" {
if (native_os == .wasi) return error.SkipZigTest;
if (native_os == .openbsd) return error.SkipZigTest;
+ const io = testing.io;
+ const gpa = testing.allocator;
+
var tmp = tmpDir(.{});
defer tmp.cleanup();
- const base_path = try tmp.dir.realpathAlloc(testing.allocator, ".");
- defer testing.allocator.free(base_path);
+ const base_path = try tmp.dir.realPathAlloc(io, ".", gpa);
+ defer gpa.free(base_path);
- try fs.accessAbsolute(base_path, .{});
+ try Dir.accessAbsolute(io, base_path, .{});
}
test "openDirAbsolute" {
@@ -335,6 +337,7 @@ test "openDirAbsolute" {
if (native_os == .openbsd) return error.SkipZigTest;
const io = testing.io;
+ const gpa = testing.allocator;
var tmp = tmpDir(.{});
defer tmp.cleanup();
@@ -342,8 +345,8 @@ test "openDirAbsolute" {
const tmp_ino = (try tmp.dir.stat(io)).inode;
try tmp.dir.makeDir(io, "subdir", .default_dir);
- const sub_path = try tmp.dir.realpathAlloc(testing.allocator, "subdir");
- defer testing.allocator.free(sub_path);
+ const sub_path = try tmp.dir.realPathAlloc(io, "subdir", gpa);
+ defer gpa.free(sub_path);
// Can open sub_path
var tmp_sub = try Dir.openDirAbsolute(io, sub_path, .{});
@@ -353,7 +356,7 @@ test "openDirAbsolute" {
{
// Can open sub_path + ".."
- const dir_path = try fs.path.join(testing.allocator, &.{ sub_path, ".." });
+ const dir_path = try Dir.path.join(testing.allocator, &.{ sub_path, ".." });
defer testing.allocator.free(dir_path);
var dir = try Dir.openDirAbsolute(io, dir_path, .{});
@@ -365,7 +368,7 @@ test "openDirAbsolute" {
{
// Can open sub_path + "."
- const dir_path = try fs.path.join(testing.allocator, &.{ sub_path, "." });
+ const dir_path = try Dir.path.join(testing.allocator, &.{ sub_path, "." });
defer testing.allocator.free(dir_path);
var dir = try Dir.openDirAbsolute(io, dir_path, .{});
@@ -377,7 +380,7 @@ test "openDirAbsolute" {
{
// Can open subdir + "..", with some extra "."
- const dir_path = try fs.path.join(testing.allocator, &.{ sub_path, ".", "..", "." });
+ const dir_path = try Dir.path.join(testing.allocator, &.{ sub_path, ".", "..", "." });
defer testing.allocator.free(dir_path);
var dir = try Dir.openDirAbsolute(io, dir_path, .{});
@@ -391,7 +394,7 @@ test "openDirAbsolute" {
test "openDir cwd parent '..'" {
const io = testing.io;
- var dir = Io.Dir.cwd().openDir(io, "..", .{}) catch |err| {
+ var dir = Dir.cwd().openDir(io, "..", .{}) catch |err| {
if (native_os == .wasi and err == error.PermissionDenied) {
return; // This is okay. WASI disallows escaping from the fs sandbox
}
@@ -407,6 +410,7 @@ test "openDir non-cwd parent '..'" {
}
const io = testing.io;
+ const gpa = testing.allocator;
var tmp = tmpDir(.{});
defer tmp.cleanup();
@@ -417,11 +421,11 @@ test "openDir non-cwd parent '..'" {
var dir = try subdir.openDir(io, "..", .{});
defer dir.close(io);
- const expected_path = try tmp.dir.realpathAlloc(testing.allocator, ".");
- defer testing.allocator.free(expected_path);
+ const expected_path = try tmp.dir.realPathAlloc(io, ".", gpa);
+ defer gpa.free(expected_path);
- const actual_path = try dir.realpathAlloc(testing.allocator, ".");
- defer testing.allocator.free(actual_path);
+ const actual_path = try dir.realPathAlloc(io, ".", gpa);
+ defer gpa.free(actual_path);
try expectEqualStrings(expected_path, actual_path);
}
@@ -440,27 +444,27 @@ test "readLinkAbsolute" {
try tmp.dir.makeDir(io, "subdir", .default_dir);
// Get base abs path
- var arena = ArenaAllocator.init(testing.allocator);
- defer arena.deinit();
- const allocator = arena.allocator();
+ var arena_allocator = ArenaAllocator.init(testing.allocator);
+ defer arena_allocator.deinit();
+ const arena = arena_allocator.allocator();
- const base_path = try tmp.dir.realpathAlloc(allocator, ".");
+ const base_path = try tmp.dir.realPathAlloc(io, ".", arena);
{
- const target_path = try fs.path.join(allocator, &.{ base_path, "file.txt" });
- const symlink_path = try fs.path.join(allocator, &.{ base_path, "symlink1" });
+ const target_path = try Dir.path.join(arena, &.{ base_path, "file.txt" });
+ const symlink_path = try Dir.path.join(arena, &.{ base_path, "symlink1" });
// Create symbolic link by path
- try setupSymlinkAbsolute(target_path, symlink_path, .{});
- try testReadLinkAbsolute(target_path, symlink_path);
+ try setupSymlinkAbsolute(io, target_path, symlink_path, .{});
+ try testReadLinkAbsolute(io, target_path, symlink_path);
}
{
- const target_path = try fs.path.join(allocator, &.{ base_path, "subdir" });
- const symlink_path = try fs.path.join(allocator, &.{ base_path, "symlink2" });
+ const target_path = try Dir.path.join(arena, &.{ base_path, "subdir" });
+ const symlink_path = try Dir.path.join(arena, &.{ base_path, "symlink2" });
// Create symbolic link to a directory by path
- try setupSymlinkAbsolute(target_path, symlink_path, .{ .is_directory = true });
- try testReadLinkAbsolute(target_path, symlink_path);
+ try setupSymlinkAbsolute(io, target_path, symlink_path, .{ .is_directory = true });
+ try testReadLinkAbsolute(io, target_path, symlink_path);
}
}
@@ -492,8 +496,8 @@ test "Dir.Iterator" {
}
try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
- try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
- try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
+ try expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
+ try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
}
test "Dir.Iterator many entries" {
@@ -529,7 +533,7 @@ test "Dir.Iterator many entries" {
i = 0;
while (i < num) : (i += 1) {
const name = try std.fmt.bufPrint(&buf, "{}", .{i});
- try testing.expect(contains(&entries, .{ .name = name, .kind = .file }));
+ try expect(contains(&entries, .{ .name = name, .kind = .file }));
}
}
@@ -563,8 +567,8 @@ test "Dir.Iterator twice" {
}
try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
- try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
- try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
+ try expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
+ try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
}
}
@@ -599,8 +603,8 @@ test "Dir.Iterator reset" {
}
try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
- try testing.expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
- try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
+ try expect(contains(&entries, .{ .name = "some_file", .kind = .file }));
+ try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));
iter.reset();
}
@@ -619,7 +623,7 @@ test "Dir.Iterator but dir is deleted during iteration" {
var iterator = subdir.iterate();
// Create something to iterate over within the subdir
- try tmp.dir.makePath(io, "subdir" ++ fs.path.sep_str ++ "b");
+ try tmp.dir.makePath(io, "subdir" ++ Dir.path.sep_str ++ "b");
// Then, before iterating, delete the directory that we're iterating.
// This is a contrived reproduction, but this could happen outside of the program, in another thread, etc.
@@ -629,7 +633,7 @@ test "Dir.Iterator but dir is deleted during iteration" {
// Now, when we try to iterate, the next call should return null immediately.
const entry = try iterator.next();
- try std.testing.expect(entry == null);
+ try std.expect(entry == null);
// On Linux, we can opt-in to receiving a more specific error by calling `nextLinux`
if (native_os == .linux) {
@@ -657,25 +661,25 @@ test "Dir.realpath smoke test" {
const allocator = ctx.arena.allocator();
const test_file_path = try ctx.transformPath("test_file");
const test_dir_path = try ctx.transformPath("test_dir");
- var buf: [fs.max_path_bytes]u8 = undefined;
+ var buf: [Dir.max_path_bytes]u8 = undefined;
// FileNotFound if the path doesn't exist
- try expectError(error.FileNotFound, ctx.dir.realpathAlloc(allocator, test_file_path));
- try expectError(error.FileNotFound, ctx.dir.realpath(test_file_path, &buf));
- try expectError(error.FileNotFound, ctx.dir.realpathAlloc(allocator, test_dir_path));
- try expectError(error.FileNotFound, ctx.dir.realpath(test_dir_path, &buf));
+ try expectError(error.FileNotFound, ctx.dir.realPathAlloc(io, test_file_path, allocator));
+ try expectError(error.FileNotFound, ctx.dir.realPath(io, test_file_path, &buf));
+ try expectError(error.FileNotFound, ctx.dir.realPathAlloc(io, test_dir_path, allocator));
+ try expectError(error.FileNotFound, ctx.dir.realPath(io, test_dir_path, &buf));
// Now create the file and dir
try ctx.dir.writeFile(io, .{ .sub_path = test_file_path, .data = "" });
try ctx.dir.makeDir(io, test_dir_path, .default_dir);
const base_path = try ctx.transformPath(".");
- const base_realpath = try ctx.dir.realpathAlloc(allocator, base_path);
- const expected_file_path = try fs.path.join(
+ const base_realpath = try ctx.dir.realPathAlloc(io, base_path, allocator);
+ const expected_file_path = try Dir.path.join(
allocator,
&.{ base_realpath, "test_file" },
);
- const expected_dir_path = try fs.path.join(
+ const expected_dir_path = try Dir.path.join(
allocator,
&.{ base_realpath, "test_dir" },
);
@@ -691,10 +695,10 @@ test "Dir.realpath smoke test" {
// Next, test alloc version
{
- const file_path = try ctx.dir.realpathAlloc(allocator, test_file_path);
+ const file_path = try ctx.dir.realPathAlloc(io, test_file_path, allocator);
try expectEqualStrings(expected_file_path, file_path);
- const dir_path = try ctx.dir.realpathAlloc(allocator, test_dir_path);
+ const dir_path = try ctx.dir.realPathAlloc(io, test_dir_path, allocator);
try expectEqualStrings(expected_dir_path, dir_path);
}
}
@@ -715,7 +719,7 @@ test "readFileAlloc" {
try expectEqualStrings("", buf1);
const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n";
- try file.writeAll(write_buf);
+ try file.writeStreamingAll(io, write_buf);
{
// max_bytes > file_size
@@ -779,7 +783,7 @@ test "statFile on dangling symlink" {
fn impl(ctx: *TestContext) !void {
const io = ctx.io;
const symlink_name = try ctx.transformPath("dangling-symlink");
- const symlink_target = "." ++ fs.path.sep_str ++ "doesnotexist";
+ const symlink_target = "." ++ Dir.path.sep_str ++ "doesnotexist";
try setupSymlink(io, ctx.dir, symlink_target, symlink_name, .{});
@@ -803,8 +807,8 @@ test "directory operations on files" {
try expectError(error.NotDir, ctx.dir.deleteDir(io, test_file_name));
if (ctx.path_type == .absolute and comptime PathType.absolute.isSupported(builtin.os)) {
- try expectError(error.PathAlreadyExists, fs.makeDirAbsolute(test_file_name));
- try expectError(error.NotDir, fs.deleteDirAbsolute(test_file_name));
+ try expectError(error.PathAlreadyExists, Dir.makeDirAbsolute(io, test_file_name));
+ try expectError(error.NotDir, Dir.deleteDirAbsolute(io, test_file_name));
}
// ensure the file still exists and is a file as a sanity check
@@ -862,8 +866,8 @@ test "file operations on directories" {
try expectError(error.IsDir, ctx.dir.openFile(io, test_dir_name, .{ .allow_directory = false, .mode = .read_only }));
if (ctx.path_type == .absolute and comptime PathType.absolute.isSupported(builtin.os)) {
- try expectError(error.IsDir, fs.createFileAbsolute(test_dir_name, .{}));
- try expectError(error.IsDir, fs.deleteFileAbsolute(test_dir_name));
+ try expectError(error.IsDir, Dir.createFileAbsolute(io, test_dir_name, .{}));
+ try expectError(error.IsDir, Dir.deleteFileAbsolute(io, test_dir_name));
}
// ensure the directory still exists as a sanity check
@@ -892,7 +896,7 @@ test "deleteDir" {
fn impl(ctx: *TestContext) !void {
const io = ctx.io;
const test_dir_path = try ctx.transformPath("test_dir");
- const test_file_path = try ctx.transformPath("test_dir" ++ fs.path.sep_str ++ "test_file");
+ const test_file_path = try ctx.transformPath("test_dir" ++ Dir.path.sep_str ++ "test_file");
// deleting a non-existent directory
try expectError(error.FileNotFound, ctx.dir.deleteDir(io, test_dir_path));
@@ -1097,11 +1101,12 @@ test "renameAbsolute" {
defer arena.deinit();
const allocator = arena.allocator();
- const base_path = try tmp_dir.dir.realpathAlloc(allocator, ".");
+ const base_path = try tmp_dir.dir.realPathAlloc(io, ".", allocator);
- try expectError(error.FileNotFound, fs.renameAbsolute(
- try fs.path.join(allocator, &.{ base_path, "missing_file_name" }),
- try fs.path.join(allocator, &.{ base_path, "something_else" }),
+ try expectError(error.FileNotFound, Dir.renameAbsolute(
+ io,
+ try Dir.path.join(allocator, &.{ base_path, "missing_file_name" }),
+ try Dir.path.join(allocator, &.{ base_path, "something_else" }),
));
// Renaming files
@@ -1109,9 +1114,10 @@ test "renameAbsolute" {
const renamed_test_file_name = "test_file_renamed";
var file = try tmp_dir.dir.createFile(io, test_file_name, .{ .read = true });
file.close(io);
- try fs.renameAbsolute(
- try fs.path.join(allocator, &.{ base_path, test_file_name }),
- try fs.path.join(allocator, &.{ base_path, renamed_test_file_name }),
+ try Dir.renameAbsolute(
+ io,
+ try Dir.path.join(allocator, &.{ base_path, test_file_name }),
+ try Dir.path.join(allocator, &.{ base_path, renamed_test_file_name }),
);
// ensure the file was renamed
@@ -1125,9 +1131,10 @@ test "renameAbsolute" {
const test_dir_name = "test_dir";
const renamed_test_dir_name = "test_dir_renamed";
try tmp_dir.dir.makeDir(io, test_dir_name, .default_dir);
- try fs.renameAbsolute(
- try fs.path.join(allocator, &.{ base_path, test_dir_name }),
- try fs.path.join(allocator, &.{ base_path, renamed_test_dir_name }),
+ try Dir.renameAbsolute(
+ io,
+ try Dir.path.join(allocator, &.{ base_path, test_dir_name }),
+ try Dir.path.join(allocator, &.{ base_path, renamed_test_dir_name }),
);
// ensure the directory was renamed
@@ -1149,7 +1156,7 @@ test "executablePath" {
if (native_os == .wasi) return error.SkipZigTest;
const io = testing.io;
- var buf: [fs.max_path_bytes]u8 = undefined;
+ var buf: [Dir.max_path_bytes]u8 = undefined;
const buf_self_exe_path = try std.process.executablePath(io, &buf);
const alloc_self_exe_path = try std.process.executablePathAlloc(io, testing.allocator);
defer testing.allocator.free(alloc_self_exe_path);
@@ -1206,13 +1213,13 @@ test "makePath, put some files in it, deleteTree" {
const allocator = ctx.arena.allocator();
const dir_path = try ctx.transformPath("os_test_tmp");
- try ctx.dir.makePath(io, try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c" }));
+ try ctx.dir.makePath(io, try Dir.path.join(allocator, &.{ "os_test_tmp", "b", "c" }));
try ctx.dir.writeFile(io, .{
- .sub_path = try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c", "file.txt" }),
+ .sub_path = try Dir.path.join(allocator, &.{ "os_test_tmp", "b", "c", "file.txt" }),
.data = "nonsense",
});
try ctx.dir.writeFile(io, .{
- .sub_path = try fs.path.join(allocator, &.{ "os_test_tmp", "b", "file2.txt" }),
+ .sub_path = try Dir.path.join(allocator, &.{ "os_test_tmp", "b", "file2.txt" }),
.data = "blah",
});
@@ -1229,13 +1236,13 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {
const allocator = ctx.arena.allocator();
const dir_path = try ctx.transformPath("os_test_tmp");
- try ctx.dir.makePath(io, try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c" }));
+ try ctx.dir.makePath(io, try Dir.path.join(allocator, &.{ "os_test_tmp", "b", "c" }));
try ctx.dir.writeFile(io, .{
- .sub_path = try fs.path.join(allocator, &.{ "os_test_tmp", "b", "c", "file.txt" }),
+ .sub_path = try Dir.path.join(allocator, &.{ "os_test_tmp", "b", "c", "file.txt" }),
.data = "nonsense",
});
try ctx.dir.writeFile(io, .{
- .sub_path = try fs.path.join(allocator, &.{ "os_test_tmp", "b", "file2.txt" }),
+ .sub_path = try Dir.path.join(allocator, &.{ "os_test_tmp", "b", "file2.txt" }),
.data = "blah",
});
@@ -1285,7 +1292,7 @@ test "makepath existing directories" {
defer tmpA.close(io);
try tmpA.makeDir(io, "B", .default_dir);
- const testPath = "A" ++ fs.path.sep_str ++ "B" ++ fs.path.sep_str ++ "C";
+ const testPath = "A" ++ Dir.path.sep_str ++ "B" ++ Dir.path.sep_str ++ "C";
try tmp.dir.makePath(io, testPath);
try expectDir(io, tmp.dir, testPath);
@@ -1298,11 +1305,11 @@ test "makepath through existing valid symlink" {
defer tmp.cleanup();
try tmp.dir.makeDir(io, "realfolder", .default_dir);
- try setupSymlink(io, tmp.dir, "." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{});
+ try setupSymlink(io, tmp.dir, "." ++ Dir.path.sep_str ++ "realfolder", "working-symlink", .{});
- try tmp.dir.makePath(io, "working-symlink" ++ fs.path.sep_str ++ "in-realfolder");
+ try tmp.dir.makePath(io, "working-symlink" ++ Dir.path.sep_str ++ "in-realfolder");
- try expectDir(io, tmp.dir, "realfolder" ++ fs.path.sep_str ++ "in-realfolder");
+ try expectDir(io, tmp.dir, "realfolder" ++ Dir.path.sep_str ++ "in-realfolder");
}
test "makepath relative walks" {
@@ -1311,7 +1318,7 @@ test "makepath relative walks" {
var tmp = tmpDir(.{});
defer tmp.cleanup();
- const relPath = try fs.path.join(testing.allocator, &.{
+ const relPath = try Dir.path.join(testing.allocator, &.{
"first", "..", "second", "..", "third", "..", "first", "A", "..", "B", "..", "C",
});
defer testing.allocator.free(relPath);
@@ -1323,14 +1330,14 @@ test "makepath relative walks" {
.windows => {
// On Windows, .. is resolved before passing the path to NtCreateFile,
// meaning everything except `first/C` drops out.
- try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "C");
+ try expectDir(io, tmp.dir, "first" ++ Dir.path.sep_str ++ "C");
try expectError(error.FileNotFound, tmp.dir.access(io, "second", .{}));
try expectError(error.FileNotFound, tmp.dir.access(io, "third", .{}));
},
else => {
- try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "A");
- try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "B");
- try expectDir(io, tmp.dir, "first" ++ fs.path.sep_str ++ "C");
+ try expectDir(io, tmp.dir, "first" ++ Dir.path.sep_str ++ "A");
+ try expectDir(io, tmp.dir, "first" ++ Dir.path.sep_str ++ "B");
+ try expectDir(io, tmp.dir, "first" ++ Dir.path.sep_str ++ "C");
try expectDir(io, tmp.dir, "second");
try expectDir(io, tmp.dir, "third");
},
@@ -1344,13 +1351,13 @@ test "makepath ignores '.'" {
defer tmp.cleanup();
// Path to create, with "." elements:
- const dotPath = try fs.path.join(testing.allocator, &.{
+ const dotPath = try Dir.path.join(testing.allocator, &.{
"first", ".", "second", ".", "third",
});
defer testing.allocator.free(dotPath);
// Path to expect to find:
- const expectedPath = try fs.path.join(testing.allocator, &.{
+ const expectedPath = try Dir.path.join(testing.allocator, &.{
"first", "second", "third",
});
defer testing.allocator.free(expectedPath);
@@ -1473,7 +1480,7 @@ test "access file" {
fn impl(ctx: *TestContext) !void {
const io = ctx.io;
const dir_path = try ctx.transformPath("os_test_tmp");
- const file_path = try ctx.transformPath("os_test_tmp" ++ fs.path.sep_str ++ "file.txt");
+ const file_path = try ctx.transformPath("os_test_tmp" ++ Dir.path.sep_str ++ "file.txt");
try ctx.dir.makePath(io, dir_path);
try expectError(error.FileNotFound, ctx.dir.access(io, file_path, .{}));
@@ -1546,7 +1553,7 @@ test "sendfile with buffered data" {
var src_file = try dir.createFile(io, "sendfile1.txt", .{ .read = true });
defer src_file.close(io);
- try src_file.writeAll("AAAABBBB");
+ try src_file.writeStreamingAll(io, "AAAABBBB");
var dest_file = try dir.createFile(io, "sendfile2.txt", .{ .read = true });
defer dest_file.close(io);
@@ -1691,7 +1698,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
errdefer file.close(io);
const S = struct {
- fn checkFn(dir: *Io.Dir, path: []const u8, started: *std.Thread.ResetEvent, locked: *std.Thread.ResetEvent) !void {
+ fn checkFn(dir: *Dir, path: []const u8, started: *std.Thread.ResetEvent, locked: *std.Thread.ResetEvent) !void {
started.set();
const file1 = try dir.createFile(io, path, .{ .lock = .exclusive });
@@ -1731,8 +1738,8 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
var random_bytes: [12]u8 = undefined;
std.crypto.random.bytes(&random_bytes);
- var random_b64: [fs.base64_encoder.calcSize(random_bytes.len)]u8 = undefined;
- _ = fs.base64_encoder.encode(&random_b64, &random_bytes);
+ var random_b64: [std.fs.base64_encoder.calcSize(random_bytes.len)]u8 = undefined;
+ _ = std.fs.base64_encoder.encode(&random_b64, &random_bytes);
const sub_path = random_b64 ++ "-zig-test-absolute-paths.txt";
@@ -1741,16 +1748,16 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
const cwd = try std.process.getCwdAlloc(gpa);
defer gpa.free(cwd);
- const filename = try fs.path.resolve(gpa, &.{ cwd, sub_path });
+ const filename = try Dir.path.resolve(gpa, &.{ cwd, sub_path });
defer gpa.free(filename);
- defer fs.deleteFileAbsolute(filename) catch {}; // createFileAbsolute can leave files on failures
- const file1 = try fs.createFileAbsolute(filename, .{
+ defer Dir.deleteFileAbsolute(io, filename) catch {}; // createFileAbsolute can leave files on failures
+ const file1 = try Dir.createFileAbsolute(io, filename, .{
.lock = .exclusive,
.lock_nonblocking = true,
});
- const file2 = fs.createFileAbsolute(filename, .{
+ const file2 = Dir.createFileAbsolute(io, filename, .{
.lock = .exclusive,
.lock_nonblocking = true,
});
@@ -1802,9 +1809,9 @@ test "walker" {
.{ "dir2", 1 },
.{ "dir3", 1 },
.{ "dir4", 1 },
- .{ "dir3" ++ fs.path.sep_str ++ "sub1", 2 },
- .{ "dir3" ++ fs.path.sep_str ++ "sub2", 2 },
- .{ "dir3" ++ fs.path.sep_str ++ "sub2" ++ fs.path.sep_str ++ "subsub1", 3 },
+ .{ "dir3" ++ Dir.path.sep_str ++ "sub1", 2 },
+ .{ "dir3" ++ Dir.path.sep_str ++ "sub2", 2 },
+ .{ "dir3" ++ Dir.path.sep_str ++ "sub2" ++ Dir.path.sep_str ++ "subsub1", 3 },
});
const expected_basenames = std.StaticStringMap(void).initComptime(.{
@@ -1826,11 +1833,11 @@ test "walker" {
var num_walked: usize = 0;
while (try walker.next()) |entry| {
- testing.expect(expected_basenames.has(entry.basename)) catch |err| {
+ expect(expected_basenames.has(entry.basename)) catch |err| {
std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)});
return err;
};
- testing.expect(expected_paths.has(entry.path)) catch |err| {
+ expect(expected_paths.has(entry.path)) catch |err| {
std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
return err;
};
@@ -1863,11 +1870,11 @@ test "selective walker, skip entries that start with ." {
const expected_paths = std.StaticStringMap(usize).initComptime(.{
.{ "dir1", 1 },
- .{ "dir1" ++ fs.path.sep_str ++ "foo", 2 },
+ .{ "dir1" ++ Dir.path.sep_str ++ "foo", 2 },
.{ "a", 1 },
- .{ "a" ++ fs.path.sep_str ++ "b", 2 },
- .{ "a" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c", 3 },
- .{ "a" ++ fs.path.sep_str ++ "baz", 2 },
+ .{ "a" ++ Dir.path.sep_str ++ "b", 2 },
+ .{ "a" ++ Dir.path.sep_str ++ "b" ++ Dir.path.sep_str ++ "c", 3 },
+ .{ "a" ++ Dir.path.sep_str ++ "baz", 2 },
});
const expected_basenames = std.StaticStringMap(void).initComptime(.{
@@ -1893,11 +1900,11 @@ test "selective walker, skip entries that start with ." {
try walker.enter(entry);
}
- testing.expect(expected_basenames.has(entry.basename)) catch |err| {
+ expect(expected_basenames.has(entry.basename)) catch |err| {
std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)});
return err;
};
- testing.expect(expected_paths.has(entry.path)) catch |err| {
+ expect(expected_paths.has(entry.path)) catch |err| {
std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
return err;
};
@@ -1937,7 +1944,7 @@ test "walker without fully iterating" {
try expectEqual(@as(usize, 1), num_walked);
}
-test "'.' and '..' in Io.Dir functions" {
+test "'.' and '..' in Dir functions" {
if (native_os == .windows and builtin.cpu.arch == .aarch64) {
// https://github.com/ziglang/zig/issues/17134
return error.SkipZigTest;
@@ -1970,7 +1977,7 @@ test "'.' and '..' in Io.Dir functions" {
try ctx.dir.writeFile(io, .{ .sub_path = update_path, .data = "something" });
var dir = ctx.dir;
const prev_status = try dir.updateFile(io, file_path, dir, update_path, .{});
- try expectEqual(Io.Dir.PrevStatus.stale, prev_status);
+ try expectEqual(Dir.PrevStatus.stale, prev_status);
try ctx.dir.deleteDir(io, subdir_path);
}
@@ -1990,28 +1997,28 @@ test "'.' and '..' in absolute functions" {
defer arena.deinit();
const allocator = arena.allocator();
- const base_path = try tmp.dir.realpathAlloc(allocator, ".");
+ const base_path = try tmp.dir.realPathAlloc(io, ".", allocator);
- const subdir_path = try fs.path.join(allocator, &.{ base_path, "./subdir" });
- try fs.makeDirAbsolute(subdir_path);
- try fs.accessAbsolute(subdir_path, .{});
+ const subdir_path = try Dir.path.join(allocator, &.{ base_path, "./subdir" });
+ try Dir.makeDirAbsolute(io, subdir_path);
+ try Dir.accessAbsolute(io, subdir_path, .{});
var created_subdir = try Dir.openDirAbsolute(io, subdir_path, .{});
created_subdir.close(io);
- const created_file_path = try fs.path.join(allocator, &.{ subdir_path, "../file" });
- const created_file = try fs.createFileAbsolute(created_file_path, .{});
+ const created_file_path = try Dir.path.join(allocator, &.{ subdir_path, "../file" });
+ const created_file = try Dir.createFileAbsolute(io, created_file_path, .{});
created_file.close(io);
- try fs.accessAbsolute(created_file_path, .{});
+ try Dir.accessAbsolute(io, created_file_path, .{});
- const copied_file_path = try fs.path.join(allocator, &.{ subdir_path, "../copy" });
- try fs.copyFileAbsolute(created_file_path, copied_file_path, .{});
- const renamed_file_path = try fs.path.join(allocator, &.{ subdir_path, "../rename" });
- try fs.renameAbsolute(copied_file_path, renamed_file_path);
+ const copied_file_path = try Dir.path.join(allocator, &.{ subdir_path, "../copy" });
+ try Dir.copyFileAbsolute(io, created_file_path, copied_file_path, .{});
+ const renamed_file_path = try Dir.path.join(allocator, &.{ subdir_path, "../rename" });
+ try Dir.renameAbsolute(io, copied_file_path, renamed_file_path);
const renamed_file = try Dir.openFileAbsolute(renamed_file_path, .{});
renamed_file.close(io);
- try fs.deleteFileAbsolute(renamed_file_path);
+ try Dir.deleteFileAbsolute(io, renamed_file_path);
- try fs.deleteDirAbsolute(subdir_path);
+ try Dir.deleteDirAbsolute(io, subdir_path);
}
test "chmod" {
@@ -2114,8 +2121,8 @@ test "invalid UTF-8/WTF-8 paths" {
try expectError(expected_err, ctx.dir.statFile(invalid_path));
if (native_os != .wasi) {
- try expectError(expected_err, ctx.dir.realpath(invalid_path, &[_]u8{}));
- try expectError(expected_err, ctx.dir.realpathAlloc(testing.allocator, invalid_path));
+ try expectError(expected_err, ctx.dir.realPath(io, invalid_path, &[_]u8{}));
+ try expectError(expected_err, ctx.dir.realPathAlloc(io, invalid_path, testing.allocator));
}
try expectError(expected_err, Dir.rename(ctx.dir, invalid_path, ctx.dir, invalid_path, io));
@@ -2133,7 +2140,7 @@ test "invalid UTF-8/WTF-8 paths" {
var readlink_buf: [Dir.max_path_bytes]u8 = undefined;
try expectError(expected_err, Dir.readLinkAbsolute(invalid_path, &readlink_buf));
try expectError(expected_err, Dir.symLinkAbsolute(invalid_path, invalid_path, .{}));
- try expectError(expected_err, Dir.realpathAlloc(testing.allocator, invalid_path));
+ try expectError(expected_err, Dir.realPathAlloc(io, invalid_path, testing.allocator));
}
}
}.impl);
@@ -2303,7 +2310,7 @@ test "readlink on Windows" {
}
fn testReadLinkWindows(io: Io, target_path: []const u8, symlink_path: []const u8) !void {
- var buffer: [fs.max_path_bytes]u8 = undefined;
+ var buffer: [Dir.max_path_bytes]u8 = undefined;
const given = try Dir.readLinkAbsolute(io, symlink_path, &buffer);
try expect(mem.eql(u8, target_path, given));
}
@@ -2326,7 +2333,7 @@ test "readlinkat" {
};
// read the link
- var buffer: [fs.max_path_bytes]u8 = undefined;
+ var buffer: [Dir.max_path_bytes]u8 = undefined;
const read_link = try tmp.dir.readLink(io, "link", &buffer);
try expectEqualStrings("file.txt", read_link);
}
@@ -2387,3 +2394,239 @@ fn expectMode(io: Io, dir: Dir, file: []const u8, permissions: File.Permissions)
const st = try dir.statFile(io, file, .{ .follow_symlinks = false });
try expectEqual(mode, st.mode & 0b111_111_111);
}
+
+test "isatty" {
+ const io = testing.io;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ var file = try tmp.dir.createFile(io, "foo", .{});
+ defer file.close(io);
+
+ try expectEqual(false, try file.isTty(io));
+}
+
+test "read positional empty buffer" {
+ const io = testing.io;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ var file = try tmp.dir.createFile(io, "pread_empty", .{ .read = true });
+ defer file.close(io);
+
+ var buffer: [0]u8 = undefined;
+ try expectEqual(0, try file.readPositional(io, &buffer, 0));
+}
+
+test "write streaming empty buffer" {
+ const io = testing.io;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ var file = try tmp.dir.createFile(io, "write_empty", .{});
+ defer file.close(io);
+
+ var buffer: [0]u8 = &.{};
+ try expectEqual(0, try file.writeStreaming(io, &buffer));
+}
+
+test "write positional empty buffer" {
+ const io = testing.io;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ var file = try tmp.dir.createFile(io, "pwrite_empty", .{});
+ defer file.close(io);
+
+ var buffer: [0]u8 = &.{};
+ try expectEqual(0, try file.writePositional(io, &buffer, 0));
+}
+
+test "access smoke test" {
+ if (native_os == .wasi) return error.SkipZigTest;
+ if (native_os == .windows) return error.SkipZigTest;
+ if (native_os == .openbsd) return error.SkipZigTest;
+
+ const io = testing.io;
+ const gpa = testing.allocator;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ const base_path = try tmp.dir.realPathAlloc(io, ".", gpa);
+ defer gpa.free(base_path);
+
+ {
+ // Create some file using `open`.
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });
+ defer gpa.free(file_path);
+ const file = Dir.cwd().createFile(io, file_path, .{ .read = true, .exclusive = true });
+ file.close(io);
+ }
+
+ {
+ // Try to access() the file
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });
+ defer gpa.free(file_path);
+ if (native_os == .windows) {
+ try Dir.cwd().access(io, file_path, .{});
+ } else {
+ try Dir.cwd().access(io, file_path, .{ .read = true, .write = true });
+ }
+ }
+
+ {
+ // Try to access() a non-existent file - should fail with error.FileNotFound
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });
+ defer gpa.free(file_path);
+ try expectError(error.FileNotFound, Dir.cwd().access(io, file_path, .{}));
+ }
+
+ {
+ // Create some directory
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_dir" });
+ defer gpa.free(file_path);
+ try Dir.makeDir(io, file_path, .default_file);
+ }
+
+ {
+ // Try to access() the directory
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_dir" });
+ defer gpa.free(file_path);
+
+ try Dir.access(io, file_path, .{});
+ }
+}
+
+test "write streaming a long vector" {
+ const io = testing.io;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ var file = try tmp.dir.createFile(io, "pwritev", .{});
+ defer file.close(io);
+
+ var vecs: [2000][]const u8 = undefined;
+ for (&vecs) |*v| v.* = "a";
+
+ const n = try file.writePositional(io, &vecs, 0);
+ try expect(n <= vecs.len);
+}
+
+test "open smoke test" {
+ if (native_os == .wasi) return error.SkipZigTest;
+ if (native_os == .windows) return error.SkipZigTest;
+ if (native_os == .openbsd) return error.SkipZigTest;
+
+ // TODO verify file attributes using `fstat`
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ const io = testing.io;
+
+ {
+ // Create some file using `open`.
+ const file = try tmp.dir.createFile(io, "some_file", .{ .exclusive = true });
+ file.close(io);
+ }
+
+ // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
+ try expectError(
+ error.PathAlreadyExists,
+ tmp.dir.createFile(io, "some_file", .{ .exclusive = true }),
+ );
+
+ {
+ // Try opening without exclusive flag.
+ const file = try tmp.dir.createFile(io, "some_file", .{});
+ file.close(io);
+ }
+
+ try expectError(error.NotDir, tmp.dir.openDir(io, "some_file", .{}));
+ try tmp.dir.makeDir(io, "some_dir", .default_dir);
+
+ {
+ const dir = try tmp.dir.openDir("some_dir", .{});
+ dir.close(io);
+ }
+
+ // Try opening as file which should fail.
+ try expectError(error.IsDir, tmp.dir.openFile("some_dir", .{}));
+}
+
+test "hard link with different directories" {
+ const io = testing.io;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ const target_name = "link-target";
+ const link_name = "newlink";
+
+ const subdir = try tmp.dir.makeOpenPath(io, "subdir", .{});
+
+ defer tmp.dir.deleteFile(io, target_name) catch {};
+ try tmp.dir.writeFile(io, .{ .sub_path = target_name, .data = "example" });
+
+ // Test 1: link from file in subdir back up to target in parent directory
+ tmp.dir.hardLink(target_name, subdir, link_name, 0) catch |err| switch (err) {
+ error.OperationUnsupported => return error.SkipZigTest,
+ else => |e| return e,
+ };
+
+ const efd = try tmp.dir.openFile(io, target_name, .{});
+ defer efd.close(io);
+
+ const nfd = try subdir.openFile(io, link_name, .{});
+ defer nfd.close(io);
+
+ {
+ const e_stat = try efd.stat(io);
+ const n_stat = try nfd.stat(io);
+
+ try expectEqual(e_stat.inode, n_stat.inode);
+ try expectEqual(2, e_stat.nlink);
+ try expectEqual(2, n_stat.nlink);
+ }
+
+ // Test 2: remove link
+ try subdir.deleteFile(io, link_name, .{});
+ const e_stat = try efd.stat(io);
+ try expectEqual(1, e_stat.nlink);
+}
+
+test "stat smoke test" {
+ if (native_os == .wasi and !builtin.link_libc) return error.SkipZigTest;
+
+ const io = testing.io;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ // create dummy file
+ const contents = "nonsense";
+ try tmp.dir.writeFile(io, .{ .sub_path = "file.txt", .data = contents });
+
+ // fetch file's info on the opened fd directly
+ const file = try tmp.dir.openFile(io, "file.txt", .{});
+ const stat = try file.stat(io);
+ defer file.close(io);
+
+ // now repeat but using directory handle instead
+ const statat = try tmp.dir.statFile(io, "file.txt", .{ .follow_symlinks = false });
+
+ try expectEqual(stat.inode, statat.inode);
+ try expectEqual(stat.nlink, statat.nlink);
+ try expectEqual(stat.size, statat.size);
+ try expectEqual(stat.permissions, statat.permissions);
+ try expectEqual(stat.kind, statat.kind);
+ try expectEqual(stat.atime, statat.atime);
+ try expectEqual(stat.mtime, statat.mtime);
+ try expectEqual(stat.ctime, statat.ctime);
+}
diff --git a/lib/std/posix.zig b/lib/std/posix.zig
@@ -1034,163 +1034,6 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
}
}
-pub const LinkError = UnexpectedError || error{
- AccessDenied,
- PermissionDenied,
- DiskQuota,
- PathAlreadyExists,
- FileSystem,
- SymLinkLoop,
- LinkQuotaExceeded,
- NameTooLong,
- FileNotFound,
- SystemResources,
- NoSpaceLeft,
- ReadOnlyFileSystem,
- NotSameFileSystem,
- BadPathName,
-};
-
-/// On WASI, both paths should be encoded as valid UTF-8.
-/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
-pub fn linkZ(oldpath: [*:0]const u8, newpath: [*:0]const u8) LinkError!void {
- if (native_os == .wasi and !builtin.link_libc) {
- return link(mem.sliceTo(oldpath, 0), mem.sliceTo(newpath, 0));
- }
- switch (errno(system.link(oldpath, newpath))) {
- .SUCCESS => return,
- .ACCES => return error.AccessDenied,
- .DQUOT => return error.DiskQuota,
- .EXIST => return error.PathAlreadyExists,
- .FAULT => unreachable,
- .IO => return error.FileSystem,
- .LOOP => return error.SymLinkLoop,
- .MLINK => return error.LinkQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOSPC => return error.NoSpaceLeft,
- .PERM => return error.PermissionDenied,
- .ROFS => return error.ReadOnlyFileSystem,
- .XDEV => return error.NotSameFileSystem,
- .INVAL => unreachable,
- .ILSEQ => return error.BadPathName,
- else => |err| return unexpectedErrno(err),
- }
-}
-
-/// On WASI, both paths should be encoded as valid UTF-8.
-/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
-pub fn link(oldpath: []const u8, newpath: []const u8) LinkError!void {
- if (native_os == .wasi and !builtin.link_libc) {
- return linkat(AT.FDCWD, oldpath, AT.FDCWD, newpath, 0) catch |err| switch (err) {
- error.NotDir => unreachable, // link() does not support directories
- else => |e| return e,
- };
- }
- const old = try toPosixPath(oldpath);
- const new = try toPosixPath(newpath);
- return try linkZ(&old, &new);
-}
-
-pub const LinkatError = LinkError || error{NotDir};
-
-/// On WASI, both paths should be encoded as valid UTF-8.
-/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
-pub fn linkatZ(
- olddir: fd_t,
- oldpath: [*:0]const u8,
- newdir: fd_t,
- newpath: [*:0]const u8,
- flags: i32,
-) LinkatError!void {
- if (native_os == .wasi and !builtin.link_libc) {
- return linkat(olddir, mem.sliceTo(oldpath, 0), newdir, mem.sliceTo(newpath, 0), flags);
- }
- switch (errno(system.linkat(olddir, oldpath, newdir, newpath, flags))) {
- .SUCCESS => return,
- .ACCES => return error.AccessDenied,
- .DQUOT => return error.DiskQuota,
- .EXIST => return error.PathAlreadyExists,
- .FAULT => unreachable,
- .IO => return error.FileSystem,
- .LOOP => return error.SymLinkLoop,
- .MLINK => return error.LinkQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOSPC => return error.NoSpaceLeft,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .ROFS => return error.ReadOnlyFileSystem,
- .XDEV => return error.NotSameFileSystem,
- .INVAL => unreachable,
- .ILSEQ => return error.BadPathName,
- else => |err| return unexpectedErrno(err),
- }
-}
-
-/// On WASI, both paths should be encoded as valid UTF-8.
-/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
-pub fn linkat(
- olddir: fd_t,
- oldpath: []const u8,
- newdir: fd_t,
- newpath: []const u8,
- flags: i32,
-) LinkatError!void {
- if (native_os == .wasi and !builtin.link_libc) {
- const old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath };
- const new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath };
- const old_flags: wasi.lookupflags_t = .{
- .SYMLINK_FOLLOW = (flags & AT.SYMLINK_FOLLOW) != 0,
- };
- switch (wasi.path_link(
- old.dir_fd,
- old_flags,
- old.relative_path.ptr,
- old.relative_path.len,
- new.dir_fd,
- new.relative_path.ptr,
- new.relative_path.len,
- )) {
- .SUCCESS => return,
- .ACCES => return error.AccessDenied,
- .DQUOT => return error.DiskQuota,
- .EXIST => return error.PathAlreadyExists,
- .FAULT => unreachable,
- .IO => return error.FileSystem,
- .LOOP => return error.SymLinkLoop,
- .MLINK => return error.LinkQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOSPC => return error.NoSpaceLeft,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .ROFS => return error.ReadOnlyFileSystem,
- .XDEV => return error.NotSameFileSystem,
- .INVAL => unreachable,
- .ILSEQ => return error.BadPathName,
- else => |err| return unexpectedErrno(err),
- }
- }
- const old = try toPosixPath(oldpath);
- const new = try toPosixPath(newpath);
- return try linkatZ(olddir, &old, newdir, &new, flags);
-}
-
-/// An fd-relative file path
-///
-/// This is currently only used for WASI-specific functionality, but the concept
-/// is the same as the dirfd/pathname pairs in the `*at(...)` POSIX functions.
-const RelativePathWasi = struct {
- /// Handle to directory
- dir_fd: fd_t,
- /// Path to resource within `dir_fd`.
- relative_path: []const u8,
-};
-
/// On Windows, `sub_dir_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
/// On WASI, `sub_dir_path` should be encoded as valid UTF-8.
/// On other platforms, `sub_dir_path` is an opaque sequence of bytes with no particular encoding.
diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig
@@ -1,25 +1,24 @@
const builtin = @import("builtin");
const native_os = builtin.target.os.tag;
+const AtomicRmwOp = std.builtin.AtomicRmwOp;
+const AtomicOrder = std.builtin.AtomicOrder;
const std = @import("../std.zig");
const Io = std.Io;
+const Dir = std.Io.Dir;
const posix = std.posix;
+const mem = std.mem;
+const elf = std.elf;
+const linux = std.os.linux;
+const AT = std.posix.AT;
+
const testing = std.testing;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
+const expectEqualSlices = std.testing.expectEqualSlices;
+const expectEqualStrings = std.testing.expectEqualStrings;
const expectError = std.testing.expectError;
-const fs = std.fs;
-const mem = std.mem;
-const elf = std.elf;
-const linux = std.os.linux;
-const a = std.testing.allocator;
-const AtomicRmwOp = std.builtin.AtomicRmwOp;
-const AtomicOrder = std.builtin.AtomicOrder;
const tmpDir = std.testing.tmpDir;
-const AT = posix.AT;
-
-// 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" {
@@ -43,165 +42,6 @@ test "check WASI CWD" {
}
}
-test "open smoke test" {
- if (native_os == .wasi) return error.SkipZigTest;
- if (native_os == .windows) return error.SkipZigTest;
- if (native_os == .openbsd) return error.SkipZigTest;
-
- // TODO verify file attributes using `fstat`
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- const base_path = try tmp.dir.realpathAlloc(a, ".");
- defer a.free(base_path);
-
- const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
-
- {
- // Create some file using `open`.
- const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
- defer a.free(file_path);
- const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
- posix.close(fd);
- }
-
- {
- // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
- const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
- defer a.free(file_path);
- try expectError(error.PathAlreadyExists, posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode));
- }
-
- {
- // Try opening without `EXCL` flag.
- const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
- defer a.free(file_path);
- const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true }, mode);
- posix.close(fd);
- }
-
- {
- // Try opening as a directory which should fail.
- const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
- defer a.free(file_path);
- try expectError(error.NotDir, posix.open(file_path, .{ .ACCMODE = .RDWR, .DIRECTORY = true }, mode));
- }
-
- {
- // Create some directory
- const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
- defer a.free(file_path);
- try posix.mkdir(file_path, mode);
- }
-
- {
- // Open dir using `open`
- const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
- defer a.free(file_path);
- const fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
- posix.close(fd);
- }
-
- {
- // Try opening as file which should fail.
- const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
- defer a.free(file_path);
- try expectError(error.IsDir, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
- }
-}
-
-fn getLinkInfo(fd: posix.fd_t) !struct { posix.ino_t, posix.nlink_t } {
- if (native_os == .linux) {
- const stx = try linux.wrapped.statx(
- fd,
- "",
- posix.AT.EMPTY_PATH,
- .{ .INO = true, .NLINK = true },
- );
- std.debug.assert(stx.mask.INO);
- std.debug.assert(stx.mask.NLINK);
- return .{ stx.ino, stx.nlink };
- }
-
- const st = try posix.fstat(fd);
- return .{ st.ino, st.nlink };
-}
-
-test "linkat with different directories" {
- switch (native_os) {
- .wasi, .linux, .illumos => {},
- else => return error.SkipZigTest,
- }
-
- const io = testing.io;
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- const target_name = "link-target";
- const link_name = "newlink";
-
- const subdir = try tmp.dir.makeOpenPath(io, "subdir", .{});
-
- defer tmp.dir.deleteFile(io, target_name) catch {};
- try tmp.dir.writeFile(io, .{ .sub_path = target_name, .data = "example" });
-
- // Test 1: link from file in subdir back up to target in parent directory
- try posix.linkat(tmp.dir.handle, target_name, subdir.handle, link_name, 0);
-
- const efd = try tmp.dir.openFile(io, target_name, .{});
- defer efd.close(io);
-
- const nfd = try subdir.openFile(io, link_name, .{});
- defer nfd.close(io);
-
- {
- const eino, _ = try getLinkInfo(efd.handle);
- const nino, const nlink = try getLinkInfo(nfd.handle);
- try testing.expectEqual(eino, nino);
- try testing.expectEqual(@as(posix.nlink_t, 2), nlink);
- }
-
- // Test 2: remove link
- try posix.unlinkat(subdir.handle, link_name, 0);
- _, const elink = try getLinkInfo(efd.handle);
- try testing.expectEqual(@as(posix.nlink_t, 1), elink);
-}
-
-test "fstatat" {
- if (posix.Stat == void) return error.SkipZigTest;
- if (native_os == .wasi and !builtin.link_libc) return error.SkipZigTest;
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- // create dummy file
- const contents = "nonsense";
- try tmp.dir.writeFile(.{ .sub_path = "file.txt", .data = contents });
-
- // fetch file's info on the opened fd directly
- const file = try tmp.dir.openFile("file.txt", .{});
- const stat = try posix.fstat(file.handle);
- defer file.close();
-
- // now repeat but using `fstatat` instead
- const statat = try posix.fstatat(tmp.dir.fd, "file.txt", posix.AT.SYMLINK_NOFOLLOW);
-
- try expectEqual(stat.dev, statat.dev);
- try expectEqual(stat.ino, statat.ino);
- try expectEqual(stat.nlink, statat.nlink);
- try expectEqual(stat.mode, statat.mode);
- try expectEqual(stat.uid, statat.uid);
- try expectEqual(stat.gid, statat.gid);
- try expectEqual(stat.rdev, statat.rdev);
- try expectEqual(stat.size, statat.size);
- try expectEqual(stat.blksize, statat.blksize);
- // The stat.blocks/statat.blocks count is managed by the filesystem and may
- // change if the file is stored in a journal or "inline".
- // try expectEqual(stat.blocks, statat.blocks);
-}
-
test "getrandom" {
var buf_a: [50]u8 = undefined;
var buf_b: [50]u8 = undefined;
@@ -232,7 +72,7 @@ test "sigaltstack" {
// Setting a stack size less than MINSIGSTKSZ returns ENOMEM
st.flags = 0;
st.size = 1;
- try testing.expectError(error.SizeTooSmall, posix.sigaltstack(&st, null));
+ try expectError(error.SizeTooSmall, posix.sigaltstack(&st, null));
}
// If the type is not available use void to avoid erroring out when `iter_fn` is
@@ -304,7 +144,7 @@ test "pipe" {
try expect((try posix.write(fds[1], "hello")) == 5);
var buf: [16]u8 = undefined;
try expect((try posix.read(fds[0], buf[0..])) == 5);
- try testing.expectEqualSlices(u8, buf[0..5], "hello");
+ try expectEqualSlices(u8, buf[0..5], "hello");
posix.close(fds[1]);
posix.close(fds[0]);
}
@@ -315,6 +155,8 @@ test "argsAlloc" {
}
test "memfd_create" {
+ const io = testing.io;
+
// memfd_create is only supported by linux and freebsd.
switch (native_os) {
.linux => {},
@@ -325,15 +167,14 @@ test "memfd_create" {
else => return error.SkipZigTest,
}
- const fd = try posix.memfd_create("test", 0);
- defer posix.close(fd);
- try expect((try posix.write(fd, "test")) == 4);
- try posix.lseek_SET(fd, 0);
+ const file: Io.File = .{ .handle = try posix.memfd_create("test", 0) };
+ defer file.close(io);
+ try file.writePositionalAll(io, "test", 0);
var buf: [10]u8 = undefined;
- const bytes_read = try posix.read(fd, &buf);
+ const bytes_read = try file.readPositionalAll(io, &buf, 0);
try expect(bytes_read == 4);
- try expect(mem.eql(u8, buf[0..4], "test"));
+ try expectEqualStrings("test", buf[0..4]);
}
test "mmap" {
@@ -357,14 +198,14 @@ test "mmap" {
);
defer posix.munmap(data);
- try testing.expectEqual(@as(usize, 1234), data.len);
+ try expectEqual(@as(usize, 1234), data.len);
// By definition the data returned by mmap is zero-filled
- try testing.expect(mem.eql(u8, data, &[_]u8{0x00} ** 1234));
+ try expect(mem.eql(u8, data, &[_]u8{0x00} ** 1234));
// Make sure the memory is writeable as requested
@memset(data, 0x55);
- try testing.expect(mem.eql(u8, data, &[_]u8{0x55} ** 1234));
+ try expect(mem.eql(u8, data, &[_]u8{0x55} ** 1234));
}
const test_out_file = "os_tmp_test";
@@ -403,7 +244,7 @@ test "mmap" {
var i: usize = 0;
while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
- try testing.expectEqual(i, try stream.takeInt(u32, .little));
+ try expectEqual(i, try stream.takeInt(u32, .little));
}
}
@@ -428,7 +269,7 @@ test "mmap" {
var i: usize = alloc_size / 2 / @sizeOf(u32);
while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
- try testing.expectEqual(i, try stream.takeInt(u32, .little));
+ try expectEqual(i, try stream.takeInt(u32, .little));
}
}
}
@@ -498,7 +339,7 @@ test "fsync" {
const file = try tmp.dir.createFile(io, test_out_file, .{});
defer file.close(io);
- try posix.fsync(file.handle);
+ try file.sync(io);
try posix.fdatasync(file.handle);
}
@@ -536,9 +377,9 @@ test "sigrtmin/max" {
return error.SkipZigTest;
}
- try std.testing.expect(posix.sigrtmin() >= 32);
- try std.testing.expect(posix.sigrtmin() >= posix.system.sigrtmin());
- try std.testing.expect(posix.sigrtmin() < posix.system.sigrtmax());
+ try expect(posix.sigrtmin() >= 32);
+ try expect(posix.sigrtmin() >= posix.system.sigrtmin());
+ try expect(posix.sigrtmin() < posix.system.sigrtmax());
}
test "sigset empty/full" {
@@ -622,18 +463,18 @@ test "dup & dup2" {
var duped = Io.File{ .handle = try posix.dup(file.handle) };
defer duped.close(io);
- try duped.writeAll("dup");
+ try duped.writeStreamingAll(io, "dup");
// Tests aren't run in parallel so using the next fd shouldn't be an issue.
const new_fd = duped.handle + 1;
try posix.dup2(file.handle, new_fd);
var dup2ed = Io.File{ .handle = new_fd };
defer dup2ed.close(io);
- try dup2ed.writeAll("dup2");
+ try dup2ed.writeStreamingAll(io, "dup2");
}
var buffer: [8]u8 = undefined;
- try testing.expectEqualStrings("dupdup2", try tmp.dir.readFile("os_dup_test", &buffer));
+ try expectEqualStrings("dupdup2", try tmp.dir.readFile(io, "os_dup_test", &buffer));
}
test "getpid" {
@@ -651,147 +492,78 @@ test "getppid" {
try expect(posix.getppid() >= 0);
}
-test "writev longer than IOV_MAX" {
- if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
-
- const io = testing.io;
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- var file = try tmp.dir.createFile(io, "pwritev", .{});
- defer file.close(io);
-
- const iovecs = [_]posix.iovec_const{.{ .base = "a", .len = 1 }} ** (posix.IOV_MAX + 1);
- const amt = try file.writev(&iovecs);
- try testing.expectEqual(@as(usize, posix.IOV_MAX), amt);
-}
-
test "rename smoke test" {
if (native_os == .wasi) return error.SkipZigTest;
if (native_os == .windows) return error.SkipZigTest;
if (native_os == .openbsd) return error.SkipZigTest;
+ const io = testing.io;
+ const gpa = testing.allocator;
+
var tmp = tmpDir(.{});
defer tmp.cleanup();
- const base_path = try tmp.dir.realpathAlloc(a, ".");
- defer a.free(base_path);
+ const base_path = try tmp.dir.realPathAlloc(io, ".", gpa);
+ defer gpa.free(base_path);
const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
{
// Create some file using `open`.
- const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
- defer a.free(file_path);
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });
+ defer gpa.free(file_path);
const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
posix.close(fd);
// Rename the file
- const new_file_path = try fs.path.join(a, &.{ base_path, "some_other_file" });
- defer a.free(new_file_path);
- try Io.Dir.renameAbsolute(file_path, new_file_path);
+ const new_file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });
+ defer gpa.free(new_file_path);
+ try Io.Dir.renameAbsolute(io, file_path, new_file_path);
}
{
// Try opening renamed file
- const file_path = try fs.path.join(a, &.{ base_path, "some_other_file" });
- defer a.free(file_path);
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });
+ defer gpa.free(file_path);
const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR }, mode);
posix.close(fd);
}
{
// Try opening original file - should fail with error.FileNotFound
- const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
- defer a.free(file_path);
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });
+ defer gpa.free(file_path);
try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
}
{
// Create some directory
- const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
- defer a.free(file_path);
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_dir" });
+ defer gpa.free(file_path);
try posix.mkdir(file_path, mode);
// Rename the directory
- const new_file_path = try fs.path.join(a, &.{ base_path, "some_other_dir" });
- defer a.free(new_file_path);
- try Io.Dir.renameAbsolute(file_path, new_file_path);
+ const new_file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_dir" });
+ defer gpa.free(new_file_path);
+ try Io.Dir.renameAbsolute(io, file_path, new_file_path);
}
{
// Try opening renamed directory
- const file_path = try fs.path.join(a, &.{ base_path, "some_other_dir" });
- defer a.free(file_path);
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_dir" });
+ defer gpa.free(file_path);
const fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
posix.close(fd);
}
{
// Try opening original directory - should fail with error.FileNotFound
- const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
- defer a.free(file_path);
+ const file_path = try Dir.path.join(gpa, &.{ base_path, "some_dir" });
+ defer gpa.free(file_path);
try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));
}
}
-test "access smoke test" {
- if (native_os == .wasi) return error.SkipZigTest;
- if (native_os == .windows) return error.SkipZigTest;
- if (native_os == .openbsd) return error.SkipZigTest;
-
- const io = testing.io;
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- const base_path = try tmp.dir.realpathAlloc(a, ".");
- defer a.free(base_path);
-
- const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
- {
- // Create some file using `open`.
- const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
- defer a.free(file_path);
- const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
- posix.close(fd);
- }
-
- {
- // Try to access() the file
- const file_path = try fs.path.join(a, &.{ base_path, "some_file" });
- defer a.free(file_path);
- if (native_os == .windows) {
- try posix.access(io, file_path, posix.F_OK);
- } else {
- try posix.access(io, file_path, posix.F_OK | posix.W_OK | posix.R_OK);
- }
- }
-
- {
- // Try to access() a non-existent file - should fail with error.FileNotFound
- const file_path = try fs.path.join(a, &.{ base_path, "some_other_file" });
- defer a.free(file_path);
- try expectError(error.FileNotFound, posix.access(io, file_path, posix.F_OK));
- }
-
- {
- // Create some directory
- const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
- defer a.free(file_path);
- try posix.mkdir(file_path, mode);
- }
-
- {
- // Try to access() the directory
- const file_path = try fs.path.join(a, &.{ base_path, "some_dir" });
- defer a.free(file_path);
-
- try posix.access(io, file_path, posix.F_OK);
- }
-}
-
test "timerfd" {
if (native_os != .linux) return error.SkipZigTest;
@@ -809,89 +581,3 @@ test "timerfd" {
const expect_disarmed_timer: linux.itimerspec = .{ .it_interval = .{ .sec = 0, .nsec = 0 }, .it_value = .{ .sec = 0, .nsec = 0 } };
try expectEqual(expect_disarmed_timer, git);
}
-
-test "isatty" {
- const io = testing.io;
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- var file = try tmp.dir.createFile(io, "foo", .{});
- defer file.close(io);
-
- try expectEqual(posix.isatty(file.handle), false);
-}
-
-test "pread with empty buffer" {
- const io = testing.io;
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- var file = try tmp.dir.createFile(io, "pread_empty", .{ .read = true });
- defer file.close(io);
-
- const bytes = try a.alloc(u8, 0);
- defer a.free(bytes);
-
- const rc = try posix.pread(file.handle, bytes, 0);
- try expectEqual(rc, 0);
-}
-
-test "write with empty buffer" {
- const io = testing.io;
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- var file = try tmp.dir.createFile(io, "write_empty", .{});
- defer file.close(io);
-
- const bytes = try a.alloc(u8, 0);
- defer a.free(bytes);
-
- const rc = try posix.write(file.handle, bytes);
- try expectEqual(rc, 0);
-}
-
-test "pwrite with empty buffer" {
- const io = testing.io;
-
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- var file = try tmp.dir.createFile(io, "pwrite_empty", .{});
- defer file.close(io);
-
- const bytes = try a.alloc(u8, 0);
- defer a.free(bytes);
-
- const rc = try posix.pwrite(file.handle, bytes, 0);
- try expectEqual(rc, 0);
-}
-
-const CommonOpenFlags = packed struct {
- ACCMODE: posix.ACCMODE = .RDONLY,
- CREAT: bool = false,
- EXCL: bool = false,
- LARGEFILE: bool = false,
- DIRECTORY: bool = false,
- CLOEXEC: bool = false,
- NONBLOCK: bool = false,
-
- pub fn lower(cof: CommonOpenFlags) posix.O {
- var result: posix.O = if (native_os == .wasi) .{
- .read = cof.ACCMODE != .WRONLY,
- .write = cof.ACCMODE != .RDONLY,
- } else .{
- .ACCMODE = cof.ACCMODE,
- };
- result.CREAT = cof.CREAT;
- result.EXCL = cof.EXCL;
- result.DIRECTORY = cof.DIRECTORY;
- result.NONBLOCK = cof.NONBLOCK;
- if (@hasField(posix.O, "CLOEXEC")) result.CLOEXEC = cof.CLOEXEC;
- if (@hasField(posix.O, "LARGEFILE")) result.LARGEFILE = cof.LARGEFILE;
- return result;
- }
-};
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
@@ -6335,23 +6335,24 @@ fn testParse(io: Io, source: [:0]const u8, allocator: Allocator, anything_change
var buffer: [64]u8 = undefined;
const stderr = try io.lockStderr(&buffer, null);
defer io.unlockStderr();
+ const writer = &stderr.file_writer.interface;
var tree = try std.zig.Ast.parse(allocator, source, .zig);
defer tree.deinit(allocator);
for (tree.errors) |parse_error| {
const loc = tree.tokenLocation(0, parse_error.token);
- try stderr.writer.print("(memory buffer):{d}:{d}: error: ", .{ loc.line + 1, loc.column + 1 });
- try tree.renderError(parse_error, stderr.writer);
- try stderr.writer.print("\n{s}\n", .{source[loc.line_start..loc.line_end]});
+ try writer.print("(memory buffer):{d}:{d}: error: ", .{ loc.line + 1, loc.column + 1 });
+ try tree.renderError(parse_error, writer);
+ try writer.print("\n{s}\n", .{source[loc.line_start..loc.line_end]});
{
var i: usize = 0;
while (i < loc.column) : (i += 1) {
- try stderr.writer.writeAll(" ");
+ try writer.writeAll(" ");
}
- try stderr.writer.writeAll("^");
+ try writer.writeAll("^");
}
- try stderr.writer.writeAll("\n");
+ try writer.writeAll("\n");
}
if (tree.errors.len != 0) {
return error.ParseError;