Terrace/test/helpers.js
Joshua Bemenderfer 9d9757e868 Updates.
2025-09-08 16:24:38 -04:00

115 lines
3.2 KiB
JavaScript

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 reader = createFileReader(path)
const doc = useDocument(reader)
const descriptions = {}
let currentSuite = null
let currentTest = null
for await (const node of doc) {
if (node.head === '#schema') {
// Skip schema declarations
continue
}
if (node.head === 'describe') {
currentSuite = node.tail
descriptions[currentSuite] = []
continue
}
if (node.head === 'it' && currentSuite) {
currentTest = {
it: node.tail,
packages: [],
key: '',
input: '',
output: ''
}
descriptions[currentSuite].push(currentTest)
// Collect test properties
let collectingInput = false
let collectingOutput = false
let inputLevel = 0
for await (const child of node.children()) {
if (child.head === 'key') {
currentTest.key = child.tail
} else if (child.head === 'packages') {
currentTest.packages = child.tail.split(' ')
} else if (child.head === 'input') {
collectingInput = true
collectingOutput = false
inputLevel = child.level
// If input has content on the same line
if (child.tail) {
currentTest.input = child.tail
}
} else if (child.head === 'output') {
collectingInput = false
collectingOutput = true
// If output has content on the same line
if (child.tail) {
currentTest.output = child.tail
}
} else if (collectingInput) {
// Collect input lines
currentTest.input += (currentTest.input ? '\n' : '') + child.raw(inputLevel + 1)
} else if (collectingOutput) {
// Collect output lines
currentTest.output += (currentTest.output ? '\n' : '') + child.content
}
}
// Process escape sequences
if (typeof currentTest.input === 'string') {
currentTest.input = currentTest.input
.replaceAll('\\n', '\n')
.replaceAll('\\t', '\t')
.replaceAll('\\s', ' ')
}
if (typeof currentTest.output === 'string') {
currentTest.output = currentTest.output.trimEnd()
}
continue
}
}
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())
})
}