Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com> Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
144 lines
4.1 KiB
JavaScript
144 lines
4.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { referencesMethod } from "./reference-contracts.mjs";
|
|
import { methods } from "./api.mjs";
|
|
import { NativeReferenceReads } from "./reference-reads.mjs";
|
|
|
|
test("range selectors preserve old inputs and reject ambiguous/directional/malformed choices", () => {
|
|
assert.equal(methods.references, referencesMethod);
|
|
const schema = methods.references.input;
|
|
assert.deepEqual(schema.parse({ addresses: ["0x1"] }).addresses, ["0x1"]);
|
|
assert.equal(
|
|
schema.parse({
|
|
addresses: ["0x1"],
|
|
direction: "outgoing",
|
|
scope: "function",
|
|
}).scope,
|
|
"function",
|
|
);
|
|
const ranges = [{ start: "0x0", end_inclusive: "0xffffffffffffffff" }];
|
|
assert.equal(schema.parse({ ranges }).scope, "range");
|
|
for (const input of [
|
|
{ ranges, addresses: ["0x0"] },
|
|
{ addresses: ["0x1"], scope: "function", direction: "incoming" },
|
|
{ addresses: ["0x1"], scope: "function" },
|
|
{ ranges, scope: "function" },
|
|
{ ranges, direction: "outgoing" },
|
|
{ ranges: [] },
|
|
{ ranges: [{ start: "0x2", end_inclusive: "0x1" }] },
|
|
{ ranges: [{ start: "0xg", end_inclusive: "0x1" }] },
|
|
{ ranges: [{ start: "0x0", end_inclusive: "0x10000000000000000" }] },
|
|
{ ranges, limit: 129 },
|
|
{ ranges, offset: -1 },
|
|
])
|
|
assert.equal(schema.safeParse(input).success, false, JSON.stringify(input));
|
|
});
|
|
|
|
const range = { start: "0x100", end_inclusive: "0x10d" };
|
|
const wire = JSON.stringify({
|
|
schema_version: 1,
|
|
binary: "/input",
|
|
direction: "to",
|
|
count: 1,
|
|
ranges: [
|
|
{
|
|
...range,
|
|
index: 0,
|
|
offset: 0,
|
|
limit: 20,
|
|
total: 1,
|
|
count: 1,
|
|
next_offset: null,
|
|
},
|
|
],
|
|
xrefs: [
|
|
{
|
|
range_index: 0,
|
|
address: 8,
|
|
address_hex: "0x8",
|
|
kind: "data",
|
|
from_address: 8,
|
|
from_address_hex: "0x8",
|
|
to_address: 264,
|
|
to_address_hex: "0x108",
|
|
from_function: null,
|
|
to_function: null,
|
|
instruction: "LEA pointer",
|
|
},
|
|
],
|
|
});
|
|
const source = {
|
|
evidence_id: "ev_page",
|
|
sha256: "owned-sha",
|
|
bytes: Buffer.byteLength(wire),
|
|
elapsed_ms: 1,
|
|
};
|
|
test("range pages reuse one immutable parsed source across fields and expire on clear", async () => {
|
|
let reads = 0;
|
|
const invocations = [];
|
|
const reader = new NativeReferenceReads(
|
|
async (key, args) => {
|
|
invocations.push({ key, args: args("/input") });
|
|
return { input: "/input", source };
|
|
},
|
|
async () => {
|
|
reads++;
|
|
return wire;
|
|
},
|
|
() => {},
|
|
);
|
|
const input = referencesMethod.input.parse({ ranges: [range] });
|
|
const first = await reader.read(input);
|
|
const selected = await reader.read({ ...input, fields: [] });
|
|
assert.equal(reads, 1);
|
|
assert.equal(invocations[0].key, invocations[1].key);
|
|
assert.deepEqual(Object.keys(selected.results[0].items[0]), [
|
|
"source_row",
|
|
"from",
|
|
"to",
|
|
"kind",
|
|
]);
|
|
assert.throws(() => {
|
|
first.results[0].items[0].instruction = "corrupt";
|
|
}, TypeError);
|
|
first.results[0].items.length = 0;
|
|
assert.equal((await reader.read(input)).results[0].items.length, 1);
|
|
assert.equal(
|
|
selected.results[0].coverage.whole_string_use,
|
|
"not-established",
|
|
);
|
|
reader.clear();
|
|
await reader.read(input);
|
|
assert.equal(reads, 2);
|
|
});
|
|
test("unavailable and malformed ranges cannot masquerade as empty observations", async () => {
|
|
const input = referencesMethod.input.parse({ ranges: [range] });
|
|
const unavailable = new NativeReferenceReads(
|
|
() => {
|
|
throw Error("must not launch");
|
|
},
|
|
() => {},
|
|
() => {
|
|
throw Object.assign(Error("requires native"), {
|
|
code: "capability_unavailable",
|
|
});
|
|
},
|
|
);
|
|
await assert.rejects(
|
|
unavailable.read(input),
|
|
(e) => e.code === "capability_unavailable",
|
|
);
|
|
const malformed = new NativeReferenceReads(
|
|
async () => ({ input: "/input", source }),
|
|
async () => "{}",
|
|
() => {},
|
|
);
|
|
await assert.rejects(
|
|
malformed.read(input),
|
|
(e) =>
|
|
e.code === "invalid_provider_output" &&
|
|
e.details.evidence_id === source.evidence_id &&
|
|
e.details.source_retained === true,
|
|
);
|
|
});
|