Initial commit

This commit is contained in:
Brian McGonagill 2026-03-18 09:02:21 -05:00
commit b3a51a4115
10336 changed files with 2381973 additions and 0 deletions

View file

@ -0,0 +1,66 @@
import { stringify } from '../../../utils/stringify.js';
import { array } from '../../array.js';
import { oneof } from '../../oneof.js';
import { tuple } from '../../tuple.js';
import { bigInt } from '../../bigInt.js';
import { date } from '../../date.js';
import { float32Array } from '../../float32Array.js';
import { float64Array } from '../../float64Array.js';
import { int16Array } from '../../int16Array.js';
import { int32Array } from '../../int32Array.js';
import { int8Array } from '../../int8Array.js';
import { uint16Array } from '../../uint16Array.js';
import { uint32Array } from '../../uint32Array.js';
import { uint8Array } from '../../uint8Array.js';
import { uint8ClampedArray } from '../../uint8ClampedArray.js';
import { sparseArray } from '../../sparseArray.js';
import { arrayToMapMapper, arrayToMapUnmapper } from '../mappers/ArrayToMap.js';
import { arrayToSetMapper, arrayToSetUnmapper } from '../mappers/ArrayToSet.js';
import { letrec } from '../../letrec.js';
import { uniqueArray } from '../../uniqueArray.js';
import { createDepthIdentifier } from '../helpers/DepthContext.js';
import { dictionary } from '../../dictionary.js';
function mapOf(ka, va, maxKeys, size, depthIdentifier) {
return uniqueArray(tuple(ka, va), {
maxLength: maxKeys,
size,
comparator: 'SameValueZero',
selector: (t) => t[0],
depthIdentifier,
}).map(arrayToMapMapper, arrayToMapUnmapper);
}
function dictOf(ka, va, maxKeys, size, depthIdentifier, withNullPrototype) {
return dictionary(ka, va, {
maxKeys,
noNullPrototype: !withNullPrototype,
size,
depthIdentifier,
});
}
function setOf(va, maxKeys, size, depthIdentifier) {
return uniqueArray(va, { maxLength: maxKeys, size, comparator: 'SameValueZero', depthIdentifier }).map(arrayToSetMapper, arrayToSetUnmapper);
}
function typedArray(constraints) {
return oneof(int8Array(constraints), uint8Array(constraints), uint8ClampedArray(constraints), int16Array(constraints), uint16Array(constraints), int32Array(constraints), uint32Array(constraints), float32Array(constraints), float64Array(constraints));
}
export function anyArbitraryBuilder(constraints) {
const arbitrariesForBase = constraints.values;
const depthSize = constraints.depthSize;
const depthIdentifier = createDepthIdentifier();
const maxDepth = constraints.maxDepth;
const maxKeys = constraints.maxKeys;
const size = constraints.size;
const baseArb = oneof(...arbitrariesForBase, ...(constraints.withBigInt ? [bigInt()] : []), ...(constraints.withDate ? [date()] : []));
return letrec((tie) => ({
anything: oneof({ maxDepth, depthSize, depthIdentifier }, baseArb, tie('array'), tie('object'), ...(constraints.withMap ? [tie('map')] : []), ...(constraints.withSet ? [tie('set')] : []), ...(constraints.withObjectString ? [tie('anything').map((o) => stringify(o))] : []), ...(constraints.withTypedArray ? [typedArray({ maxLength: maxKeys, size })] : []), ...(constraints.withSparseArray
? [sparseArray(tie('anything'), { maxNumElements: maxKeys, size, depthIdentifier })]
: [])),
keys: constraints.withObjectString
? oneof({ arbitrary: constraints.key, weight: 10 }, { arbitrary: tie('anything').map((o) => stringify(o)), weight: 1 })
: constraints.key,
array: array(tie('anything'), { maxLength: maxKeys, size, depthIdentifier }),
set: setOf(tie('anything'), maxKeys, size, depthIdentifier),
map: oneof(mapOf(tie('keys'), tie('anything'), maxKeys, size, depthIdentifier), mapOf(tie('anything'), tie('anything'), maxKeys, size, depthIdentifier)),
object: dictOf(tie('keys'), tie('anything'), maxKeys, size, depthIdentifier, constraints.withNullPrototype),
})).anything;
}

View file

@ -0,0 +1,4 @@
import { unboxedToBoxedMapper, unboxedToBoxedUnmapper } from '../mappers/UnboxedToBoxed.js';
export function boxedArbitraryBuilder(arb) {
return arb.map(unboxedToBoxedMapper, unboxedToBoxedUnmapper);
}

View file

