Files
scriptc/tests/corpus/994-fs-errors.ts
T
Malte UblandClaude Sonnet 5.5 fab4b403e9 Give corpus scratch paths a per-process name
The differential and LLVM differential suites can run the same corpus
program's Node oracle at the same time in one shard. Programs whose
scratch directory or file was derived only from argv[1] collided, and
one oracle removed the paths under the other. Their names now include
the pid, as 1403 and 5567 already do. Printed output never carries the
name.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 09:07:41 -07:00

106 lines
2.8 KiB
TypeScript

// fs failures are CATCHABLE — the payoff of the exceptions phase: a try
// around each failing call recovers and execution continues after the
// catch, exactly like Node. The message text itself cannot be observed here
// (the supported catch form is bindingless); its Node-matching format
// ("ENOENT: no such file or directory, open 'x'") is asserted by the
// runtime C tests instead.
import {
existsSync,
mkdirSync,
readdirSync,
readFileSync,
rmdirSync,
rmSync,
writeFileSync,
} from "node:fs";
function tail(path: string): string {
let i = path.length - 1;
while (i >= 0 && path.charAt(i) !== "/" && path.charAt(i) !== "\\") {
i = i - 1;
}
return path.slice(i + 1);
}
function freshDir(dir: string): void {
if (existsSync(dir)) {
for (const name of readdirSync(dir)) {
rmSync(dir + "/" + name);
}
rmdirSync(dir);
}
mkdirSync(dir);
}
const scratch = "tmp-994-" + tail(process.argv[1]) + "-" + process.pid;
freshDir(scratch);
let caught = 0;
try {
const text = readFileSync(scratch + "/missing.txt", "utf8");
console.log("unreachable", text);
} catch {
caught = caught + 1;
console.log("caught: read of a missing file");
}
try {
mkdirSync(scratch); // already exists → EEXIST
} catch {
caught = caught + 1;
console.log("caught: mkdir of an existing path");
}
try {
mkdirSync(scratch + "/nope/deep"); // missing parent → ENOENT
} catch {
caught = caught + 1;
console.log("caught: mkdir under a missing parent");
}
try {
rmSync(scratch + "/missing.txt");
} catch {
caught = caught + 1;
console.log("caught: rm of a missing path");
}
try {
rmdirSync(scratch + "/missing");
} catch {
caught = caught + 1;
console.log("caught: rmdir of a missing path");
}
try {
const names = readdirSync(scratch + "/missing");
console.log("unreachable", names.length);
} catch {
caught = caught + 1;
console.log("caught: readdir of a missing path");
}
console.log("total caught:", caught);
// existsSync never throws — a missing path is simply false.
console.log(existsSync(scratch + "/missing.txt"));
// Errors propagate through call chains to the nearest catch, like any throw.
function readOrDefault(path: string, fallback: string): string {
try {
return readFileSync(path, "utf8");
} catch {
return fallback;
}
}
console.log(readOrDefault(scratch + "/missing.txt", "the default"));
writeFileSync(scratch + "/real.txt", "the real content");
console.log(readOrDefault(scratch + "/real.txt", "the default"));
// finally runs on the exception path of a failing fs call.
try {
try {
readFileSync(scratch + "/also-missing.txt", "utf8");
} finally {
console.log("finally ran");
}
} catch {
console.log("caught after finally");
}
rmSync(scratch + "/real.txt");
rmdirSync(scratch);
console.log(existsSync(scratch));