test(desktop): make Python output fixtures portable (#9066)

* test(process): align symlink fixture with filesystem checkpoints

* test(frida): assert the CLI spawn Evidence contract

* test(mcp): use an unsupported analysis-view parent

* test(browser): separate source-location line bounds from parity

* test(desktop): make Python output fixtures portable
This commit is contained in:
ShuaixinHuang authored and GitHub committed 2026-11-06 14:41:44 +08:00
1 parent d3a4fc87cd
commit f624c3b8e3
1 file changed
+48 -17
@@ -1,4 +1,9 @@
import { execFileSync } from "node:child_process";
import {
execFileSync,
type ExecFileSyncOptionsWithStringEncoding,
} from "node:child_process";
import { mkdtempSync, writeFileSync, unlinkSync, rmdirSync } from "node:fs";
import { tmpdir } from "node:os";
import { chmod, writeFile } from "node:fs/promises";
import { join } from "node:path";
@@ -18,6 +23,33 @@ import {
import { safeParseJson } from "../../../src/domain/safeJson.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
/** Keep the exported Python helpers out of the host command-line size limit. */
const execPython = (
args: string[],
options: ExecFileSyncOptionsWithStringEncoding,
): string => {
const directory = mkdtempSync(join(tmpdir(), "rea-export-python-"));
const script = join(directory, "fixture.py");
const codeIndex = args.indexOf("-c");
try {
writeFileSync(script, args[codeIndex + 1]!, "utf8");
return execFileSync(
"python3",
[
"-X",
"utf8",
...args.slice(0, codeIndex),
script,
...args.slice(codeIndex + 2),
],
options,
);
} finally {
unlinkSync(script);
rmdirSync(directory);
}
};
/** The exported module's view format for each file, run with only its standard library imports. */
const pythonFormats = (files: readonly (readonly [string, string])[]) => {
const imports = PYTHON_IMPORTS.split("\n")
@@ -27,12 +59,12 @@ const pythonFormats = (files: readonly (readonly [string, string])[]) => {
for name, text in json.load(sys.stdin):
print(_text_view(name, text, len(text.encode()))["format"])
`;
return execFileSync("python3", ["-I", "-B", "-c", program], {
return execPython(["-I", "-B", "-c", program], {
input: JSON.stringify(files),
encoding: "utf8",
})
.trim()
.split("\n");
.split(/\r?\n/u);
};
it("detects key files by the state view's rule rather than a name or any group header", () => {
@@ -79,17 +111,18 @@ const pythonUtf16Respelled = (files: readonly string[]) => {
.filter((line) => !line.includes("agentenv_protocol"))
.join("\n");
const program = `${imports}
from pathlib import PurePosixPath
SEED_HOME = "/home/ada"
${PYTHON_HELPERS}
for data in json.load(sys.stdin):
print(_respelled_utf16(bytes.fromhex(data), Path("/home/user")).hex())
print(_respelled_utf16(bytes.fromhex(data), PurePosixPath("/home/user")).hex())
`;
return execFileSync("python3", ["-I", "-B", "-c", program], {
return execPython(["-I", "-B", "-c", program], {
input: JSON.stringify(files),
encoding: "utf8",
})
.trim()
.split("\n");
.split(/\r?\n/u);
};
const utf16 = (text: string, order: "le" | "be") => {
@@ -143,13 +176,13 @@ const taskbarWindow = (bin: string, windowClass: string): string => {
const imports = PYTHON_IMPORTS.split("\n")
.filter((line) => !line.includes("agentenv_protocol"))
.join("\n");
return execFileSync(
"python3",
return execPython(
[
"-I",
"-B",
"-c",
`${imports}\nSEED_HOME = "/home/ada"\n${PYTHON_HELPERS}\nprint(_taskbar_window(sys.argv[1]))`,
`${imports}\nfrom pathlib import PurePosixPath
SEED_HOME = "/home/ada"\n${PYTHON_HELPERS}\nprint(_taskbar_window(sys.argv[1]))`,
windowClass,
],
{
@@ -195,12 +228,12 @@ const pythonJson = (texts: readonly string[]) => {
for text in json.load(sys.stdin):
print(json.dumps(_text_view("a.json", text, len(text.encode()))))
`;
return execFileSync("python3", ["-I", "-B", "-c", program], {
return execPython(["-I", "-B", "-c", program], {
input: JSON.stringify(texts),
encoding: "utf8",
})
.trim()
.split("\n")
.split(/\r?\n/u)
.map((line) => JSON.parse(line) as { view: unknown; error?: string });
};
@@ -256,7 +289,7 @@ for name, text in json.load(sys.stdin):
view = _text_view(name, text, len(text.encode()))
print(json.dumps({"format": view["format"], "view": view["view"], "error": view.get("error")}))
`;
const python = execFileSync("python3", ["-I", "-B", "-c", program], {
const python = execPython(["-I", "-B", "-c", program], {
input: JSON.stringify(files),
encoding: "utf8",
maxBuffer: 64 * 1024 * 1024,
@@ -336,8 +369,7 @@ it("checks text for JSON the way REA does, token by token, without parsing it",
.join("\n");
const python = JSON.parse(
execFileSync(
"python3",
execPython(
[
"-I",
"-B",
@@ -373,7 +405,7 @@ print(json.dumps({"deep": deep, "peak": peak, "edge": _deeper_than(nested, 501),
`;
const result = JSON.parse(
execFileSync("python3", ["-I", "-B", "-c", program], { encoding: "utf8" }),
execPython(["-I", "-B", "-c", program], { encoding: "utf8" }),
) as { deep: boolean; peak: number; edge: boolean; over: boolean };
expect(result).toMatchObject({ deep: false, edge: false, over: true });
@@ -385,8 +417,7 @@ it("spells infinite and negative-zero SQLite reals as REA's SQLite reader does",
const imports = PYTHON_IMPORTS.split("\n")
.filter((line) => !line.includes("agentenv_protocol"))
.join("\n");
const cells = execFileSync(
"python3",
const cells = execPython(
[
"-I",
"-B",