glados-chamber
Version:
Simple unit testing library
328 lines (283 loc) • 8.08 kB
JavaScript
// Config stuff
const chalk = require('chalk')
const fs = require('fs')
const path = require('path')
const ctx = new chalk.Instance({level: 3})
const player = require('play-sound')(opts = {})
const stackTrace = require('stack-trace')
let loc = ''
let backup = {}
let args = {
voice: false,
applause: true,
'error-quit': true,
production: false,
silent: false
}
let devMode = false
let cliMode = false
// --- API ---
// Match results to be the same
const equal = create((success, error) => {
return (...args) => {
let item = args[0]
for (const arg of args) {
if (arg === item) item = arg
else return error(`Given values don't match: ${args.join(', ')}`)
}
success()
}
})
// Match results to not be the same
const nequal = create((success, error) => {
return (...args) => {
let item = null
if (args[0] === null) item = undefined
for (const arg of args) {
if (arg !== item) item = arg
else return error(`Given values do match: ${args.join(', ')}`)
}
success()
}
})
// // Test result to return true
const test = create((success, error) => {
return callback => {
const value = callback()
if (value)
success()
else
error('Test didn\'t return true value')
}
})
// If codeblock ran well
const succeed = create((success, error) => {
return callback => {
try {
callback()
success()
}
catch (e) {
error('Executed code didn\'t succeed')
}
}
})
// If codeblock failed with exception
const fail = create((success, error) => {
return callback => {
try {
callback()
error('Executed code didn\'t fail')
}
catch (e) {
success()
}
}
})
// --- CLI ---
if (require.main === module) {
// Parse Arguments
for (const arg of process.argv.slice(2)) {
if (arg.slice(0, 2) === '--') {
if (arg.slice(2, 5) === 'no-'){
args[arg.slice(5)] = false
}
else {
args[arg.slice(2)] = true
}
}
else {
loc = arg
}
}
cliMode = true
cli()
}
// --- STD ---
// Show error when something is wrong
function error({title, reason, text, code}) {
console.log(ctx.hex('#000').bold.bgRed('️ ERROR '), chalk.dim.red(title || 'Something went wrong'))
if (reason)
console.log(chalk.red('\n\tReason:'), chalk.dim.red(reason), (text) ? '': '\n')
if (text)
console.log(chalk.dim.red(`\t${text}\n`))
if (code == null) code = 1
process.exitCode = code
if (args['error-quit'])
process.exit(code)
}
// Show success when something succeeded
function success({title}) {
if (args.silent && !devMode) return null
console.log(chalk.green(' ✓'), chalk.dim.green(title || 'Done'))
}
// Create a new testing schema
function create(exec) {
return (title, ...argv) => {
if (args.production) return null
const suc = (arg = {}) => success(Object.assign({title}, arg))
const err = (arg = {}, text) => {
if (typeof arg === 'string') {
arg = { reason: arg }
}
if (typeof text === 'string') {
arg.text = text
}
error(Object.assign({title}, arg))
}
const func = exec(suc, err, title)
if (devMode) console.log(`\n${trace(true)}`)
return func(...argv)
}
}
// --- DEV ---
// Trace location
function trace(style = false) {
let pathreg = /[\\\/]([^\\\/]+)$/
let filename = ''
let line = 0
if (cliMode) {
filename = pathreg.exec(loc)[1]
line = stackTrace.get()[2].getLineNumber()
}
else {
filename = pathreg.exec(stackTrace.get()[2].getFileName())[1]
line = stackTrace.get()[2].getLineNumber()
}
if (style) return chalk.gray(`(${filename}:${line})${(cliMode) ? ' [cli]': ''}`)
return [filename, line]
}
// Toggle dev mode
function dev(bool) {
if (bool == null)
throw 'Bad parameter passed when trying to toggle dev mode (Glados)'
if (bool) {
console.log(chalk.gray(`Started Dev Mode ${trace(true)}`))
devMode = true
}
else {
console.log(chalk.gray(`Stopped Dev Mode ${trace(true)}`))
devMode = false
}
}
// Run this in CLI
function cli() {
// Module resolution
const req = require
require = (module) => {
if (module[0] === '.') {
return req(path.join(process.env.PWD, module))
}
else return req(module)
}
// When there is no file provided
if (!loc.length) {
error({
title: 'Bad Input',
reason: 'Please, provide path to testing file\n',
code: 2
})
}
// Get absolute path to the script
loc = path.join(process.env.PWD, loc)
// Spit error when script does not exist
if (!fs.existsSync(loc)) {
error({
title: 'Bad Input',
reason: 'Filepath does not exist',
text: loc,
code: 2
})
}
// Run script
let script = fs.readFileSync(loc, 'utf-8')
console.log(ctx.hex('#000').bold.bgYellow('️ START '), chalk.yellow('Opening chamberlock...\n'))
if (args.production) {
alert('Production flag is on - no tests are going to perform\n')
}
eval(script)
}
// Play Glados voiceline
function say(type) {
if (!args.voice) return null
// Proceed to saying something
if (type === 'start') {
const index = Math.floor(Math.random() * 5) + 1
player.play(path.join(__dirname, `/audio/start/start${index}.wav`), () => {})
}
else if (type === 'success') {
const index = Math.floor(Math.random() * 5) + 1
player.play(path.join(__dirname, `/audio/success/success${index}.wav`), () => {})
}
else if (type === 'error') {
const index = Math.floor(Math.random() * 5) + 1
player.play(path.join(__dirname, `/audio/error/error${index}.wav`), () => {})
}
else if (type === 'file') {
player.play(path.join(__dirname, `/audio/error/file.wav`), () => {})
}
}
// Log information
function log(value) {
if (args.production || args.silent) return null
if (devMode) console.log(`\n${trace(true)}`)
console.log(chalk.blue(' ℹ'), chalk.dim.blue(value))
}
// Prompt a warning
function warn(value) {
if (args.production || args.silent) return null
if (devMode) console.log(`\n${trace(true)}`)
console.log(chalk.yellow(' ⚠'), chalk.yellow(value))
}
// Prompt a warning
function alert(value) {
if (devMode) console.log(`\n${trace(true)}`)
console.log(ctx.hex('#000').bold.bgKeyword('orange')('️ ALERT '), ctx.keyword('orange')(value))
}
// Change confguration of glados
function config(obj) {
let prox = new Proxy(args, {
get(obj, prop) {
prop = prop.replace(/([A-Z])/g, (match, group) => {
return '-' + group.toLowerCase()
})
return obj[prop]
},
set(obj, prop, value) {
prop = prop.replace(/([A-Z])/g, (match, group) => {
return '-' + group.toLowerCase()
})
obj[prop] = value
return true
}
})
Object.assign(prox, obj)
return prox
}
// On exit sum up success
process.on('exit', (code) => {
if (code === 0) {
if (!args.applause) return null
if (args.silent) return null
if (args.production) return null
say('success')
console.log(chalk.green('\nDone 🎉'))
console.log(chalk.green('All tests passed\n'))
}
if (code == 1) say('error')
if (code == 2) say('file')
})
module.exports = {
equal,
nequal,
test,
succeed,
fail,
log,
warn,
alert,
config,
create,
dev
}