114 lines
3.6 KiB
JavaScript
114 lines
3.6 KiB
JavaScript
|
// Allows browsers to perform doctests.
|
||
|
// Uses the code highlight package from http://highlightjs.readthedocs.io
|
||
|
// if available
|
||
|
|
||
|
var docTestLogMessages = []
|
||
|
|
||
|
Array.prototype.equals = function(array) {
|
||
|
return this.length == array.length &&
|
||
|
this.every( function(this_i,i) { return this_i == array[i] } )
|
||
|
}
|
||
|
|
||
|
export default class Doctest {
|
||
|
|
||
|
static assert(value) {
|
||
|
if (!value) {
|
||
|
throw new Error('Assertion violated')
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static pprint(obj) {
|
||
|
if (obj === null)
|
||
|
return 'null'
|
||
|
let stringified = obj.toString()
|
||
|
if (stringified == '[object Object]')
|
||
|
return JSON.stringify(obj)
|
||
|
return stringified
|
||
|
}
|
||
|
|
||
|
static expect(expr, value) {
|
||
|
if (this.pprint(expr) != this.pprint(value)) {
|
||
|
//throw new Error("got `" + expr + "` but expected `" + value + "`.")
|
||
|
throw new Error('got `' + this.pprint(expr) + '` but expected `' + this.pprint(value) + '`.')
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static expectError(error, message) {
|
||
|
let index = error.toString().indexOf(message)
|
||
|
if (index < 0) {
|
||
|
throw new Error('got `' + message + '` but expected `' + error + '`.')
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static expectLog(...messages) {
|
||
|
// if (!docTestLogMessages.equals(messages)) {
|
||
|
docTestLogMessages.forEach((msg, i) => {
|
||
|
if (msg != messages[i])
|
||
|
throw new Error('Unexpected log message: `' + messages[i] + '`.')
|
||
|
})
|
||
|
// throw new Error('Uups')
|
||
|
//}
|
||
|
}
|
||
|
|
||
|
static log(message) {
|
||
|
docTestLogMessages.push(message)
|
||
|
}
|
||
|
|
||
|
static highlight(code) {
|
||
|
if (typeof(hljs) == 'undefined')
|
||
|
return code
|
||
|
return hljs.highlight('javascript', code)
|
||
|
}
|
||
|
|
||
|
static stripLeadingLines(code) {
|
||
|
let result = []
|
||
|
let informative = false
|
||
|
for(let line of code.split('\n')) {
|
||
|
if (line.trim().length > 0) {
|
||
|
informative = true
|
||
|
}
|
||
|
if (informative)
|
||
|
result.push(line)
|
||
|
}
|
||
|
return result.join('\n')
|
||
|
}
|
||
|
|
||
|
static event(type='mouse', {clientX = 0, clientY = 0} = {}) {
|
||
|
if (type.startsWith('mouse')) {
|
||
|
return new MouseEvent(type, { clientX, clientY })
|
||
|
}
|
||
|
return { type, clientX, clientY }
|
||
|
}
|
||
|
|
||
|
static run(replaceExpect=false) {
|
||
|
if (typeof(hljs) != 'undefined') {
|
||
|
hljs.initHighlighting()
|
||
|
}
|
||
|
let doctests = document.querySelectorAll('.doctest')
|
||
|
for(let i=0; i<doctests.length; i++) {
|
||
|
let doctest = doctests[i]
|
||
|
let code = this.stripLeadingLines(doctest.innerHTML)
|
||
|
let text = this.highlight(code)
|
||
|
let pre = document.createElement('pre')
|
||
|
// See http://stackoverflow.com/questions/1068280/javascript-regex-multiline-flag-doesnt-work
|
||
|
// let re = /Doctest\.expect\(([\s\S]*)[\,\s\S]*([\s\S]*)\)/g
|
||
|
let lines = text.value.split('\n')
|
||
|
let better = []
|
||
|
for(let line of lines) {
|
||
|
if (replaceExpect && line.trim().startsWith('Doctest.expect(')) {
|
||
|
line = line.replace(/Doctest\.expect\(/, '>>> ').trim()
|
||
|
if (line.endsWith(')') || line.endsWith(',')) {
|
||
|
line = line.slice(0, -1)
|
||
|
}
|
||
|
}
|
||
|
better.push(line)
|
||
|
}
|
||
|
pre.innerHTML = better.join('\n') // text.value.replace(re, ">>> $1\n$2")
|
||
|
doctest.parentNode.replaceChild(pre, doctest)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Needed to make Doctest visible in modules
|
||
|
//window.Doctest = Doctest
|