@ -0,0 +1,5 @@
import { integer } from '../../integer.js';
import { indexToCharStringMapper, indexToCharStringUnmapper } from '../mappers/IndexToCharString.js';
export function buildCharacterArbitrary(min, max, mapToCode, unmapFromCode) {
return integer({ min, max }).map((n) => indexToCharStringMapper(mapToCode(n)), (c) => unmapFromCode(indexToCharStringUnmapper(c)));
}

View file

@ -0,0 +1,61 @@
import { fullUnicode } from '../../fullUnicode.js';
import { oneof } from '../../oneof.js';
import { mapToConstant } from '../../mapToConstant.js';
import { safeCharCodeAt, safeNumberToString, encodeURIComponent, safeMapGet, safeMapSet } from '../../../utils/globals.js';
const SMap = Map;
const safeStringFromCharCode = String.fromCharCode;
const lowerCaseMapper = { num: 26, build: (v) => safeStringFromCharCode(v + 0x61) };
const upperCaseMapper = { num: 26, build: (v) => safeStringFromCharCode(v + 0x41) };
const numericMapper = { num: 10, build: (v) => safeStringFromCharCode(v + 0x30) };
function percentCharArbMapper(c) {
const encoded = encodeURIComponent(c);
return c !== encoded ? encoded : `%${safeNumberToString(safeCharCodeAt(c, 0), 16)}`;
}
function percentCharArbUnmapper(value) {
if (typeof value !== 'string') {
throw new Error('Unsupported');
}
const decoded = decodeURIComponent(value);
return decoded;
}
const percentCharArb = fullUnicode().map(percentCharArbMapper, percentCharArbUnmapper);
let lowerAlphaArbitrary = undefined;
export function getOrCreateLowerAlphaArbitrary() {
if (lowerAlphaArbitrary === undefined) {
lowerAlphaArbitrary = mapToConstant(lowerCaseMapper);
}
return lowerAlphaArbitrary;
}
let lowerAlphaNumericArbitraries = undefined;
export function getOrCreateLowerAlphaNumericArbitrary(others) {
if (lowerAlphaNumericArbitraries === undefined) {
lowerAlphaNumericArbitraries = new SMap();
}
let match = safeMapGet(lowerAlphaNumericArbitraries, others);
if (match === undefined) {
match = mapToConstant(lowerCaseMapper, numericMapper, {
num: others.length,
build: (v) => others[v],
});
safeMapSet(lowerAlphaNumericArbitraries, others, match);
}
return match;
}
function buildAlphaNumericArbitrary(others) {
return mapToConstant(lowerCaseMapper, upperCaseMapper, numericMapper, {
num: others.length,
build: (v) => others[v],
});
}
let alphaNumericPercentArbitraries = undefined;
export function getOrCreateAlphaNumericPercentArbitrary(others) {
if (alphaNumericPercentArbitraries === undefined) {
alphaNumericPercentArbitraries = new SMap();
}
let match = safeMapGet(alphaNumericPercentArbitraries, others);
if (match === undefined) {
match = oneof({ weight: 10, arbitrary: buildAlphaNumericArbitrary(others) }, { weight: 1, arbitrary: percentCharArb });
safeMapSet(alphaNumericPercentArbitraries, others, match);
}
return match;
}

View file

@ -0,0 +1,43 @@
import { escapeForMultilineComments } from '../helpers/TextEscaper.js';
import { cloneMethod } from '../../../check/symbols.js';
import { hash } from '../../../utils/hash.js';
import { stringify } from '../../../utils/stringify.js';
import { integer } from '../../integer.js';
import { noShrink } from '../../noShrink.js';
import { tuple } from '../../tuple.js';
import { safeJoin } from '../../../utils/globals.js';
const safeObjectAssign = Object.assign;
const safeObjectKeys = Object.keys;
export function buildCompareFunctionArbitrary(cmp) {
return tuple(noShrink(integer()), noShrink(integer({ min: 1, max: 0xffffffff }))).map(([seed, hashEnvSize]) => {
const producer = () => {
const recorded = {};
const f = (a, b) => {
const reprA = stringify(a);
const reprB = stringify(b);
const hA = hash(`${seed}${reprA}`) % hashEnvSize;
const hB = hash(`${seed}${reprB}`) % hashEnvSize;
const val = cmp(hA, hB);
recorded[`[${reprA},${reprB}]`] = val;
return val;
};
return safeObjectAssign(f, {
toString: () => {
const seenValues = safeObjectKeys(recorded)
.sort()
.map((k) => `${k} => ${stringify(recorded[k])}`)
.map((line) => `/* ${escapeForMultilineComments(line)} */`);
return `function(a, b) {
// With hash and stringify coming from fast-check${seenValues.length !== 0 ? `\n ${safeJoin(seenValues, '\n ')}` : ''}
const cmp = ${cmp};
const hA = hash('${seed}' + stringify(a)) % ${hashEnvSize};
const hB = hash('${seed}' + stringify(b)) % ${hashEnvSize};
return cmp(hA, hB);
}`;
},
[cloneMethod]: producer,
});
};
return producer();
});
}

