Files
pdf/wasm/pdfengine.test.mjs
2026-06-22 15:18:47 +05:30

125 lines
5.5 KiB
JavaScript

import { strict as assert } from "node:assert";
import { existsSync } from "node:fs";
import { fileURLToPath, pathToFileURL } from "node:url";
import { dirname, resolve } from "node:path";
const here = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(here, "..");
const enginePath =
process.env.PDFENGINE_MJS ?? resolve(repoRoot, "out/build/wasm/bin/pdfengine.mjs");
if (!existsSync(enginePath)) {
console.error(
`[pdfengine-smoke] pdfengine.mjs not found at: ${enginePath}\n` +
`Did you run \`cmake --build --preset wasm\` first?`,
);
process.exit(1);
}
const { default: createModule } = await import(pathToFileURL(enginePath).href);
const Module = await createModule();
const buildInfo = Module.ccall("engineBuildInfo", "string", [], []);
console.log(`[pdfengine-smoke] buildInfo: "${buildInfo}"`);
assert.ok(buildInfo && buildInfo.toLowerCase().includes("pdfengine"), `unexpected buildInfo: ${buildInfo}`);
const hasSkia = Module.ccall("engineHasSkia", "number", [], []);
console.log(`[pdfengine-smoke] hasSkia: ${hasSkia}`);
assert.equal(hasSkia, 0);
const mockPdfData = new TextEncoder().encode("%PDF-1.4\n1 0 obj\n<< /Type /Page >>\nendobj\n2 0 obj\n<< /Type /Page >>\nendobj\n");
const dataSize = mockPdfData.length;
const dataPtr = Module._malloc(dataSize);
Module.HEAPU8.set(mockPdfData, dataPtr);
const loadDocument = Module.cwrap("loadDocument", "number", ["number", "number"]);
const docHandle = loadDocument(dataPtr, dataSize);
console.log(`[pdfengine-smoke] docHandle: ${docHandle}`);
assert.ok(docHandle > 0, "loadDocument should return a valid handle (> 0)");
const renderPage = Module.cwrap("renderPage", "number", ["number", "number", "number", "number", "number", "number"]);
const width = 100;
const height = 100;
const bufferSize = width * height * 4;
const outputBufferPtr = Module._malloc(bufferSize);
const renderResult = renderPage(docHandle, 0, 1.0, outputBufferPtr, width, height);
console.log(`[pdfengine-smoke] renderResult: ${renderResult}`);
assert.equal(renderResult, 1, "renderPage should return 1 for success");
const pixels = new Uint8Array(Module.HEAPU8.buffer, outputBufferPtr, bufferSize);
assert.equal(pixels[0], 0);
assert.equal(pixels[1], 0);
assert.equal(pixels[2], 0);
assert.equal(pixels[3], 255);
const renderResultPage1 = renderPage(docHandle, 1, 1.0, outputBufferPtr, width, height);
assert.equal(renderResultPage1, 1, "renderPage should return 1 for page 1");
const pixelsPage1 = new Uint8Array(Module.HEAPU8.buffer, outputBufferPtr, bufferSize);
const idx10_10 = (10 * width + 10) * 4;
assert.equal(pixelsPage1[idx10_10 + 0], 0);
assert.equal(pixelsPage1[idx10_10 + 1], 0);
assert.equal(pixelsPage1[idx10_10 + 2], 0);
assert.equal(pixelsPage1[idx10_10 + 3], 255);
const renderResultOob = renderPage(docHandle, 3, 1.0, outputBufferPtr, width, height);
assert.equal(renderResultOob, 0, "renderPage should return 0 for out-of-bounds page index");
const freeDocument = Module.cwrap("freeDocument", "void", ["number"]);
freeDocument(docHandle);
Module._free(dataPtr);
Module._free(outputBufferPtr);
const dataPtr2 = Module._malloc(dataSize);
Module.HEAPU8.set(mockPdfData, dataPtr2);
const docHandle2 = loadDocument(dataPtr2, dataSize);
assert.ok(docHandle2 > 0, "second loadDocument should return valid handle");
const getDocumentFonts = Module.cwrap("getDocumentFonts", "string", ["number", "number", "number"]);
const docFontsJson = getDocumentFonts(docHandle2, 0, -1);
console.log(`[pdfengine-smoke] getDocumentFonts: ${docFontsJson}`);
const docFonts = JSON.parse(docFontsJson);
assert.ok(Array.isArray(docFonts), "getDocumentFonts should return a JSON array");
assert.ok(docFonts.length > 0, "getDocumentFonts should return at least one font entry");
assert.equal(docFonts[0].fontName, "Helvetica", "font name should be Helvetica");
assert.equal(docFonts[0].sourceType, "Substituted", "sourceType should be Substituted");
assert.ok(docFonts[0].substitutedTo.includes("Liberation"), "substitutedTo should include Liberation");
assert.equal(docFonts[0].isEmbedded, false, "Helvetica should not be embedded");
const getPageFonts = Module.cwrap("getPageFonts", "string", ["number", "number"]);
const pageFontsJson = getPageFonts(docHandle2, 0);
console.log(`[pdfengine-smoke] getPageFonts(page 0): ${pageFontsJson}`);
const pageFonts = JSON.parse(pageFontsJson);
assert.ok(Array.isArray(pageFonts), "getPageFonts should return a JSON array");
assert.ok(pageFonts.length > 0, "getPageFonts should return at least one entry");
assert.equal(pageFonts[0].substitutedFrom, "Helvetica");
assert.ok(pageFonts[0].ascent > 0, "font ascent should be positive");
assert.ok(pageFonts[0].descent < 0, "font descent should be negative");
const invalidFontsJson = getDocumentFonts(9999, 0, -1);
assert.equal(invalidFontsJson, "[]", "invalid docHandle should return empty array");
const getPageTextJson = Module.cwrap("getPageTextJson", "string", ["number", "number"]);
const pageTextJson = getPageTextJson(docHandle2, 0);
console.log(`[pdfengine-smoke] getPageTextJson(page 0): ${pageTextJson}`);
const pageText = JSON.parse(pageTextJson);
assert.ok(Array.isArray(pageText), "getPageTextJson should return a JSON array");
assert.ok(pageText.length > 0, "getPageTextJson should return at least one entry");
assert.equal(pageText[0].text, "P", "First char text should be P");
assert.ok(pageText[0].fontSize > 0, "font size should be positive");
assert.ok(pageText[0].x > 0, "x should be positive");
assert.ok(pageText[0].y > 0, "y should be positive");
freeDocument(docHandle2);
Module._free(dataPtr2);
console.log("[pdfengine-smoke] ALL TESTS PASSED SUCCESSFULLY!");