From 1ee3aef85cbccca502fea3dc54d9a250da14cc35 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Fri, 10 Jan 2025 21:50:42 -0800 Subject: [PATCH] Deprecate unnecessary test tooling file and just include the few functions being used in the test page itself. --- test-tools.mjs | 231 ------------------------------------------------- test.html | 45 +++++++++- 2 files changed, 42 insertions(+), 234 deletions(-) delete mode 100644 test-tools.mjs diff --git a/test-tools.mjs b/test-tools.mjs deleted file mode 100644 index 65c5c78..0000000 --- a/test-tools.mjs +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Chris Duncan -// SPDX-License-Identifier: GPL-3.0-or-later - -export function random (size = 32) { - const bytes = new Uint8Array(size) - crypto.getRandomValues(bytes) - let hex = '' - for (let i = 0; i < size; i++) hex += bytes[i].toString(16).padStart(2, '0') - return hex -} - -export function average (times) { - let count = times.length, sum = 0, reciprocals = 0, logarithms = 0, truncated = 0, min = 0xffff, max = 0 - times.sort() - for (let i = 0; i < count; i++) { - sum += times[i] - reciprocals += 1 / times[i] - logarithms += Math.log(times[i]) - min = Math.min(min, times[i]) - max = Math.max(max, times[i]) - if (i > (count * 0.1) && i < (count * 0.9)) truncated += times[i] - } - return { - total: sum, - arithmetic: sum / count, - harmonic: count / reciprocals, - geometric: Math.exp(logarithms / count), - truncated: truncated / count, - min: min, - max: max - } -} - -export function print (times) { - const { arithmetic, geometric, harmonic, min, max, total, truncated } = average(times) - console.log(`Total: ${total} ms`) - console.log(`Average: ${arithmetic} ms`) - console.log(`Harmonic: ${harmonic} ms`) - console.log(`Geometric: ${geometric} ms`) - console.log(`Truncated: ${truncated} ms`) - console.log(`Minimum: ${min} ms`) - console.log(`Maximum: ${max} ms`) -} - -const failures = [] -const passes = [] -function fail (...args) { - failures.push(args) - console.error(`%cFAIL `, 'color:red', ...args) -} -function pass (...args) { - passes.push(args) - console.log(`%cPASS `, 'color:green', ...args) -} - -/** -* Who watches the watchers? -*/ -await suite('TEST RUNNER CHECK', async () => { - console.assert(failures.length === 0) - console.assert(passes.length === 0) - - await test('promise should pass', new Promise(resolve => { resolve('') })) - console.assert(failures.some(call => /.*promise should pass.*/.test(call[0])) === false, `good promise errored`) - console.assert(passes.some(call => /.*promise should pass.*/.test(call[0])) === true, `good promise not logged`) - - await test('promise should fail', new Promise((resolve, reject) => { reject('FAILURE EXPECTED HERE') })) - console.assert(failures.some(call => /.*promise should fail.*/.test(call[0])) === true, `bad promise not errored`) - console.assert(passes.some(call => /.*promise should fail.*/.test(call[0])) === false, 'bad promise logged') - - await test('async should pass', async () => {}) - console.assert(failures.some(call => /.*async should pass.*/.test(call[0])) === false, 'good async errored') - console.assert(passes.some(call => /.*async should pass.*/.test(call[0])) === true, 'good async not logged') - - await test('async should fail', async () => { throw new Error('FAILURE EXPECTED HERE') }) - console.assert(failures.some(call => /.*async should fail.*/.test(call[0])) === true, 'bad async not errored') - console.assert(passes.some(call => /.*async should fail.*/.test(call[0])) === false, 'bad async logged') - - await test('function should pass', () => {}) - console.assert(failures.some(call => /.*function should pass.*/.test(call[0])) === false, 'good function errored') - console.assert(passes.some(call => /.*function should pass.*/.test(call[0])) === true, 'good function not logged') - - await test('function should fail', 'FAILURE EXPECTED HERE') - console.assert(failures.some(call => /.*function should fail.*/.test(call[0])) === true, 'bad function not errored') - console.assert(passes.some(call => /.*function should fail.*/.test(call[0])) === false, 'bad function logged') - - console.log(`%cTEST RUNNER CHECK DONE`, 'font-weight:bold') -}) - -export function skip (name, fn) { - return new Promise(resolve => { - console.log(`%cSKIP `, 'color:blue', name) - resolve(null) - }) -} - -export function suite (name, fn) { - if (fn.constructor.name === 'AsyncFunction') fn = fn() - if (typeof fn === 'function') fn = new Promise(resolve => resolve(fn())) - return new Promise(async (resolve) => { - console.group(`%c${name}`, 'font-weight:bold') - await fn - console.groupEnd() - resolve(null) - }) -} - -export function test (name, fn) { - if (fn instanceof Promise) { - try { - return fn - .then(() => pass(name)) - .catch((err) => { fail(`${name}: ${err}`) }) - } catch (err) { - fail(`${name}: ${err.message}`) - fail(err) - } - } else if (fn?.constructor?.name === 'AsyncFunction') { - try { - return fn() - .then(() => pass(name)) - .catch((err) => fail(`${name}: ${err.message}`)) - } catch (err) { - fail(`${name}: ${err.message}`) - fail(err) - } - } else if (typeof fn === 'function') { - try { - fn() - pass(name) - } catch (err) { - fail(`${name}: ${err.message}`) - fail(err) - } - } else { - fail(`${name}: test cannot execute on ${typeof fn} ${fn}`) - } -} - -export const assert = { - ok: (bool) => { - if (typeof bool !== 'boolean') { - throw new Error('Invalid assertion') - } - if (!bool) { - throw new Error(`test result falsy`) - } - return true - }, - exists: (a) => { - if (a == null) { - const type = /^[aeiou]/i.test(typeof a) ? `an ${typeof a}` : `a ${typeof a}` - throw new Error(`argument exists and is ${type}`) - } - return a != null - }, - equals: (a, b) => { - if (a == null || b == null) { - throw new Error(`assert.equals() will not compare null or undefined`) - } - if (a !== b) { - throw new Error(`${a} not equal to ${b}`) - } - return a === b - }, - notEqual: (a, b) => { - if (a == null || b == null) { - throw new Error(`assert.notEqual() will not compare null or undefined`) - } - if (a === b) { - throw new Error(`${a} equals ${b}`) - } - return a !== b - }, - rejects: async (fn, msg) => { - if (fn instanceof Promise) { - try { - fn.then(() => { throw new Error(msg ?? 'expected async function to reject') }) - .catch((err) => { return true }) - } catch (err) { - return true - } - } else if (fn.constructor.name === 'AsyncFunction') { - try { - fn.then(() => { throw new Error(msg ?? 'expected async function to reject') }) - .catch((err) => { return true }) - } catch (err) { - return true - } - } else { - throw new Error(msg ?? 'expected async function') - } - }, - resolves: async (fn, msg) => { - if (fn instanceof Promise) { - try { - fn.then(() => { return true }) - .catch((err) => { throw new Error(msg ?? 'expected async function to resolve') }) - return true - } catch (err) { - throw new Error(msg ?? 'expected async function to resolve') - } - } else if (fn.constructor.name === 'AsyncFunction') { - try { - fn().then(() => { return true }) - .catch((err) => { throw new Error(msg ?? 'expected async function to resolve') }) - return true - } catch (err) { - throw new Error(msg ?? 'expected async function to resolve') - } - } else { - throw new Error('expected async function') - } - }, - throws: (fn, msg) => { - if (typeof fn !== 'function') { - throw new Error('expected function') - } - if (fn instanceof Promise || fn.constructor.name === 'AsyncFunction') { - throw new Error('expected synchronous function') - } - try { - fn() - throw new Error(msg ?? `expected function to throw an exception`) - } catch (err) { - return true - } - } -} - -globalThis.TOOLING ??= { assert, average, print, random, skip, suite, test } diff --git a/test.html b/test.html index b9987b4..5f3810b 100644 --- a/test.html +++ b/test.html @@ -7,17 +7,56 @@ SPDX-License-Identifier: GPL-3.0-or-later - -