Add a tester script
This commit is contained in:
144
tools/tester.js
Normal file
144
tools/tester.js
Normal file
@ -0,0 +1,144 @@
|
||||
import { glob } from 'glob'
|
||||
import path from 'path'
|
||||
import childProcess from 'node:child_process'
|
||||
import fs from 'node:fs/promises'
|
||||
import chalk from 'chalk'
|
||||
|
||||
// Define constants.
|
||||
const tmp = path.resolve('./build/riscv')
|
||||
const toolDirectory = path.resolve('./build/tools')
|
||||
|
||||
async function compileTest (parsedPath) {
|
||||
const testObject = path.join(tmp, `tests/${parsedPath.name}.o`)
|
||||
const compilerArguments = [
|
||||
'-o', testObject,
|
||||
path.join(parsedPath.dir, parsedPath.base)
|
||||
]
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const compilerChild = childProcess.spawn('./build/bin/elna', compilerArguments)
|
||||
const buffers = []
|
||||
|
||||
compilerChild.stdout.on('data', data => buffers.push(data))
|
||||
compilerChild.stderr.on('data', data => buffers.push(data))
|
||||
|
||||
compilerChild.on('exit', function (code, signal) {
|
||||
resolve({
|
||||
code: code === null ? signal : code,
|
||||
output: Buffer.concat(buffers).toString(),
|
||||
object: testObject
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function checkFailure (parsedPath, buildResult) {
|
||||
const diffArguments = [
|
||||
'-u', '--color=always',
|
||||
path.resolve('./tests/failures', `${parsedPath.name}.txt`),
|
||||
'-'
|
||||
]
|
||||
|
||||
try {
|
||||
childProcess.execFileSync('diff', diffArguments, {
|
||||
input: buildResult.output,
|
||||
stdio: ['pipe', 'inherit', 'inherit']
|
||||
})
|
||||
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function buildTest (parsedPath) {
|
||||
const linker = path.join(toolDirectory, 'rootfs/riscv32-unknown-linux-gnu/bin/ld')
|
||||
const testBinary = path.join(tmp, 'root/tests', parsedPath.name)
|
||||
const testObject = path.join(tmp, `tests/${parsedPath.name}.o`)
|
||||
|
||||
childProcess.execFileSync(linker, ['-o', testBinary, testObject])
|
||||
}
|
||||
|
||||
async function cpioArchive () {
|
||||
const cwd = path.join(tmp, 'root')
|
||||
const cpioImage = path.join(tmp, 'root.cpio')
|
||||
const rootFiles = (await glob(path.join(cwd, '**')))
|
||||
.map(file => path.relative(cwd, file))
|
||||
.filter(file => file !== '')
|
||||
const cpioFile = await fs.open(cpioImage, 'w')
|
||||
const cpioStream = cpioFile.createWriteStream()
|
||||
try {
|
||||
const cpioChild = childProcess.execSync('cpio -o --format=newc', {
|
||||
stdio: ['pipe', cpioStream, 'ignore'],
|
||||
input: rootFiles.join("\n"),
|
||||
cwd,
|
||||
shell: false
|
||||
})
|
||||
return cpioImage
|
||||
} finally {
|
||||
await cpioFile.close()
|
||||
}
|
||||
}
|
||||
|
||||
async function runVM(cpioImage) {
|
||||
const kernels = await glob(path.join(toolDirectory, 'linux-*/arch/riscv/boot/Image'))
|
||||
const vmArguments = [
|
||||
'-nographic',
|
||||
'-M', 'virt',
|
||||
'-bios', 'default',
|
||||
'-kernel', kernels[0],
|
||||
'-append', 'quiet',
|
||||
'-initrd', cpioImage
|
||||
]
|
||||
childProcess.execFileSync('qemu-system-riscv32', vmArguments, {
|
||||
stdio: ['ignore', 'inherit', 'inherit']
|
||||
});
|
||||
}
|
||||
|
||||
async function runInDirectory (directoryPath) {
|
||||
const testSources = await glob(path.join(directoryPath, '*.eln'))
|
||||
let failed = 0
|
||||
|
||||
for (const testEntry of testSources) {
|
||||
console.log(`Compiling ${path.basename(testEntry)}.`)
|
||||
|
||||
const parsedPath = path.parse(testEntry)
|
||||
const buildResult = await compileTest(parsedPath)
|
||||
|
||||
if (buildResult.output !== '') {
|
||||
if (!(await checkFailure(parsedPath, buildResult))) {
|
||||
++failed
|
||||
}
|
||||
continue
|
||||
}
|
||||
buildTest(parsedPath)
|
||||
}
|
||||
const rootDirectory = path.join(tmp, 'root')
|
||||
await fs.cp('./tests/expectations', path.join(rootDirectory, 'expectations'), { recursive: true })
|
||||
await fs.cp(path.join(toolDirectory, 'init'), path.join(rootDirectory, 'init'));
|
||||
const cpioImage = await cpioArchive()
|
||||
await runVM(cpioImage)
|
||||
|
||||
return {
|
||||
total: testSources.length,
|
||||
failed,
|
||||
|
||||
passed () {
|
||||
return this.total - this.failed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function createDirectories () {
|
||||
await fs.rm(tmp, { recursive: true, force: true })
|
||||
await fs.mkdir(path.join(tmp, 'tests'), { recursive: true })
|
||||
await fs.mkdir(path.join(tmp, 'root/tests'), { recursive: true })
|
||||
}
|
||||
|
||||
console.log('Run all tests and check the results.')
|
||||
|
||||
await createDirectories()
|
||||
const results = await runInDirectory('./tests')
|
||||
|
||||
const summaryMessage = `${results.total} tests run, ${results.passed()} passed, ${results.failed} failed.`
|
||||
console.log(results.failed === 0 ? chalk.green(summaryMessage) : chalk.yellow(summaryMessage))
|
Reference in New Issue
Block a user