fallow
Version:
Codebase intelligence for TypeScript and JavaScript: health, complexity, duplication, architecture, styling drift, and unused code from one graph. CLI, LSP, and MCP server. Zero config for over 100 frameworks.
235 lines (211 loc) • 10.1 kB
JavaScript
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const os = require("node:os");
const { spawnSync } = require("node:child_process");
const path = require("node:path");
const RUN_BINARY = path.join(__dirname, "run-binary.js");
const BIN_DIR = path.join(__dirname, "..", "bin");
function currentPlatformPackage() {
const { getPlatformPackage } = require("./platform-package");
if (process.platform !== "linux") {
return getPlatformPackage(process.platform, process.arch);
}
let libcFamily;
try {
libcFamily = require("detect-libc").familySync();
} catch {
libcFamily = undefined;
}
return getPlatformPackage(process.platform, process.arch, libcFamily);
}
function runLauncher(t, launcher, args) {
const work = fs.mkdtempSync(path.join(os.tmpdir(), "fallow-launcher-"));
t.after(() => fs.rmSync(work, { recursive: true, force: true }));
const pkg = currentPlatformPackage();
assert.ok(pkg, "the test host must map to a supported platform package");
const pkgDir = path.join(work, "node_modules", ...pkg.split("/"));
fs.mkdirSync(pkgDir, { recursive: true });
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({ name: pkg, version: "3.5.0" }),
);
const binary = path.join(pkgDir, "fallow");
fs.writeFileSync(
binary,
"#!/usr/bin/env node\n" +
'require("node:fs").writeFileSync(process.env.FALLOW_TEST_ARGS, JSON.stringify(process.argv.slice(2)));\n',
);
fs.chmodSync(binary, 0o755);
const argsFile = path.join(work, "args.json");
const result = spawnSync(process.execPath, [path.join(BIN_DIR, launcher), ...args], {
encoding: "utf8",
env: {
...process.env,
NODE_PATH: path.join(work, "node_modules"),
FALLOW_SKIP_BINARY_VERIFY: "1",
FALLOW_TEST_ARGS: argsFile,
},
});
assert.equal(result.status, 0, result.stderr);
return JSON.parse(fs.readFileSync(argsFile, "utf8"));
}
// Run a child that installs guardBrokenStdout, then emits a synthetic stdout
// 'error' with the given code. Node delivers a broken-pipe failure as exactly
// this event ("Emitted 'error' event on Socket instance"), so emitting it is a
// faithful reproduction of `fallow --version | head` without needing a live
// pipe or an installed @fallow-cli platform package. Requiring run-binary.js
// has no side effects beyond defining functions, so no binary is resolved.
function runGuardChild(errorCode) {
const script =
`const { guardBrokenStdout } = require(${JSON.stringify(RUN_BINARY)});` +
`guardBrokenStdout();` +
`process.stdout.emit("error", Object.assign(new Error("write ${errorCode}"), { code: "${errorCode}" }));` +
// Reached only if the guard neither exited (EPIPE) nor rethrew (other).
`process.exit(42);`;
return spawnSync(process.execPath, ["-e", script], { encoding: "utf8" });
}
test("guardBrokenStdout swallows EPIPE on stdout and exits 0", () => {
const res = runGuardChild("EPIPE");
assert.equal(res.status, 0, "EPIPE on stdout should exit 0 cleanly, not crash");
assert.doesNotMatch(res.stderr, /EPIPE/, "no EPIPE stack trace on stderr");
});
test("guardBrokenStdout rethrows non-EPIPE stdout errors (exit 1)", () => {
const res = runGuardChild("ENOSPC");
assert.equal(res.status, 1, "a non-EPIPE stdout error must surface, not be swallowed");
// Match the thrown error's header ("Error: write ENOSPC"), not just the
// message substring: a missing-guard TypeError would leak the script source
// (`new Error("write ENOSPC")`) into its code frame and match a looser regex,
// masking a regression. The colon-space header only appears on a real rethrow.
assert.match(res.stderr, /Error: write ENOSPC/, "the rethrown error reaches stderr");
assert.doesNotMatch(res.stderr, /is not a function/, "guard must be present, not absent");
});
test("isVersionQuery recognizes --version, -V, and -v as the first argument", () => {
const { isVersionQuery } = require(RUN_BINARY);
assert.equal(isVersionQuery(["node", "fallow", "--version"]), true);
assert.equal(isVersionQuery(["node", "fallow", "-V"]), true);
assert.equal(
isVersionQuery(["node", "fallow", "-v"]),
true,
"-v must append the verified line too",
);
assert.equal(isVersionQuery(["node", "fallow"]), false);
assert.equal(isVersionQuery(["node", "fallow", "dead-code"]), false);
assert.equal(
isVersionQuery(["node", "fallow", "dead-code", "-v"]),
false,
"-v only counts as the first arg",
);
});
test("describeVerified annotates the resolved version's signing status", () => {
const { describeVerified } = require(RUN_BINARY);
const ok = { ok: true, sentinelPath: "/c/s" };
// Signed-era version: appended as `signed`.
assert.match(
describeVerified(ok, "2.83.0"),
/verified: yes \(sentinel \/c\/s\); fallow 2\.83\.0 signed/,
);
// Pre-signing version: the fleet pre-flight signal, most useful on skip.
const skipped = { skipped: true, reason: "FALLOW_SKIP_BINARY_VERIFY is set" };
assert.match(
describeVerified(skipped, "2.76.0"),
/verified: skipped \(.*\); fallow 2\.76\.0 unsigned \(predates 2\.77\.0\)/,
);
// Unknown / unreadable version: no annotation, version line stays intact.
assert.equal(describeVerified(ok, undefined), "verified: yes (sentinel /c/s)");
assert.equal(describeVerified(ok, ""), "verified: yes (sentinel /c/s)");
});
test("exitCodeForChildFailure preserves status codes and maps signal deaths", () => {
const { exitCodeForChildFailure } = require(RUN_BINARY);
assert.equal(exitCodeForChildFailure({ status: 3 }), 3);
assert.equal(exitCodeForChildFailure({ status: 0 }), 0);
assert.equal(
exitCodeForChildFailure({ status: null, signal: "SIGSEGV" }),
128 + os.constants.signals.SIGSEGV,
);
assert.equal(
exitCodeForChildFailure({ status: null, signal: "SIGKILL" }),
128 + os.constants.signals.SIGKILL,
);
assert.equal(exitCodeForChildFailure({ status: null, signal: undefined }), 1);
assert.equal(exitCodeForChildFailure({ status: null, signal: "NOT_A_SIGNAL" }), 1);
});
test("resolveTypeAwareCompanion accepts only an exact matching package", (t) => {
const { resolveTypeAwareCompanion } = require(RUN_BINARY);
const work = fs.mkdtempSync(path.join(os.tmpdir(), "fallow-type-aware-package-"));
t.after(() => fs.rmSync(work, { recursive: true, force: true }));
const manifestPath = path.join(work, "package.json");
const companionPath = path.join(work, "fallow-type-aware.mjs");
fs.writeFileSync(companionPath, "#!/usr/bin/env node\n");
const resolvePackage = () => manifestPath;
fs.writeFileSync(manifestPath, JSON.stringify({ version: "3.8.0" }));
assert.equal(resolveTypeAwareCompanion("3.8.0", resolvePackage), companionPath);
fs.writeFileSync(manifestPath, JSON.stringify({ version: "3.7.0" }));
assert.equal(resolveTypeAwareCompanion("3.8.0", resolvePackage), undefined);
});
test("childEnvironment marks launcher-wired companions as npm-wrapper", (t) => {
const { childEnvironment } = require(RUN_BINARY);
const previousBin = process.env.FALLOW_TYPE_AWARE_BIN;
const previousScript = process.env.FALLOW_TYPE_AWARE_SCRIPT;
delete process.env.FALLOW_TYPE_AWARE_BIN;
delete process.env.FALLOW_TYPE_AWARE_SCRIPT;
t.after(() => {
if (previousBin === undefined) delete process.env.FALLOW_TYPE_AWARE_BIN;
else process.env.FALLOW_TYPE_AWARE_BIN = previousBin;
if (previousScript === undefined) delete process.env.FALLOW_TYPE_AWARE_SCRIPT;
else process.env.FALLOW_TYPE_AWARE_SCRIPT = previousScript;
});
const env = childEnvironment("3.8.0", () => "/tmp/fallow-type-aware.mjs", {
platform: "linux",
execPath: "/usr/bin/node",
});
assert.equal(env.FALLOW_TYPE_AWARE_BIN, "/tmp/fallow-type-aware.mjs");
assert.equal(env.FALLOW_TYPE_AWARE_SCRIPT, undefined);
assert.equal(env.FALLOW_TYPE_AWARE_BIN_SOURCE, "npm-wrapper");
const windowsEnv = childEnvironment("3.8.0", () => "C:\\pkg\\fallow-type-aware.mjs", {
platform: "win32",
execPath: "C:\\Program Files\\nodejs\\node.exe",
});
assert.equal(windowsEnv.FALLOW_TYPE_AWARE_BIN, "C:\\Program Files\\nodejs\\node.exe");
assert.equal(windowsEnv.FALLOW_TYPE_AWARE_SCRIPT, "C:\\pkg\\fallow-type-aware.mjs");
assert.equal(windowsEnv.FALLOW_TYPE_AWARE_BIN_SOURCE, "npm-wrapper");
// No resolvable companion: the environment passes through untouched.
const untouched = childEnvironment("3.8.0", () => undefined);
assert.equal(untouched, process.env);
assert.equal(untouched.FALLOW_TYPE_AWARE_BIN_SOURCE, undefined);
});
test("childEnvironment leaves a user-set override unmarked", (t) => {
const { childEnvironment } = require(RUN_BINARY);
const previousBin = process.env.FALLOW_TYPE_AWARE_BIN;
const previousScript = process.env.FALLOW_TYPE_AWARE_SCRIPT;
process.env.FALLOW_TYPE_AWARE_BIN = "/opt/custom-sidecar";
process.env.FALLOW_TYPE_AWARE_SCRIPT = "/opt/custom-sidecar.mjs";
t.after(() => {
if (previousBin === undefined) delete process.env.FALLOW_TYPE_AWARE_BIN;
else process.env.FALLOW_TYPE_AWARE_BIN = previousBin;
if (previousScript === undefined) delete process.env.FALLOW_TYPE_AWARE_SCRIPT;
else process.env.FALLOW_TYPE_AWARE_SCRIPT = previousScript;
});
const env = childEnvironment("3.8.0", () => "/tmp/fallow-type-aware.mjs");
assert.equal(env, process.env);
assert.equal(env.FALLOW_TYPE_AWARE_SCRIPT, "/opt/custom-sidecar.mjs");
assert.equal(env.FALLOW_TYPE_AWARE_BIN_SOURCE, undefined);
});
test(
"fallow-lsp executes the multicall binary with the lsp-server subcommand",
{ skip: process.platform === "win32" },
(t) => {
assert.deepEqual(runLauncher(t, "fallow-lsp", ["--stdio"]), ["lsp-server", "--stdio"]);
},
);
test(
"fallow-mcp executes the multicall binary with the mcp-server subcommand",
{ skip: process.platform === "win32" },
(t) => {
assert.deepEqual(runLauncher(t, "fallow-mcp", ["--transport", "stdio"]), [
"mcp-server",
"--transport",
"stdio",
]);
},
);