Skip to content

Commit

Permalink
implement repetition of tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dmonad committed Mar 2, 2019
1 parent 7044390 commit 35a3e8a
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 47 deletions.
1 change: 1 addition & 0 deletions array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const last = arr => arr[arr.length - 1]
15 changes: 7 additions & 8 deletions diff.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ export const testDiffing = tc => {
runDiffTest('abc', 'xyz', { pos: 0, remove: 3, insert: 'xyz' })
runDiffTest('axz', 'au', { pos: 1, remove: 2, insert: 'u' })
runDiffTest('ax', 'axy', { pos: 2, remove: 0, insert: 'y' })
}

t.describe(`Running ${tc.repititions} random tests`)
for (let i = 0; i < tc.repititions; i++) {
const a = prng.word(tc.prng)
const b = prng.word(tc.prng)
const change = simpleDiff(a, b)
const recomposed = `${a.slice(0, change.pos)}${change.insert}${a.slice(change.pos + change.remove)}`
t.compareStrings(recomposed, b)
}
export const testRepeatDiffing = tc => {
const a = prng.word(tc.prng)
const b = prng.word(tc.prng)
const change = simpleDiff(a, b)
const recomposed = `${a.slice(0, change.pos)}${change.insert}${a.slice(change.pos + change.remove)}`
t.compareStrings(recomposed, b)
}
21 changes: 7 additions & 14 deletions encoding.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,11 @@ export const testVarUintEncoding = tc => {
test('varUint 3 bytes', writeVarUint, readVarUint, 1 << 17 | 1 << 9 | 3)
test('varUint 4 bytes', writeVarUint, readVarUint, 1 << 25 | 1 << 17 | 1 << 9 | 3)
test('varUint of 2839012934', writeVarUint, readVarUint, 2839012934)
}

t.describe(`Running ${tc.repititions} random tests on varUint`)
let allUtf8ByteLength = 0
let allBinaryByteLength = 0
for (let i = 0; i < tc.repititions; i++) {
const n = prng.int31(tc.prng, 0, (1 << 28) - 1)
const { utf8ByteLength, binaryByteLength } = test(`varUint of ${n}`, writeVarUint, readVarUint, n, false)
allUtf8ByteLength += utf8ByteLength
allBinaryByteLength += binaryByteLength
}
t.describe(`compression of ${math.round((allBinaryByteLength / allUtf8ByteLength) * 100)}%`)
export const testRepeatVarUintEncoding = tc => {
const n = prng.int31(tc.prng, 0, (1 << 28) - 1)
test(`varUint of ${n}`, writeVarUint, readVarUint, n, false)
}

export const testStringEncoding = tc => {
Expand All @@ -107,8 +101,7 @@ export const testStringEncoding = tc => {
testVarString('쾟')
testVarString('龟') // surrogate length 3
testVarString('😝') // surrogate length 4
t.describe(`Running ${tc.repititions} random tests on varString`)
for (let i = 0; i < tc.repititions; i++) {
testVarString(prng.utf16String(tc.prng))
}
}

export const testRepeatStringEncoding = tc =>
testVarString(prng.utf16String(tc.prng))
1 change: 1 addition & 0 deletions math.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @module math
*/
export const floor = Math.floor
export const ceil = Math.ceil

export const round = Math.round

Expand Down
24 changes: 13 additions & 11 deletions prng.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Mt19937 } from './prng/Mt19937.js'
import * as dom from './dom.js'
import { isBrowser } from './environment.js'

const genTestData = 5000

