| ... | ... | @@ -2491,3 +2491,964 @@ test { |
| 2491 | 2491 | _ = Semaphore; |
| 2492 | 2492 | _ = @import("Io/test.zig"); |
| 2493 | 2493 | } |
| 2494 | |
| 2495 | /// An implementation of `Io` which simulates a system supporting no `Io` operations. |
| 2496 | /// |
| 2497 | /// This system has the following properties: |
| 2498 | /// * Concurrency is unavailable. |
| 2499 | /// * The stdio handles are pipes whose remote ends are already closed. |
| 2500 | /// * The filesystem is entirely empty, including that the cwd is no longer present. |
| 2501 | /// * The filesystem is full, so attempting to create entries always returns `error.NoSpaceLeft`. |
| 2502 | /// * No entropy source is supported, so `randomSecure` always returns `error.EntropyUnavailable`, and `random` always returns (fills the buffer) with 0. |
| 2503 | /// * No clocks are supported, so `now` and `sleep` always return `error.UnsupportedClock`. |
| 2504 | /// * No network is connected, so network operations always return `error.NetworkDown`. |
| 2505 | pub const failing: std.Io = .{ |
| 2506 | .userdata = null, |
| 2507 | .vtable = &.{ |
| 2508 | .crashHandler = noCrashHandler, |
| 2509 | |
| 2510 | .async = noAsync, |
| 2511 | .concurrent = failingConcurrent, |
| 2512 | .await = unreachableAwait, |
| 2513 | .cancel = unreachableCancel, |
| 2514 | |
| 2515 | .groupAsync = noGroupAsync, |
| 2516 | .groupConcurrent = failingGroupConcurrent, |
| 2517 | .groupAwait = unreachableGroupAwait, |
| 2518 | .groupCancel = unreachableGroupCancel, |
| 2519 | |
| 2520 | .recancel = unreachableRecancel, |
| 2521 | .swapCancelProtection = unreachableSwapCancelProtection, |
| 2522 | .checkCancel = unreachableCheckCancel, |
| 2523 | |
| 2524 | .futexWait = noFutexWait, |
| 2525 | .futexWaitUncancelable = noFutexWaitUncancelable, |
| 2526 | .futexWake = noFutexWake, |
| 2527 | |
| 2528 | .operate = failingOperate, |
| 2529 | .batchAwaitAsync = unreachableBatchAwaitAsync, |
| 2530 | .batchAwaitConcurrent = unreachableBatchAwaitConcurrent, |
| 2531 | .batchCancel = unreachableBatchCancel, |
| 2532 | |
| 2533 | .dirCreateDir = failingDirCreateDir, |
| 2534 | .dirCreateDirPath = failingDirCreateDirPath, |
| 2535 | .dirCreateDirPathOpen = failingDirCreateDirPathOpen, |
| 2536 | .dirOpenDir = failingDirOpenDir, |
| 2537 | .dirStat = failingDirStat, |
| 2538 | .dirStatFile = failingDirStatFile, |
| 2539 | .dirAccess = failingDirAccess, |
| 2540 | .dirCreateFile = failingDirCreateFile, |
| 2541 | .dirCreateFileAtomic = failingDirCreateFileAtomic, |
| 2542 | .dirOpenFile = failingDirOpenFile, |
| 2543 | .dirClose = unreachableDirClose, |
| 2544 | .dirRead = noDirRead, |
| 2545 | .dirRealPath = failingDirRealPath, |
| 2546 | .dirRealPathFile = failingDirRealPathFile, |
| 2547 | .dirDeleteFile = failingDirDeleteFile, |
| 2548 | .dirDeleteDir = failingDirDeleteDir, |
| 2549 | .dirRename = failingDirRename, |
| 2550 | .dirRenamePreserve = failingDirRenamePreserve, |
| 2551 | .dirSymLink = failingDirSymLink, |
| 2552 | .dirReadLink = failingDirReadLink, |
| 2553 | .dirSetOwner = failingDirSetOwner, |
| 2554 | .dirSetFileOwner = failingDirSetFileOwner, |
| 2555 | .dirSetPermissions = failingDirSetPermissions, |
| 2556 | .dirSetFilePermissions = failingDirSetFilePermissions, |
| 2557 | .dirSetTimestamps = noDirSetTimestamps, |
| 2558 | .dirHardLink = failingDirHardLink, |
| 2559 | |
| 2560 | .fileStat = failingFileStat, |
| 2561 | .fileLength = failingFileLength, |
| 2562 | .fileClose = unreachableFileClose, |
| 2563 | .fileWritePositional = failingFileWritePositional, |
| 2564 | .fileWriteFileStreaming = noFileWriteFileStreaming, |
| 2565 | .fileWriteFilePositional = noFileWriteFilePositional, |
| 2566 | .fileReadPositional = failingFileReadPositional, |
| 2567 | .fileSeekBy = failingFileSeekBy, |
| 2568 | .fileSeekTo = failingFileSeekTo, |
| 2569 | .fileSync = failingFileSync, |
| 2570 | .fileIsTty = unreachableFileIsTty, |
| 2571 | .fileEnableAnsiEscapeCodes = unreachableFileEnableAnsiEscapeCodes, |
| 2572 | .fileSupportsAnsiEscapeCodes = unreachableFileSupportsAnsiEscapeCodes, |
| 2573 | .fileSetLength = failingFileSetLength, |
| 2574 | .fileSetOwner = failingFileSetOwner, |
| 2575 | .fileSetPermissions = failingFileSetPermissions, |
| 2576 | .fileSetTimestamps = noFileSetTimestamps, |
| 2577 | .fileLock = failingFileLock, |
| 2578 | .fileTryLock = failingFileTryLock, |
| 2579 | .fileUnlock = unreachableFileUnlock, |
| 2580 | .fileDowngradeLock = failingFileDowngradeLock, |
| 2581 | .fileRealPath = failingFileRealPath, |
| 2582 | .fileHardLink = failingFileHardLink, |
| 2583 | |
| 2584 | .fileMemoryMapCreate = failingFileMemoryMapCreate, |
| 2585 | .fileMemoryMapDestroy = unreachableFileMemoryMapDestroy, |
| 2586 | .fileMemoryMapSetLength = unreachableFileMemoryMapSetLength, |
| 2587 | .fileMemoryMapRead = unreachableFileMemoryMapRead, |
| 2588 | .fileMemoryMapWrite = unreachableFileMemoryMapWrite, |
| 2589 | |
| 2590 | .processExecutableOpen = failingProcessExecutableOpen, |
| 2591 | .processExecutablePath = failingProcessExecutablePath, |
| 2592 | .lockStderr = unreachableLockStderr, |
| 2593 | .tryLockStderr = noTryLockStderr, |
| 2594 | .unlockStderr = unreachableUnlockStderr, |
| 2595 | .processCurrentPath = failingProcessCurrentPath, |
| 2596 | .processSetCurrentDir = failingProcessSetCurrentDir, |
| 2597 | .processSetCurrentPath = failingProcessSetCurrentPath, |
| 2598 | .processReplace = failingProcessReplace, |
| 2599 | .processReplacePath = failingProcessReplacePath, |
| 2600 | .processSpawn = failingProcessSpawn, |
| 2601 | .processSpawnPath = failingProcessSpawnPath, |
| 2602 | .childWait = unreachableChildWait, |
| 2603 | .childKill = unreachableChildKill, |
| 2604 | |
| 2605 | .progressParentFile = failingProgressParentFile, |
| 2606 | |
| 2607 | .random = noRandom, |
| 2608 | .randomSecure = failingRandomSecure, |
| 2609 | |
| 2610 | .now = noNow, |
| 2611 | .clockResolution = failingClockResolution, |
| 2612 | .sleep = noSleep, |
| 2613 | |
| 2614 | .netListenIp = failingNetListenIp, |
| 2615 | .netAccept = failingNetAccept, |
| 2616 | .netBindIp = failingNetBindIp, |
| 2617 | .netConnectIp = failingNetConnectIp, |
| 2618 | .netListenUnix = failingNetListenUnix, |
| 2619 | .netConnectUnix = failingNetConnectUnix, |
| 2620 | .netSocketCreatePair = failingNetSocketCreatePair, |
| 2621 | .netSend = failingNetSend, |
| 2622 | .netRead = failingNetRead, |
| 2623 | .netWrite = failingNetWrite, |
| 2624 | .netWriteFile = failingNetWriteFile, |
| 2625 | .netClose = unreachableNetClose, |
| 2626 | .netShutdown = failingNetShutdown, |
| 2627 | .netInterfaceNameResolve = failingNetInterfaceNameResolve, |
| 2628 | .netInterfaceName = unreachableNetInterfaceName, |
| 2629 | .netLookup = failingNetLookup, |
| 2630 | }, |
| 2631 | }; |
| 2632 | |
| 2633 | pub fn noCrashHandler(userdata: ?*anyopaque) void { |
| 2634 | _ = userdata; |
| 2635 | } |
| 2636 | |
| 2637 | 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 { |
| 2638 | _ = userdata; |
| 2639 | _ = result_alignment; |
| 2640 | _ = context_alignment; |
| 2641 | start(context.ptr, result.ptr); |
| 2642 | return null; |
| 2643 | } |
| 2644 | |
| 2645 | pub fn failingConcurrent( |
| 2646 | userdata: ?*anyopaque, |
| 2647 | result_len: usize, |
| 2648 | result_alignment: std.mem.Alignment, |
| 2649 | context: []const u8, |
| 2650 | context_alignment: std.mem.Alignment, |
| 2651 | start: *const fn (context: *const anyopaque, result: *anyopaque) void, |
| 2652 | ) ConcurrentError!*AnyFuture { |
| 2653 | _ = userdata; |
| 2654 | _ = result_len; |
| 2655 | _ = result_alignment; |
| 2656 | _ = context; |
| 2657 | _ = context_alignment; |
| 2658 | _ = start; |
| 2659 | return error.ConcurrencyUnavailable; |
| 2660 | } |
| 2661 | |
| 2662 | pub fn unreachableAwait( |
| 2663 | userdata: ?*anyopaque, |
| 2664 | any_future: *AnyFuture, |
| 2665 | result: []u8, |
| 2666 | result_alignment: std.mem.Alignment, |
| 2667 | ) void { |
| 2668 | _ = userdata; |
| 2669 | _ = any_future; |
| 2670 | _ = result; |
| 2671 | _ = result_alignment; |
| 2672 | unreachable; |
| 2673 | } |
| 2674 | |
| 2675 | pub fn unreachableCancel( |
| 2676 | userdata: ?*anyopaque, |
| 2677 | any_future: *AnyFuture, |
| 2678 | result: []u8, |
| 2679 | result_alignment: std.mem.Alignment, |
| 2680 | ) void { |
| 2681 | _ = userdata; |
| 2682 | _ = any_future; |
| 2683 | _ = result; |
| 2684 | _ = result_alignment; |
| 2685 | unreachable; |
| 2686 | } |
| 2687 | |
| 2688 | pub fn noGroupAsync( |
| 2689 | userdata: ?*anyopaque, |
| 2690 | group: *Group, |
| 2691 | context: []const u8, |
| 2692 | context_alignment: std.mem.Alignment, |
| 2693 | start: *const fn (context: *const anyopaque) void, |
| 2694 | ) void { |
| 2695 | _ = userdata; |
| 2696 | _ = group; |
| 2697 | _ = context_alignment; |
| 2698 | start(context.ptr); |
| 2699 | } |
| 2700 | |
| 2701 | pub fn failingGroupConcurrent( |
| 2702 | userdata: ?*anyopaque, |
| 2703 | group: *Group, |
| 2704 | context: []const u8, |
| 2705 | context_alignment: std.mem.Alignment, |
| 2706 | start: *const fn (context: *const anyopaque) void, |
| 2707 | ) ConcurrentError!void { |
| 2708 | _ = userdata; |
| 2709 | _ = group; |
| 2710 | _ = context; |
| 2711 | _ = context_alignment; |
| 2712 | _ = start; |
| 2713 | return error.ConcurrencyUnavailable; |
| 2714 | } |
| 2715 | |
| 2716 | pub fn unreachableGroupAwait(userdata: ?*anyopaque, group: *Group, token: *anyopaque) Cancelable!void { |
| 2717 | _ = userdata; |
| 2718 | _ = group; |
| 2719 | _ = token; |
| 2720 | unreachable; |
| 2721 | } |
| 2722 | |
| 2723 | pub fn unreachableGroupCancel(userdata: ?*anyopaque, group: *Group, token: *anyopaque) void { |
| 2724 | _ = userdata; |
| 2725 | _ = group; |
| 2726 | _ = token; |
| 2727 | unreachable; |
| 2728 | } |
| 2729 | |
| 2730 | pub fn unreachableRecancel(userdata: ?*anyopaque) void { |
| 2731 | _ = userdata; |
| 2732 | unreachable; |
| 2733 | } |
| 2734 | |
| 2735 | pub fn unreachableSwapCancelProtection(userdata: ?*anyopaque, new: CancelProtection) CancelProtection { |
| 2736 | _ = userdata; |
| 2737 | _ = new; |
| 2738 | unreachable; |
| 2739 | } |
| 2740 | |
| 2741 | pub fn unreachableCheckCancel(userdata: ?*anyopaque) Cancelable!void { |
| 2742 | _ = userdata; |
| 2743 | unreachable; |
| 2744 | } |
| 2745 | |
| 2746 | pub fn noFutexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Timeout) Cancelable!void { |
| 2747 | _ = userdata; |
| 2748 | std.debug.assert(ptr.* == expected or timeout != .none); |
| 2749 | } |
| 2750 | |
| 2751 | pub fn noFutexWaitUncancelable(userdata: ?*anyopaque, ptr: *const u32, expected: u32) void { |
| 2752 | _ = userdata; |
| 2753 | std.debug.assert(ptr.* == expected); |
| 2754 | } |
| 2755 | |
| 2756 | pub fn noFutexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void { |
| 2757 | _ = userdata; |
| 2758 | _ = ptr; |
| 2759 | _ = max_waiters; |
| 2760 | // no-op |
| 2761 | } |
| 2762 | |
| 2763 | pub fn failingOperate(userdata: ?*anyopaque, operation: Operation) Cancelable!Operation.Result { |
| 2764 | _ = userdata; |
| 2765 | return switch (operation) { |
| 2766 | .file_read_streaming => .{ .file_read_streaming = error.InputOutput }, |
| 2767 | .file_write_streaming => .{ .file_write_streaming = error.InputOutput }, |
| 2768 | .device_io_control => unreachable, |
| 2769 | .net_receive => .{ .net_receive = .{ error.NetworkDown, 0 } }, |
| 2770 | }; |
| 2771 | } |
| 2772 | |
| 2773 | pub fn unreachableBatchAwaitAsync(userdata: ?*anyopaque, b: *Batch) Cancelable!void { |
| 2774 | _ = userdata; |
| 2775 | _ = b; |
| 2776 | unreachable; |
| 2777 | } |
| 2778 | |
| 2779 | pub fn unreachableBatchAwaitConcurrent(userdata: ?*anyopaque, b: *Batch, timeout: Timeout) Batch.AwaitConcurrentError!void { |
| 2780 | _ = userdata; |
| 2781 | _ = b; |
| 2782 | _ = timeout; |
| 2783 | unreachable; |
| 2784 | } |
| 2785 | |
| 2786 | pub fn unreachableBatchCancel(userdata: ?*anyopaque, b: *Batch) void { |
| 2787 | _ = userdata; |
| 2788 | _ = b; |
| 2789 | unreachable; |
| 2790 | } |
| 2791 | |
| 2792 | pub fn failingDirCreateDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void { |
| 2793 | _ = userdata; |
| 2794 | _ = dir; |
| 2795 | _ = sub_path; |
| 2796 | _ = permissions; |
| 2797 | return error.NoSpaceLeft; |
| 2798 | } |
| 2799 | |
| 2800 | pub fn failingDirCreateDirPath(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirPathError!Dir.CreatePathStatus { |
| 2801 | _ = userdata; |
| 2802 | _ = dir; |
| 2803 | _ = sub_path; |
| 2804 | _ = permissions; |
| 2805 | return error.NoSpaceLeft; |
| 2806 | } |
| 2807 | |
| 2808 | pub fn failingDirCreateDirPathOpen(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions, options: Dir.OpenOptions) Dir.CreateDirPathOpenError!Dir { |
| 2809 | _ = userdata; |
| 2810 | _ = dir; |
| 2811 | _ = sub_path; |
| 2812 | _ = permissions; |
| 2813 | _ = options; |
| 2814 | return error.NoSpaceLeft; |
| 2815 | } |
| 2816 | |
| 2817 | pub fn failingDirOpenDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.OpenOptions) Dir.OpenError!Dir { |
| 2818 | _ = userdata; |
| 2819 | _ = dir; |
| 2820 | _ = sub_path; |
| 2821 | _ = options; |
| 2822 | return error.FileNotFound; |
| 2823 | } |
| 2824 | |
| 2825 | pub fn failingDirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat { |
| 2826 | _ = userdata; |
| 2827 | _ = dir; |
| 2828 | return error.Streaming; |
| 2829 | } |
| 2830 | |
| 2831 | pub fn failingDirStatFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.StatFileOptions) Dir.StatFileError!File.Stat { |
| 2832 | _ = userdata; |
| 2833 | _ = dir; |
| 2834 | _ = sub_path; |
| 2835 | _ = options; |
| 2836 | return error.FileNotFound; |
| 2837 | } |
| 2838 | |
| 2839 | pub fn failingDirAccess(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.AccessOptions) Dir.AccessError!void { |
| 2840 | _ = userdata; |
| 2841 | _ = dir; |
| 2842 | _ = sub_path; |
| 2843 | _ = options; |
| 2844 | return error.FileNotFound; |
| 2845 | } |
| 2846 | |
| 2847 | pub fn failingDirCreateFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: File.CreateFlags) File.OpenError!File { |
| 2848 | _ = userdata; |
| 2849 | _ = dir; |
| 2850 | _ = sub_path; |
| 2851 | _ = options; |
| 2852 | return error.NoSpaceLeft; |
| 2853 | } |
| 2854 | |
| 2855 | pub fn failingDirCreateFileAtomic(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.CreateFileAtomicOptions) Dir.CreateFileAtomicError!File.Atomic { |
| 2856 | _ = userdata; |
| 2857 | _ = dir; |
| 2858 | _ = sub_path; |
| 2859 | _ = options; |
| 2860 | return error.NoSpaceLeft; |
| 2861 | } |
| 2862 | |
| 2863 | pub fn failingDirOpenFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { |
| 2864 | _ = userdata; |
| 2865 | _ = dir; |
| 2866 | _ = sub_path; |
| 2867 | _ = flags; |
| 2868 | return error.FileNotFound; |
| 2869 | } |
| 2870 | |
| 2871 | pub fn unreachableDirClose(userdata: ?*anyopaque, dirs: []const Dir) void { |
| 2872 | _ = userdata; |
| 2873 | _ = dirs; |
| 2874 | unreachable; |
| 2875 | } |
| 2876 | |
| 2877 | pub fn noDirRead(userdata: ?*anyopaque, dir_reader: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize { |
| 2878 | _ = userdata; |
| 2879 | _ = dir_reader; |
| 2880 | _ = buffer; |
| 2881 | return 0; |
| 2882 | } |
| 2883 | |
| 2884 | pub fn failingDirRealPath(userdata: ?*anyopaque, dir: Dir, out_buffer: []u8) Dir.RealPathError!usize { |
| 2885 | _ = userdata; |
| 2886 | _ = dir; |
| 2887 | _ = out_buffer; |
| 2888 | return error.FileNotFound; |
| 2889 | } |
| 2890 | |
| 2891 | pub fn failingDirRealPathFile(userdata: ?*anyopaque, dir: Dir, path_name: []const u8, out_buffer: []u8) Dir.RealPathFileError!usize { |
| 2892 | _ = userdata; |
| 2893 | _ = dir; |
| 2894 | _ = path_name; |
| 2895 | _ = out_buffer; |
| 2896 | return error.FileNotFound; |
| 2897 | } |
| 2898 | |
| 2899 | pub fn failingDirDeleteFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteFileError!void { |
| 2900 | _ = userdata; |
| 2901 | _ = dir; |
| 2902 | _ = sub_path; |
| 2903 | return error.FileNotFound; |
| 2904 | } |
| 2905 | |
| 2906 | pub fn failingDirDeleteDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteDirError!void { |
| 2907 | _ = userdata; |
| 2908 | _ = dir; |
| 2909 | _ = sub_path; |
| 2910 | return error.FileNotFound; |
| 2911 | } |
| 2912 | |
| 2913 | pub fn failingDirRename(userdata: ?*anyopaque, old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) Dir.RenameError!void { |
| 2914 | _ = userdata; |
| 2915 | _ = old_dir; |
| 2916 | _ = old_sub_path; |
| 2917 | _ = new_dir; |
| 2918 | _ = new_sub_path; |
| 2919 | return error.FileNotFound; |
| 2920 | } |
| 2921 | |
| 2922 | pub fn failingDirRenamePreserve(userdata: ?*anyopaque, old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) Dir.RenamePreserveError!void { |
| 2923 | _ = userdata; |
| 2924 | _ = old_dir; |
| 2925 | _ = old_sub_path; |
| 2926 | _ = new_dir; |
| 2927 | _ = new_sub_path; |
| 2928 | return error.FileNotFound; |
| 2929 | } |
| 2930 | |
| 2931 | pub fn failingDirSymLink(userdata: ?*anyopaque, dir: Dir, target_path: []const u8, sym_link_path: []const u8, flags: Dir.SymLinkFlags) Dir.SymLinkError!void { |
| 2932 | _ = userdata; |
| 2933 | _ = dir; |
| 2934 | _ = target_path; |
| 2935 | _ = sym_link_path; |
| 2936 | _ = flags; |
| 2937 | return error.FileNotFound; |
| 2938 | } |
| 2939 | |
| 2940 | pub fn failingDirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize { |
| 2941 | _ = userdata; |
| 2942 | _ = dir; |
| 2943 | _ = sub_path; |
| 2944 | _ = buffer; |
| 2945 | return error.FileNotFound; |
| 2946 | } |
| 2947 | |
| 2948 | pub fn failingDirSetOwner(userdata: ?*anyopaque, dir: Dir, owner: ?File.Uid, group: ?File.Gid) Dir.SetOwnerError!void { |
| 2949 | _ = userdata; |
| 2950 | _ = dir; |
| 2951 | _ = owner; |
| 2952 | _ = group; |
| 2953 | return error.FileNotFound; |
| 2954 | } |
| 2955 | |
| 2956 | 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 { |
| 2957 | _ = userdata; |
| 2958 | _ = dir; |
| 2959 | _ = sub_path; |
| 2960 | _ = owner; |
| 2961 | _ = group; |
| 2962 | _ = options; |
| 2963 | return error.FileNotFound; |
| 2964 | } |
| 2965 | |
| 2966 | pub fn failingDirSetPermissions(userdata: ?*anyopaque, dir: Dir, permissions: Dir.Permissions) Dir.SetPermissionsError!void { |
| 2967 | _ = userdata; |
| 2968 | _ = dir; |
| 2969 | _ = permissions; |
| 2970 | return error.FileNotFound; |
| 2971 | } |
| 2972 | |
| 2973 | pub fn failingDirSetFilePermissions(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: File.Permissions, options: Dir.SetFilePermissionsOptions) Dir.SetFilePermissionsError!void { |
| 2974 | _ = userdata; |
| 2975 | _ = dir; |
| 2976 | _ = sub_path; |
| 2977 | _ = permissions; |
| 2978 | _ = options; |
| 2979 | return error.FileNotFound; |
| 2980 | } |
| 2981 | |
| 2982 | pub fn noDirSetTimestamps(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.SetTimestampsOptions) Dir.SetTimestampsError!void { |
| 2983 | _ = userdata; |
| 2984 | _ = dir; |
| 2985 | _ = sub_path; |
| 2986 | _ = options; |
| 2987 | // no-op |
| 2988 | } |
| 2989 | |
| 2990 | 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 { |
| 2991 | _ = userdata; |
| 2992 | _ = old_dir; |
| 2993 | _ = old_sub_path; |
| 2994 | _ = new_dir; |
| 2995 | _ = new_sub_path; |
| 2996 | _ = options; |
| 2997 | return error.FileNotFound; |
| 2998 | } |
| 2999 | |
| 3000 | pub fn failingFileStat(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 3001 | _ = userdata; |
| 3002 | _ = file; |
| 3003 | return error.Streaming; |
| 3004 | } |
| 3005 | |
| 3006 | pub fn failingFileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 { |
| 3007 | _ = userdata; |
| 3008 | _ = file; |
| 3009 | return error.Streaming; |
| 3010 | } |
| 3011 | |
| 3012 | pub fn unreachableFileClose(userdata: ?*anyopaque, files: []const File) void { |
| 3013 | _ = userdata; |
| 3014 | _ = files; |
| 3015 | unreachable; |
| 3016 | } |
| 3017 | |
| 3018 | pub fn failingFileWritePositional(userdata: ?*anyopaque, file: File, header: []const u8, data: []const []const u8, splat: usize, offset: u64) File.WritePositionalError!usize { |
| 3019 | _ = userdata; |
| 3020 | _ = file; |
| 3021 | _ = header; |
| 3022 | _ = offset; |
| 3023 | for (data[0 .. data.len - 1]) |item| { |
| 3024 | if (item.len > 0) return error.BrokenPipe; |
| 3025 | } |
| 3026 | if (data[data.len - 1].len != 0 and splat != 0) return error.BrokenPipe; |
| 3027 | return 0; |
| 3028 | } |
| 3029 | |
| 3030 | pub fn noFileWriteFileStreaming(userdata: ?*anyopaque, file: File, header: []const u8, file_reader: *Io.File.Reader, limit: Io.Limit) File.Writer.WriteFileError!usize { |
| 3031 | _ = userdata; |
| 3032 | _ = file; |
| 3033 | _ = header; |
| 3034 | _ = file_reader; |
| 3035 | _ = limit; |
| 3036 | return error.Unimplemented; |
| 3037 | } |
| 3038 | |
| 3039 | pub fn noFileWriteFilePositional(userdata: ?*anyopaque, file: File, header: []const u8, file_reader: *Io.File.Reader, limit: Io.Limit, offset: u64) File.WriteFilePositionalError!usize { |
| 3040 | _ = userdata; |
| 3041 | _ = file; |
| 3042 | _ = header; |
| 3043 | _ = file_reader; |
| 3044 | _ = limit; |
| 3045 | _ = offset; |
| 3046 | return error.Unimplemented; |
| 3047 | } |
| 3048 | |
| 3049 | pub fn failingFileReadPositional(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { |
| 3050 | _ = userdata; |
| 3051 | _ = file; |
| 3052 | _ = offset; |
| 3053 | for (data) |item| { |
| 3054 | if (item.len > 0) return error.InputOutput; |
| 3055 | } |
| 3056 | return 0; |
| 3057 | } |
| 3058 | |
| 3059 | pub fn failingFileSeekBy(userdata: ?*anyopaque, file: File, relative_offset: i64) File.SeekError!void { |
| 3060 | _ = userdata; |
| 3061 | _ = file; |
| 3062 | _ = relative_offset; |
| 3063 | return error.Unseekable; |
| 3064 | } |
| 3065 | |
| 3066 | pub fn failingFileSeekTo(userdata: ?*anyopaque, file: File, absolute_offset: u64) File.SeekError!void { |
| 3067 | _ = userdata; |
| 3068 | _ = file; |
| 3069 | _ = absolute_offset; |
| 3070 | return error.Unseekable; |
| 3071 | } |
| 3072 | |
| 3073 | pub fn failingFileSync(userdata: ?*anyopaque, file: File) File.SyncError!void { |
| 3074 | _ = userdata; |
| 3075 | _ = file; |
| 3076 | return error.NoSpaceLeft; |
| 3077 | } |
| 3078 | |
| 3079 | pub fn unreachableFileIsTty(userdata: ?*anyopaque, file: File) Cancelable!bool { |
| 3080 | _ = userdata; |
| 3081 | _ = file; |
| 3082 | unreachable; |
| 3083 | } |
| 3084 | |
| 3085 | pub fn unreachableFileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void { |
| 3086 | _ = userdata; |
| 3087 | _ = file; |
| 3088 | unreachable; |
| 3089 | } |
| 3090 | |
| 3091 | pub fn unreachableFileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Cancelable!bool { |
| 3092 | _ = userdata; |
| 3093 | _ = file; |
| 3094 | unreachable; |
| 3095 | } |
| 3096 | |
| 3097 | pub fn failingFileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthError!void { |
| 3098 | _ = userdata; |
| 3099 | _ = file; |
| 3100 | _ = length; |
| 3101 | return error.NonResizable; |
| 3102 | } |
| 3103 | |
| 3104 | pub fn failingFileSetOwner(userdata: ?*anyopaque, file: File, owner: ?File.Uid, group: ?File.Gid) File.SetOwnerError!void { |
| 3105 | _ = userdata; |
| 3106 | _ = file; |
| 3107 | _ = owner; |
| 3108 | _ = group; |
| 3109 | return error.FileNotFound; |
| 3110 | } |
| 3111 | |
| 3112 | pub fn failingFileSetPermissions(userdata: ?*anyopaque, file: File, permissions: File.Permissions) File.SetPermissionsError!void { |
| 3113 | _ = userdata; |
| 3114 | _ = file; |
| 3115 | _ = permissions; |
| 3116 | return error.FileNotFound; |
| 3117 | } |
| 3118 | |
| 3119 | pub fn noFileSetTimestamps(userdata: ?*anyopaque, file: File, options: File.SetTimestampsOptions) File.SetTimestampsError!void { |
| 3120 | _ = userdata; |
| 3121 | _ = file; |
| 3122 | _ = options; |
| 3123 | // no-op |
| 3124 | } |
| 3125 | |
| 3126 | pub fn failingFileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!void { |
| 3127 | _ = userdata; |
| 3128 | _ = file; |
| 3129 | _ = lock; |
| 3130 | return error.FileLocksUnsupported; |
| 3131 | } |
| 3132 | |
| 3133 | pub fn failingFileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!bool { |
| 3134 | _ = userdata; |
| 3135 | _ = file; |
| 3136 | _ = lock; |
| 3137 | return error.FileLocksUnsupported; |
| 3138 | } |
| 3139 | |
| 3140 | pub fn unreachableFileUnlock(userdata: ?*anyopaque, file: File) void { |
| 3141 | _ = userdata; |
| 3142 | _ = file; |
| 3143 | unreachable; |
| 3144 | } |
| 3145 | |
| 3146 | pub fn failingFileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!void { |
| 3147 | _ = userdata; |
| 3148 | _ = file; |
| 3149 | // no-op |
| 3150 | } |
| 3151 | |
| 3152 | pub fn failingFileRealPath(userdata: ?*anyopaque, file: File, out_buffer: []u8) File.RealPathError!usize { |
| 3153 | _ = userdata; |
| 3154 | _ = file; |
| 3155 | _ = out_buffer; |
| 3156 | return error.FileNotFound; |
| 3157 | } |
| 3158 | |
| 3159 | pub fn failingFileHardLink(userdata: ?*anyopaque, file: File, new_dir: Dir, new_sub_path: []const u8, options: File.HardLinkOptions) File.HardLinkError!void { |
| 3160 | _ = userdata; |
| 3161 | _ = file; |
| 3162 | _ = new_dir; |
| 3163 | _ = new_sub_path; |
| 3164 | _ = options; |
| 3165 | return error.FileNotFound; |
| 3166 | } |
| 3167 | |
| 3168 | pub fn failingFileMemoryMapCreate(userdata: ?*anyopaque, file: File, options: File.MemoryMap.CreateOptions) File.MemoryMap.CreateError!File.MemoryMap { |
| 3169 | _ = userdata; |
| 3170 | _ = file; |
| 3171 | _ = options; |
| 3172 | return error.AccessDenied; |
| 3173 | } |
| 3174 | |
| 3175 | pub fn unreachableFileMemoryMapDestroy(userdata: ?*anyopaque, mm: *File.MemoryMap) void { |
| 3176 | _ = userdata; |
| 3177 | _ = mm; |
| 3178 | unreachable; |
| 3179 | } |
| 3180 | |
| 3181 | pub fn unreachableFileMemoryMapSetLength(userdata: ?*anyopaque, mm: *File.MemoryMap, new_len: usize) File.MemoryMap.SetLengthError!void { |
| 3182 | _ = userdata; |
| 3183 | _ = mm; |
| 3184 | _ = new_len; |
| 3185 | unreachable; |
| 3186 | } |
| 3187 | |
| 3188 | pub fn unreachableFileMemoryMapRead(userdata: ?*anyopaque, mm: *File.MemoryMap) File.ReadPositionalError!void { |
| 3189 | _ = userdata; |
| 3190 | _ = mm; |
| 3191 | unreachable; |
| 3192 | } |
| 3193 | |
| 3194 | pub fn unreachableFileMemoryMapWrite(userdata: ?*anyopaque, mm: *File.MemoryMap) File.WritePositionalError!void { |
| 3195 | _ = userdata; |
| 3196 | _ = mm; |
| 3197 | unreachable; |
| 3198 | } |
| 3199 | |
| 3200 | pub fn failingProcessExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) std.process.OpenExecutableError!File { |
| 3201 | _ = userdata; |
| 3202 | _ = flags; |
| 3203 | return error.FileNotFound; |
| 3204 | } |
| 3205 | |
| 3206 | pub fn failingProcessExecutablePath(userdata: ?*anyopaque, buffer: []u8) std.process.ExecutablePathError!usize { |
| 3207 | _ = userdata; |
| 3208 | _ = buffer; |
| 3209 | return error.FileNotFound; |
| 3210 | } |
| 3211 | |
| 3212 | pub fn unreachableLockStderr(userdata: ?*anyopaque, terminal_mode: ?Terminal.Mode) Cancelable!LockedStderr { |
| 3213 | _ = userdata; |
| 3214 | _ = terminal_mode; |
| 3215 | unreachable; |
| 3216 | } |
| 3217 | |
| 3218 | pub fn noTryLockStderr(userdata: ?*anyopaque, terminal_mode: ?Terminal.Mode) Cancelable!?LockedStderr { |
| 3219 | _ = userdata; |
| 3220 | _ = terminal_mode; |
| 3221 | return null; |
| 3222 | } |
| 3223 | |
| 3224 | pub fn unreachableUnlockStderr(userdata: ?*anyopaque) void { |
| 3225 | _ = userdata; |
| 3226 | unreachable; |
| 3227 | } |
| 3228 | |
| 3229 | pub fn failingProcessCurrentPath(userdata: ?*anyopaque, buffer: []u8) std.process.CurrentPathError!usize { |
| 3230 | _ = userdata; |
| 3231 | _ = buffer; |
| 3232 | return error.CurrentDirUnlinked; |
| 3233 | } |
| 3234 | |
| 3235 | pub fn failingProcessSetCurrentDir(userdata: ?*anyopaque, dir: Dir) std.process.SetCurrentDirError!void { |
| 3236 | _ = userdata; |
| 3237 | _ = dir; |
| 3238 | return error.FileNotFound; |
| 3239 | } |
| 3240 | |
| 3241 | pub fn failingProcessSetCurrentPath(userdata: ?*anyopaque, path: []const u8) std.process.SetCurrentPathError!void { |
| 3242 | _ = userdata; |
| 3243 | _ = path; |
| 3244 | return error.FileNotFound; |
| 3245 | } |
| 3246 | |
| 3247 | pub fn failingProcessReplace(userdata: ?*anyopaque, options: std.process.ReplaceOptions) std.process.ReplaceError { |
| 3248 | _ = userdata; |
| 3249 | _ = options; |
| 3250 | return error.OperationUnsupported; |
| 3251 | } |
| 3252 | |
| 3253 | pub fn failingProcessReplacePath(userdata: ?*anyopaque, dir: Dir, options: std.process.ReplaceOptions) std.process.ReplaceError { |
| 3254 | _ = userdata; |
| 3255 | _ = dir; |
| 3256 | _ = options; |
| 3257 | return error.OperationUnsupported; |
| 3258 | } |
| 3259 | |
| 3260 | pub fn failingProcessSpawn(userdata: ?*anyopaque, options: std.process.SpawnOptions) std.process.SpawnError!std.process.Child { |
| 3261 | _ = userdata; |
| 3262 | _ = options; |
| 3263 | return error.OperationUnsupported; |
| 3264 | } |
| 3265 | |
| 3266 | pub fn failingProcessSpawnPath(userdata: ?*anyopaque, dir: Dir, options: std.process.SpawnOptions) std.process.SpawnError!std.process.Child { |
| 3267 | _ = userdata; |
| 3268 | _ = dir; |
| 3269 | _ = options; |
| 3270 | return error.OperationUnsupported; |
| 3271 | } |
| 3272 | |
| 3273 | pub fn unreachableChildWait(userdata: ?*anyopaque, child: *std.process.Child) std.process.Child.WaitError!std.process.Child.Term { |
| 3274 | _ = userdata; |
| 3275 | _ = child; |
| 3276 | unreachable; |
| 3277 | } |
| 3278 | |
| 3279 | pub fn unreachableChildKill(userdata: ?*anyopaque, child: *std.process.Child) void { |
| 3280 | _ = userdata; |
| 3281 | _ = child; |
| 3282 | unreachable; |
| 3283 | } |
| 3284 | |
| 3285 | pub fn failingProgressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File { |
| 3286 | _ = userdata; |
| 3287 | return error.UnsupportedOperation; |
| 3288 | } |
| 3289 | |
| 3290 | pub fn noRandom(userdata: ?*anyopaque, buffer: []u8) void { |
| 3291 | _ = userdata; |
| 3292 | @memset(buffer, 0); |
| 3293 | } |
| 3294 | |
| 3295 | pub fn failingRandomSecure(userdata: ?*anyopaque, buffer: []u8) RandomSecureError!void { |
| 3296 | _ = userdata; |
| 3297 | _ = buffer; |
| 3298 | return error.EntropyUnavailable; |
| 3299 | } |
| 3300 | |
| 3301 | pub fn noNow(userdata: ?*anyopaque, clock: Clock) Timestamp { |
| 3302 | _ = userdata; |
| 3303 | _ = clock; |
| 3304 | return .zero; |
| 3305 | } |
| 3306 | |
| 3307 | pub fn failingClockResolution(userdata: ?*anyopaque, clock: Clock) Clock.ResolutionError!Duration { |
| 3308 | _ = userdata; |
| 3309 | _ = clock; |
| 3310 | return error.ClockUnavailable; |
| 3311 | } |
| 3312 | |
| 3313 | pub fn noSleep(userdata: ?*anyopaque, clock: Timeout) Cancelable!void { |
| 3314 | _ = userdata; |
| 3315 | _ = clock; |
| 3316 | } |
| 3317 | |
| 3318 | pub fn failingNetListenIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Socket { |
| 3319 | _ = userdata; |
| 3320 | _ = address; |
| 3321 | _ = options; |
| 3322 | return error.NetworkDown; |
| 3323 | } |
| 3324 | |
| 3325 | pub fn failingNetAccept(userdata: ?*anyopaque, listen_fd: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket { |
| 3326 | _ = userdata; |
| 3327 | _ = listen_fd; |
| 3328 | _ = options; |
| 3329 | return error.NetworkDown; |
| 3330 | } |
| 3331 | |
| 3332 | pub fn failingNetBindIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket { |
| 3333 | _ = userdata; |
| 3334 | _ = address; |
| 3335 | _ = options; |
| 3336 | return error.NetworkDown; |
| 3337 | } |
| 3338 | |
| 3339 | pub fn failingNetConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Socket { |
| 3340 | _ = userdata; |
| 3341 | _ = address; |
| 3342 | _ = options; |
| 3343 | return error.NetworkDown; |
| 3344 | } |
| 3345 | |
| 3346 | pub fn failingNetListenUnix(userdata: ?*anyopaque, address: *const net.UnixAddress, options: net.UnixAddress.ListenOptions) net.UnixAddress.ListenError!net.Socket.Handle { |
| 3347 | _ = userdata; |
| 3348 | _ = address; |
| 3349 | _ = options; |
| 3350 | return error.NetworkDown; |
| 3351 | } |
| 3352 | |
| 3353 | pub fn failingNetConnectUnix(userdata: ?*anyopaque, address: *const net.UnixAddress) net.UnixAddress.ConnectError!net.Socket.Handle { |
| 3354 | _ = userdata; |
| 3355 | _ = address; |
| 3356 | return error.NetworkDown; |
| 3357 | } |
| 3358 | |
| 3359 | pub fn failingNetSocketCreatePair(userdata: ?*anyopaque, options: net.Socket.CreatePairOptions) net.Socket.CreatePairError![2]net.Socket { |
| 3360 | _ = userdata; |
| 3361 | _ = options; |
| 3362 | return error.OperationUnsupported; |
| 3363 | } |
| 3364 | |
| 3365 | pub fn failingNetSend(userdata: ?*anyopaque, handle: net.Socket.Handle, messages: []net.OutgoingMessage, flags: net.SendFlags) struct { ?net.Socket.SendError, usize } { |
| 3366 | _ = userdata; |
| 3367 | _ = handle; |
| 3368 | _ = messages; |
| 3369 | _ = flags; |
| 3370 | return .{ error.NetworkDown, 0 }; |
| 3371 | } |
| 3372 | |
| 3373 | pub fn failingNetRead(userdata: ?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { |
| 3374 | _ = userdata; |
| 3375 | _ = src; |
| 3376 | _ = data; |
| 3377 | return error.NetworkDown; |
| 3378 | } |
| 3379 | |
| 3380 | pub fn failingNetWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize { |
| 3381 | _ = userdata; |
| 3382 | _ = dest; |
| 3383 | _ = header; |
| 3384 | _ = data; |
| 3385 | _ = splat; |
| 3386 | return error.NetworkDown; |
| 3387 | } |
| 3388 | |
| 3389 | 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 { |
| 3390 | _ = userdata; |
| 3391 | _ = handle; |
| 3392 | _ = header; |
| 3393 | _ = file_reader; |
| 3394 | _ = limit; |
| 3395 | return error.NetworkDown; |
| 3396 | } |
| 3397 | |
| 3398 | pub fn unreachableNetClose(userdata: ?*anyopaque, handle: []const net.Socket.Handle) void { |
| 3399 | _ = userdata; |
| 3400 | _ = handle; |
| 3401 | unreachable; |
| 3402 | } |
| 3403 | |
| 3404 | pub fn failingNetShutdown(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void { |
| 3405 | _ = userdata; |
| 3406 | _ = handle; |
| 3407 | _ = how; |
| 3408 | return error.NetworkDown; |
| 3409 | } |
| 3410 | |
| 3411 | pub fn failingNetInterfaceNameResolve(userdata: ?*anyopaque, name: *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface { |
| 3412 | _ = userdata; |
| 3413 | _ = name; |
| 3414 | return error.InterfaceNotFound; |
| 3415 | } |
| 3416 | |
| 3417 | pub fn unreachableNetInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { |
| 3418 | _ = userdata; |
| 3419 | _ = interface; |
| 3420 | unreachable; |
| 3421 | } |
| 3422 | |
| 3423 | pub fn failingNetLookup(userdata: ?*anyopaque, host_name: net.HostName, resolved: *Queue(net.HostName.LookupResult), options: net.HostName.LookupOptions) net.HostName.LookupError!void { |
| 3424 | _ = userdata; |
| 3425 | _ = host_name; |
| 3426 | _ = resolved; |
| 3427 | _ = options; |
| 3428 | return error.NetworkDown; |
| 3429 | } |
| 3430 | |
| 3431 | test failing { |
| 3432 | const f: Io = .failing; |
| 3433 | // file stuff |
| 3434 | try std.testing.expectError(error.NoSpaceLeft, Dir.createDir(.cwd(), f, "test", .default_dir)); |
| 3435 | try std.testing.expectError(error.NoSpaceLeft, Dir.createFile(.cwd(), f, "test", .{})); |
| 3436 | try std.testing.expectError(error.FileNotFound, Dir.openDir(.cwd(), f, "test", .{})); |
| 3437 | try std.testing.expectError(error.FileNotFound, Dir.openFile(.cwd(), f, "test", .{})); |
| 3438 | try File.writeStreamingAll(.stdout(), f, &.{}); |
| 3439 | try std.testing.expectError(error.AccessDenied, File.MemoryMap.create(f, .stdout(), .{ .len = 0 })); |
| 3440 | // async stuff |
| 3441 | const closure = struct { |
| 3442 | var foo: usize = 0; |
| 3443 | fn doOp() void { |
| 3444 | foo = 4; |
| 3445 | } |
| 3446 | }; |
| 3447 | var future = f.async(closure.doOp, .{}); |
| 3448 | _ = future.await(f); |
| 3449 | try std.testing.expect(closure.foo == 4); |
| 3450 | // random stuff |
| 3451 | var buffer: [1]u8 = undefined; |
| 3452 | f.random(&buffer); |
| 3453 | try std.testing.expect(buffer[0] == 0); |
| 3454 | } |