1
1
mirror of https://github.com/theoludwig/programming-challenges.git synced 2024-07-18 02:20:12 +02:00
programming-challenges/scripts/test.ts
2020-07-05 15:48:51 +02:00

196 lines
5.2 KiB
TypeScript

import util from 'util'
import path from 'path'
import * as fsWithCallbacks from 'fs'
import childProcess from 'child_process'
import { performance } from 'perf_hooks'
import chalk from 'chalk'
import deleteAllFilesExceptOne from './utils/deleteAllFilesExceptOne'
import emoji from 'node-emoji'
import prettyMilliseconds from 'pretty-ms'
import { table } from 'table'
;(async () => {
const fs = fsWithCallbacks.promises
const exec = util.promisify(childProcess.exec)
const args = process.argv.slice(2)
const [challengeName, solutionName] = args
if (!challengeName || !solutionName) {
console.log(`
Please specify the challenge and solution name:
${chalk.cyan(`npm run test [challenge-name] [solution-name]`)}
For example:
${chalk.cyan('npm run test hello-world python-hello')}
`)
process.exit(0)
}
const challengePath = path.resolve(
__dirname,
'..',
'challenges',
challengeName
)
const solutionFolderPath = path.resolve(
challengePath,
'solutions',
solutionName
)
// Challenge valid ?
try {
await fs.access(challengePath)
} catch {
console.log(`The challenge was not found: ${chalk.red(challengeName)}`)
process.exit(0)
}
// Solution valid ?
try {
await fs.access(solutionFolderPath)
} catch {
console.log(`The solution was not found: ${chalk.red(solutionName)}`)
process.exit(0)
}
// Determinate the language to execute
const solutionFilesName = await fs.readdir(solutionFolderPath)
let solutionFilePath
for (const solutionFileName of solutionFilesName) {
const fileName = solutionFileName
.split('.')
.slice(0, -1)
.join('.')
if (fileName === 'solution') {
solutionFilePath = solutionFileName
break
}
}
if (!solutionFilePath) {
console.log(`The ${chalk.red('solution')} file was not found.`)
process.exit(0)
}
const languages: {
name: string
extension: string
launch: string
}[] = require('./languages-wrapper/_languages.json')
const extensionSolution = path.extname(solutionFilePath)
const languageToExecute = languages.find(
language => language.extension === extensionSolution
)
if (!languageToExecute) {
console.log(`Sadly, this ${chalk.red('language')} is not supported yet.`)
process.exit(0)
}
// Copy 'solution' and 'execute' files in temp
const inputOutputJSON: { input: any[]; output: any }[] = require(path.join(
__dirname,
'..',
'challenges',
challengeName,
'input-output.json'
))
const tempPath = path.join(__dirname, '..', 'temp')
const executeFile = `execute${languageToExecute.extension}`
const executeLanguagePath = path.resolve(
__dirname,
'languages-wrapper',
executeFile
)
const executeLanguageTempPath = path.join(tempPath, executeFile)
const inputPath = path.join(tempPath, 'input.json')
const outputPath = path.join(tempPath, 'output.json')
await fs.copyFile(
path.resolve(solutionFolderPath, solutionFilePath),
path.join(tempPath, solutionFilePath)
)
await fs.copyFile(executeLanguagePath, executeLanguageTempPath)
// Console.log & Tests
const totalCorrect = {
total: 0,
correct: 0
}
const tableResult = [
[
chalk.cyan('Result'),
chalk.cyan('Input'),
chalk.cyan('Output'),
chalk.cyan('Expected output')
]
]
const startTest = performance.now()
// Loop I/O
for (const { input, output } of inputOutputJSON) {
// Write input.json
const inputStringify = JSON.stringify(input)
await fs.writeFile(inputPath, inputStringify)
// Execute script (create output.json)
try {
await exec(`${languageToExecute.launch} ${executeLanguageTempPath}`)
} catch (error) {
console.log(chalk.bgRedBright.black(error.stderr))
await deleteAllFilesExceptOne(tempPath, '.gitignore')
process.exit(0)
}
// Read output.json
const data = await fs.readFile(outputPath)
const outputJSON = JSON.parse(data.toString())
// Tests
totalCorrect.total += 1
const outputJSONStringify = JSON.stringify(outputJSON)
const outputStringify = JSON.stringify(output)
const isCorrect = outputJSONStringify === outputStringify
if (isCorrect) {
tableResult.push([
emoji.get('white_check_mark'),
inputStringify,
outputJSONStringify,
outputStringify
])
totalCorrect.correct += 1
} else {
tableResult.push([
emoji.get('x'),
inputStringify,
outputJSONStringify,
outputStringify
])
}
// Delete I/O file
await fs.unlink(inputPath)
await fs.unlink(outputPath)
}
const endTest = performance.now()
console.log(
table(tableResult, {
columns: {
0: { width: 6, alignment: 'center' },
1: { width: 20, wrapWord: true },
2: { width: 30, wrapWord: true },
3: { width: 30, wrapWord: true }
}
})
)
console.log(`
Challenge : ${challengeName}
Solution : ${solutionName}
Tests : ${chalk.green(`${totalCorrect.correct} passed`)}, ${
totalCorrect.total
} total
Time : ${chalk.yellow(prettyMilliseconds(endTest - startTest))}
`)
await deleteAllFilesExceptOne(tempPath, '.gitignore')
})()