90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
|
/**
|
||
|
* Unit tests framework
|
||
|
*/
|
||
|
//% weight=100 color=#0fbc11 icon=""
|
||
|
namespace tests {
|
||
|
class Test {
|
||
|
name: string;
|
||
|
handler: () => void;
|
||
|
errors: string[];
|
||
|
|
||
|
constructor(name: string, handler: () => void) {
|
||
|
this.name = name;
|
||
|
this.handler = handler;
|
||
|
this.errors = [];
|
||
|
}
|
||
|
|
||
|
reset() {
|
||
|
motors.stopAllMotors();
|
||
|
motors.resetAllMotors();
|
||
|
}
|
||
|
|
||
|
run() {
|
||
|
// clear state
|
||
|
this.reset();
|
||
|
|
||
|
console.log(`# ${this.name}`)
|
||
|
this.handler()
|
||
|
|
||
|
// ensure clean state after test
|
||
|
this.reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let _tests: Test[] = undefined;
|
||
|
let _currentTest: Test = undefined;
|
||
|
|
||
|
function run() {
|
||
|
if (!_tests) return;
|
||
|
|
||
|
const start = control.millis();
|
||
|
console.sendToScreen();
|
||
|
console.log(`${_tests.length} tests`)
|
||
|
for (let i = 0; i < _tests.length; ++i) {
|
||
|
const t = _currentTest = _tests[i];
|
||
|
t.run();
|
||
|
_currentTest = undefined;
|
||
|
}
|
||
|
console.log(`${_tests.map(t => t.errors.length).reduce((p, c) => p + c, 0)} X, ${Math.ceil((control.millis() - start) / 1000)}s`)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Registers a test to run
|
||
|
*/
|
||
|
//% blockId=testtest block="test %name"
|
||
|
export function test(name: string, handler: () => void): void {
|
||
|
if (!name || !handler) return;
|
||
|
if (!_tests) {
|
||
|
_tests = [];
|
||
|
control.runInBackground(function () {
|
||
|
// should run after on start
|
||
|
loops.pause(100)
|
||
|
run()
|
||
|
})
|
||
|
}
|
||
|
_tests.push(new Test(name, handler));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks a boolean condition
|
||
|
*/
|
||
|
//% blockId=testAssert block="assert %message|%condition"
|
||
|
export function assert(message: string, condition: boolean) {
|
||
|
if (!condition) {
|
||
|
console.log(` X ${message || ''}`)
|
||
|
if (_currentTest)
|
||
|
_currentTest.errors.push(message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks that 2 values are close to each other
|
||
|
* @param expected what the value should be
|
||
|
* @param actual what the value was
|
||
|
* @param tolerance the acceptable error margin
|
||
|
*/
|
||
|
export function assertClose(name: string, expected: number, actual: number, tolerance: number) {
|
||
|
assert(`${name} ${expected} != ${actual} +-${tolerance}`, Math.abs(expected - actual) <= tolerance);
|
||
|
}
|
||
|
}
|