rapid-check
Advanced tools
Comparing version 0.2.0 to 0.3.0
{ | ||
"name": "rapid-check", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"main": "src/index.js", | ||
@@ -11,4 +11,7 @@ "author": "jan.brecka@gmail.com", | ||
"devDependencies": { | ||
"jest": "^21.2.1" | ||
"jest": "^23.0.0" | ||
}, | ||
"jest": { | ||
"transform": {} | ||
} | ||
} |
@@ -5,2 +5,6 @@ # rapid-check [![CircleCI](https://circleci.com/gh/honzabrecka/rapid-check/tree/master.svg?style=svg&circle-token=14045240bf5689c38b0a3dcbf478a2f012ab6574)](https://circleci.com/gh/honzabrecka/rapid-check/tree/master) | ||
## Prerequisities | ||
It's based on async generators, therefore it requires nodejs >=10. | ||
## Installation | ||
@@ -14,17 +18,13 @@ | ||
Works with any testing framework, here's example using [jest](https://facebook.github.io/jest/): | ||
Works with any testing framework, here's an example using [jest >=23](https://facebook.github.io/jest/): | ||
```js | ||
it('tests Set.has function', () => { | ||
const s = new Set([1, 2, 3]) | ||
const prop = (v) => s.has(v) | ||
const [result, _] = forAll(choose(1, 3), prop) | ||
expect(result).toBe(true) | ||
}) | ||
const { gen } = require('rapid-check') | ||
const toMatchProperty = require('rapid-check/src/jest.matcher') | ||
it('tests async Set.has function', async () => { | ||
const s = new Set([1, 2, 3]) | ||
const prop = (v) => Promise.resolve(s.has(v)) | ||
const [result, _] = await asyncForAll(choose(1, 3), prop) | ||
expect(result).toBe(true) | ||
expect.extend({ toMatchProperty }) | ||
test('Set.has function', async () => { | ||
const prop = (v) => new Set([1, 2, 3]).has(v) | ||
await expect(gen.choose(1, 3)).toMatchProperty(prop) | ||
}) | ||
@@ -31,0 +31,0 @@ ``` |
@@ -13,3 +13,3 @@ const rng = require('./rng') | ||
const { shrink, asyncShrink } = require('./shrink') | ||
const { shrink } = require('./shrink') | ||
@@ -22,3 +22,3 @@ const defaultSampleCount = 10 | ||
function* sampleG(rng, gen, count = defaultSampleCount) { | ||
function* sampleGen(rng, gen, count = defaultSampleCount) { | ||
for (let i = 0; i < count; i++) | ||
@@ -29,27 +29,14 @@ yield gen(rng, Math.floor(i / 2) + 1) | ||
const sample = (gen, count = defaultSampleCount) => | ||
intoArray(map(([v, _]) => v), sampleG(rng(timestamp()), gen, count)) | ||
intoArray(map(([v, _]) => v), sampleGen(rng(timestamp()), gen, count)) | ||
function shrinkFailing(tree, prop) { | ||
return reduce( | ||
([reduced, [lastFailingNode, attempts, shrinks]], [result, node]) => | ||
[reduced, [ | ||
result ? lastFailingNode : node, | ||
attempts + 1, | ||
shrinks + (result ? 0 : 1) | ||
]], | ||
[tree, 0, 0] | ||
)(shrink(tree[1], prop)) | ||
} | ||
const shrinkTupleToMap = ([[min, _], attempts, shrinks]) => ({ | ||
min, | ||
attempts, | ||
shrinks, | ||
}) | ||
async function asyncShrinkFailing(tree, prop) { | ||
const gen = asyncShrink(tree[1], prop) | ||
let current | ||
let result | ||
async function shrinkFailing(tree, prop) { | ||
let reduced = [tree, 0, 0] | ||
let node | ||
while (!(current = gen.next()).done) { | ||
result = await current.value; | ||
[result, node] = gen.next(result).value | ||
for await (const [result, node] of shrink(tree[1], prop)) { | ||
reduced = [ | ||
@@ -65,4 +52,5 @@ result ? reduced[0] : node, | ||
const forAll = (gen, prop, count = defaultForAllCount) => { | ||
const samples = sampleG(rng(timestamp()), gen, count) | ||
const forAll = async (gen, prop, { count, seed } = {}) => { | ||
seed = seed || timestamp() | ||
const samples = sampleGen(rng(seed), gen, count || defaultForAllCount) | ||
let sample | ||
@@ -73,25 +61,14 @@ let result | ||
sample = sample.value | ||
result = prop(sample[0]) | ||
if (!result) | ||
return [false, shrinkFailing(sample, prop)] | ||
} | ||
return [true, sample] | ||
} | ||
const asyncForAll = async (gen, prop, count = defaultForAllCount) => { | ||
const samples = sampleG(rng(timestamp()), gen, count) | ||
let sample | ||
let result | ||
while (!(sample = samples.next()).done) { | ||
sample = sample.value | ||
result = await prop(sample[0]) | ||
if (!result) | ||
return [false, await asyncShrinkFailing(sample, prop)] | ||
return { | ||
success: false, | ||
seed, | ||
shrink: shrinkTupleToMap(await shrinkFailing(sample, prop)), | ||
fail: sample, | ||
} | ||
} | ||
return [true, sample] | ||
return { success: true, seed } | ||
} | ||
@@ -101,4 +78,4 @@ | ||
sample, | ||
sampleGen, | ||
forAll, | ||
asyncForAll, | ||
} |
@@ -1,2 +0,2 @@ | ||
const { sample, forAll, asyncForAll } = require('./check') | ||
const { sample, sampleGen, forAll } = require('./check') | ||
const generators = require('./generators') | ||
@@ -6,5 +6,6 @@ | ||
sample, | ||
sampleGen, | ||
forAll, | ||
asyncForAll, | ||
generators, | ||
gen: generators | ||
} |
@@ -1,9 +0,2 @@ | ||
const { | ||
comp, | ||
intoArray, | ||
takeWhile, | ||
map, | ||
range, | ||
conj | ||
} = require('./core') | ||
const { conj } = require('./core') | ||
@@ -66,3 +59,3 @@ const { RoseTree, rvalue } = require('./rosetree') | ||
function* shrink(nextChildren, prop) { | ||
async function* shrink(nextChildren, prop) { | ||
let children = nextChildren() | ||
@@ -75,3 +68,3 @@ let i = 0 | ||
[value, nextChildren] = children[i] | ||
result = prop(value) | ||
result = await prop(value) | ||
@@ -89,23 +82,2 @@ if (result) { | ||
function* asyncShrink(nextChildren, prop) { | ||
let children = nextChildren() | ||
let i = 0 | ||
let result | ||
let value | ||
while (i < children.length) { | ||
[value, nextChildren] = children[i] | ||
result = yield prop(value) | ||
if (result) { | ||
i++ | ||
} else { | ||
i = 0 | ||
children = nextChildren() | ||
} | ||
yield ShrinkResult(result, RoseTree(value, nextChildren)) | ||
} | ||
} | ||
module.exports = { | ||
@@ -116,3 +88,2 @@ roundTowardZero, | ||
shrink, | ||
asyncShrink, | ||
} |
12
12299
355