commit 5ec8e45f3d11265634c4943daf95f85745d17c2f (tree)
parent fd2718f82ab70d99186f43845e4291515efb66a5
Author: Samuel Fiedler <samuel.fiedler@proton.me>
Date: Mon, 5 Jan 2026 11:57:25 +0100
Io: add failing io (Io.failing)
Diffstat:
| M | lib/std/Io.zig | | | 961 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 961 insertions(+), 0 deletions(-)
diff --git a/lib/std/Io.zig b/lib/std/Io.zig
@@ -2491,3 +2491,964 @@ test {
_ = Semaphore;
_ = @import("Io/test.zig");
}
+
+/// An implementation of `Io` which simulates a system supporting no `Io` operations.
+///
+/// This system has the following properties:
+/// * Concurrency is unavailable.
+/// * The stdio handles are pipes whose remote ends are already closed.
+/// * The filesystem is entirely empty, including that the cwd is no longer present.
+/// * The filesystem is full, so attempting to create entries always returns `error.NoSpaceLeft`.
+/// * No entropy source is supported, so `randomSecure` always returns `error.EntropyUnavailable`, and `random` always returns (fills the buffer) with 0.
+/// * No clocks are supported, so `now` and `sleep` always return `error.UnsupportedClock`.
+/// * No network is connected, so network operations always return `error.NetworkDown`.
+pub const failing: std.Io = .{
+ .userdata = null,
+ .vtable = &.{
+ .crashHandler = noCrashHandler,
+
+ .async = noAsync,
+ .concurrent = failingConcurrent,
+ .await = unreachableAwait,
+ .cancel = unreachableCancel,
+
+ .groupAsync = noGroupAsync,
+ .groupConcurrent = failingGroupConcurrent,
+ .groupAwait = unreachableGroupAwait,
+ .groupCancel = unreachableGroupCancel,
+
+ .recancel = unreachableRecancel,
+ .swapCancelProtection = unreachableSwapCancelProtection,
+ .checkCancel = unreachableCheckCancel,
+
+ .futexWait = noFutexWait,
+ .futexWaitUncancelable = noFutexWaitUncancelable,
+ .futexWake = noFutexWake,
+
+ .operate = failingOperate,
+ .batchAwaitAsync = unreachableBatchAwaitAsync,
+ .batchAwaitConcurrent = unreachableBatchAwaitConcurrent,
+ .batchCancel = unreachableBatchCancel,
+
+ .dirCreateDir = failingDirCreateDir,
+ .dirCreateDirPath = failingDirCreateDirPath,
+ .dirCreateDirPathOpen = failingDirCreateDirPathOpen,
+ .dirOpenDir = failingDirOpenDir,
+ .dirStat = failingDirStat,
+ .dirStatFile = failingDirStatFile,
+ .dirAccess = failingDirAccess,
+ .dirCreateFile = failingDirCreateFile,
+ .dirCreateFileAtomic = failingDirCreateFileAtomic,
+ .dirOpenFile = failingDirOpenFile,
+ .dirClose = unreachableDirClose,
+ .dirRead = noDirRead,
+ .dirRealPath = failingDirRealPath,
+ .dirRealPathFile = failingDirRealPathFile,
+ .dirDeleteFile = failingDirDeleteFile,
+ .dirDeleteDir = failingDirDeleteDir,
+ .dirRename = failingDirRename,
+ .dirRenamePreserve = failingDirRenamePreserve,
+ .dirSymLink = failingDirSymLink,
+ .dirReadLink = failingDirReadLink,
+ .dirSetOwner = failingDirSetOwner,
+ .dirSetFileOwner = failingDirSetFileOwner,
+ .dirSetPermissions = failingDirSetPermissions,
+ .dirSetFilePermissions = failingDirSetFilePermissions,
+ .dirSetTimestamps = noDirSetTimestamps,
+ .dirHardLink = failingDirHardLink,
+
+ .fileStat = failingFileStat,
+ .fileLength = failingFileLength,
+ .fileClose = unreachableFileClose,
+ .fileWritePositional = failingFileWritePositional,
+ .fileWriteFileStreaming = noFileWriteFileStreaming,
+ .fileWriteFilePositional = noFileWriteFilePositional,
+ .fileReadPositional = failingFileReadPositional,
+ .fileSeekBy = failingFileSeekBy,
+ .fileSeekTo = failingFileSeekTo,
+ .fileSync = failingFileSync,
+ .fileIsTty = unreachableFileIsTty,
+ .fileEnableAnsiEscapeCodes = unreachableFileEnableAnsiEscapeCodes,
+ .fileSupportsAnsiEscapeCodes = unreachableFileSupportsAnsiEscapeCodes,
+ .fileSetLength = failingFileSetLength,
+ .fileSetOwner = failingFileSetOwner,
+ .fileSetPermissions = failingFileSetPermissions,
+ .fileSetTimestamps = noFileSetTimestamps,
+ .fileLock = failingFileLock,
+ .fileTryLock = failingFileTryLock,
+ .fileUnlock = unreachableFileUnlock,
+ .fileDowngradeLock = failingFileDowngradeLock,
+ .fileRealPath = failingFileRealPath,
+ .fileHardLink = failingFileHardLink,
+
+ .fileMemoryMapCreate = failingFileMemoryMapCreate,
+ .fileMemoryMapDestroy = unreachableFileMemoryMapDestroy,
+ .fileMemoryMapSetLength = unreachableFileMemoryMapSetLength,
+ .fileMemoryMapRead = unreachableFileMemoryMapRead,
+ .fileMemoryMapWrite = unreachableFileMemoryMapWrite,
+
+ .processExecutableOpen = failingProcessExecutableOpen,
+ .processExecutablePath = failingProcessExecutablePath,
+ .lockStderr = unreachableLockStderr,
+ .tryLockStderr = noTryLockStderr,
+ .unlockStderr = unreachableUnlockStderr,
+ .processCurrentPath = failingProcessCurrentPath,
+ .processSetCurrentDir = failingProcessSetCurrentDir,
+ .processSetCurrentPath = failingProcessSetCurrentPath,
+ .processReplace = failingProcessReplace,
+ .processReplacePath = failingProcessReplacePath,
+ .processSpawn = failingProcessSpawn,
+ .processSpawnPath = failingProcessSpawnPath,
+ .childWait = unreachableChildWait,
+ .childKill = unreachableChildKill,
+
+ .progressParentFile = failingProgressParentFile,
+
+ .random = noRandom,
+ .randomSecure = failingRandomSecure,
+
+ .now = noNow,
+ .clockResolution = failingClockResolution,
+ .sleep = noSleep,
+
+ .netListenIp = failingNetListenIp,
+ .netAccept = failingNetAccept,
+ .netBindIp = failingNetBindIp,
+ .netConnectIp = failingNetConnectIp,
+ .netListenUnix = failingNetListenUnix,
+ .netConnectUnix = failingNetConnectUnix,
+ .netSocketCreatePair = failingNetSocketCreatePair,
+ .netSend = failingNetSend,
+ .netRead = failingNetRead,
+ .netWrite = failingNetWrite,
+ .netWriteFile = failingNetWriteFile,
+ .netClose = unreachableNetClose,
+ .netShutdown = failingNetShutdown,
+ .netInterfaceNameResolve = failingNetInterfaceNameResolve,
+ .netInterfaceName = unreachableNetInterfaceName,
+ .netLookup = failingNetLookup,
+ },
+};
+
+pub fn noCrashHandler(userdata: ?*anyopaque) void {
+ _ = userdata;
+}
+
+pub fn noAsync(userdata: ?*anyopaque, result: []u8, result_alignment: std.mem.Alignment, context: []const u8, context_alignment: std.mem.Alignment, start: *const fn (context: *const anyopaque, result: *anyopaque) void) ?*AnyFuture {
+ _ = userdata;
+ _ = result_alignment;
+ _ = context_alignment;
+ start(context.ptr, result.ptr);
+ return null;
+}
+
+pub fn failingConcurrent(
+ userdata: ?*anyopaque,
+ result_len: usize,
+ result_alignment: std.mem.Alignment,
+ context: []const u8,
+ context_alignment: std.mem.Alignment,
+ start: *const fn (context: *const anyopaque, result: *anyopaque) void,
+) ConcurrentError!*AnyFuture {
+ _ = userdata;
+ _ = result_len;
+ _ = result_alignment;
+ _ = context;
+ _ = context_alignment;
+ _ = start;
+ return error.ConcurrencyUnavailable;
+}
+
+pub fn unreachableAwait(
+ userdata: ?*anyopaque,
+ any_future: *AnyFuture,
+ result: []u8,
+ result_alignment: std.mem.Alignment,
+) void {
+ _ = userdata;
+ _ = any_future;
+ _ = result;
+ _ = result_alignment;
+ unreachable;
+}
+
+pub fn unreachableCancel(
+ userdata: ?*anyopaque,
+ any_future: *AnyFuture,
+ result: []u8,
+ result_alignment: std.mem.Alignment,
+) void {
+ _ = userdata;
+ _ = any_future;
+ _ = result;
+ _ = result_alignment;
+ unreachable;
+}
+
+pub fn noGroupAsync(
+ userdata: ?*anyopaque,
+ group: *Group,
+ context: []const u8,
+ context_alignment: std.mem.Alignment,
+ start: *const fn (context: *const anyopaque) void,
+) void {
+ _ = userdata;
+ _ = group;
+ _ = context_alignment;
+ start(context.ptr);
+}
+
+pub fn failingGroupConcurrent(
+ userdata: ?*anyopaque,
+ group: *Group,
+ context: []const u8,
+ context_alignment: std.mem.Alignment,
+ start: *const fn (context: *const anyopaque) void,
+) ConcurrentError!void {
+ _ = userdata;
+ _ = group;
+ _ = context;
+ _ = context_alignment;
+ _ = start;
+ return error.ConcurrencyUnavailable;
+}
+
+pub fn unreachableGroupAwait(userdata: ?*anyopaque, group: *Group, token: *anyopaque) Cancelable!void {
+ _ = userdata;
+ _ = group;
+ _ = token;
+ unreachable;
+}
+
+pub fn unreachableGroupCancel(userdata: ?*anyopaque, group: *Group, token: *anyopaque) void {
+ _ = userdata;
+ _ = group;
+ _ = token;
+ unreachable;
+}
+
+pub fn unreachableRecancel(userdata: ?*anyopaque) void {
+ _ = userdata;
+ unreachable;
+}
+
+pub fn unreachableSwapCancelProtection(userdata: ?*anyopaque, new: CancelProtection) CancelProtection {
+ _ = userdata;
+ _ = new;
+ unreachable;
+}
+
+pub fn unreachableCheckCancel(userdata: ?*anyopaque) Cancelable!void {
+ _ = userdata;
+ unreachable;
+}
+
+pub fn noFutexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Timeout) Cancelable!void {
+ _ = userdata;
+ std.debug.assert(ptr.* == expected or timeout != .none);
+}
+
+pub fn noFutexWaitUncancelable(userdata: ?*anyopaque, ptr: *const u32, expected: u32) void {
+ _ = userdata;
+ std.debug.assert(ptr.* == expected);
+}
+
+pub fn noFutexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void {
+ _ = userdata;
+ _ = ptr;
+ _ = max_waiters;
+ // no-op
+}
+
+pub fn failingOperate(userdata: ?*anyopaque, operation: Operation) Cancelable!Operation.Result {
+ _ = userdata;
+ return switch (operation) {
+ .file_read_streaming => .{ .file_read_streaming = error.InputOutput },
+ .file_write_streaming => .{ .file_write_streaming = error.InputOutput },
+ .device_io_control => unreachable,
+ .net_receive => .{ .net_receive = .{ error.NetworkDown, 0 } },
+ };
+}
+
+pub fn unreachableBatchAwaitAsync(userdata: ?*anyopaque, b: *Batch) Cancelable!void {
+ _ = userdata;
+ _ = b;
+ unreachable;
+}
+
+pub fn unreachableBatchAwaitConcurrent(userdata: ?*anyopaque, b: *Batch, timeout: Timeout) Batch.AwaitConcurrentError!void {
+ _ = userdata;
+ _ = b;
+ _ = timeout;
+ unreachable;
+}
+
+pub fn unreachableBatchCancel(userdata: ?*anyopaque, b: *Batch) void {
+ _ = userdata;
+ _ = b;
+ unreachable;
+}
+
+pub fn failingDirCreateDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = permissions;
+ return error.NoSpaceLeft;
+}
+
+pub fn failingDirCreateDirPath(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirPathError!Dir.CreatePathStatus {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = permissions;
+ return error.NoSpaceLeft;
+}
+
+pub fn failingDirCreateDirPathOpen(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions, options: Dir.OpenOptions) Dir.CreateDirPathOpenError!Dir {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = permissions;
+ _ = options;
+ return error.NoSpaceLeft;
+}
+
+pub fn failingDirOpenDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.OpenOptions) Dir.OpenError!Dir {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = options;
+ return error.FileNotFound;
+}
+
+pub fn failingDirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat {
+ _ = userdata;
+ _ = dir;
+ return error.Streaming;
+}
+
+pub fn failingDirStatFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.StatFileOptions) Dir.StatFileError!File.Stat {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = options;
+ return error.FileNotFound;
+}
+
+pub fn failingDirAccess(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.AccessOptions) Dir.AccessError!void {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = options;
+ return error.FileNotFound;
+}
+
+pub fn failingDirCreateFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: File.CreateFlags) File.OpenError!File {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = options;
+ return error.NoSpaceLeft;
+}
+
+pub fn failingDirCreateFileAtomic(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.CreateFileAtomicOptions) Dir.CreateFileAtomicError!File.Atomic {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = options;
+ return error.NoSpaceLeft;
+}
+
+pub fn failingDirOpenFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = flags;
+ return error.FileNotFound;
+}
+
+pub fn unreachableDirClose(userdata: ?*anyopaque, dirs: []const Dir) void {
+ _ = userdata;
+ _ = dirs;
+ unreachable;
+}
+
+pub fn noDirRead(userdata: ?*anyopaque, dir_reader: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize {
+ _ = userdata;
+ _ = dir_reader;
+ _ = buffer;
+ return 0;
+}
+
+pub fn failingDirRealPath(userdata: ?*anyopaque, dir: Dir, out_buffer: []u8) Dir.RealPathError!usize {
+ _ = userdata;
+ _ = dir;
+ _ = out_buffer;
+ return error.FileNotFound;
+}
+
+pub fn failingDirRealPathFile(userdata: ?*anyopaque, dir: Dir, path_name: []const u8, out_buffer: []u8) Dir.RealPathFileError!usize {
+ _ = userdata;
+ _ = dir;
+ _ = path_name;
+ _ = out_buffer;
+ return error.FileNotFound;
+}
+
+pub fn failingDirDeleteFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteFileError!void {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ return error.FileNotFound;
+}
+
+pub fn failingDirDeleteDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteDirError!void {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ return error.FileNotFound;
+}
+
+pub fn failingDirRename(userdata: ?*anyopaque, old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) Dir.RenameError!void {
+ _ = userdata;
+ _ = old_dir;
+ _ = old_sub_path;
+ _ = new_dir;
+ _ = new_sub_path;
+ return error.FileNotFound;
+}
+
+pub fn failingDirRenamePreserve(userdata: ?*anyopaque, old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) Dir.RenamePreserveError!void {
+ _ = userdata;
+ _ = old_dir;
+ _ = old_sub_path;
+ _ = new_dir;
+ _ = new_sub_path;
+ return error.FileNotFound;
+}
+
+pub fn failingDirSymLink(userdata: ?*anyopaque, dir: Dir, target_path: []const u8, sym_link_path: []const u8, flags: Dir.SymLinkFlags) Dir.SymLinkError!void {
+ _ = userdata;
+ _ = dir;
+ _ = target_path;
+ _ = sym_link_path;
+ _ = flags;
+ return error.FileNotFound;
+}
+
+pub fn failingDirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = buffer;
+ return error.FileNotFound;
+}
+
+pub fn failingDirSetOwner(userdata: ?*anyopaque, dir: Dir, owner: ?File.Uid, group: ?File.Gid) Dir.SetOwnerError!void {
+ _ = userdata;
+ _ = dir;
+ _ = owner;
+ _ = group;
+ return error.FileNotFound;
+}
+
+pub fn failingDirSetFileOwner(userdata: ?*anyopaque, dir: std.Io.Dir, sub_path: []const u8, owner: ?File.Uid, group: ?File.Gid, options: Dir.SetFileOwnerOptions) Dir.SetFileOwnerError!void {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = owner;
+ _ = group;
+ _ = options;
+ return error.FileNotFound;
+}
+
+pub fn failingDirSetPermissions(userdata: ?*anyopaque, dir: Dir, permissions: Dir.Permissions) Dir.SetPermissionsError!void {
+ _ = userdata;
+ _ = dir;
+ _ = permissions;
+ return error.FileNotFound;
+}
+
+pub fn failingDirSetFilePermissions(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: File.Permissions, options: Dir.SetFilePermissionsOptions) Dir.SetFilePermissionsError!void {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = permissions;
+ _ = options;
+ return error.FileNotFound;
+}
+
+pub fn noDirSetTimestamps(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.SetTimestampsOptions) Dir.SetTimestampsError!void {
+ _ = userdata;
+ _ = dir;
+ _ = sub_path;
+ _ = options;
+ // no-op
+}
+
+pub fn failingDirHardLink(userdata: ?*anyopaque, old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8, options: Dir.HardLinkOptions) Dir.HardLinkError!void {
+ _ = userdata;
+ _ = old_dir;
+ _ = old_sub_path;
+ _ = new_dir;
+ _ = new_sub_path;
+ _ = options;
+ return error.FileNotFound;
+}
+
+pub fn failingFileStat(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {
+ _ = userdata;
+ _ = file;
+ return error.Streaming;
+}
+
+pub fn failingFileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 {
+ _ = userdata;
+ _ = file;
+ return error.Streaming;
+}
+
+pub fn unreachableFileClose(userdata: ?*anyopaque, files: []const File) void {
+ _ = userdata;
+ _ = files;
+ unreachable;
+}
+
+pub fn failingFileWritePositional(userdata: ?*anyopaque, file: File, header: []const u8, data: []const []const u8, splat: usize, offset: u64) File.WritePositionalError!usize {
+ _ = userdata;
+ _ = file;
+ _ = header;
+ _ = offset;
+ for (data[0 .. data.len - 1]) |item| {
+ if (item.len > 0) return error.BrokenPipe;
+ }
+ if (data[data.len - 1].len != 0 and splat != 0) return error.BrokenPipe;
+ return 0;
+}
+
+pub fn noFileWriteFileStreaming(userdata: ?*anyopaque, file: File, header: []const u8, file_reader: *Io.File.Reader, limit: Io.Limit) File.Writer.WriteFileError!usize {
+ _ = userdata;
+ _ = file;
+ _ = header;
+ _ = file_reader;
+ _ = limit;
+ return error.Unimplemented;
+}
+
+pub fn noFileWriteFilePositional(userdata: ?*anyopaque, file: File, header: []const u8, file_reader: *Io.File.Reader, limit: Io.Limit, offset: u64) File.WriteFilePositionalError!usize {
+ _ = userdata;
+ _ = file;
+ _ = header;
+ _ = file_reader;
+ _ = limit;
+ _ = offset;
+ return error.Unimplemented;
+}
+
+pub fn failingFileReadPositional(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {
+ _ = userdata;
+ _ = file;
+ _ = offset;
+ for (data) |item| {
+ if (item.len > 0) return error.InputOutput;
+ }
+ return 0;
+}
+
+pub fn failingFileSeekBy(userdata: ?*anyopaque, file: File, relative_offset: i64) File.SeekError!void {
+ _ = userdata;
+ _ = file;
+ _ = relative_offset;
+ return error.Unseekable;
+}
+
+pub fn failingFileSeekTo(userdata: ?*anyopaque, file: File, absolute_offset: u64) File.SeekError!void {
+ _ = userdata;
+ _ = file;
+ _ = absolute_offset;
+ return error.Unseekable;
+}
+
+pub fn failingFileSync(userdata: ?*anyopaque, file: File) File.SyncError!void {
+ _ = userdata;
+ _ = file;
+ return error.NoSpaceLeft;
+}
+
+pub fn unreachableFileIsTty(userdata: ?*anyopaque, file: File) Cancelable!bool {
+ _ = userdata;
+ _ = file;
+ unreachable;
+}
+
+pub fn unreachableFileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void {
+ _ = userdata;
+ _ = file;
+ unreachable;
+}
+
+pub fn unreachableFileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Cancelable!bool {
+ _ = userdata;
+ _ = file;
+ unreachable;
+}
+
+pub fn failingFileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthError!void {
+ _ = userdata;
+ _ = file;
+ _ = length;
+ return error.NonResizable;
+}
+
+pub fn failingFileSetOwner(userdata: ?*anyopaque, file: File, owner: ?File.Uid, group: ?File.Gid) File.SetOwnerError!void {
+ _ = userdata;
+ _ = file;
+ _ = owner;
+ _ = group;
+ return error.FileNotFound;
+}
+
+pub fn failingFileSetPermissions(userdata: ?*anyopaque, file: File, permissions: File.Permissions) File.SetPermissionsError!void {
+ _ = userdata;
+ _ = file;
+ _ = permissions;
+ return error.FileNotFound;
+}
+
+pub fn noFileSetTimestamps(userdata: ?*anyopaque, file: File, options: File.SetTimestampsOptions) File.SetTimestampsError!void {
+ _ = userdata;
+ _ = file;
+ _ = options;
+ // no-op
+}
+
+pub fn failingFileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!void {
+ _ = userdata;
+ _ = file;
+ _ = lock;
+ return error.FileLocksUnsupported;
+}
+
+pub fn failingFileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!bool {
+ _ = userdata;
+ _ = file;
+ _ = lock;
+ return error.FileLocksUnsupported;
+}
+
+pub fn unreachableFileUnlock(userdata: ?*anyopaque, file: File) void {
+ _ = userdata;
+ _ = file;
+ unreachable;
+}
+
+pub fn failingFileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!void {
+ _ = userdata;
+ _ = file;
+ // no-op
+}
+
+pub fn failingFileRealPath(userdata: ?*anyopaque, file: File, out_buffer: []u8) File.RealPathError!usize {
+ _ = userdata;
+ _ = file;
+ _ = out_buffer;
+ return error.FileNotFound;
+}
+
+pub fn failingFileHardLink(userdata: ?*anyopaque, file: File, new_dir: Dir, new_sub_path: []const u8, options: File.HardLinkOptions) File.HardLinkError!void {
+ _ = userdata;
+ _ = file;
+ _ = new_dir;
+ _ = new_sub_path;
+ _ = options;
+ return error.FileNotFound;
+}
+
+pub fn failingFileMemoryMapCreate(userdata: ?*anyopaque, file: File, options: File.MemoryMap.CreateOptions) File.MemoryMap.CreateError!File.MemoryMap {
+ _ = userdata;
+ _ = file;
+ _ = options;
+ return error.AccessDenied;
+}
+
+pub fn unreachableFileMemoryMapDestroy(userdata: ?*anyopaque, mm: *File.MemoryMap) void {
+ _ = userdata;
+ _ = mm;
+ unreachable;
+}
+
+pub fn unreachableFileMemoryMapSetLength(userdata: ?*anyopaque, mm: *File.MemoryMap, new_len: usize) File.MemoryMap.SetLengthError!void {
+ _ = userdata;
+ _ = mm;
+ _ = new_len;
+ unreachable;
+}
+
+pub fn unreachableFileMemoryMapRead(userdata: ?*anyopaque, mm: *File.MemoryMap) File.ReadPositionalError!void {
+ _ = userdata;
+ _ = mm;
+ unreachable;
+}
+
+pub fn unreachableFileMemoryMapWrite(userdata: ?*anyopaque, mm: *File.MemoryMap) File.WritePositionalError!void {
+ _ = userdata;
+ _ = mm;
+ unreachable;
+}
+
+pub fn failingProcessExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) std.process.OpenExecutableError!File {
+ _ = userdata;
+ _ = flags;
+ return error.FileNotFound;
+}
+
+pub fn failingProcessExecutablePath(userdata: ?*anyopaque, buffer: []u8) std.process.ExecutablePathError!usize {
+ _ = userdata;
+ _ = buffer;
+ return error.FileNotFound;
+}
+
+pub fn unreachableLockStderr(userdata: ?*anyopaque, terminal_mode: ?Terminal.Mode) Cancelable!LockedStderr {
+ _ = userdata;
+ _ = terminal_mode;
+ unreachable;
+}
+
+pub fn noTryLockStderr(userdata: ?*anyopaque, terminal_mode: ?Terminal.Mode) Cancelable!?LockedStderr {
+ _ = userdata;
+ _ = terminal_mode;
+ return null;
+}
+
+pub fn unreachableUnlockStderr(userdata: ?*anyopaque) void {
+ _ = userdata;
+ unreachable;
+}
+
+pub fn failingProcessCurrentPath(userdata: ?*anyopaque, buffer: []u8) std.process.CurrentPathError!usize {
+ _ = userdata;
+ _ = buffer;
+ return error.CurrentDirUnlinked;
+}
+
+pub fn failingProcessSetCurrentDir(userdata: ?*anyopaque, dir: Dir) std.process.SetCurrentDirError!void {
+ _ = userdata;
+ _ = dir;
+ return error.FileNotFound;
+}
+
+pub fn failingProcessSetCurrentPath(userdata: ?*anyopaque, path: []const u8) std.process.SetCurrentPathError!void {
+ _ = userdata;
+ _ = path;
+ return error.FileNotFound;
+}
+
+pub fn failingProcessReplace(userdata: ?*anyopaque, options: std.process.ReplaceOptions) std.process.ReplaceError {
+ _ = userdata;
+ _ = options;
+ return error.OperationUnsupported;
+}
+
+pub fn failingProcessReplacePath(userdata: ?*anyopaque, dir: Dir, options: std.process.ReplaceOptions) std.process.ReplaceError {
+ _ = userdata;
+ _ = dir;
+ _ = options;
+ return error.OperationUnsupported;
+}
+
+pub fn failingProcessSpawn(userdata: ?*anyopaque, options: std.process.SpawnOptions) std.process.SpawnError!std.process.Child {
+ _ = userdata;
+ _ = options;
+ return error.OperationUnsupported;
+}
+
+pub fn failingProcessSpawnPath(userdata: ?*anyopaque, dir: Dir, options: std.process.SpawnOptions) std.process.SpawnError!std.process.Child {
+ _ = userdata;
+ _ = dir;
+ _ = options;
+ return error.OperationUnsupported;
+}
+
+pub fn unreachableChildWait(userdata: ?*anyopaque, child: *std.process.Child) std.process.Child.WaitError!std.process.Child.Term {
+ _ = userdata;
+ _ = child;
+ unreachable;
+}
+
+pub fn unreachableChildKill(userdata: ?*anyopaque, child: *std.process.Child) void {
+ _ = userdata;
+ _ = child;
+ unreachable;
+}
+
+pub fn failingProgressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File {
+ _ = userdata;
+ return error.UnsupportedOperation;
+}
+
+pub fn noRandom(userdata: ?*anyopaque, buffer: []u8) void {
+ _ = userdata;
+ @memset(buffer, 0);
+}
+
+pub fn failingRandomSecure(userdata: ?*anyopaque, buffer: []u8) RandomSecureError!void {
+ _ = userdata;
+ _ = buffer;
+ return error.EntropyUnavailable;
+}
+
+pub fn noNow(userdata: ?*anyopaque, clock: Clock) Timestamp {
+ _ = userdata;
+ _ = clock;
+ return .zero;
+}
+
+pub fn failingClockResolution(userdata: ?*anyopaque, clock: Clock) Clock.ResolutionError!Duration {
+ _ = userdata;
+ _ = clock;
+ return error.ClockUnavailable;
+}
+
+pub fn noSleep(userdata: ?*anyopaque, clock: Timeout) Cancelable!void {
+ _ = userdata;
+ _ = clock;
+}
+
+pub fn failingNetListenIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Socket {
+ _ = userdata;
+ _ = address;
+ _ = options;
+ return error.NetworkDown;
+}
+
+pub fn failingNetAccept(userdata: ?*anyopaque, listen_fd: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket {
+ _ = userdata;
+ _ = listen_fd;
+ _ = options;
+ return error.NetworkDown;
+}
+
+pub fn failingNetBindIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket {
+ _ = userdata;
+ _ = address;
+ _ = options;
+ return error.NetworkDown;
+}
+
+pub fn failingNetConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Socket {
+ _ = userdata;
+ _ = address;
+ _ = options;
+ return error.NetworkDown;
+}
+
+pub fn failingNetListenUnix(userdata: ?*anyopaque, address: *const net.UnixAddress, options: net.UnixAddress.ListenOptions) net.UnixAddress.ListenError!net.Socket.Handle {
+ _ = userdata;
+ _ = address;
+ _ = options;
+ return error.NetworkDown;
+}
+
+pub fn failingNetConnectUnix(userdata: ?*anyopaque, address: *const net.UnixAddress) net.UnixAddress.ConnectError!net.Socket.Handle {
+ _ = userdata;
+ _ = address;
+ return error.NetworkDown;
+}
+
+pub fn failingNetSocketCreatePair(userdata: ?*anyopaque, options: net.Socket.CreatePairOptions) net.Socket.CreatePairError![2]net.Socket {
+ _ = userdata;
+ _ = options;
+ return error.OperationUnsupported;
+}
+
+pub fn failingNetSend(userdata: ?*anyopaque, handle: net.Socket.Handle, messages: []net.OutgoingMessage, flags: net.SendFlags) struct { ?net.Socket.SendError, usize } {
+ _ = userdata;
+ _ = handle;
+ _ = messages;
+ _ = flags;
+ return .{ error.NetworkDown, 0 };
+}
+
+pub fn failingNetRead(userdata: ?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
+ _ = userdata;
+ _ = src;
+ _ = data;
+ return error.NetworkDown;
+}
+
+pub fn failingNetWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize {
+ _ = userdata;
+ _ = dest;
+ _ = header;
+ _ = data;
+ _ = splat;
+ return error.NetworkDown;
+}
+
+pub fn failingNetWriteFile(userdata: ?*anyopaque, handle: net.Socket.Handle, header: []const u8, file_reader: *Io.File.Reader, limit: Io.Limit) net.Stream.Writer.WriteFileError!usize {
+ _ = userdata;
+ _ = handle;
+ _ = header;
+ _ = file_reader;
+ _ = limit;
+ return error.NetworkDown;
+}
+
+pub fn unreachableNetClose(userdata: ?*anyopaque, handle: []const net.Socket.Handle) void {
+ _ = userdata;
+ _ = handle;
+ unreachable;
+}
+
+pub fn failingNetShutdown(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void {
+ _ = userdata;
+ _ = handle;
+ _ = how;
+ return error.NetworkDown;
+}
+
+pub fn failingNetInterfaceNameResolve(userdata: ?*anyopaque, name: *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface {
+ _ = userdata;
+ _ = name;
+ return error.InterfaceNotFound;
+}
+
+pub fn unreachableNetInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
+ _ = userdata;
+ _ = interface;
+ unreachable;
+}
+
+pub fn failingNetLookup(userdata: ?*anyopaque, host_name: net.HostName, resolved: *Queue(net.HostName.LookupResult), options: net.HostName.LookupOptions) net.HostName.LookupError!void {
+ _ = userdata;
+ _ = host_name;
+ _ = resolved;
+ _ = options;
+ return error.NetworkDown;
+}
+
+test failing {
+ const f: Io = .failing;
+ // file stuff
+ try std.testing.expectError(error.NoSpaceLeft, Dir.createDir(.cwd(), f, "test", .default_dir));
+ try std.testing.expectError(error.NoSpaceLeft, Dir.createFile(.cwd(), f, "test", .{}));
+ try std.testing.expectError(error.FileNotFound, Dir.openDir(.cwd(), f, "test", .{}));
+ try std.testing.expectError(error.FileNotFound, Dir.openFile(.cwd(), f, "test", .{}));
+ try File.writeStreamingAll(.stdout(), f, &.{});
+ try std.testing.expectError(error.AccessDenied, File.MemoryMap.create(f, .stdout(), .{ .len = 0 }));
+ // async stuff
+ const closure = struct {
+ var foo: usize = 0;
+ fn doOp() void {
+ foo = 4;
+ }
+ };
+ var future = f.async(closure.doOp, .{});
+ _ = future.await(f);
+ try std.testing.expect(closure.foo == 4);
+ // random stuff
+ var buffer: [1]u8 = undefined;
+ f.random(&buffer);
+ try std.testing.expect(buffer[0] == 0);
+}