mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 21:14:28 -08:00
initial
This commit is contained in:
4
test/run.js
Normal file
4
test/run.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import {tests} from './test.js'
|
||||
import {run} from './utils.js'
|
||||
|
||||
run(tests)
|
||||
82
test/self_hosted_test.js
Normal file
82
test/self_hosted_test.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import {load_modules} from '../src/parse_js.js'
|
||||
import {eval_modules, eval_frame} from '../src/eval.js'
|
||||
|
||||
import {
|
||||
assert_equal,
|
||||
run,
|
||||
stringify,
|
||||
test,
|
||||
} from './utils.js'
|
||||
|
||||
const entry = `
|
||||
import {parse, load_modules} from './src/parse_js.js';
|
||||
|
||||
import {get_initial_state} from './src/cmd.js';
|
||||
//console.time('p');
|
||||
//const parsed = parse(globalThis.module_cache['./src/parse_js.js']);
|
||||
//console.timeEnd('p');
|
||||
//const parsed = parse('1');
|
||||
|
||||
const loader = module => globalThis.module_cache[module];
|
||||
console.time('p2');
|
||||
load_modules('src/parse_js.js', (m) => {
|
||||
return loader(m)
|
||||
|
||||
});
|
||||
console.timeEnd('p2')
|
||||
//import {} from './test/test.js'
|
||||
`
|
||||
|
||||
globalThis.module_cache = {}
|
||||
|
||||
const load_module = (dir, module) => {
|
||||
return (globalThis.module_cache[module] = fs.readFileSync(dir + module, 'utf8'))
|
||||
}
|
||||
const loader = module => {
|
||||
return module == ''
|
||||
? entry
|
||||
: load_module('./', module)
|
||||
}
|
||||
|
||||
run([
|
||||
test('self-hosted', () => {
|
||||
//console.time('p0')
|
||||
const parsed = load_modules('', loader)
|
||||
//log('cache', Object.keys(globalThis.module_cache))
|
||||
//console.log('p', parsed)
|
||||
//console.timeEnd('p0')
|
||||
if(!parsed.ok) {
|
||||
const p = parsed.problems[0]
|
||||
console.error('FAIL', p.index, p.message, p.module)
|
||||
console.log(loader(p.module).slice(p.index, p.index + 100))
|
||||
} else {
|
||||
assert_equal(parsed.ok, true)
|
||||
console.time('eval')
|
||||
const result = eval_modules(parsed.modules, parsed.sorted).calltree
|
||||
console.timeEnd('eval')
|
||||
|
||||
/* TODO remove
|
||||
|
||||
const count_nodes = node => node.children == null
|
||||
? 1
|
||||
: 1 + node.children.reduce(
|
||||
(total, c) => total + count_nodes(c),
|
||||
0,
|
||||
)
|
||||
console.log(
|
||||
Object.entries(result)
|
||||
.map(([k,v]) => count_nodes(v.calls))
|
||||
.reduce((total, c) => total +c)
|
||||
)
|
||||
*/
|
||||
///const frame = eval_frame(result[''].calls, result)
|
||||
///log('f', frame.children[frame.children.length - 1])
|
||||
///assert_equal(
|
||||
/// frame.children[frame.children.length - 1].result.value.value,
|
||||
/// 1
|
||||
///)
|
||||
}
|
||||
})
|
||||
])
|
||||
1998
test/test.js
Normal file
1998
test/test.js
Normal file
File diff suppressed because it is too large
Load Diff
141
test/utils.js
Normal file
141
test/utils.js
Normal file
@@ -0,0 +1,141 @@
|
||||
import {parse, print_debug_node, load_modules} from '../src/parse_js.js'
|
||||
import {eval_tree, eval_frame} from '../src/eval.js'
|
||||
import {get_initial_state} from '../src/cmd.js'
|
||||
|
||||
Object.assign(globalThis, {log: console.log})
|
||||
|
||||
export const parse_modules = (entry, modules) =>
|
||||
load_modules(entry, module_name => modules[module_name])
|
||||
|
||||
export const assert_code_evals_to = (codestring, expected) => {
|
||||
const parse_result = parse(codestring)
|
||||
assert_equal(parse_result.ok, true)
|
||||
const tree = eval_tree(parse_result.node)
|
||||
const frame = eval_frame(tree)
|
||||
const result = frame.children[frame.children.length - 1].result
|
||||
assert_equal({ok: result.ok, value: result.value}, {ok: true, value: expected})
|
||||
return frame
|
||||
}
|
||||
|
||||
export const assert_code_error = (codestring, error) => {
|
||||
const parse_result = parse(codestring)
|
||||
assert_equal(parse_result.ok, true)
|
||||
const tree = eval_tree(parse_result.node)
|
||||
const frame = eval_frame(tree)
|
||||
const result = frame.children[frame.children.length - 1].result
|
||||
assert_equal(result.ok, false)
|
||||
assert_equal(result.error, error)
|
||||
}
|
||||
|
||||
export const test_initial_state = code => {
|
||||
return get_initial_state({
|
||||
files: typeof(code) == 'object' ? code : { '' : code},
|
||||
entrypoint: '',
|
||||
current_module: '',
|
||||
})
|
||||
}
|
||||
|
||||
export const stringify = val =>
|
||||
JSON.stringify(val, (key, value) => {
|
||||
// TODO do not use instanceof because currently not implemented in parser
|
||||
if(value?.constructor == Set){
|
||||
return [...value]
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}, 2)
|
||||
|
||||
export const assert_equal = (exp, actual) => {
|
||||
if(typeof(exp) == 'object' && typeof(actual) == 'object'){
|
||||
const exp_json = stringify(exp)
|
||||
const act_json = stringify(actual)
|
||||
if(exp_json != act_json){
|
||||
throw new Error(`FAIL: ${exp_json} != ${act_json}`)
|
||||
}
|
||||
} else {
|
||||
if(exp != actual){
|
||||
throw new Error(`FAIL: ${exp} != ${actual}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const print_debug_ct_node = node => {
|
||||
const do_print = node => {
|
||||
const {id, fn, ok, value, error, args, has_more_children} = node
|
||||
const res = {id, fn: fn?.name, ok, value, error, args, has_more_children}
|
||||
if(node.children == null) {
|
||||
return res
|
||||
} else {
|
||||
const next_children = node.children.map(do_print)
|
||||
return {...res, children: next_children}
|
||||
}
|
||||
}
|
||||
return stringify(do_print(node))
|
||||
}
|
||||
|
||||
export const test = (message, test, only = false) => {
|
||||
return {
|
||||
message,
|
||||
test: Object.defineProperty(test, 'name', {value: message}),
|
||||
only,
|
||||
}
|
||||
}
|
||||
|
||||
export const test_only = (message, t) => test(message, t, true)
|
||||
|
||||
// Wrap to Function constructor to hide from calltree view
|
||||
// TODO in calltree view, hide fn which has special flag set (see
|
||||
// filter_calltree)
|
||||
export const run = Object.defineProperty(new Function('tests', `
|
||||
const run_test = t => {
|
||||
try {
|
||||
t.test()
|
||||
} catch(e) {
|
||||
if(globalThis.process != null) {
|
||||
// In node.js runner, fail fast
|
||||
console.error('Failed: ' + t.message)
|
||||
throw e
|
||||
} else {
|
||||
return e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If not run in node, then dont apply filter
|
||||
const filter = globalThis.process && globalThis.process.argv[2]
|
||||
|
||||
if(filter == null) {
|
||||
|
||||
const only = tests.find(t => t.only)
|
||||
const tests_to_run = only == null ? tests : [only]
|
||||
|
||||
// Exec each test. After all tests are done, we rethrow first failer if
|
||||
// any. So we will mark root calltree node if one of tests failed
|
||||
const failure = tests_to_run.reduce(
|
||||
(failure, t) => {
|
||||
const next_failure = run_test(t)
|
||||
return failure ?? next_failure
|
||||
},
|
||||
null
|
||||
)
|
||||
|
||||
if(failure != null) {
|
||||
throw failure
|
||||
} else {
|
||||
if(globalThis.process != null) {
|
||||
console.log('Ok')
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
const test = tests.find(t => t.message.includes(filter))
|
||||
if(test == null) {
|
||||
throw new Error('test not found')
|
||||
} else {
|
||||
run_test(test)
|
||||
if(globalThis.process != null) {
|
||||
console.log('Ok')
|
||||
}
|
||||
}
|
||||
}
|
||||
`), 'name', {value: 'run'})
|
||||
Reference in New Issue
Block a user