Files
rea/scripts/lib/real-hopper-cli-selectors.mjs

89 lines
2.4 KiB
JavaScript

import assert from "node:assert/strict";
/** Compare exact native symbol and literal selectors through MCP and the real CLI. */
export async function verifyHopperCliSelectors(call, runCli, dispatcher, path) {
const procedures = await call("list_procedures");
const delegate = procedures.find(
(item) => item.value === "-[REAWidget delegate]",
);
assert.ok(delegate, "Objective-C fixture omitted its tail-call method");
const cases = [
{
command: "function",
option: "procedure",
operation: "analyze_function",
parameters: { procedure: delegate.value },
},
{
command: "instructions",
option: "procedure",
operation: "read_function_instructions",
parameters: { procedure: delegate.value },
},
{
command: "decompile",
option: "procedure",
operation: "procedure_pseudo_code",
parameters: { procedure: delegate.value },
},
{
command: "xrefs",
option: "address",
operation: "xrefs",
parameters: { address: delegate.value },
},
{
command: "search",
option: "pattern",
operation: "search_procedures",
parameters: {
pattern: delegate.value,
mode: "literal",
case_sensitive: true,
},
flags: ["--kind", "procedures", "--case-sensitive"],
},
{
command: "trace",
option: "query",
operation: "trace_feature",
parameters: { query: "--help" },
},
];
const expected = [];
for (const item of cases)
expected.push(await call(item.operation, item.parameters));
await call("close_binary");
for (let i = 0; i < cases.length; i++) {
const item = cases[i];
const selector = item.parameters[item.option];
const { stdout } = await runCli([
dispatcher,
item.command,
path,
`--${item.option}=${selector}`,
...(item.flags ?? []),
"--provider",
"hopper",
"--format",
"json",
]);
const evidence = JSON.parse(stdout);
assert.deepEqual(
evidence.normalized_result,
expected[i],
`${item.command} named selector differs from MCP`,
);
assert.equal(
evidence.parameters[item.option],
selector,
`${item.command} altered its selector`,
);
}
return {
commands: cases.map(({ command }) => command),
exactObjectiveCNames: true,
literalGlobalFlagPreserved: true,
};
}