const textDecoder = new TextDecoder(); const textEncoder = new TextEncoder(); const linuxCncParameterScratchFiles = ["rs274ngc.var", "rs274ngc.var.new", "rs274ngc.var.bak"]; export function createBrowserSmokeHarness(result) { const sectionResults = []; const near = (actual, expected) => Math.abs(actual - expected) < 1e-6; const waitFor = async (predicate, message) => { for (let i = 0; i < 50; i += 1) { if (predicate()) { return; } await new Promise((resolve) => setTimeout(resolve, 100)); } throw new Error(message); }; const runSection = async (name, action) => { const sectionNumber = sectionResults.length + 1; result.textContent = `running: ${sectionNumber}: ${name}`; try { await action(); sectionResults.push(name); } catch (error) { const detail = error && error.stack ? error.stack : error; throw new Error(`section "${name}" failed: ${detail}`); } }; const completedMessage = () => `browser wasm smoke passed (${sectionResults.length} sections)`; const browserHasOpfs = () => navigator.storage && navigator.storage.getDirectory; const expectEvent = (events, predicate, message) => { if (!events.some(predicate)) { throw new Error(message); } }; const expectNoEvent = (events, predicate, message) => { if (events.some(predicate)) { throw new Error(message); } }; const expectText = (actual, expected, message) => { if (actual !== expected) { throw new Error(message); } }; const expectIncludes = (actual, expected, message) => { if (!actual.includes(expected)) { throw new Error(message); } }; const expectFileList = (actual, expected, message) => { if ( actual.length !== expected.length || expected.some((entry) => !actual.includes(entry)) ) { throw new Error(`${message}: ${actual.join(",")}`); } }; const expectErrorContaining = async (action, expectedText, message) => { try { await action(); throw new Error(message); } catch (error) { if (!String(error?.message ?? error).includes(expectedText)) { throw error; } } }; const expectMissingOpfsFile = async (action, message) => { try { await action(); throw new Error(message); } catch (error) { if (error?.name !== "NotFoundError") { throw error; } } }; const expectMissingWasmPath = (action, message) => { try { action(); throw new Error(message); } catch (error) { if (error?.errno !== 44) { throw error; } } }; const expectWasmFilesMissing = (fs, paths, messageForPath) => { for (const wasmPath of paths) { expectMissingWasmPath( () => fs.readFile(wasmPath), messageForPath(wasmPath), ); } }; const decodeBytes = (bytes) => textDecoder.decode(bytes); const encodeText = (text) => textEncoder.encode(text); const readOpfsText = async (simulator, path) => decodeBytes(await simulator.fs.opfs.readFile(path)); const readWasmText = (simulator, path) => decodeBytes(simulator.fs.module.FS.readFile(path)); const writeWasmText = (simulator, path, text) => simulator.fs.module.FS.writeFile(path, encodeText(text)); const removeWasmPathIfExists = (simulator, path) => { try { simulator.fs.module.FS.unlink(path); } catch (error) { if (error?.errno !== 44) { throw error; } } }; const expectOpfsText = async (simulator, path, expected, message) => { expectText(await readOpfsText(simulator, path), expected, message); }; const expectWasmText = (simulator, path, expected, message) => { expectText(readWasmText(simulator, path), expected, message); }; const expectOpfsExists = async (simulator, path, message) => { if (!(await simulator.fs.opfs.exists(path))) { throw new Error(message); } }; const expectOpfsMissing = async (simulator, path, message) => { if (await simulator.fs.opfs.exists(path)) { throw new Error(message); } }; const expectOpfsFileStat = async (simulator, path, expectedSize, message) => { const stat = await simulator.fs.opfs.stat(path); if (stat.kind !== "file" || stat.size !== expectedSize) { throw new Error(message); } }; const expectOpfsDirectoryStat = async (simulator, path, message) => { const stat = await simulator.fs.opfs.stat(path); if (stat.kind !== "directory" || stat.size !== null) { throw new Error(message); } }; const expectLinuxCncParameterScratchMissing = (simulator, messageForPath) => { for (const parameterPath of linuxCncParameterScratchFiles) { expectMissingWasmPath( () => simulator.fs.module.FS.stat(parameterPath), messageForPath(parameterPath), ); } }; return { browserHasOpfs, completedMessage, decodeBytes, encodeText, expectErrorContaining, expectEvent, expectFileList, expectIncludes, expectLinuxCncParameterScratchMissing, expectMissingOpfsFile, expectMissingWasmPath, expectNoEvent, expectOpfsDirectoryStat, expectOpfsExists, expectOpfsFileStat, expectOpfsMissing, expectOpfsText, expectText, expectWasmFilesMissing, expectWasmText, near, readOpfsText, readWasmText, removeWasmPathIfExists, runSection, waitFor, writeWasmText, }; }