import { expect } from 'chai' import fs from 'node:fs/promises' import { execSync } from 'node:child_process' import { useDocument } from '@terrace-lang/js' import { createFileReader } from '@terrace-lang/js/readers/node-readline' export async function loadTestMap(path) { const { next, level, head, tail, line, match } = useDocument(createFileReader(path)) const descriptions = {} while (await next()) { if (!head() || match('#schema')) continue const tests = descriptions[tail()] = [] const rootLevel = level() while (await next(rootLevel)) { if (!match('it')) continue const test = { it: tail(), packages: [], key: '', input: [], output: [] } tests.push(test) const testLevel = level() while (await next(testLevel)) { if (match('key')) test.key = tail() if (match('packages')) test.packages = tail().split(' ') const propertyLevel = level() if (match('input')) { // TODO: Find a way to handle newlines better. if (tail()) { test.input = tail() continue } while (await next(propertyLevel)) test.input.push(line(propertyLevel + 1)) test.input = test.input.join('\n').trimEnd() } if (match('output')) { while (await next(propertyLevel)) test.output.push(line(propertyLevel + 1)) } } test.input = test.input .replaceAll('\\n', '\n') .replaceAll('\\t', '\t') .replaceAll('\\s', ' ') test.output = test.output.join('\n').trimEnd() .replaceAll('\\n', '\n') .replaceAll('\\t', '\t') .replaceAll('\\s', ' ') } } return descriptions } export function defineTests(testMap) { for (const [name, tests] of Object.entries(testMap)) { describe(name, () => { for (const test of tests) { test.packages.forEach(pkg => { it(`${pkg}: ${test.it}`, async () => { expect(await callTest(pkg, test.key, test.input)).to.equal(test.output) }) }) } }) } } function callTest(pkg, name, input) { return new Promise((resolve, reject) => { const stdout = execSync(`npm run --silent test ${name}`, { cwd: `../packages/${pkg}`, input }) // TODO: Find a way to clean all this trimming up. Most caused by VSCode happily trimming empty spaces off the ends of lines. resolve(stdout.toString().trim()) }) }