UNPKG

thenavisapp

Version:

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

164 lines (133 loc) 5.27 kB
import type { ParserOptions, TreeAdapter, TreeAdapterTypeMap, ParserError } from 'parse5'; import * as fs from 'node:fs'; import * as path from 'node:path'; import * as assert from 'node:assert'; import { serializeToDatFileFormat } from './serialize-to-dat-file-format.js'; import { generateTestsForEachTreeAdapter } from './common.js'; import { parseDatFile, type DatFile } from './parse-dat-file.js'; export interface TreeConstructionTestData<T extends TreeAdapterTypeMap> extends DatFile<T> { idx: number; setName: string; dirName: string; } export function loadTreeConstructionTestData<T extends TreeAdapterTypeMap>( dataDir: URL, treeAdapter: TreeAdapter<T>, ): TreeConstructionTestData<T>[] { const tests: TreeConstructionTestData<T>[] = []; const dataDirPath = dataDir.pathname; const testSetFileNames = fs.readdirSync(dataDir); const dirName = path.basename(dataDirPath); for (const fileName of testSetFileNames) { if (path.extname(fileName) !== '.dat') { continue; } const filePath = path.join(dataDirPath, fileName); const testSet = fs.readFileSync(filePath, 'utf8'); const setName = fileName.replace('.dat', ''); for (const [idx, test] of parseDatFile(testSet, treeAdapter).entries()) { tests.push({ ...test, idx, setName, dirName, }); } } return tests; } function prettyPrintParserAssertionArgs(actual: string, expected: string, chunks?: string[]): string { let msg = '\nExpected:\n'; msg += '-----------------\n'; msg += `${expected}\n`; msg += '\nActual:\n'; msg += '-----------------\n'; msg += `${actual}\n`; if (chunks) { msg += 'Chunks:\n'; msg += JSON.stringify(chunks); } return msg; } interface ParseMethodOptions<T extends TreeAdapterTypeMap> extends ParserOptions<T> { treeAdapter: TreeAdapter<T>; } interface ParseResult<T extends TreeAdapterTypeMap> { node: T['node']; chunks?: string[]; } type ParseMethod<T extends TreeAdapterTypeMap> = ( input: TreeConstructionTestData<T>, options: ParseMethodOptions<T>, ) => ParseResult<T> | Promise<ParseResult<T>>; function createParsingTest<T extends TreeAdapterTypeMap>( test: TreeConstructionTestData<T>, treeAdapter: TreeAdapter<T>, parse: ParseMethod<T>, { withoutErrors, expectError }: { withoutErrors?: boolean; expectError?: boolean } = {}, ): () => Promise<void> { return async (): Promise<void> => { const errs: string[] = []; const opts = { scriptingEnabled: test.scriptingEnabled, treeAdapter, onParseError: (err: ParserError): void => { let errStr = `(${err.startLine}:${err.startCol}`; // NOTE: use ranges for token errors if (err.startLine !== err.endLine || err.startCol !== err.endCol) { errStr += `-${err.endLine}:${err.endCol}`; } errStr += `) ${err.code}`; errs.push(errStr); }, }; const { node, chunks } = await parse(test, opts); const actual = serializeToDatFileFormat(node, opts.treeAdapter); const msg = prettyPrintParserAssertionArgs(actual, test.expected, chunks); let sawError = false; try { assert.ok(actual === test.expected, msg); if (!withoutErrors) { assert.deepEqual(errs.sort(), test.expectedErrors.sort()); } } catch (error) { if (expectError) { return; } sawError = true; throw error; } if (!sawError && expectError) { throw new Error(`Expected error but none was thrown`); } }; } // TODO: Stop using the fork here. const treePath = new URL('../data/html5lib-tests-fork/tree-construction', import.meta.url); export function generateParsingTests( name: string, prefix: string, { withoutErrors, expectErrors: expectError = [], suitePath = treePath, }: { withoutErrors?: boolean; expectErrors?: string[]; suitePath?: URL }, parse: ParseMethod<TreeAdapterTypeMap>, ): void { generateTestsForEachTreeAdapter(name, (treeAdapter) => { const errorsToExpect = new Set(expectError); for (const test of loadTreeConstructionTestData(suitePath, treeAdapter)) { const expectError = errorsToExpect.delete(`${test.idx}.${test.setName}`); it( `${prefix}(${test.dirName}) - ${test.idx}.${test.setName} - \`${test.input}\` (line ${test.lineNum})`, createParsingTest<TreeAdapterTypeMap>(test, treeAdapter, parse, { withoutErrors, expectError, }), ); } if (errorsToExpect.size > 0) { throw new Error(`Expected errors were not found: ${[...errorsToExpect].join(', ')}`); } }); }