mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 01:13:39 +00:00
test: consolidate JavaScript and provider fixture coverage
This commit is contained in:
1 parent
439c197c3f
commit
3c4be703cd
16 files changed
+23
-223
No files matched your search
@@ -454,7 +454,7 @@ describe("dyld resolution outcomes: deriving path and weak-load outcomes", () =>
|
||||
);
|
||||
});
|
||||
|
||||
it("derives unresolved and earlier-candidate findings separately for weak loads", async () => {
|
||||
it("reports earlier-rpath misses under environment uncertainty", async () => {
|
||||
const trace = await traceDylibLoading(
|
||||
memoryView({
|
||||
[MAIN]: executable({
|
||||
@@ -462,14 +462,7 @@ describe("dyld resolution outcomes: deriving path and weak-load outcomes", () =>
|
||||
"@executable_path/../Overrides",
|
||||
"@executable_path/../Frameworks",
|
||||
],
|
||||
dependencies: [
|
||||
dependency("@rpath/libfound.dylib"),
|
||||
dependency("@rpath/libgone.dylib", {
|
||||
command: "LC_LOAD_WEAK_DYLIB",
|
||||
weak: true,
|
||||
}),
|
||||
dependency("@rpath/libmissing.dylib"),
|
||||
],
|
||||
dependencies: [dependency("@rpath/libfound.dylib")],
|
||||
dyld_environment: ["DYLD_LIBRARY_PATH=/tmp"],
|
||||
}),
|
||||
"Contents/Frameworks/libfound.dylib": parsed(slice()),
|
||||
|
||||
@@ -1178,15 +1178,7 @@ it("keeps distinct exposed renderer listener callsites distinct", () => {
|
||||
result.electron.call_paths?.filter(({ channel }) => channel === "pong"),
|
||||
).toHaveLength(2);
|
||||
});
|
||||
it("does not identify overwritten Electron namespaces or shadowed require", () => {
|
||||
for (const source of [
|
||||
`const e=require("electron");e.ipcMain={on(){}};e.ipcMain.on("bad",event=>event.sender.copy());`,
|
||||
`function require(){return {ipcMain:{on(){}}}};const e=require("electron");e.ipcMain.on("bad",event=>event.sender.copy());`,
|
||||
])
|
||||
expect(
|
||||
analyzeJavaScriptStaticSource(source).electron.call_paths ?? [],
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("preserves guarded alternatives in direct exposed object literals", () => {
|
||||
const result = analyzeJavaScriptStaticSource(`
|
||||
const e=require("electron");
|
||||
|
||||
@@ -73,24 +73,4 @@ describe("JavaScript semantic analysis: logical assignment", () => {
|
||||
"unknown",
|
||||
);
|
||||
});
|
||||
|
||||
it("reproduces the issue #2646 inputs without an exact literal", () => {
|
||||
for (const operator of ["||=", "??="]) {
|
||||
const { binding, returned } = observe(
|
||||
`function read(x) { x ${operator} 2; return x; }`,
|
||||
);
|
||||
expect(binding).not.toEqual({ status: "literal", value: 2 });
|
||||
expect(returned).not.toEqual({ status: "literal", value: 2 });
|
||||
}
|
||||
const readOr = (x: number) => {
|
||||
x ||= 2;
|
||||
return x;
|
||||
};
|
||||
const readNullish = (x: number) => {
|
||||
x ??= 2;
|
||||
return x;
|
||||
};
|
||||
expect(readOr(5)).toBe(5);
|
||||
expect(readNullish(5)).toBe(5);
|
||||
});
|
||||
});
|
||||
@@ -874,21 +874,6 @@ describe("property mutation collection on minified bundles", () => {
|
||||
],
|
||||
});
|
||||
}, 30000);
|
||||
|
||||
it("indexes many returned object methods instead of rescanning the object", () => {
|
||||
const methods = Array.from(
|
||||
{ length: 2000 },
|
||||
(_, index) => `m${index}() { return shared; }`,
|
||||
).join(",");
|
||||
const writes = Array.from(
|
||||
{ length: 2000 },
|
||||
(_, index) => `box.m${index}().p${index} = ${index};`,
|
||||
).join(" ");
|
||||
const value = resultValue(
|
||||
`const shared = { token: "TOKEN" }; const box = { ${methods} }; ${writes} return shared.token;`,
|
||||
);
|
||||
expect(value?.status).toBe("unknown");
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
describe("results of methods on an escaped receiver", () => {
|
||||
|
||||
@@ -8,9 +8,9 @@ import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js";
|
||||
*
|
||||
* Measured on Node 24.22.1: `"pipe"`, `"overlapped"`, `"inherit"` and `"ignore"` start a
|
||||
* child, while `"ipc"`, `"PIPE"`, `"pipe "`, `"pipeline"`, `"stream"` and `"stdio"` throw
|
||||
* `ERR_INVALID_ARG_VALUE`. The set is exact and case-sensitive. `fork` appends `"ipc"` to a
|
||||
* string and splits it, so an empty string becomes the lone element `"ipc"`, which `fork`
|
||||
* refuses — `spawn(..., {stdio: ""})` still starts a child.
|
||||
* `ERR_INVALID_ARG_VALUE`. The set is exact and case-sensitive. `fork` refuses an empty string in its
|
||||
* own stdio-string validation; it does not split the string or append `"ipc"`.
|
||||
* `spawn(..., {stdio: ""})` still starts a child.
|
||||
*/
|
||||
const spawnsFor = (body: string) =>
|
||||
analyzeJavaScriptSemantics(
|
||||
|
||||
@@ -78,30 +78,6 @@ it.each(cases)(
|
||||
},
|
||||
);
|
||||
|
||||
it.each(["call", "apply"] as const)(
|
||||
"does not treat an owned local %s replacement as a loader invocation",
|
||||
(method) => {
|
||||
const args = method === "call" ? "null,'node:path'" : "null,['node:path']";
|
||||
const analysis = analyzeJavaScriptStaticSource(
|
||||
`${named}const load=make(import.meta.url);load.${method}=()=>({kind:'local'});load.${method}(${args});`,
|
||||
);
|
||||
expect(analysis.parse_error_count).toBe(0);
|
||||
expect(
|
||||
analysis.references.filter(({ kind }) => kind === "require"),
|
||||
).toEqual([]);
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps uncertainty for conditional call-member replacement", () => {
|
||||
const analysis = analyzeJavaScriptStaticSource(
|
||||
`${named}const load=make(import.meta.url);if(flag)load.call=()=>({kind:'local'});load.call(null,'node:path');`,
|
||||
);
|
||||
expect(analysis.parse_error_count).toBe(0);
|
||||
expect(analysis.references.filter(({ kind }) => kind === "require")).toEqual([
|
||||
expect.objectContaining({ kind: "require", specifier: null }),
|
||||
]);
|
||||
});
|
||||
|
||||
it("uses the restored call member after a local replacement", () => {
|
||||
const source = `${named}const load=make(import.meta.url);load.call=()=>({kind:'local'});load.call=Function.prototype.call;load.call(null,'node:path');`;
|
||||
const analysis = analyzeJavaScriptStaticSource(source);
|
||||
|
||||
@@ -491,32 +491,6 @@ describe("historical source graph validation", () => {
|
||||
],
|
||||
}),
|
||||
).toThrow(/normalized and inventoried/u);
|
||||
expect(() =>
|
||||
createHistoricalSourceGraph({
|
||||
...graphInput(),
|
||||
inventory_state: "partial",
|
||||
entries: graphInput().entries.map((entry) =>
|
||||
entry.kind === "symlink"
|
||||
? { ...entry, target: "/etc/passwd", target_state: "external" }
|
||||
: entry,
|
||||
),
|
||||
}),
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
createHistoricalSourceGraph({
|
||||
...graphInput(),
|
||||
inventory_state: "partial",
|
||||
entries: graphInput().entries.map((entry) =>
|
||||
entry.kind === "symlink"
|
||||
? {
|
||||
...entry,
|
||||
target: "<outside-root>",
|
||||
target_state: "external",
|
||||
}
|
||||
: entry,
|
||||
),
|
||||
}),
|
||||
).toThrow(/target path does not match/u);
|
||||
expect(() =>
|
||||
createHistoricalSourceGraph({
|
||||
...graphInput(),
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
ghidraDisabledAnalyzersSchema,
|
||||
MAX_GHIDRA_DISABLED_ANALYZER_NAMES,
|
||||
} from "../config/ghidraDisabledAnalyzers.js";
|
||||
import { MAX_GHIDRA_DISABLED_ANALYZER_NAMES } from "../config/ghidraDisabledAnalyzers.js";
|
||||
import { parseConfig } from "../config/parseConfig.js";
|
||||
|
||||
const INSTALL = "/opt/ghidra_12.1.4_PUBLIC";
|
||||
@@ -81,10 +78,4 @@ describe("REA_GHIDRA_DISABLED_ANALYZERS", () => {
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("admits the documented Objective-C analyzer name", () => {
|
||||
expect(
|
||||
ghidraDisabledAnalyzersSchema.parse("Objective-C Message Analyzer"),
|
||||
).toEqual(["Objective-C Message Analyzer"]);
|
||||
});
|
||||
});
|
||||
@@ -1534,27 +1534,6 @@ describe("Ghidra JVM native directory admission", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("accepts a JDK whose os.arch selects the validated native decompiler directory", async () => {
|
||||
const result = await inspectGhidraInstallation(
|
||||
{
|
||||
resourceOwner: inspectionResources.owner,
|
||||
environment: {},
|
||||
installDir: INSTALL,
|
||||
platform: "darwin",
|
||||
architecture: "arm64",
|
||||
},
|
||||
host({
|
||||
probeJava: () =>
|
||||
javaProbeOk<GhidraJavaObservation>({
|
||||
...JAVA,
|
||||
osArch: "aarch64",
|
||||
osName: "Mac OS X",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(result.status).toBe("available");
|
||||
});
|
||||
|
||||
it("rejects a successful Java probe that omits os.arch", async () => {
|
||||
const { osArch: _observedArchitecture, ...withoutArchitecture } = JAVA;
|
||||
const result = await inspectGhidraInstallation(
|
||||
|
||||
@@ -5117,17 +5117,6 @@ describe("Ghidra disabled analyzer applicability per program", () => {
|
||||
}
|
||||
expect(counts).toEqual({ starts: 1, calls: 0, closes: 1 });
|
||||
});
|
||||
|
||||
it("fails closed on an analyzer report the profile did not commit", async () => {
|
||||
const { counts, client } = await analyzerSession(
|
||||
undefined,
|
||||
analyzerReport(["Objective-C Message Analyzer", "not_applicable"]),
|
||||
);
|
||||
const failed = await client.execute("health", {});
|
||||
expect(failed.ok).toBe(false);
|
||||
if (!failed.ok) expect(failed.error._tag).toBe("ProviderAdapterError");
|
||||
expect(counts).toEqual({ starts: 1, calls: 0, closes: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
type Handshake = Partial<GhidraSessionInfo>;
|
||||
|
||||
@@ -3,7 +3,6 @@ import { join } from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { createIdaTarget } from "../../tests/fixtures/idaMcp.js";
|
||||
import { readIdaConfiguration } from "./IdaConfiguration.js";
|
||||
import { decodeIdaToolResult } from "./IdaMcpConnection.js";
|
||||
import type { RetainedResourceScope } from "../application/AnalysisProvider.js";
|
||||
import { OwnedFileHandle } from "../filesystem/OwnedFileHandle.js";
|
||||
import * as regularFile from "../filesystem/RegularFile.js";
|
||||
@@ -252,36 +251,6 @@ describe("IDA registration descriptor ownership", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("IDA MCP result decoding", () => {
|
||||
it("parses FastMCP wrappers, structured dictionaries, text, arrays, and explicit errors", () => {
|
||||
expect(
|
||||
decodeIdaToolResult({
|
||||
content: [],
|
||||
structuredContent: { result: [{ address: "0x1" }] },
|
||||
}),
|
||||
).toEqual([{ address: "0x1" }]);
|
||||
expect(
|
||||
decodeIdaToolResult({
|
||||
content: [],
|
||||
structuredContent: { address: "0x1", name: "f" },
|
||||
}),
|
||||
).toEqual({ address: "0x1", name: "f" });
|
||||
expect(
|
||||
decodeIdaToolResult({ content: [{ type: "text", text: "int f() {}" }] }),
|
||||
).toBe("int f() {}");
|
||||
expect(
|
||||
decodeIdaToolResult({ content: [{ type: "text", text: '{"data":[]}' }] }),
|
||||
).toEqual({ data: [] });
|
||||
expect(() =>
|
||||
decodeIdaToolResult({
|
||||
content: [{ type: "text", text: "No function at 0x1" }],
|
||||
isError: true,
|
||||
}),
|
||||
).toThrow("No function at 0x1");
|
||||
expect(() => decodeIdaToolResult({ content: "invalid" })).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["env", "headers"] as const)(
|
||||
"preserves all explicit IDA %s keys",
|
||||
async (field) => {
|
||||
|
||||
@@ -620,16 +620,4 @@ describe("headless IDA document identity", () => {
|
||||
expect((await client.close()).ok).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("lists exactly the admitted program", async () => {
|
||||
const { client, target } = await session();
|
||||
try {
|
||||
const result = await client.execute("list_documents", {});
|
||||
|
||||
if (!result.ok) throw result.error;
|
||||
expect(result.value.result).toEqual([target.path]);
|
||||
} finally {
|
||||
expect((await client.close()).ok).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -75,6 +75,15 @@ describe("upstream IDA tool result decoding", () => {
|
||||
);
|
||||
});
|
||||
it("decodes scalar wrappers and legacy text without dropping structured dictionaries", () => {
|
||||
expect(
|
||||
decodeIdaToolResult({
|
||||
content: [],
|
||||
structuredContent: { result: [{ address: "0x1" }] },
|
||||
}),
|
||||
).toEqual([{ address: "0x1" }]);
|
||||
expect(
|
||||
decodeIdaToolResult({ content: [{ type: "text", text: '{"data":[]}' }] }),
|
||||
).toEqual({ data: [] });
|
||||
expect(
|
||||
decodeIdaToolResult({
|
||||
content: [],
|
||||
@@ -707,6 +716,7 @@ it("keeps error, truncation and native-text precedence ahead of structured JSON
|
||||
|
||||
it("requires a valid content array even when IDA supplies structured evidence", () => {
|
||||
for (const content of [
|
||||
"invalid",
|
||||
undefined,
|
||||
null,
|
||||
{},
|
||||
|
||||
@@ -29,26 +29,6 @@ it("names the Wakaru configuration requirement when it is not configured", async
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects an exhausted shared execution budget before launching the next command", async () => {
|
||||
await expect(
|
||||
runWakaruCommand({
|
||||
command: "/selected/wakaru",
|
||||
limiter: "/usr/bin/prlimit",
|
||||
arguments: ["--version"],
|
||||
cwd: "/tmp/unused",
|
||||
environment: {},
|
||||
deadline: performance.now() - 1,
|
||||
launcher: async () => {
|
||||
throw new Error("An expired budget must not launch");
|
||||
},
|
||||
}),
|
||||
).rejects.toMatchObject({
|
||||
_tag: "AnalysisTimeoutError",
|
||||
operation: "recover_javascript_sources",
|
||||
timeoutMs: RECOVERY_LIMITS.timeoutMs,
|
||||
});
|
||||
});
|
||||
|
||||
it("projects the fixed Wakaru deadline without an editable setting", async () => {
|
||||
const refusal: unknown = await runWakaruCommand({
|
||||
command: "/selected/wakaru",
|
||||
@@ -63,6 +43,10 @@ it("projects the fixed Wakaru deadline without an editable setting", async () =>
|
||||
}).catch((cause: unknown) => cause);
|
||||
if (!(refusal instanceof AnalysisTimeoutError))
|
||||
throw new Error("Expected the Wakaru deadline");
|
||||
expect(refusal).toMatchObject({
|
||||
operation: "recover_javascript_sources",
|
||||
timeoutMs: RECOVERY_LIMITS.timeoutMs,
|
||||
});
|
||||
const projected = projectAnalysisError(refusal);
|
||||
expect(projected).toMatchObject({
|
||||
code: "provider_timeout",
|
||||
|
||||
@@ -290,7 +290,7 @@ describe("upstream source-map point evidence", () => {
|
||||
});
|
||||
|
||||
describe("source-map layout admission", () => {
|
||||
it.each(["ACAA", "AAAAC", "g", "!", "AA", "D"])(
|
||||
it.each(["AAAAC", "g", "!", "AA", "D"])(
|
||||
"rejects malformed VLQ/components/indexes: %s",
|
||||
(mappings) => {
|
||||
expect(() => trace({ ...leaf, mappings })).toThrow();
|
||||
|
||||
@@ -458,20 +458,10 @@ it("keeps signed zero and non-finite float and complex constants JSON-safe", ()
|
||||
it("truncates string previews without introducing a lone surrogate", () => {
|
||||
const prefix = "x".repeat(79);
|
||||
const report = parse(
|
||||
withConsts([
|
||||
marshalUnicode(Buffer.from(`${prefix}😀tail`)),
|
||||
marshalUnicode(
|
||||
Buffer.concat([
|
||||
Buffer.from(prefix),
|
||||
Buffer.from("eda080", "hex"),
|
||||
Buffer.from("tail"),
|
||||
]),
|
||||
),
|
||||
]),
|
||||
withConsts([marshalUnicode(Buffer.from(`${prefix}😀tail`))]),
|
||||
);
|
||||
expect(root(report).consts).toEqual([
|
||||
{ kind: "str", bytes: 87, truncated: true, value: prefix },
|
||||
{ kind: "str", bytes: 86, truncated: true, value: `${prefix}\ud800` },
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user