UNPKG

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
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", ]); }, );