+++ /dev/null
-// SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
-// 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 }
<head>
<link rel="icon" href="./favicon.ico">
- <script type="module" src="./test-tools.mjs"></script>
<script type="module" src="../dist/global.min.js"></script>
- <script type="module" src="https://zoso.dev/?p=nano-pow.git;a=blob_plain;f=test-tools.mjs;hb=refs/heads/main"></script>
<script type="module" src="https://zoso.dev/?p=nano-pow.git;a=blob_plain;f=dist/global.min.js;hb=refs/heads/main"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/nano-webgl-pow@1.1.1/nano-webgl-pow.js"></script>
<script type="module">
- const { assert, average, print, random, skip, suite, test } = TOOLING
const { NanoPowGl, NanoPowGpu } = NanoPow
const COUNT = 0x4
let times = []
+ 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
+ }
+
+ 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
+ }
+ }
+
+ 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`)
+ }
+
+
console.log(`%cNanoPowGpu `, 'color:green', `Calculate proof-of-work for ${COUNT} unique send block hashes`)
times = []
for (let i = 0; i < COUNT; i++) {