fast-check
Version:
Property based testing framework for JavaScript (like QuickCheck)
72 lines (71 loc) • 3.57 kB
JavaScript
import { Stream } from '../../stream/Stream.js';
import { Arbitrary } from './definition/Arbitrary.js';
import { biasWrapper } from './definition/BiasedArbitraryWrapper.js';
import { Shrinkable } from './definition/Shrinkable.js';
import { integer } from './IntegerArbitrary.js';
import { makeLazy } from '../../stream/LazyIterableIterator.js';
class SubarrayArbitrary extends Arbitrary {
constructor(originalArray, isOrdered, minLength, maxLength) {
super();
this.originalArray = originalArray;
this.isOrdered = isOrdered;
this.minLength = minLength;
this.maxLength = maxLength;
if (minLength < 0 || minLength > originalArray.length)
throw new Error('fc.*{s|S}ubarrayOf expects the minimal length to be between 0 and the size of the original array');
if (maxLength < 0 || maxLength > originalArray.length)
throw new Error('fc.*{s|S}ubarrayOf expects the maximal length to be between 0 and the size of the original array');
if (minLength > maxLength)
throw new Error('fc.*{s|S}ubarrayOf expects the minimal length to be inferior or equal to the maximal length');
this.lengthArb = integer(minLength, maxLength);
}
wrapper(items, shrunkOnce) {
return new Shrinkable(items, () => this.shrinkImpl(items, shrunkOnce).map((v) => this.wrapper(v, true)));
}
generate(mrng) {
const remainingElements = this.originalArray.map((v, idx) => idx);
const size = this.lengthArb.generate(mrng).value;
const ids = [];
for (let idx = 0; idx !== size; ++idx) {
const selectedIdIndex = mrng.nextInt(0, remainingElements.length - 1);
ids.push(remainingElements[selectedIdIndex]);
remainingElements.splice(selectedIdIndex, 1);
}
if (this.isOrdered)
ids.sort((a, b) => a - b);
return this.wrapper(ids.map((i) => this.originalArray[i]), false);
}
shrinkImpl(items, shrunkOnce) {
if (items.length === 0) {
return Stream.nil();
}
const size = this.lengthArb.shrinkableFor(items.length, shrunkOnce);
return size
.shrink()
.map((l) => items.slice(items.length - l.value))
.join(items.length > this.minLength
? makeLazy(() => this.shrinkImpl(items.slice(1), false)
.filter((vs) => this.minLength <= vs.length + 1)
.map((vs) => [items[0]].concat(vs)))
: Stream.nil());
}
withBias(freq) {
return this.minLength !== this.maxLength
? biasWrapper(freq, this, (originalArbitrary) => {
return new SubarrayArbitrary(originalArbitrary.originalArray, originalArbitrary.isOrdered, originalArbitrary.minLength, originalArbitrary.minLength +
Math.floor(Math.log(originalArbitrary.maxLength - originalArbitrary.minLength) / Math.log(2)));
})
: this;
}
}
function subarray(originalArray, minLength, maxLength) {
if (minLength != null && maxLength != null)
return new SubarrayArbitrary(originalArray, true, minLength, maxLength);
return new SubarrayArbitrary(originalArray, true, 0, originalArray.length);
}
function shuffledSubarray(originalArray, minLength, maxLength) {
if (minLength != null && maxLength != null)
return new SubarrayArbitrary(originalArray, false, minLength, maxLength);
return new SubarrayArbitrary(originalArray, false, 0, originalArray.length);
}
export { subarray, shuffledSubarray };