mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(android): decode guardian output as UTF-8 streams
This commit is contained in:
1 parent
8dbe92a4a3
commit
73be86c39e
2 files changed
+95
-4
No files matched your search
@@ -0,0 +1,89 @@
|
||||
import { EventEmitter } from "node:events";
|
||||
import { win32 } from "node:path";
|
||||
import { PassThrough } from "node:stream";
|
||||
|
||||
import { afterEach, expect, it, vi } from "vitest";
|
||||
|
||||
const { spawnMock, tmpdirMock, lstatMock } = vi.hoisted(() => ({
|
||||
spawnMock: vi.fn(),
|
||||
tmpdirMock: vi.fn(),
|
||||
lstatMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("node:child_process", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("node:child_process")>()),
|
||||
spawn: spawnMock,
|
||||
}));
|
||||
vi.mock("node:os", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("node:os")>()),
|
||||
tmpdir: tmpdirMock,
|
||||
}));
|
||||
vi.mock("node:fs/promises", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("node:fs/promises")>()),
|
||||
lstat: lstatMock,
|
||||
}));
|
||||
|
||||
import { createJadxWorkspaceRoot } from "./JadxWorkspaceRoot.js";
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("decodes a Windows guardian path across split UTF-8 stdout writes", async () => {
|
||||
const previousPlatform = process.platform;
|
||||
Object.defineProperty(process, "platform", {
|
||||
configurable: true,
|
||||
value: "win32",
|
||||
});
|
||||
const parent = "C:\\Users\\研究者\\AppData\\Local\\Temp";
|
||||
const path = win32.join(parent, `rea-android-${"a".repeat(32)}`);
|
||||
const child = Object.assign(new EventEmitter(), {
|
||||
stdin: new PassThrough(),
|
||||
stdout: new PassThrough(),
|
||||
stderr: new PassThrough(),
|
||||
unref: vi.fn(),
|
||||
});
|
||||
child.stdin.once("finish", () => {
|
||||
child.stdout.end();
|
||||
child.stderr.end();
|
||||
child.emit("close", 0, null);
|
||||
});
|
||||
tmpdirMock.mockReturnValue(parent);
|
||||
const missingPath = Object.assign(new Error("missing after cleanup"), {
|
||||
code: "ENOENT",
|
||||
});
|
||||
lstatMock.mockRejectedValue(missingPath);
|
||||
spawnMock.mockReturnValue(child);
|
||||
const ready = Buffer.from(
|
||||
`${JSON.stringify({
|
||||
path,
|
||||
volumeSerial: "0123456789abcdef",
|
||||
fileId: "0123456789abcdef0123456789abcdef",
|
||||
privateDacl: true,
|
||||
})}\n`,
|
||||
);
|
||||
const split = ready.indexOf(Buffer.from("研")) + 1;
|
||||
|
||||
try {
|
||||
const start = createJadxWorkspaceRoot();
|
||||
setImmediate(() => {
|
||||
child.stdout.write(ready.subarray(0, split), () => {
|
||||
setImmediate(() => child.stdout.write(ready.subarray(split)));
|
||||
});
|
||||
});
|
||||
|
||||
const root = await start;
|
||||
try {
|
||||
expect(root.path).toBe(path);
|
||||
} finally {
|
||||
await expect(root.close()).resolves.toBeUndefined();
|
||||
}
|
||||
expect(lstatMock).toHaveBeenCalledWith(path);
|
||||
} finally {
|
||||
Object.defineProperty(process, "platform", {
|
||||
configurable: true,
|
||||
value: previousPlatform,
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -105,8 +105,9 @@ class WindowsJadxWorkspaceRoot implements JadxWorkspaceRoot {
|
||||
},
|
||||
});
|
||||
let diagnostics = "";
|
||||
child.stderr.on("data", (chunk: Buffer) => {
|
||||
diagnostics = (diagnostics + chunk.toString()).slice(-8192);
|
||||
child.stderr.setEncoding("utf8");
|
||||
child.stderr.on("data", (chunk: string) => {
|
||||
diagnostics = (diagnostics + chunk).slice(-8192);
|
||||
});
|
||||
const exit = new Promise<GuardianExit>((resolve) => {
|
||||
child.once("error", (error: Error) =>
|
||||
@@ -116,8 +117,9 @@ class WindowsJadxWorkspaceRoot implements JadxWorkspaceRoot {
|
||||
});
|
||||
const ready = new Promise<string>((resolve, reject) => {
|
||||
let frame = "";
|
||||
child.stdout.on("data", (chunk: Buffer) => {
|
||||
frame += chunk.toString();
|
||||
child.stdout.setEncoding("utf8");
|
||||
child.stdout.on("data", (chunk: string) => {
|
||||
frame += chunk;
|
||||
if (frame.length > 4096) {
|
||||
reject(
|
||||
new Error("Android workspace guardian readiness exceeded 4 KiB"),
|
||||
|
||||
Reference in new issue
Block a user