fast-check
Version:
Property based testing framework for JavaScript (like QuickCheck)
82 lines (81 loc) • 2.99 kB
JavaScript
import { Stream } from '../../stream/Stream.js';
import { cloneIfNeeded, cloneMethod } from '../../check/symbols.js';
import { Arbitrary } from '../../check/arbitrary/definition/Arbitrary.js';
import { Value } from '../../check/arbitrary/definition/Value.js';
import { safeMap, safePush, safeSlice } from '../../utils/globals.js';
import { makeLazy } from '../../stream/LazyIterableIterator.js';
const safeArrayIsArray = Array.isArray;
const safeObjectDefineProperty = Object.defineProperty;
function tupleMakeItCloneable(vs, values) {
return safeObjectDefineProperty(vs, cloneMethod, {
value: () => {
const cloned = [];
for (let idx = 0; idx !== values.length; ++idx) {
safePush(cloned, values[idx].value);
}
tupleMakeItCloneable(cloned, values);
return cloned;
},
});
}
function tupleWrapper(values) {
let cloneable = false;
const vs = [];
const ctxs = [];
for (let idx = 0; idx !== values.length; ++idx) {
const v = values[idx];
cloneable = cloneable || v.hasToBeCloned;
safePush(vs, v.value);
safePush(ctxs, v.context);
}
if (cloneable) {
tupleMakeItCloneable(vs, values);
}
return new Value(vs, ctxs);
}
export function tupleShrink(arbs, value, context) {
const shrinks = [];
const safeContext = safeArrayIsArray(context) ? context : [];
for (let idx = 0; idx !== arbs.length; ++idx) {
safePush(shrinks, makeLazy(() => arbs[idx]
.shrink(value[idx], safeContext[idx])
.map((v) => {
const nextValues = safeMap(value, (v, idx) => new Value(cloneIfNeeded(v), safeContext[idx]));
return [...safeSlice(nextValues, 0, idx), v, ...safeSlice(nextValues, idx + 1)];
})
.map(tupleWrapper)));
}
return Stream.nil().join(...shrinks);
}
export class TupleArbitrary extends Arbitrary {
constructor(arbs) {
super();
this.arbs = arbs;
for (let idx = 0; idx !== arbs.length; ++idx) {
const arb = arbs[idx];
if (arb == null || arb.generate == null)
throw new Error(`Invalid parameter encountered at index ${idx}: expecting an Arbitrary`);
}
}
generate(mrng, biasFactor) {
const mapped = [];
for (let idx = 0; idx !== this.arbs.length; ++idx) {
safePush(mapped, this.arbs[idx].generate(mrng, biasFactor));
}
return tupleWrapper(mapped);
}
canShrinkWithoutContext(value) {
if (!safeArrayIsArray(value) || value.length !== this.arbs.length) {
return false;
}
for (let index = 0; index !== this.arbs.length; ++index) {
if (!this.arbs[index].canShrinkWithoutContext(value[index])) {
return false;
}
}
return true;
}
shrink(value, context) {
return tupleShrink(this.arbs, value, context);
}
}