/**
* @param {t.TestCase} tc
* @param {prng.PRNG} gen
Expand All @@ -20,7 +22,7 @@ const runGenTest = (tc, gen) => {
let b
let i

for (i = 0; i < tc.repititions; i++) {
for (i = 0; i < genTestData; i++) {
b = prng.bool(gen)
if (b) {
head++
Expand All @@ -29,17 +31,17 @@ const runGenTest = (tc, gen) => {
}
}
t.info(`Generated ${head} heads and ${tail} tails.`)
t.assert(tail >= Math.floor(tc.repititions * 0.48), 'Generated enough tails.')
t.assert(head >= Math.floor(tc.repititions * 0.48), 'Generated enough heads.')
t.assert(tail >= Math.floor(genTestData * 0.48), 'Generated enough tails.')
t.assert(head >= Math.floor(genTestData * 0.48), 'Generated enough heads.')
})
t.group('int31 - integers average correctly', () => {
let count = 0
let i

for (i = 0; i < tc.repititions; i++) {
for (i = 0; i < genTestData; i++) {
count += prng.int31(gen, 0, 100)
}
const average = count / tc.repititions
const average = count / genTestData
const expectedAverage = 100 / 2
t.info(`Average is: ${average}. Expected average is ${expectedAverage}.`)
t.assert(Math.abs(average - expectedAverage) <= 2, 'Expected average is at most 1 off.')
Expand All @@ -49,7 +51,7 @@ const runGenTest = (tc, gen) => {
let num = 0
let i
let newNum
for (i = 0; i < tc.repititions; i++) {
for (i = 0; i < genTestData; i++) {
newNum = prng.int32(gen, 0, BITS32)
if (newNum > num) {
num = newNum
Expand All @@ -63,7 +65,7 @@ const runGenTest = (tc, gen) => {
let num = 0
let i
let newNum
for (i = 0; i < tc.repititions; i++) {
for (i = 0; i < genTestData; i++) {
newNum = prng.int31(gen, 0, BITS31)
if (newNum > num) {
num = newNum
Expand All @@ -77,7 +79,7 @@ const runGenTest = (tc, gen) => {
let num = 0
let i
let newNum
for (i = 0; i < tc.repititions; i++) {
for (i = 0; i < genTestData; i++) {
newNum = prng.real53(gen) * MAX_SAFE_INTEGER
if (newNum > num) {
num = newNum
Expand All @@ -93,7 +95,7 @@ const runGenTest = (tc, gen) => {
for (let i = chars.length - 1; i >= 0; i--) {
charSet.add(chars[i])
}
for (let i = 0; i < tc.repititions; i++) {
for (let i = 0; i < genTestData; i++) {
const char = prng.char(gen)
charSet.delete(char)
}
Expand All @@ -114,14 +116,14 @@ export const testGeneratorMt19937 = tc => runGenTest(tc, new Mt19937(tc.seed))
* @param {t.TestCase} tc
*/
const printDistribution = (gen, tc) => {
const DIAMETER = tc.repititions / 50
const DIAMETER = genTestData / 50
const canvas = dom.canvas(DIAMETER * 3, DIAMETER)
const ctx = canvas.getContext('2d')
if (ctx == null) {
return t.skip()
}
ctx.fillStyle = 'blue'
for (let i = 0; i < tc.repititions; i++) {
for (let i = 0; i < genTestData; i++) {
const x = prng.int31(gen, 0, DIAMETER * 3)
const y = prng.int31(gen, 0, DIAMETER)
ctx.fillRect(x, y, 1, 2)
Expand Down
10 changes: 10 additions & 0 deletions statistics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

import * as math from './math.js'

/**
* @param {Array<number>} arr Array of values
* @return {number}
*/
export const median = arr => (arr[math.floor(arr.length / 2)] + arr[math.ceil(arr.length / 2)]) / 2

export const average = arr => arr.reduce(math.add, 0) / arr.length
45 changes: 31 additions & 14 deletions testing.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import * as string from './string.js'
import * as math from './math.js'
import * as random from './random.js'
import * as prng from './prng.js'
import * as statistics from './statistics.js'
import * as array from './array.js'

const seed = random.uint32()

Expand All @@ -20,7 +22,6 @@ export class TestCase {
this.prng = prng.create(seed)
this.moduleName = moduleName
this.testName = testName
this.repititions = 5000
}
get seed () {
return seed
Expand All @@ -32,39 +33,54 @@ const perf = typeof performance === 'undefined'
? require('perf_hooks').performance
: performance // eslint-disable-line no-undef

const repititionTime = 50

const repeatTestRegex = /^(repeat|repeating)\s/

export const run = async (moduleName, name, f, i, numberOfTests) => {
const t = new TestCase(moduleName, name)
const uncamelized = string.fromCamelCase(name.slice(4), ' ')
const repeat = repeatTestRegex.test(uncamelized)
log.groupCollapsed(log.GREY, `[${i + 1}/${numberOfTests}] `, log.PURPLE, `${moduleName}: `, log.BLUE, uncamelized)
perf.mark(`${name}-start`)
let err = null
const times = []
const start = perf.now()
try {
const p = f(t)
if (p != null && p.constructor === Promise) {
await p
let lastTime = start
do {
try {
const p = f(t)
if (p != null && p.constructor === Promise) {
await p
}
} catch (_err) {
err = _err
}
} catch (_err) {
err = _err
}
const end = perf.now()
const currTime = perf.now()
times.push(currTime - lastTime)
lastTime = currTime
} while (repeat && err === null && (lastTime - start) < repititionTime)
perf.mark(`${name}-end`)
if (err !== null && err.constructor !== SkipError) {
log.printError(err)
}
log.groupEnd()
perf.measure(name, `${name}-start`, `${name}-end`)
const duration = end - start
const duration = lastTime - start
let success = true
times.sort()
const timeInfo = repeat
? ` - ${times.length} repititions in ${duration.toFixed(2)}ms (best: ${times[0].toFixed(2)}ms, worst: ${array.last(times).toFixed(2)}ms, median: ${statistics.median(times).toFixed(2)}ms, average: ${statistics.average(times).toFixed(2)}ms)`
: ` in ${duration.toFixed(2)}ms`
if (err !== null) {
if (err.constructor === SkipError) {
log.print(log.GREY, log.BOLD, 'Skipped: ', log.UNBOLD, uncamelized)
} else {
success = false
log.print(log.RED, log.BOLD, 'Failure: ', log.UNBOLD, log.UNCOLOR, uncamelized, log.GREY, ` in ${duration}ms`)
log.print(log.RED, log.BOLD, 'Failure: ', log.UNBOLD, log.UNCOLOR, uncamelized, log.GREY, timeInfo)
}
} else {
log.print(log.GREEN, log.BOLD, 'Success: ', log.UNBOLD, log.UNCOLOR, uncamelized, log.GREY, ` in ${duration}ms`)
log.print(log.GREEN, log.BOLD, 'Success: ', log.UNBOLD, log.UNCOLOR, uncamelized, log.GREY, timeInfo)
}
return success
}
Expand Down Expand Up @@ -188,6 +204,7 @@ export const runTests = async tests => {
const numberOfTests = object.map(tests, mod => object.map(mod, f => f ? 1 : 0).reduce(math.add, 0)).reduce(math.add, 0)
let successfulTests = 0
let i = 0
const start = perf.now()
for (const modName in tests) {
const mod = tests[modName]
for (const fname in mod) {
Expand All @@ -200,10 +217,10 @@ export const runTests = async tests => {
}
}
}

const end = perf.now()
log.print('')
if (successfulTests === numberOfTests) {
log.print(log.GREEN, log.BOLD, 'All tests successful!')
log.print(log.GREEN, log.BOLD, 'All tests successful!', log.GREY, log.UNBOLD, ` in ${(end - start).toFixed(2)}ms`)
log.printImgBase64(nyanCatImage, 50)
} else {
const failedTests = numberOfTests - successfulTests
Expand Down
10 changes: 10 additions & 0 deletions testing.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as t from './testing.js'
import * as math from './math.js'

export const testComparing = () => {
t.compare({}, {})
Expand All @@ -18,3 +19,12 @@ export const testSkipping = () => {
t.skip()
t.fail('should have skipped')
}

export const testRepeatRepitition = () => {
const arr = []
const n = 100
for (let i = 1; i <= n; i++) {
arr.push(i)
}
t.assert(arr.reduce(math.add, 0) === (n+1)*n/2, 'We can count the smart way')
}

0 comments on commit 35a3e8a

Please sign in to comment.