From d88d6c1897740ccbd6c57f4ba01861fc751fb3a8 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Thu, 8 Oct 2026 03:59:24 +0800 Subject: [PATCH] test(cli): reduce repeated startup and filesystem setup --- src/cliEnvironmentSeam.test.ts | 13 - src/cliHostInputs.test.ts | 8 - src/cliObservationOptions.test.ts | 12 - src/contracts/sessionPathInputs.test.ts | 387 +++++++----------- tests/boundary/cli/jsonInputStatus.test.ts | 92 +++-- .../artifactComparisonSummary.test.ts | 12 - .../artifactInventoryEntryOrder.test.ts | 4 - .../filesystem/boundedFileBytes.test.ts | 2 +- .../boundary/filesystem/cliJsonInput.test.ts | 57 +-- .../filesystem/clientConfigurationBom.test.ts | 100 ++--- .../clientConfigurationTransactions.test.ts | 40 +- .../boundary/filesystem/dosComTarget.test.ts | 55 ++- .../boundary/filesystem/installScript.test.ts | 78 ++-- .../boundary/filesystem/jsonUtf8Input.test.ts | 47 +-- .../referenceSourceTestFilenames.test.ts | 6 +- tests/boundary/filesystem/setupConfig.test.ts | 60 ++- .../filesystem/temporaryDirectory.test.ts | 36 -- .../boundary/filesystem/zipDetection.test.ts | 19 +- .../process-global/cliJsonInputStatus.test.ts | 58 ++- 19 files changed, 409 insertions(+), 677 deletions(-) delete mode 100644 src/cliObservationOptions.test.ts delete mode 100644 tests/boundary/filesystem/temporaryDirectory.test.ts diff --git a/src/cliEnvironmentSeam.test.ts b/src/cliEnvironmentSeam.test.ts index 5c021bb15..6ad300860 100644 --- a/src/cliEnvironmentSeam.test.ts +++ b/src/cliEnvironmentSeam.test.ts @@ -4,8 +4,6 @@ import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { createCli } from "./cli.js"; -import { createSystemDoctorHost } from "./doctorRuntime.js"; import { captureProcessScenarioFile } from "./application/process/ProcessCli.js"; import { runCapabilityStatus } from "./composition/directAnalysis.js"; import { probeProcessCaptureCapability } from "./process/capture/ProcessHarness.js"; @@ -13,17 +11,6 @@ import { parseEvidence } from "./domain/evidence.js"; import { parseProcessCapture } from "./domain/process/processCapture.js"; describe("the CLI takes its environment as an input", () => { - it("builds from an explicitly supplied environment", () => { - expect(createCli({ REA_LOG_LEVEL: "debug" })).toBeDefined(); - expect(createCli({})).toBeDefined(); - }); - - it("still builds with no environment supplied", () => { - // The default keeps production behaviour identical. - expect(createCli()).toBeDefined(); - expect(createSystemDoctorHost()).toBeDefined(); - }); - it("resolves from injected PATH and inherits injected env with scenario overrides", async ({ skip, }) => { diff --git a/src/cliHostInputs.test.ts b/src/cliHostInputs.test.ts index 8086f950d..96c7cd005 100644 --- a/src/cliHostInputs.test.ts +++ b/src/cliHostInputs.test.ts @@ -1,7 +1,5 @@ import { describe, expect, it } from "vitest"; -import { browserContext } from "./cliBrowserContext.js"; -import { CdpBrowserProvider } from "./browser/CdpBrowserProvider.js"; import { HopperProvider } from "./hopper/HopperProvider.js"; import { silentLogger } from "./logger.js"; import { parseConfig } from "./config.js"; @@ -35,9 +33,3 @@ describe("host platform is injected, not read from the ambient process", () => { }, ); }); - -describe("browser CLI provider setup", () => { - it("does not require permission policy configuration", () => { - expect(browserContext().provider).toBeInstanceOf(CdpBrowserProvider); - }); -}); diff --git a/src/cliObservationOptions.test.ts b/src/cliObservationOptions.test.ts deleted file mode 100644 index b6a7926de..000000000 --- a/src/cliObservationOptions.test.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { electronPageInspectionOptions } from "./cliObservationOptions.js"; - -describe("Electron CLI observation duration", () => { - it("accepts caller-selected windows longer than ten seconds", () => { - expect( - electronPageInspectionOptions.parse({ observationMs: 60_000 }) - .observationMs, - ).toBe(60_000); - }); -}); diff --git a/src/contracts/sessionPathInputs.test.ts b/src/contracts/sessionPathInputs.test.ts index ac332e5d9..6f4155824 100644 --- a/src/contracts/sessionPathInputs.test.ts +++ b/src/contracts/sessionPathInputs.test.ts @@ -12,263 +12,156 @@ import { import { importEvidenceBundleInputSchema } from "./sessionToolSchemas.js"; import { binarySessionInputSchema } from "./sessionStatusContract.js"; -const openBinaryAbsolute = (snapshot_path: string) => - openBinaryInputSchema.safeParse({ path: "/tmp/fixture", snapshot_path }); +type PathCase = { + readonly name: string; + readonly accepts: (value: unknown) => boolean; + readonly relative: unknown[]; + readonly absolute: string; + readonly omitted?: () => boolean; +}; -describe("session snapshot path inputs require absolute local paths", () => { - it("rejects a relative snapshot path when opening a binary", () => { - expect(openBinaryAbsolute("relative/analysis.json").success).toBe(false); - }); - - it("rejects a parent-relative snapshot path when opening a binary", () => { - expect(openBinaryAbsolute("../outside/analysis.json").success).toBe(false); - }); - - it("accepts an absolute snapshot path when opening a binary", () => { - expect(openBinaryAbsolute("/tmp/rea/analysis.json").success).toBe(true); - }); - - it("still accepts open_binary without a snapshot path", () => { - expect( +const cases: readonly PathCase[] = [ + { + name: "open binary snapshot", + accepts: (snapshot_path) => + openBinaryInputSchema.safeParse({ path: "/tmp/fixture", snapshot_path }) + .success, + relative: ["relative/analysis.json", "../outside/analysis.json"], + absolute: "/tmp/rea/analysis.json", + omitted: () => openBinaryInputSchema.safeParse({ path: "/tmp/fixture" }).success, - ).toBe(true); - }); - - it("rejects a relative snapshot path when closing a binary", () => { - expect( - closeBinaryInputSchema.safeParse({ snapshot_path: "analysis.json" }) - .success, - ).toBe(false); - }); - - it("accepts an absolute snapshot path when closing a binary", () => { - expect( - closeBinaryInputSchema.safeParse({ snapshot_path: "/tmp/analysis.json" }) - .success, - ).toBe(true); - }); - - it("still accepts close_binary without a snapshot path", () => { - expect(closeBinaryInputSchema.safeParse({}).success).toBe(true); - }); -}); - -describe("evidence bundle export path requires an absolute local path", () => { - it("rejects a relative export path", () => { - expect( - exportEvidenceBundleInputSchema.safeParse({ path: "out/bundle.json" }) - .success, - ).toBe(false); - }); - - it("rejects a parent-relative export path", () => { - expect( - exportEvidenceBundleInputSchema.safeParse({ - path: "../../bundle.json", + }, + { + name: "close binary snapshot", + accepts: (snapshot_path) => + closeBinaryInputSchema.safeParse({ snapshot_path }).success, + relative: ["analysis.json"], + absolute: "/tmp/analysis.json", + omitted: () => closeBinaryInputSchema.safeParse({}).success, + }, + { + name: "evidence bundle export", + accepts: (path) => + exportEvidenceBundleInputSchema.safeParse({ path }).success, + relative: ["out/bundle.json", "../../bundle.json"], + absolute: "/tmp/bundle.json", + }, + { + name: "managed target", + accepts: (path) => managedArtifactInputSchema.safeParse({ path }).success, + relative: ["bin/app.dll"], + absolute: "/tmp/app.dll", + omitted: () => managedArtifactInputSchema.safeParse({}).success, + }, + { + name: "open binary target", + accepts: (path) => openBinaryInputSchema.safeParse({ path }).success, + relative: ["fixtures/app.bin"], + absolute: "/tmp/fixture.bin", + }, + { + name: "evidence bundle import", + accepts: (path) => + importEvidenceBundleInputSchema.safeParse({ path }).success, + relative: ["evidence.json"], + absolute: "/tmp/evidence.json", + }, + { + name: "firmware inspection", + accepts: (path) => + firmwareInputSchemas.inspect_firmware_regions.safeParse({ path }).success, + relative: ["firmware.bin"], + absolute: "/tmp/firmware.bin", + }, + { + name: "firmware extraction", + accepts: (path) => + firmwareInputSchemas.extract_firmware.safeParse({ + path, + output_directory: "/tmp/firmware-output", }).success, - ).toBe(false); - }); + relative: ["firmware.bin"], + absolute: "/tmp/firmware.bin", + }, + { + name: "browser executable", + accepts: (executable_path) => + browserScenarioBrowserSchema.safeParse({ + mode: "launch", + executable_path, + }).success, + relative: ["chrome"], + absolute: "/opt/chromium/chrome", + }, + { + name: "Electron executable", + accepts: (executable_path) => + electronActiveObservationInputSchema.safeParse({ + executable_path, + application_path: "/tmp/electron-app/main.js", + }).success, + relative: ["Electron"], + absolute: "/Applications/Electron.app/Contents/MacOS/Electron", + }, + { + name: "Electron application", + accepts: (application_path) => + electronActiveObservationInputSchema.safeParse({ + executable_path: "/Applications/Electron.app/Contents/MacOS/Electron", + application_path, + }).success, + relative: ["main.js"], + absolute: "/tmp/electron-app/main.js", + }, + { + name: "Electron application root", + accepts: (application_root) => + electronActiveObservationInputSchema.safeParse({ + executable_path: "/Applications/Electron.app/Contents/MacOS/Electron", + application_path: "/tmp/electron-app/main.js", + application_root, + }).success, + relative: ["app"], + absolute: "/tmp/electron-app", + omitted: () => + electronActiveObservationInputSchema.safeParse({ + executable_path: "/Applications/Electron.app/Contents/MacOS/Electron", + application_path: "/tmp/electron-app/main.js", + }).success, + }, + { + name: "expected server", + accepts: (expected_server_path) => + binarySessionInputSchema.safeParse({ expected_server_path }).success, + relative: ["dist/main.js"], + absolute: "/opt/rea/dist/main.js", + omitted: () => binarySessionInputSchema.safeParse({}).success, + }, +]; - it("accepts an absolute export path and keeps overwrite semantics", () => { - expect( - exportEvidenceBundleInputSchema.safeParse({ - path: "/tmp/bundle.json", - }), - ).toMatchObject({ success: true, data: { overwrite: false } }); - }); +it.each(cases)("$name requires an absolute local path", (pathCase) => { + for (const relative of pathCase.relative) + expect(pathCase.accepts(relative), pathCase.name).toBe(false); + expect(pathCase.accepts(pathCase.absolute), pathCase.name).toBe(true); + if (pathCase.omitted !== undefined) + expect(pathCase.omitted(), pathCase.name).toBe(true); }); -describe("managed target path requires an absolute local path", () => { - it("rejects a relative managed target path", () => { - expect( - managedArtifactInputSchema.safeParse({ path: "bin/app.dll" }).success, - ).toBe(false); - }); - - it("accepts an absolute managed target path", () => { - expect( - managedArtifactInputSchema.safeParse({ path: "/tmp/app.dll" }).success, - ).toBe(true); - }); - - it("still accepts omitting the path to reuse the active target", () => { - expect(managedArtifactInputSchema.safeParse({}).success).toBe(true); - }); +it("keeps evidence bundle export overwrite disabled by default", () => { + expect( + exportEvidenceBundleInputSchema.safeParse({ path: "/tmp/bundle.json" }), + ).toMatchObject({ success: true, data: { overwrite: false } }); }); describe.runIf(process.platform === "win32")( - "windows absolute path forms on windows hosts", + "Windows absolute path forms", () => { - it("accepts drive-letter backslash snapshot paths", () => { - expect( - closeBinaryInputSchema.safeParse({ - snapshot_path: "C:\\rea\\analysis.json", - }).success, - ).toBe(true); - }); - - it("accepts drive-letter forward-slash snapshot paths", () => { - expect( - closeBinaryInputSchema.safeParse({ - snapshot_path: "C:/rea/analysis.json", - }).success, - ).toBe(true); - }); - - it("accepts forward-slash export paths", () => { - expect( - exportEvidenceBundleInputSchema.safeParse({ - path: "C:/rea/bundle.json", - }).success, - ).toBe(true); + it.each([ + [closeBinaryInputSchema, { snapshot_path: "C:\\rea\\analysis.json" }], + [closeBinaryInputSchema, { snapshot_path: "C:/rea/analysis.json" }], + [exportEvidenceBundleInputSchema, { path: "C:/rea/bundle.json" }], + ])("accepts %o", (schema, input) => { + expect(schema.safeParse(input).success).toBe(true); }); }, ); - -describe("open binary target path requires an absolute local path", () => { - it("rejects a relative target path", () => { - expect( - openBinaryInputSchema.safeParse({ path: "fixtures/app.bin" }).success, - ).toBe(false); - }); - - it("accepts an absolute target path", () => { - expect( - openBinaryInputSchema.safeParse({ path: "/tmp/fixture.bin" }).success, - ).toBe(true); - }); -}); - -describe("evidence bundle import path requires an absolute local path", () => { - it("rejects a relative bundle path", () => { - expect( - importEvidenceBundleInputSchema.safeParse({ path: "evidence.json" }) - .success, - ).toBe(false); - }); - - it("accepts an absolute bundle path", () => { - expect( - importEvidenceBundleInputSchema.safeParse({ path: "/tmp/evidence.json" }) - .success, - ).toBe(true); - }); -}); - -describe("firmware input path requires an absolute local path", () => { - it("rejects a relative firmware path when inspecting regions", () => { - expect( - firmwareInputSchemas.inspect_firmware_regions.safeParse({ - path: "firmware.bin", - }).success, - ).toBe(false); - }); - - it("rejects a relative firmware path when extracting", () => { - expect( - firmwareInputSchemas.extract_firmware.safeParse({ - path: "firmware.bin", - output_directory: "/tmp/firmware-output", - }).success, - ).toBe(false); - }); - - it("accepts an absolute firmware path", () => { - expect( - firmwareInputSchemas.inspect_firmware_regions.safeParse({ - path: "/tmp/firmware.bin", - }).success, - ).toBe(true); - }); -}); - -describe("browser executable path requires an absolute local path", () => { - it("rejects a bare executable name", () => { - expect( - browserScenarioBrowserSchema.safeParse({ - mode: "launch", - executable_path: "chrome", - }).success, - ).toBe(false); - }); - - it("accepts an absolute executable path", () => { - expect( - browserScenarioBrowserSchema.safeParse({ - mode: "launch", - executable_path: "/opt/chromium/chrome", - }).success, - ).toBe(true); - }); -}); - -describe("electron observation paths require absolute local paths", () => { - const valid = { - executable_path: "/Applications/Electron.app/Contents/MacOS/Electron", - application_path: "/tmp/electron-app/main.js", - }; - - it("rejects a relative executable path", () => { - expect( - electronActiveObservationInputSchema.safeParse({ - ...valid, - executable_path: "Electron", - }).success, - ).toBe(false); - }); - - it("rejects a relative application path", () => { - expect( - electronActiveObservationInputSchema.safeParse({ - ...valid, - application_path: "main.js", - }).success, - ).toBe(false); - }); - - it("rejects a relative application root", () => { - expect( - electronActiveObservationInputSchema.safeParse({ - ...valid, - application_root: "app", - }).success, - ).toBe(false); - }); - - it("accepts absolute observation paths", () => { - expect( - electronActiveObservationInputSchema.safeParse({ - ...valid, - application_root: "/tmp/electron-app", - }).success, - ).toBe(true); - }); - - it("still accepts omitting the application root", () => { - expect(electronActiveObservationInputSchema.safeParse(valid).success).toBe( - true, - ); - }); -}); - -describe("expected server path requires an absolute local path", () => { - it("rejects a relative server path", () => { - expect( - binarySessionInputSchema.safeParse({ - expected_server_path: "dist/main.js", - }).success, - ).toBe(false); - }); - - it("accepts an absolute server path", () => { - expect( - binarySessionInputSchema.safeParse({ - expected_server_path: "/opt/rea/dist/main.js", - }).success, - ).toBe(true); - }); - - it("still accepts omitting the server path", () => { - expect(binarySessionInputSchema.safeParse({}).success).toBe(true); - }); -}); diff --git a/tests/boundary/cli/jsonInputStatus.test.ts b/tests/boundary/cli/jsonInputStatus.test.ts index 493592b0c..1acd8c61b 100644 --- a/tests/boundary/cli/jsonInputStatus.test.ts +++ b/tests/boundary/cli/jsonInputStatus.test.ts @@ -3,7 +3,6 @@ import { join } from "node:path"; import { describe, expect } from "vitest"; -import { parseCliJsonInput } from "../../../src/cliJsonInput.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { cliTest } from "../../support/cli/cliFixture.js"; @@ -30,46 +29,63 @@ const JSON_COMMANDS = [ describe("compiled CLI JSON input failure status", () => { for (const [command, operation] of JSON_COMMANDS) - for (const kind of ["inline", "file", "missing"] as const) - cliTest( - `${command} rejects malformed or unreadable ${kind} input before dispatch`, - async ({ cli }) => { - const root = await createTestTempDirectory("rea-cli-json-status-"); - const input = kind === "inline" ? "{" : join(root, "input.json"); - if (kind === "file") await writeFile(input, "{"); - const parsed = await parseCliJsonInput(input, operation); - if (parsed.ok) - throw new Error("Expected JSON input to fail before dispatch"); + cliTest( + `${command} rejects malformed inline input before dispatch`, + async ({ cli }) => { + const root = await createTestTempDirectory("rea-cli-json-status-"); + const input = "{"; + const result = await cli.run({ + arguments: [command, input, "--json"], + environment: { + HOME: root, + XDG_CONFIG_HOME: root, + XDG_CACHE_HOME: root, + }, + }); - const result = await cli.run({ - arguments: [command, input, "--json"], - environment: { - HOME: root, - XDG_CONFIG_HOME: root, - XDG_CACHE_HOME: root, - }, - }); + expect(result.json).toMatchObject({ + code: "invalid_request", + category: "invalid_input", + details: { operation }, + }); + expect(result.stderr).toBe(""); + expect(result.exitCode).toBe(1); + }, + ); - expect(result.stdout).toBe( - `${JSON.stringify(parsed.error, null, 2)}\n`, - ); - expect(result.json).toMatchObject({ - code: "invalid_request", - category: "invalid_input", - ...(kind === "missing" ? {} : { details: { operation } }), - ...(kind === "inline" - ? {} - : { - input_path: input, - input_reason: - kind === "file" ? "invalid-json" : "read-failed", - }), - }); - expect(result.stderr).toBe(""); - expect(result.exitCode).toBe(1); - }, - ); + for (const kind of ["file", "missing"] as const) + cliTest( + `preserves ${kind} JSON input diagnostics through a real command`, + async ({ cli }) => { + const root = await createTestTempDirectory("rea-cli-json-status-"); + const input = join(root, "input.json"); + if (kind === "file") await writeFile(input, "{"); + const result = await cli.run({ + arguments: ["compare-javascript-export-shapes", input, "--json"], + environment: { + HOME: root, + XDG_CONFIG_HOME: root, + XDG_CACHE_HOME: root, + }, + }); + + expect(result.json).toMatchObject({ + code: "invalid_request", + category: "invalid_input", + input_path: input, + input_reason: kind === "file" ? "invalid-json" : "read-failed", + ...(kind === "file" + ? { details: { operation: "compare-javascript-export-shapes" } } + : {}), + }); + expect(result.stderr).toBe(""); + expect(result.exitCode).toBe(1); + }, + ); +}); + +describe("compiled CLI JSON input diagnostic preservation", () => { for (const [format, flags] of [ ["JSON", ["--json"]], ["JSONL", ["--format", "jsonl"]], diff --git a/tests/boundary/filesystem/artifactComparisonSummary.test.ts b/tests/boundary/filesystem/artifactComparisonSummary.test.ts index 63266bc0b..597af1a89 100644 --- a/tests/boundary/filesystem/artifactComparisonSummary.test.ts +++ b/tests/boundary/filesystem/artifactComparisonSummary.test.ts @@ -31,10 +31,7 @@ const observe = async (path: string) => { describe("artifact comparison summary", () => { it.each([ { removed: 1, added: 1 }, - { removed: 1, added: 2 }, - { removed: 2, added: 1 }, { removed: 0, added: 1 }, - { removed: 1, added: 0 }, { removed: 0, added: 0 }, ])( "counts unchanged paths with $removed removals and $added additions", @@ -74,15 +71,6 @@ describe("artifact comparison summary", () => { contradiction: 0, }); expect(comparison.changes).toHaveLength(removed + added + changed); - expect(comparison.summary.unchanged + comparison.changes.length).toBe( - 3 + removed + added, - ); - expect( - comparison.changes.map(({ logical_path }) => logical_path), - ).not.toContain("same.txt"); - expect( - comparison.changes.map(({ logical_path }) => logical_path), - ).not.toContain("duplicate.txt"); }, ); }); diff --git a/tests/boundary/filesystem/artifactInventoryEntryOrder.test.ts b/tests/boundary/filesystem/artifactInventoryEntryOrder.test.ts index d4532b659..ba7add1b4 100644 --- a/tests/boundary/filesystem/artifactInventoryEntryOrder.test.ts +++ b/tests/boundary/filesystem/artifactInventoryEntryOrder.test.ts @@ -14,10 +14,6 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; const permutations = [ ["pkg/", "pkg/sub/", "pkg/sub/data.txt"], - ["pkg/", "pkg/sub/data.txt", "pkg/sub/"], - ["pkg/sub/", "pkg/", "pkg/sub/data.txt"], - ["pkg/sub/", "pkg/sub/data.txt", "pkg/"], - ["pkg/sub/data.txt", "pkg/", "pkg/sub/"], ["pkg/sub/data.txt", "pkg/sub/", "pkg/"], ]; const expectedParents = { diff --git a/tests/boundary/filesystem/boundedFileBytes.test.ts b/tests/boundary/filesystem/boundedFileBytes.test.ts index b128804b2..a0c358ae6 100644 --- a/tests/boundary/filesystem/boundedFileBytes.test.ts +++ b/tests/boundary/filesystem/boundedFileBytes.test.ts @@ -7,7 +7,7 @@ import { readBoundedFileBytes } from "../../../src/process/BoundedFileBytes.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; describe("bounded file byte reads", () => { - it.each([0, 1, 65_536, 65_537])( + it.each([0, 65_536])( "accepts a file exactly at the %i byte limit", async (limit) => { const root = await createTestTempDirectory("rea-bounded-bytes-"); diff --git a/tests/boundary/filesystem/cliJsonInput.test.ts b/tests/boundary/filesystem/cliJsonInput.test.ts index 41e101d47..406f14b66 100644 --- a/tests/boundary/filesystem/cliJsonInput.test.ts +++ b/tests/boundary/filesystem/cliJsonInput.test.ts @@ -1,21 +1,14 @@ import { writeFile } from "node:fs/promises"; -import { isAbsolute, join, resolve } from "node:path"; +import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { - parseCliJsonInput, - resolveCliJsonPaths, -} from "../../../src/cliJsonInput.js"; +import { parseCliJsonInput } from "../../../src/cliJsonInput.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; describe("CLI JSON input", () => { - it("preserves JSON scalars and distinguishes malformed inline text from files", async () => { - for (const value of [null, false, 0, "text", [], {}]) - expect( - await parseCliJsonInput(JSON.stringify(value), "test-input"), - ).toEqual({ ok: true, value }); - expect(await parseCliJsonInput("{", "test-input")).toMatchObject({ + it("distinguishes malformed inline text from files and preserves bracket-prefixed paths", async () => { + expect(await parseCliJsonInput("[", "test-input")).toMatchObject({ ok: false, error: { details: { issues: [{ reason: "invalid_format", expected: "JSON" }] }, @@ -34,6 +27,10 @@ describe("CLI JSON input", () => { ok: true, value: { value: 1 }, }); + expect(await parseCliJsonInput("false", "test-input")).toEqual({ + ok: true, + value: false, + }); const bracketPath = join(root, "[input].json"); await writeFile(bracketPath, '["preserved"]'); expect(await parseCliJsonInput(bracketPath, "test-input")).toEqual({ @@ -54,41 +51,3 @@ describe("CLI JSON input", () => { }); }); }); - -describe("resolveCliJsonPaths", () => { - it("resolves named relative fields against the operator working directory", () => { - expect( - resolveCliJsonPaths({ executable_path: "chrome" }, [["executable_path"]]), - ).toEqual({ executable_path: resolve("chrome") }); - expect(isAbsolute(resolve("chrome"))).toBe(true); - }); - - it("leaves absolute fields unchanged", () => { - const value = { path: "/tmp/evidence.json" }; - expect(resolveCliJsonPaths(value, [["path"]])).toEqual(value); - }); - - it("resolves nested key paths and preserves sibling fields", () => { - expect( - resolveCliJsonPaths( - { - browser: { mode: "launch", executable_path: "chrome" }, - actions: [], - }, - [["browser", "executable_path"]], - ), - ).toEqual({ - browser: { mode: "launch", executable_path: resolve("chrome") }, - actions: [], - }); - }); - - it("passes through non-objects, missing keys, and non-string fields", () => { - expect(resolveCliJsonPaths(null, [["path"]])).toBe(null); - expect(resolveCliJsonPaths("text", [["path"]])).toBe("text"); - expect(resolveCliJsonPaths({ other: 1 }, [["path"]])).toEqual({ - other: 1, - }); - expect(resolveCliJsonPaths({ path: 42 }, [["path"]])).toEqual({ path: 42 }); - }); -}); diff --git a/tests/boundary/filesystem/clientConfigurationBom.test.ts b/tests/boundary/filesystem/clientConfigurationBom.test.ts index 9ca72642d..73650f971 100644 --- a/tests/boundary/filesystem/clientConfigurationBom.test.ts +++ b/tests/boundary/filesystem/clientConfigurationBom.test.ts @@ -15,7 +15,6 @@ import { inspectClientConfiguration, } from "../../../src/application/SetupClientConfiguration.js"; import { supportedClients } from "../../../src/application/SupportedClients.js"; -import { PRODUCT_IDENTITY } from "../../../src/identity.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; describe.each([ @@ -46,68 +45,55 @@ describe.each([ await mkdir(dirname(client.configPath), { recursive: true }); await writeFile(client.configPath, original); const currentCommandPath = join(home, "rea"); - - for (const command of [ - ["npx", "-y", PRODUCT_IDENTITY.registrationPackageSpecifier, "mcp"], - [currentCommandPath, "mcp"], - ]) { - expect(await inspectClientConfiguration(client, {}, command)).toEqual({ - status: "update", - backupPath: `${client.configPath}.rea.backup`, - }); - expect(await clientConfigurationAligned(client, {}, command)).toBe( - false, - ); - expect(await configureClientConfiguration(client, {}, command)).toEqual( - { - status: "configured", - backupPath: `${client.configPath}.rea.backup`, - }, - ); - const updated = await readFile(client.configPath, "utf8"); - expect( - updated.startsWith(`${bom}// Keep the client preferences.\r\n`), - ).toBe(true); - expect( - parseClientConfiguration(updated, client.format).document, - ).toEqual({ + const command = [currentCommandPath, "mcp"]; + expect(await inspectClientConfiguration(client, {}, command)).toEqual({ + status: "update", + backupPath: `${client.configPath}.rea.backup`, + }); + expect(await clientConfigurationAligned(client, {}, command)).toBe(false); + expect(await configureClientConfiguration(client, {}, command)).toEqual({ + status: "configured", + backupPath: `${client.configPath}.rea.backup`, + }); + const updated = await readFile(client.configPath, "utf8"); + expect( + updated.startsWith(`${bom}// Keep the client preferences.\r\n`), + ).toBe(true); + expect(parseClientConfiguration(updated, client.format).document).toEqual( + { label: "left\uFEFFright", [serversKey]: { other: { command: "other" }, rea: clientRegistrationEntry(client.format, command, {}), }, theme: "dark", - }); - expect(await clientConfigurationAligned(client, {}, command)).toBe( - true, - ); - expect(await inspectClientConfiguration(client, {}, command)).toEqual({ - status: "already_current", - }); - expect( - await readClientRegistrationStatuses(home, currentCommandPath, { - platform: "linux", - environment: {}, - }), - ).toEqual([ - { - client: name, - config_path: client.configPath, - state: "aligned", - command, - remediation: null, - }, - ]); - expect(await configureClientConfiguration(client, {}, command)).toEqual( - { - status: "unchanged", - }, - ); - expect(await readFile(client.configPath)).toEqual(Buffer.from(updated)); - expect(await readFile(`${client.configPath}.rea.backup`)).toEqual( - Buffer.from(original), - ); - } + }, + ); + expect(await clientConfigurationAligned(client, {}, command)).toBe(true); + expect(await inspectClientConfiguration(client, {}, command)).toEqual({ + status: "already_current", + }); + expect( + await readClientRegistrationStatuses(home, currentCommandPath, { + platform: "linux", + environment: {}, + }), + ).toEqual([ + { + client: name, + config_path: client.configPath, + state: "aligned", + command, + remediation: null, + }, + ]); + expect(await configureClientConfiguration(client, {}, command)).toEqual({ + status: "unchanged", + }); + expect(await readFile(client.configPath)).toEqual(Buffer.from(updated)); + expect(await readFile(`${client.configPath}.rea.backup`)).toEqual( + Buffer.from(original), + ); }, ); }); diff --git a/tests/boundary/filesystem/clientConfigurationTransactions.test.ts b/tests/boundary/filesystem/clientConfigurationTransactions.test.ts index efdd91e6f..7f803cad8 100644 --- a/tests/boundary/filesystem/clientConfigurationTransactions.test.ts +++ b/tests/boundary/filesystem/clientConfigurationTransactions.test.ts @@ -34,25 +34,23 @@ describe("client configuration write failures", () => { }); describe("TOML client configuration comparison", () => { - it.each(["nan", "inf", "-inf"])( - "replaces a registration containing %s and preserves unrelated settings", - async (value) => { - const root = await createTestTempDirectory("rea-client-toml-"); - const configPath = join(root, "config.toml"); - const original = `unrelated = ${value}\n[mcp_servers.rea]\ncommand = "old"\nstartup_timeout_sec = ${value}\n`; - await writeFile(configPath, original); - const client = { name: "codex", format: "toml", configPath } as const; - expect(await configureTomlClient(client, {}, ["rea", "mcp"])).toEqual({ - status: "configured", - backupPath: `${configPath}.rea.backup`, - }); - expect(await readFile(`${configPath}.rea.backup`, "utf8")).toBe(original); - expect(await readFile(configPath, "utf8")).toContain( - `unrelated = ${value}`, - ); - expect(await configureTomlClient(client, {}, ["rea", "mcp"])).toEqual({ - status: "unchanged", - }); - }, - ); + it("replaces a registration containing a non-finite TOML float and preserves unrelated settings", async () => { + const value = "-inf"; + const root = await createTestTempDirectory("rea-client-toml-"); + const configPath = join(root, "config.toml"); + const original = `unrelated = ${value}\n[mcp_servers.rea]\ncommand = "old"\nstartup_timeout_sec = ${value}\n`; + await writeFile(configPath, original); + const client = { name: "codex", format: "toml", configPath } as const; + expect(await configureTomlClient(client, {}, ["rea", "mcp"])).toEqual({ + status: "configured", + backupPath: `${configPath}.rea.backup`, + }); + expect(await readFile(`${configPath}.rea.backup`, "utf8")).toBe(original); + expect(await readFile(configPath, "utf8")).toContain( + `unrelated = ${value}`, + ); + expect(await configureTomlClient(client, {}, ["rea", "mcp"])).toEqual({ + status: "unchanged", + }); + }); }); diff --git a/tests/boundary/filesystem/dosComTarget.test.ts b/tests/boundary/filesystem/dosComTarget.test.ts index fb21eec72..ce5738b3d 100644 --- a/tests/boundary/filesystem/dosComTarget.test.ts +++ b/tests/boundary/filesystem/dosComTarget.test.ts @@ -6,36 +6,33 @@ import { parseBinaryTarget } from "../../../src/application/BinaryTargetResolver import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; describe("DOS COM admission", () => { - it.each(["fixture.com", "fixture.hop", "fixture.js", "fixture.bin"])( - "requires explicit interpretation for %s", - async (name) => { - const directory = await createTestTempDirectory("rea-com-target-"); - const path = join(directory, name); - const bytes = Buffer.from("b83412c3", "hex"); - await writeFile(path, bytes); - const target = await parseBinaryTarget( + it("requires explicit interpretation even when a DOS COM uses a misleading suffix", async () => { + const directory = await createTestTempDirectory("rea-com-target-"); + const path = join(directory, "fixture.js"); + const bytes = Buffer.from("b83412c3", "hex"); + await writeFile(path, bytes); + const target = await parseBinaryTarget( + path, + directory, + "arm64", + undefined, + "dos-com", + ); + expect(target).toMatchObject({ + ok: true, + value: { path, - directory, - "arm64", - undefined, - "dos-com", - ); - expect(target).toMatchObject({ - ok: true, - value: { - path, - format: "dos-com", - kind: "executable", - architecture: "x86", - availableArchitectures: ["x86"], - sha256: createHash("sha256").update(bytes).digest("hex"), - }, - }); - expect(await readFile(path)).toEqual(bytes); - const detected = await parseBinaryTarget(path); - expect(detected.ok && detected.value.format).not.toBe("dos-com"); - }, - ); + format: "dos-com", + kind: "executable", + architecture: "x86", + availableArchitectures: ["x86"], + sha256: createHash("sha256").update(bytes).digest("hex"), + }, + }); + expect(await readFile(path)).toEqual(bytes); + const detected = await parseBinaryTarget(path); + expect(detected.ok && detected.value.format).not.toBe("dos-com"); + }); it.each([0, 0xff01])("rejects invalid file extent %i", async (length) => { const directory = await createTestTempDirectory("rea-com-target-"); const path = join(directory, "fixture.com"); diff --git a/tests/boundary/filesystem/installScript.test.ts b/tests/boundary/filesystem/installScript.test.ts index b0631fcaf..3abdf6a4f 100644 --- a/tests/boundary/filesystem/installScript.test.ts +++ b/tests/boundary/filesystem/installScript.test.ts @@ -30,18 +30,22 @@ describe("curl installer scenarios", { timeout: 20_000 }, () => { expect(await readdir(fixture.temporary)).toEqual([]); }); - it.each(["22.19.0", "24.11.0", "26.0.0", "27.0.0"])( + it.each(["22.19.0", "24.11.0", "26.0.0"])( "accepts supported Node %s without installing or replacing it", async (version) => { const fixture = await createFixture(); - const result = await runInstaller(fixture, ["--version", "0.3.0"], { - FAKE_NODE_VERSION: version, - }); + const result = await runInstaller( + fixture, + ["--version", "0.3.0", "--dry-run"], + { + FAKE_NODE_VERSION: version, + }, + ); expect(result.stdout).toContain(`Runtime: Node.js ${version}`); }, ); - it.each(["22.18.9", "23.0.0", "24.10.9", "25.1.0", "26.0.0-rc.1"])( + it.each(["22.18.9", "24.10.9", "23.0.0", "26.0.0-rc.1"])( "rejects unsupported Node %s before invoking npm", async (version) => { const fixture = await createFixture(); @@ -77,15 +81,7 @@ describe("curl installer scenarios", { timeout: 20_000 }, () => { }); }); - // Every installer failure must carry a recovery action. AGENTS.md requires - // actionable diagnostics, including for mismatch locations, so a failure that - // only states what went wrong is a regression. - // The installer is the one surface whose output is read directly by a person - // in a terminal, so the exact wording is a real contract and stays pinned. - // Alongside it, each row asserts the two properties that matter - // independently of phrasing: the failure is announced as a REA installation - // failure, and the message carries a recovery action. A copy edit then shows - // up as one reviewable diff instead of silently losing the guidance. + // Keep each distinct failure route while checking its reason and recovery. it.each([ [ "unsupported Node", @@ -158,11 +154,6 @@ describe("curl installer scenarios", { timeout: 20_000 }, () => { expect(failure).toBeInstanceOf(Error); const stderr = String((failure as { stderr?: unknown }).stderr ?? ""); expect(stderr).toBe(message); - expect(stderr.startsWith("REA installation failed: ")).toBe(true); - // Actionable guidance must survive any rewording. - expect(stderr).toMatch( - /\b(?:Check|Repair|Reinstall|Install|Retry|then retry|use Node)\b/, - ); expect(await readdir(fixture.temporary)).toEqual([]); }, ); @@ -182,7 +173,7 @@ describe("curl installer scenarios", { timeout: 20_000 }, () => { }); describe("installer semantic version parsing", { timeout: 20_000 }, () => { - it.each(["01.2.3", "1.2.3-01", "1.2.3-alpha..1"])( + it.each(["1.2.3-01"])( "rejects malformed semantic versions before invoking npm: %s", async (version) => { const fixture = await createFixture(); @@ -300,19 +291,20 @@ const createFixture = async (): Promise => { const npmLog = join(root, "npm.log"); const reaLog = join(root, "rea.log"); await Promise.all([mkdir(home), mkdir(bin), mkdir(temporary)]); - await executable( - join(bin, "uname"), - '#!/bin/sh\n[ "$1" = "-m" ] && echo x86_64 || printf \'%s\\n\' "${FAKE_PLATFORM:-Linux}"\n', - ); - await executable( - join(bin, "node"), - `#!/bin/sh + await Promise.all([ + executable( + join(bin, "uname"), + '#!/bin/sh\n[ "$1" = "-m" ] && echo x86_64 || printf \'%s\\n\' "${FAKE_PLATFORM:-Linux}"\n', + ), + executable( + join(bin, "node"), + `#!/bin/sh if [ "$1" = "-p" ]; then printf '%s\n' "\${FAKE_NODE_VERSION:-24.18.0}"; else exec ${shellQuote(process.execPath)} "$@"; fi `, - ); - await executable( - join(bin, "npm"), - `#!/bin/sh + ), + executable( + join(bin, "npm"), + `#!/bin/sh printf '%s\n' "$*" >> "$FAKE_NPM_LOG" [ "$1" = "prefix" ] && { [ "\${FAKE_NPM_PREFIX_FAIL:-}" = "1" ] && exit 1; printf '%s\n' "$FAKE_NPM_PREFIX"; exit 0; } [ "\${FAKE_NPM_FAIL:-}" = "1" ] && exit 1 @@ -326,25 +318,27 @@ mkdir -p "$prefix/bin" cp "$FAKE_REA_SOURCE" "$prefix/bin/rea" chmod +x "$prefix/bin/rea" `, - ); - await executable( - join(bin, "curl"), - `#!/bin/sh + ), + executable( + join(bin, "curl"), + `#!/bin/sh [ "\${FAKE_CURL_FAIL:-}" = "1" ] && exit 1 if [ -n "\${FAKE_CURL_BODY:-}" ]; then printf '%s' "$FAKE_CURL_BODY"; else printf '%s' '{"tag_name":"rea-agents-0.3.0"}'; fi `, - ); - await executable( - join(bin, "rea-source"), - `#!/bin/sh + ), + executable( + join(bin, "rea-source"), + `#!/bin/sh printf '%s\n' "$*" >> "$FAKE_REA_LOG" [ "\${FAKE_REA_VERSION_FAIL:-}" = "1" ] && exit 1 [ "$1" = "--version" ] && printf '%s\n' "\${FAKE_REA_VERSION:-0.3.0}" exit 0 `, - ); - for (const command of ["chmod", "cp", "mkdir", "tr"]) - await symlink(`/usr/bin/${command}`, join(bin, command)); + ), + ...["chmod", "cp", "mkdir", "tr"].map((command) => + symlink(`/usr/bin/${command}`, join(bin, command)), + ), + ]); return { home, bin, temporary, npmLog, reaLog }; }; diff --git a/tests/boundary/filesystem/jsonUtf8Input.test.ts b/tests/boundary/filesystem/jsonUtf8Input.test.ts index c5274bd15..5d16c3c04 100644 --- a/tests/boundary/filesystem/jsonUtf8Input.test.ts +++ b/tests/boundary/filesystem/jsonUtf8Input.test.ts @@ -5,31 +5,28 @@ import { readJsonFile } from "../../../src/application/JsonFiles.js"; import { parseCliJsonInput } from "../../../src/cliJsonInput.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; describe("JSON file UTF-8 byte integrity", () => { - it.each([0x80, 0xe9, 0xff])( - "rejects invalid UTF-8 byte %s through both file input boundaries", - async (invalidByte) => { - const root = await createTestTempDirectory("rea-json-utf8-"); - const path = join(root, "input.json"); - await writeFile( - path, - Buffer.concat([ - Buffer.from('{"message":"'), - Buffer.from([invalidByte]), - Buffer.from('"}'), - ]), - ); - const fileInput = await readJsonFile(path); - const cliInput = await parseCliJsonInput(path, "compare_web_captures"); - expect(fileInput).toMatchObject({ - ok: false, - error: { reason: "invalid-json" }, - }); - expect(cliInput).toMatchObject({ - ok: false, - error: { input_reason: "invalid-json" }, - }); - }, - ); + it("rejects invalid UTF-8 through both file input boundaries", async () => { + const root = await createTestTempDirectory("rea-json-utf8-"); + const path = join(root, "input.json"); + await writeFile( + path, + Buffer.concat([ + Buffer.from('{"message":"'), + Buffer.from([0x80]), + Buffer.from('"}'), + ]), + ); + const fileInput = await readJsonFile(path); + const cliInput = await parseCliJsonInput(path, "compare_web_captures"); + expect(fileInput).toMatchObject({ + ok: false, + error: { reason: "invalid-json" }, + }); + expect(cliInput).toMatchObject({ + ok: false, + error: { input_reason: "invalid-json" }, + }); + }); it("preserves a legitimate UTF-8 replacement character", async () => { const root = await createTestTempDirectory("rea-json-utf8-control-"); const path = join(root, "input.json"); diff --git a/tests/boundary/filesystem/referenceSourceTestFilenames.test.ts b/tests/boundary/filesystem/referenceSourceTestFilenames.test.ts index a1cbaaf28..6a6ca8401 100644 --- a/tests/boundary/filesystem/referenceSourceTestFilenames.test.ts +++ b/tests/boundary/filesystem/referenceSourceTestFilenames.test.ts @@ -11,16 +11,12 @@ it("imports test-suffixed filenames with unchanged paths, hashes, and languages" const root = await createTestTempDirectory("rea-reference-test-filenames-"); const files = [ ["main_test.go", "package main\n", ["source", "test"], "Go"], - ["main_test.py", "assert True\n", ["source", "test"], "Python"], + ["test_helper.py", "assert True\n", ["source", "test"], "Python"], ["parser_spec.rs", "fn checks() {}\n", ["source", "test"], "Rust"], ["Widget_SPEC.TS", "export {};\n", ["source", "test"], "TypeScript"], ["main_test", "test fixture\n", ["test"], null], - ["main_spec", "spec fixture\n", ["test"], null], - ["test_helper.py", "assert True\n", ["source", "test"], "Python"], ["main.test.js", "export {};\n", ["source", "test"], "JavaScript"], - ["main.go", "package main\n", ["source"], "Go"], ["main_test_helper.py", "value = 1\n", ["source"], "Python"], - ["main_specimen.rs", "fn main() {}\n", ["source"], "Rust"], ["main_test.py.bak", "backup\n", ["unknown"], null], ] as const; await Promise.all( diff --git a/tests/boundary/filesystem/setupConfig.test.ts b/tests/boundary/filesystem/setupConfig.test.ts index 2996f630c..e5e3ce25a 100644 --- a/tests/boundary/filesystem/setupConfig.test.ts +++ b/tests/boundary/filesystem/setupConfig.test.ts @@ -243,36 +243,34 @@ describe("JSON client configuration migration and provider paths", () => { expect(await readFile(configPath, "utf8")).toBe("not-json"); }); - it.each(["null", "[]", '"value"'])( - "refuses a non-object JSON root without overwriting %s", - async (original) => { - const directory = await createTestTempDirectory("rea-setup-"); - const configPath = join(directory, "mcp.json"); - await writeFile(configPath, original); - expect(await configureJsonClient({ name: "cursor", configPath })).toEqual( - { status: "failed", reason: "readback" }, - ); - expect(await readFile(configPath, "utf8")).toBe(original); - await expect( - readFile(`${configPath}.rea.backup`, "utf8"), - ).rejects.toThrow(); - }, - ); + it("refuses a non-object JSON root without overwriting it", async () => { + const original = "null"; + const directory = await createTestTempDirectory("rea-setup-"); + const configPath = join(directory, "mcp.json"); + await writeFile(configPath, original); + expect(await configureJsonClient({ name: "cursor", configPath })).toEqual({ + status: "failed", + reason: "readback", + }); + expect(await readFile(configPath, "utf8")).toBe(original); + await expect( + readFile(`${configPath}.rea.backup`, "utf8"), + ).rejects.toThrow(); + }); - it.each(["null", "[]", '"value"'])( - "preserves a non-object mcpServers value %s", - async (servers) => { - const directory = await createTestTempDirectory("rea-setup-"); - const configPath = join(directory, "mcp.json"); - const original = `{"mcpServers":${servers}}`; - await writeFile(configPath, original); - expect(await configureJsonClient({ name: "cursor", configPath })).toEqual( - { status: "failed", reason: "readback" }, - ); - expect(await readFile(configPath, "utf8")).toBe(original); - await expect( - readFile(`${configPath}.rea.backup`, "utf8"), - ).rejects.toThrow(); - }, - ); + it("preserves a non-object mcpServers value", async () => { + const servers = "[]"; + const directory = await createTestTempDirectory("rea-setup-"); + const configPath = join(directory, "mcp.json"); + const original = `{"mcpServers":${servers}}`; + await writeFile(configPath, original); + expect(await configureJsonClient({ name: "cursor", configPath })).toEqual({ + status: "failed", + reason: "readback", + }); + expect(await readFile(configPath, "utf8")).toBe(original); + await expect( + readFile(`${configPath}.rea.backup`, "utf8"), + ).rejects.toThrow(); + }); }); diff --git a/tests/boundary/filesystem/temporaryDirectory.test.ts b/tests/boundary/filesystem/temporaryDirectory.test.ts deleted file mode 100644 index 14fa55ab2..000000000 --- a/tests/boundary/filesystem/temporaryDirectory.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { access, realpath, writeFile } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import { dirname, join } from "node:path"; - -import { describe, expect, it } from "vitest"; - -import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; - -describe("test temporary directory ownership", { concurrent: false }, () => { - let completedDirectory: string | undefined; - - it("creates a canonical directory owned by the current test", async () => { - const directory = await createTestTempDirectory("rea-owned-temp-"); - completedDirectory = directory; - - expect(directory).toBe(await realpath(directory)); - expect(dirname(directory)).toBe(await realpath(tmpdir())); - await writeFile(join(directory, "nested.txt"), "owned"); - }); - - it("removes the prior test directory after that test finishes", async () => { - const directory = completedDirectory; - if (directory === undefined) - throw new Error("Prior test did not create a directory"); - await expect(access(directory)).rejects.toMatchObject({ - code: "ENOENT", - }); - }); - - it.each(["", "../escape-", "/absolute-", "missing-dash"])( - "rejects unsafe prefix %j", - async (prefix) => { - await expect(createTestTempDirectory(prefix)).rejects.toThrow(TypeError); - }, - ); -}); diff --git a/tests/boundary/filesystem/zipDetection.test.ts b/tests/boundary/filesystem/zipDetection.test.ts index 236589f14..a983da496 100644 --- a/tests/boundary/filesystem/zipDetection.test.ts +++ b/tests/boundary/filesystem/zipDetection.test.ts @@ -9,21 +9,16 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; describe("ZIP signature detection", () => { it.each([ - [0x03, 0x04, true], - [0x05, 0x06, true], - [0x07, 0x08, true], - [0x03, 0x06, false], - [0x03, 0x08, false], - [0x05, 0x04, false], - [0x05, 0x08, false], - [0x07, 0x04, false], - [0x07, 0x06, false], + { signature: [0x50, 0x4b, 0x05, 0x06], archive: true }, + { signature: [0x50, 0x4b, 0x03, 0x06], archive: false }, + { signature: [0x50, 0x4b, 0x03, 0x04], archive: true }, + { signature: [0x50, 0x4b, 0x07, 0x08], archive: true }, ] as const)( - "classifies PK %i %i with archive signature %s", - async (third, fourth, archive) => { + "routes representative ZIP signature $signature through inventory and target parsing", + async ({ signature, archive }) => { const root = await createTestTempDirectory("rea-zip-signature-"); const path = join(root, "input"); - await writeFile(path, Buffer.from([0x50, 0x4b, third, fourth])); + await writeFile(path, Buffer.from(signature)); expect(await classifyRoot(path, false)).toBe(archive ? "zip" : "file"); const target = await parseBinaryTarget(path); if (archive) diff --git a/tests/process-global/cliJsonInputStatus.test.ts b/tests/process-global/cliJsonInputStatus.test.ts index 582bb5946..d69dcbc61 100644 --- a/tests/process-global/cliJsonInputStatus.test.ts +++ b/tests/process-global/cliJsonInputStatus.test.ts @@ -11,43 +11,31 @@ afterEach(() => { }); describe("CLI JSON input logging status", () => { - it.each([ - {}, - { input_path: "input.json", input_reason: "invalid-json" }, - { input_path: "missing.json", input_reason: "read-failed" }, - { input_path: "", input_reason: "read-failed" }, - ])( - "preserves failure diagnostics and logs an error for %j", - async (metadata) => { - const parsed = await parseCliJsonInput("{", "test-input"); - if (parsed.ok) throw new Error("Expected malformed inline JSON to fail"); - const value = Object.assign({}, parsed.error, metadata); - const serialized = JSON.stringify(value); - const lines: string[] = []; - const logger = pino( - { level: "info" }, - { write: (line) => lines.push(line) }, - ); - process.exitCode = undefined; + it("preserves parsed failure diagnostics and logs an error", async () => { + const parsed = await parseCliJsonInput("{", "test-input"); + if (parsed.ok) throw new Error("Expected malformed inline JSON to fail"); + const value = parsed.error; + const serialized = JSON.stringify(value); + const lines: string[] = []; + const logger = pino( + { level: "info" }, + { write: (line) => lines.push(line) }, + ); + process.exitCode = undefined; - const output = await logCliCommand( - logger, - "test-input", - async () => value, - ); + const output = await logCliCommand(logger, "test-input", async () => value); - expect(output).toBe(value); - expect(JSON.stringify(output)).toBe(serialized); - expect(process.exitCode).toBe(1); - expect(lines).toHaveLength(1); - expect(JSON.parse(lines.join(""))).toMatchObject({ - level: 50, - command: "test-input", - status: "error", - msg: "CLI command failed", - }); - }, - ); + expect(output).toBe(value); + expect(JSON.stringify(output)).toBe(serialized); + expect(process.exitCode).toBe(1); + expect(lines).toHaveLength(1); + expect(JSON.parse(lines.join(""))).toMatchObject({ + level: 50, + command: "test-input", + status: "error", + msg: "CLI command failed", + }); + }); it("leaves ordinary parsed JSON successful and unchanged", async () => { const parsed = await parseCliJsonInput(