In-Memory fs With Real Error Codes
Hard · File System
Test suites often replace the real disk with an in-memory file system (like memfs). The hard part is failing exactly like Node's fs does, so that code checking err.code still works.
Implement VirtualFS (synchronous methods, only / exists at first). Paths are always absolute and normalized (no ., .. or trailing /).
- mkdir(path, { recursive } = {}), writeFile(path, data) (creates or replaces a file; data is a string), readFile(path) (returns the string), readdir(path) (entry names, sorted with the default .sort()), stat(path) (returns { isFile, isDirectory, size } with booleans; size is the UTF-8 byte length for files and 0 for directories), rmdir(path), rm(path, { recursive } = {}).
- Errors are Error objects with a code property and the message "<CODE>: <description>, <syscall> '<path>'". Descriptions: ENOENT "no such file or directory", ENOTDIR "not a directory", EEXIST "file already exists", EISDIR "illegal operation on a directory", ENOTEMPTY "directory not empty".
- Syscall names: mkdir for mkdir, open for writeFile and readFile, scandir for readdir, stat for stat, rmdir for rmdir, lstat for rm.
- Path walk (all methods): go through the parent directories from the root. A missing one is ENOENT, a file where a directory is needed is ENOTDIR (the first problem wins). Both report the full path.
- Then: a missing target is ENOENT (not for writeFile, which creates it, or recursive mkdir). mkdir on an existing entry is EEXIST. mkdir with recursive creates every missing directory, does nothing if the directory exists, fails with EEXIST if the final entry is a file, and returns the first directory it created (or undefined). writeFile on a directory is EISDIR (syscall open). readFile on a directory is EISDIR with the exact message "EISDIR: illegal operation on a directory, read" (Node does not include the path here). readdir on a file is ENOTDIR. rmdir on a file is ENOTDIR, and on a non-empty directory ENOTEMPTY.
- rm removes a file, or a directory together with its contents when recursive is true. For a directory without recursive, throw code: "ERR_FS_EISDIR" with message "Path is a directory: rm returned EISDIR (is a directory) <path>". (These rm messages match Node 20; other Node versions word them slightly differently.)
The driver runFs(ops) is already written. Each op is [method, ...args]. It records the return value ("ok" for undefined) or "<code> | <message>" for errors.