mirror of https://github.com/garrytan/gstack.git
84 lines
3.3 KiB
TypeScript
84 lines
3.3 KiB
TypeScript
/**
|
|
* Regression test for PR #1169 bug #7 — `pdf --from-file` ran JSON.parse on
|
|
* user-supplied file contents with no try/catch. A malformed payload crashed
|
|
* the pdf handler with a raw SyntaxError. Codex flagged that JSON.parse
|
|
* accepts primitives too (numbers, strings, null) and Array.isArray must be
|
|
* checked separately, so the fix added an explicit object-shape gate.
|
|
*
|
|
* Test surface: parsePdfFromFile, exported for tests at meta-commands.ts:139.
|
|
* All fixtures land in process.cwd() (SAFE_DIRECTORIES allows TEMP_DIR or cwd;
|
|
* cwd is universally safe on every platform our CI runs on).
|
|
*/
|
|
import { describe, expect, test, beforeAll, afterAll } from "bun:test";
|
|
import * as fs from "node:fs";
|
|
import * as path from "node:path";
|
|
|
|
import { parsePdfFromFile } from "../src/meta-commands";
|
|
|
|
const FIXTURE_DIR = fs.mkdtempSync(path.join(process.cwd(), "pr1169-pdf-"));
|
|
|
|
beforeAll(() => {
|
|
// mkdtempSync already created the dir
|
|
});
|
|
|
|
afterAll(() => {
|
|
fs.rmSync(FIXTURE_DIR, { recursive: true, force: true });
|
|
});
|
|
|
|
function writeFixture(name: string, body: string): string {
|
|
const p = path.join(FIXTURE_DIR, name);
|
|
fs.writeFileSync(p, body);
|
|
return p;
|
|
}
|
|
|
|
describe("parsePdfFromFile — invalid JSON regression (PR #1169 bug #7)", () => {
|
|
test("invalid JSON: throws with file path AND parser detail", () => {
|
|
const p = writeFixture("invalid.json", "{ not-json");
|
|
expect(() => parsePdfFromFile(p)).toThrow(/not valid JSON/);
|
|
expect(() => parsePdfFromFile(p)).toThrow(p);
|
|
});
|
|
|
|
test("empty file: throws JSON-parse style error", () => {
|
|
const p = writeFixture("empty.json", "");
|
|
// Empty string is invalid JSON per ECMA-404.
|
|
expect(() => parsePdfFromFile(p)).toThrow(/not valid JSON/);
|
|
});
|
|
|
|
test("top-level array: throws 'must be a JSON object' with type", () => {
|
|
const p = writeFixture("array.json", JSON.stringify(["a", "b"]));
|
|
expect(() => parsePdfFromFile(p)).toThrow(/must be a JSON object/);
|
|
expect(() => parsePdfFromFile(p)).toThrow(/array/);
|
|
});
|
|
|
|
test("top-level number: throws with 'number' type label", () => {
|
|
const p = writeFixture("number.json", "42");
|
|
expect(() => parsePdfFromFile(p)).toThrow(/must be a JSON object/);
|
|
expect(() => parsePdfFromFile(p)).toThrow(/number/);
|
|
});
|
|
|
|
test("top-level string: throws with 'string' type label", () => {
|
|
const p = writeFixture("string.json", JSON.stringify("hello"));
|
|
expect(() => parsePdfFromFile(p)).toThrow(/must be a JSON object/);
|
|
expect(() => parsePdfFromFile(p)).toThrow(/string/);
|
|
});
|
|
|
|
test("top-level null: throws with 'object' type label (JS null typeof === object)", () => {
|
|
const p = writeFixture("null.json", "null");
|
|
// null passes typeof === 'object' but the fix's `=== null` branch catches it.
|
|
expect(() => parsePdfFromFile(p)).toThrow(/must be a JSON object/);
|
|
});
|
|
|
|
test("top-level boolean: throws with 'boolean' type label", () => {
|
|
const p = writeFixture("bool.json", "true");
|
|
expect(() => parsePdfFromFile(p)).toThrow(/must be a JSON object/);
|
|
expect(() => parsePdfFromFile(p)).toThrow(/boolean/);
|
|
});
|
|
|
|
test("valid object: parses successfully (happy-path regression)", () => {
|
|
const p = writeFixture("valid.json", JSON.stringify({ format: "A4", pageNumbers: true }));
|
|
const result = parsePdfFromFile(p);
|
|
expect(result.format).toBe("A4");
|
|
expect(result.pageNumbers).toBe(true);
|
|
});
|
|
});
|