View file

@ -0,0 +1,38 @@
import { Value } from '../../../check/arbitrary/definition/Value.js';
import { cloneMethod } from '../../../check/symbols.js';
import { safeMap, safePush } from '../../../utils/globals.js';
import { stringify, toStringMethod } from '../../../utils/stringify.js';
const safeObjectAssign = Object.assign;
export function buildGeneratorValue(mrng, biasFactor, computePreBuiltValues, arbitraryCache) {
const preBuiltValues = computePreBuiltValues();
let localMrng = mrng.clone();
const context = { mrng: mrng.clone(), biasFactor, history: [] };
const valueFunction = (arb) => {
const preBuiltValue = preBuiltValues[context.history.length];
if (preBuiltValue !== undefined && preBuiltValue.arb === arb) {
const value = preBuiltValue.value;
safePush(context.history, { arb, value, context: preBuiltValue.context, mrng: preBuiltValue.mrng });
localMrng = preBuiltValue.mrng.clone();
return value;
}
const g = arb.generate(localMrng, biasFactor);
safePush(context.history, { arb, value: g.value_, context: g.context, mrng: localMrng.clone() });
return g.value;
};
const memoedValueFunction = (arb, ...args) => {
return valueFunction(arbitraryCache(arb, args));
};
const valueMethods = {
values() {
return safeMap(context.history, (c) => c.value);
},
[cloneMethod]() {
return buildGeneratorValue(mrng, biasFactor, computePreBuiltValues, arbitraryCache).value;
},
[toStringMethod]() {
return stringify(safeMap(context.history, (c) => c.value));
},
};
const value = safeObjectAssign(memoedValueFunction, valueMethods);
return new Value(value, context);
}

View file

@ -0,0 +1,5 @@
import { integer } from '../../integer.js';
import { numberToPaddedEightMapper, numberToPaddedEightUnmapper } from '../mappers/NumberToPaddedEight.js';
export function buildPaddedNumberArbitrary(min, max) {
return integer({ min, max }).map(numberToPaddedEightMapper, numberToPaddedEightUnmapper);
}

View file

@ -0,0 +1,23 @@
import { safeIndexOf, safePush } from '../../../utils/globals.js';
import { boolean } from '../../boolean.js';
import { constant } from '../../constant.js';
import { option } from '../../option.js';
import { tuple } from '../../tuple.js';
import { extractEnumerableKeys } from '../helpers/EnumerableKeysExtractor.js';
import { buildValuesAndSeparateKeysToObjectMapper, buildValuesAndSeparateKeysToObjectUnmapper, } from '../mappers/ValuesAndSeparateKeysToObject.js';
const noKeyValue = Symbol('no-key');
export function buildPartialRecordArbitrary(recordModel, requiredKeys, noNullPrototype) {
const keys = extractEnumerableKeys(recordModel);
const arbs = [];
for (let index = 0; index !== keys.length; ++index) {
const k = keys[index];
const requiredArbitrary = recordModel[k];
if (requiredKeys === undefined || safeIndexOf(requiredKeys, k) !== -1) {
safePush(arbs, requiredArbitrary);
}
else {
safePush(arbs, option(requiredArbitrary, { nil: noKeyValue }));
}
}
return tuple(tuple(...arbs), noNullPrototype ? constant(false) : boolean()).map(buildValuesAndSeparateKeysToObjectMapper(keys, noKeyValue), buildValuesAndSeparateKeysToObjectUnmapper(keys, noKeyValue));
}

View file

@ -0,0 +1,10 @@
import { integer } from '../../integer.js';
import { WithShrinkFromOtherArbitrary } from '../WithShrinkFromOtherArbitrary.js';
export function restrictedIntegerArbitraryBuilder(min, maxGenerated, max) {
const generatorArbitrary = integer({ min, max: maxGenerated });
if (maxGenerated === max) {
return generatorArbitrary;
}
const shrinkerArbitrary = integer({ min, max });
return new WithShrinkFromOtherArbitrary(generatorArbitrary, shrinkerArbitrary);
}

View file

