mirror of
https://github.com/morluto/rea.git
synced 2026-10-27 09:55:46 +00:00
119 lines
4.4 KiB
TypeScript
119 lines
4.4 KiB
TypeScript
import { projectCliAnalysisResult } from "../../src/cli/projectCliAnalysisResult.js";
|
|
import { afterEach, expect, it, vi } from "vitest";
|
|
|
|
const statFailures = vi.hoisted(() => new Map<string, unknown>());
|
|
|
|
vi.mock("node:fs/promises", async (importOriginal) => {
|
|
const original = await importOriginal<typeof import("node:fs/promises")>();
|
|
return {
|
|
...original,
|
|
stat: vi.fn(async (...args: Parameters<typeof original.stat>) => {
|
|
const failure = statFailures.get(String(args[0]));
|
|
if (failure !== undefined) throw failure;
|
|
return original.stat(...args);
|
|
}),
|
|
};
|
|
});
|
|
|
|
import { parseConfig } from "../../src/config/parseConfig.js";
|
|
import { classifyBinaryTargetFilesystemFailure } from "../../src/application/BinaryTargetResolver.js";
|
|
import type { BinarySession } from "../../src/application/binary/BinarySession.js";
|
|
import type { DirectAnalysisDependencies } from "../../src/application/DirectAnalysisDependencies.js";
|
|
import { runProviderAnalysis } from "../../src/application/DirectAnalysis.js";
|
|
|
|
afterEach(() => statFailures.clear());
|
|
|
|
it("retains the original filesystem cause on the shared typed error", () => {
|
|
const cause = Object.assign(new Error("permission denied"), {
|
|
code: "EACCES",
|
|
});
|
|
const failure = classifyBinaryTargetFilesystemFailure(
|
|
"/tmp/rea-stat-failure-cause.app",
|
|
cause,
|
|
);
|
|
|
|
expect(failure?.cause).toBe(cause);
|
|
expect(failure?.systemCode).toBe("EACCES");
|
|
});
|
|
|
|
it.each([
|
|
{ code: "ENOENT", projectedCode: "target_unavailable" },
|
|
{ code: "ENOTDIR", projectedCode: "target_unavailable" },
|
|
{ code: "EACCES", projectedCode: "access_denied", systemCode: "EACCES" },
|
|
{ code: "EPERM", projectedCode: "access_denied", systemCode: "EPERM" },
|
|
{ code: "EIO", projectedCode: "target_unavailable" },
|
|
])(
|
|
"stops CLI resource dispatch on stat failure $code and preserves its path",
|
|
async ({ code, projectedCode, systemCode }) => {
|
|
const path = `/tmp/rea-stat-failure-${code}.app`;
|
|
const cause = Object.assign(new Error(`${code}: injected stat failure`), {
|
|
code,
|
|
});
|
|
statFailures.set(path, cause);
|
|
const session = {
|
|
close: vi.fn(async () => ({ ok: true as const, value: null })),
|
|
open: vi.fn(),
|
|
openBundleResources: vi.fn(),
|
|
execute: vi.fn(),
|
|
} as unknown as BinarySession;
|
|
const dependencies: DirectAnalysisDependencies = {
|
|
readConfiguration: () => parseConfig({}),
|
|
createBinarySession: () => session,
|
|
createNativeDispatchBinarySession: () => session,
|
|
createArtifactBinarySession: () => session,
|
|
createNativeBinarySession: () => session,
|
|
createManagedBinarySession: () => session,
|
|
};
|
|
|
|
const output = await runProviderAnalysis(
|
|
dependencies,
|
|
path,
|
|
"inspect_keyed_archive",
|
|
{ path: "Resources/Archive.plist" },
|
|
).then(projectCliAnalysisResult);
|
|
|
|
expect(output).toMatchObject({
|
|
code: projectedCode,
|
|
details: {
|
|
path,
|
|
reason: expect.stringContaining(cause.message),
|
|
...(systemCode === undefined ? {} : { system_code: systemCode }),
|
|
},
|
|
});
|
|
expect(session.open).not.toHaveBeenCalled();
|
|
expect(session.openBundleResources).not.toHaveBeenCalled();
|
|
expect(session.execute).not.toHaveBeenCalled();
|
|
expect(session.close).toHaveBeenCalledOnce();
|
|
},
|
|
);
|
|
|
|
it("rethrows an unclassified stat failure instead of treating it as a file", async () => {
|
|
const path = "/tmp/rea-stat-failure-opaque.app";
|
|
const cause = new Error("opaque filesystem failure");
|
|
statFailures.set(path, cause);
|
|
const session = {
|
|
close: vi.fn(async () => ({ ok: true as const, value: null })),
|
|
open: vi.fn(),
|
|
openBundleResources: vi.fn(),
|
|
execute: vi.fn(),
|
|
} as unknown as BinarySession;
|
|
const dependencies: DirectAnalysisDependencies = {
|
|
readConfiguration: () => parseConfig({}),
|
|
createBinarySession: () => session,
|
|
createNativeDispatchBinarySession: () => session,
|
|
createArtifactBinarySession: () => session,
|
|
createNativeBinarySession: () => session,
|
|
createManagedBinarySession: () => session,
|
|
};
|
|
|
|
await expect(
|
|
runProviderAnalysis(dependencies, path, "inspect_keyed_archive", {
|
|
path: "Resources/Archive.plist",
|
|
}).then(projectCliAnalysisResult),
|
|
).rejects.toBe(cause);
|
|
expect(session.open).not.toHaveBeenCalled();
|
|
expect(session.openBundleResources).not.toHaveBeenCalled();
|
|
expect(session.execute).not.toHaveBeenCalled();
|
|
expect(session.close).toHaveBeenCalledOnce();
|
|
});
|