mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
* fix(hopper): normalize string-backed addresses and update verification * feat(native): add inspection primitives, dispatch traces and approved UI observation * test: prioritize real artifact E2E and captured golden regressions * fix(process): queue observed output before reactive rendering actions * test: prune redundant cases and strengthen boundary assertions * fix(cli): route native value tracing through shared workflows * test: replace synthetic success with real workflows and captured data * fix(catalog): separate portable metadata from native host availability
105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { functionDossierSchema } from "../domain/hopperValues.js";
|
|
import { ghidraFunctionDossier } from "../domain/hopperValues.fixture.js";
|
|
import { nativeApiBoundarySchema } from "../domain/nativeApiBoundary.js";
|
|
import { projectNativeApiInspection } from "./NativeApiInspection.js";
|
|
|
|
describe("native API inspection", () => {
|
|
it("preserves structured type and jump-table boundary evidence", () => {
|
|
const dossier = functionDossierSchema.parse(ghidraFunctionDossier());
|
|
|
|
expect(projectNativeApiInspection(dossier)).toMatchObject({
|
|
procedure: { address: "0x401000", name: "fixture_main" },
|
|
boundary: {
|
|
available: true,
|
|
return_type: { data_type: "int", confidence: "medium" },
|
|
jump_tables: [
|
|
{
|
|
dispatch_address: "0x401010",
|
|
data_sources: [{ address: "0x403000" }],
|
|
mappings: [
|
|
{
|
|
target_address: "0x401020",
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
unsupported_branches: [],
|
|
residual_unknowns: [],
|
|
});
|
|
});
|
|
|
|
it("preserves unsupported provider branches as residual unknowns", () => {
|
|
const value = ghidraFunctionDossier();
|
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
throw new TypeError("Ghidra dossier fixture is invalid");
|
|
const dossier = functionDossierSchema.parse(
|
|
Object.fromEntries(
|
|
Object.entries(value).filter(([key]) => key !== "native_api"),
|
|
),
|
|
);
|
|
|
|
expect(projectNativeApiInspection(dossier)).toMatchObject({
|
|
boundary: { available: false },
|
|
unsupported_branches: [
|
|
"structured-boundary-types",
|
|
"jump-table-data-mapping",
|
|
],
|
|
residual_unknowns: [
|
|
expect.stringContaining("boundary types"),
|
|
expect.stringContaining("jump table"),
|
|
],
|
|
});
|
|
});
|
|
|
|
it("reports missing jump-table targets as an explicit unknown", () => {
|
|
const value = ghidraFunctionDossier();
|
|
const dossier = functionDossierSchema.parse(value);
|
|
const boundary = dossier.native_api;
|
|
if (boundary?.available !== true)
|
|
throw new TypeError("Ghidra native API fixture is unavailable");
|
|
const table = boundary.jump_tables[0];
|
|
if (table === undefined)
|
|
throw new TypeError("Ghidra jump-table fixture is unavailable");
|
|
|
|
const incomplete = functionDossierSchema.parse({
|
|
...dossier,
|
|
native_api: {
|
|
...boundary,
|
|
jump_tables: [{ ...table, mappings: [] }],
|
|
},
|
|
});
|
|
expect(projectNativeApiInspection(incomplete).residual_unknowns).toContain(
|
|
"Which case values and targets belong to the dispatch at 0x401010?",
|
|
);
|
|
});
|
|
|
|
it("rejects boundary types placed in the wrong ABI role", () => {
|
|
const boundary = functionDossierSchema.parse(
|
|
ghidraFunctionDossier(),
|
|
).native_api;
|
|
if (boundary === null || boundary.available !== true)
|
|
throw new TypeError("Ghidra native API fixture is unavailable");
|
|
|
|
expect(
|
|
nativeApiBoundarySchema.safeParse({
|
|
...boundary,
|
|
return_type: { ...boundary.return_type, role: "parameter" },
|
|
}).success,
|
|
).toBe(false);
|
|
expect(
|
|
nativeApiBoundarySchema.safeParse({
|
|
...boundary,
|
|
parameters: [
|
|
{
|
|
...boundary.return_type,
|
|
role: "return",
|
|
},
|
|
],
|
|
}).success,
|
|
).toBe(false);
|
|
});
|
|
});
|