@ -0,0 +1,52 @@
import { Map, safeMapGet, safeMapSet, safePush } from '../../../utils/globals.js';
const safeArrayIsArray = Array.isArray;
const safeObjectKeys = Object.keys;
const safeObjectIs = Object.is;
export function buildStableArbitraryGeneratorCache(isEqual) {
const previousCallsPerBuilder = new Map();
return function stableArbitraryGeneratorCache(builder, args) {
const entriesForBuilder = safeMapGet(previousCallsPerBuilder, builder);
if (entriesForBuilder === undefined) {
const newValue = builder(...args);
safeMapSet(previousCallsPerBuilder, builder, [{ args, value: newValue }]);
return newValue;
}
const safeEntriesForBuilder = entriesForBuilder;
for (const entry of safeEntriesForBuilder) {
if (isEqual(args, entry.args)) {
return entry.value;
}
}
const newValue = builder(...args);
safePush(safeEntriesForBuilder, { args, value: newValue });
return newValue;
};
}
export function naiveIsEqual(v1, v2) {
if (v1 !== null && typeof v1 === 'object' && v2 !== null && typeof v2 === 'object') {
if (safeArrayIsArray(v1)) {
if (!safeArrayIsArray(v2))
return false;
if (v1.length !== v2.length)
return false;
}
else if (safeArrayIsArray(v2)) {
return false;
}
if (safeObjectKeys(v1).length !== safeObjectKeys(v2).length) {
return false;
}
for (const index in v1) {
if (!(index in v2)) {
return false;
}
if (!naiveIsEqual(v1[index], v2[index])) {
return false;
}
}
return true;
}
else {
return safeObjectIs(v1, v2);
}
}

View file

@ -0,0 +1,7 @@
import { constantFrom } from '../../constantFrom.js';
import { nat } from '../../nat.js';
import { tuple } from '../../tuple.js';
import { natToStringifiedNatMapper, natToStringifiedNatUnmapper } from '../mappers/NatToStringifiedNat.js';
export function buildStringifiedNatArbitrary(maxValue) {
return tuple(constantFrom('dec', 'oct', 'hex'), nat(maxValue)).map(natToStringifiedNatMapper, natToStringifiedNatUnmapper);
}

View file

@ -0,0 +1,30 @@
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { array } from '../../array.js';
export function typedIntArrayArbitraryArbitraryBuilder(constraints, defaultMin, defaultMax, TypedArrayClass, arbitraryBuilder) {
const generatorName = TypedArrayClass.name;
const { min = defaultMin, max = defaultMax } = constraints, arrayConstraints = __rest(constraints, ["min", "max"]);
if (min > max) {
throw new Error(`Invalid range passed to ${generatorName}: min must be lower than or equal to max`);
}
if (min < defaultMin) {
throw new Error(`Invalid min value passed to ${generatorName}: min must be greater than or equal to ${defaultMin}`);
}
if (max > defaultMax) {
throw new Error(`Invalid max value passed to ${generatorName}: max must be lower than or equal to ${defaultMax}`);
}
return array(arbitraryBuilder({ min, max }), arrayConstraints).map((data) => TypedArrayClass.from(data), (value) => {
if (!(value instanceof TypedArrayClass))
throw new Error('Invalid type');
return [...value];
});
}

View file

@ -0,0 +1,28 @@
import { webSegment } from '../../webSegment.js';
import { array } from '../../array.js';
import { segmentsToPathMapper, segmentsToPathUnmapper } from '../mappers/SegmentsToPath.js';
import { oneof } from '../../oneof.js';
function sqrtSize(size) {
switch (size) {
case 'xsmall':
return ['xsmall', 'xsmall'];
case 'small':
return ['small', 'xsmall'];
case 'medium':
return ['small', 'small'];
case 'large':
return ['medium', 'small'];
case 'xlarge':
return ['medium', 'medium'];
}
}
function buildUriPathArbitraryInternal(segmentSize, numSegmentSize) {
return array(webSegment({ size: segmentSize }), { size: numSegmentSize }).map(segmentsToPathMapper, segmentsToPathUnmapper);
}
export function buildUriPathArbitrary(resolvedSize) {
const [segmentSize, numSegmentSize] = sqrtSize(resolvedSize);
if (segmentSize === numSegmentSize) {
return buildUriPathArbitraryInternal(segmentSize, numSegmentSize);
}
return oneof(buildUriPathArbitraryInternal(segmentSize, numSegmentSize), buildUriPathArbitraryInternal(numSegmentSize, segmentSize));
}

View file

@ -0,0 +1,5 @@
import { getOrCreateAlphaNumericPercentArbitrary } from './CharacterRangeArbitraryBuilder.js';
import { string } from '../../string.js';
export function buildUriQueryOrFragmentArbitrary(size) {
return string({ unit: getOrCreateAlphaNumericPercentArbitrary("-._~!$&'()*+,;=:@/?"), size });
}