Files
rea/src/domain/native/bytePattern.test.ts
T
morluto 255d906e15 fix(native): scan byte-pattern inputs without regexp stack growth
Keep exact wildcard, whitespace and aligned-mask validation in the shared
domain refinement. Advertise descriptive string inputs instead of repeating
regexes, and remove discarded byte/mask array materialization.

Preserve caller spelling and error precedence; cover large public stdio
queries, provider-boundary parsing and connection recovery.

Fixes #5257
2026-10-19 22:09:42 +08:00

134 lines
3.8 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { z } from "zod";
import {
bytePatternFields,
validateBytePattern,
byteSearchResultSchema,
} from "./bytePattern.js";
const patternSchema = z
.strictObject(bytePatternFields)
.superRefine(validateBytePattern);
it.each(["0x20", "overlay:0x10", "invalid"])(
"rejects a match outside reported searched coverage: %s",
(address) => {
const page = {
matches: [
{ address, segment: ".text", file_offset: null, procedure: null },
],
searched: {
blocks: [{ segment: ".text", start: "0x10", end: "0x1f", bytes: 16 }],
bytes: 16,
skipped_uninitialized: [],
skipped_not_loaded: [],
},
complete: true,
next_cursor: null,
};
expect(byteSearchResultSchema.safeParse(page).success).toBe(false);
page.matches[0]!.address = "0x10";
expect(byteSearchResultSchema.safeParse(page).success).toBe(true);
page.matches[0]!.segment = ".bss";
expect(byteSearchResultSchema.safeParse(page).success).toBe(false);
},
);
it.each(["", "overlay:"])(
"accepts matches at both inclusive coverage boundaries in address space %s",
(space) => {
const start = `${space}0x10`;
const end = `${space}0x1f`;
expect(
byteSearchResultSchema.safeParse({
matches: [start, end].map((address) => ({
address,
segment: ".text",
file_offset: null,
procedure: null,
})),
searched: {
blocks: [{ segment: ".text", start, end, bytes: 16 }],
bytes: 16,
skipped_uninitialized: [],
skipped_not_loaded: [],
},
complete: true,
next_cursor: null,
}).success,
).toBe(true);
},
);
describe("masked byte patterns", () => {
it("preserves whole-byte wildcards and combines explicit bit masks", () => {
for (const input of [
{ pattern: "48 8b\t??89", mask: "ff f0 ff 0f" },
{ pattern: "Aa\u00a000" },
{ pattern: "00" },
{ pattern: "????aa", mask: "000001" },
])
expect(patternSchema.parse(input)).toEqual(input);
});
it.each([
["", undefined, "pattern"],
["4", undefined, "pattern"],
["4?", undefined, "pattern"],
["gg", undefined, "pattern"],
["?? ??", undefined, "pattern"],
["ff", "00", "pattern"],
["ffff", "ff", "mask"],
["ff", "??", "mask"],
["aa ??", "00 ff", "pattern"],
["??", "0000", "mask"],
["aa", "00gg", "mask"],
["??gg", "00gg", "pattern"],
])("rejects invalid pattern %s with typed issues", (pattern, mask, field) => {
const parsed = patternSchema.safeParse({ pattern, mask });
expect(parsed.success).toBe(false);
if (parsed.success) throw new Error("Expected a rejected pattern");
expect(parsed.error.issues).toMatchObject([
{ path: [field], code: "custom" },
]);
});
it("accepts ECMAScript whitespace only between complete byte pairs", () => {
const whitespace = [
"\t",
"\n",
"\v",
"\f",
"\r",
" ",
"\u00a0",
"\u1680",
...Array.from({ length: 11 }, (_, i) => String.fromCharCode(0x2000 + i)),
"\u2028",
"\u2029",
"\u202f",
"\u205f",
"\u3000",
"\ufeff",
];
for (const separator of whitespace) {
expect(
patternSchema.safeParse({
pattern: `aa${separator}??`,
mask: `ff${separator}ff`,
}).success,
).toBe(true);
for (const pattern of [
`${separator}aa`,
`aa${separator}`,
`a${separator}a`,
])
expect(patternSchema.safeParse({ pattern }).success).toBe(false);
}
for (const separator of ["\u0085", "\u180e", "\u200b", "\u200c", "\u200d"])
expect(
patternSchema.safeParse({ pattern: `aa${separator}bb` }).success,
).toBe(false);
});
});