fast-check
Advanced tools
Comparing version 2.18.1 to 2.19.0
@@ -0,1 +1,47 @@ | ||
# 2.19.0 | ||
_Move to next generation of properties and unlock shrink on user definable examples_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/v2.19.0)][[Diff](https://github.com/dubzzz/fast-check/compare/v2.18.0...v2.19.0)] | ||
## Features | ||
- ([PR#2391](https://github.com/dubzzz/fast-check/pull/2391)) Automatically shrink user defined examples | ||
- ([PR#2393](https://github.com/dubzzz/fast-check/pull/2393)) Support shrink on examples with unshrinkable parts | ||
- ([PR#2395](https://github.com/dubzzz/fast-check/pull/2395)) Better shrinker for arrays requested minLength | ||
- ([PR#2423](https://github.com/dubzzz/fast-check/pull/2423)) Make fixed sized arrays as biased as tuples | ||
## Fixes | ||
- ([PR#2371](https://github.com/dubzzz/fast-check/pull/2371)) Refactor: Declare API and converters for the next gen property | ||
- ([PR#2372](https://github.com/dubzzz/fast-check/pull/2372)) Refactor: Migrate runners to rely on next gen properties | ||
- ([PR#2373](https://github.com/dubzzz/fast-check/pull/2373)) Refactor: Migrate UnbiasedProperty to next gen property | ||
- ([PR#2374](https://github.com/dubzzz/fast-check/pull/2374)) Refactor: Migrate IgnoreEqualValuesProperty to next gen property | ||
- ([PR#2375](https://github.com/dubzzz/fast-check/pull/2375)) Refactor: Migrate TimeoutProperty to next gen property | ||
- ([PR#2376](https://github.com/dubzzz/fast-check/pull/2376)) Refactor: Migrate SkipAfterProperty to next gen property | ||
- ([PR#2387](https://github.com/dubzzz/fast-check/pull/2387)) Refactor: Produce next gen properties via decorateProperty | ||
- ([PR#2388](https://github.com/dubzzz/fast-check/pull/2388)) Refactor: Migrate property builders to produce next gen | ||
- ([PR#2377](https://github.com/dubzzz/fast-check/pull/2377)) Typo: Typo in error thrown when invalid arguments passed to frequency | ||
- ([PR#2394](https://github.com/dubzzz/fast-check/pull/2394)) Bug: Properly re-wrap values on shrink in properties | ||
- ([PR#2399](https://github.com/dubzzz/fast-check/pull/2399)) Test: Ensure correct min/max for float32/64Arrays in tests | ||
- ([PR#2402](https://github.com/dubzzz/fast-check/pull/2402)) Test: Reduce the maximal minLength requested in tests | ||
- ([PR#2415](https://github.com/dubzzz/fast-check/pull/2415)) Refactor: Update the way we use flags for mixedCase | ||
- ([PR#2416](https://github.com/dubzzz/fast-check/pull/2416)) Refactor: Do not favor numeric values over others in json arbitraries | ||
- ([PR#2403](https://github.com/dubzzz/fast-check/pull/2403)) Test: Better asserts of shrinks by going deeper in path | ||
- ([PR#2417](https://github.com/dubzzz/fast-check/pull/2417)) Bug: Unmapper function of hexa was not unmapping properly | ||
- ([PR#2421](https://github.com/dubzzz/fast-check/pull/2421)) Bug: Accept already cloneable values as output of .map | ||
- ([PR#2424](https://github.com/dubzzz/fast-check/pull/2424)) CI: Run tests with verbose flag enabled | ||
- ([PR#2426](https://github.com/dubzzz/fast-check/pull/2426)) Doc: Document shrink of user definable values | ||
- ([PR#2427](https://github.com/dubzzz/fast-check/pull/2427)) Test: Stop flakiness on legacy tests of float/double | ||
--- | ||
# 2.18.1 | ||
_Fix regression when mapper returns an already cloneable value_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/v2.18.1)][[Diff](https://github.com/dubzzz/fast-check/compare/v2.18.0...v2.18.1)] | ||
## Fixes | ||
- ([PR#2421](https://github.com/dubzzz/fast-check/pull/2421)) Bug: Accept already cloneable values as output of `.map` | ||
# 2.18.0 | ||
@@ -62,2 +108,11 @@ | ||
# 2.17.1 | ||
_Fix regression when mapper returns an already cloneable value_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/v2.17.1)][[Diff](https://github.com/dubzzz/fast-check/compare/v2.17.0...v2.17.1)] | ||
## Fixes | ||
- ([PR#2421](https://github.com/dubzzz/fast-check/pull/2421)) Bug: Accept already cloneable values as output of `.map` | ||
# 2.17.0 | ||
@@ -99,2 +154,11 @@ | ||
# 2.16.1 | ||
_Fix regression when mapper returns an already cloneable value_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/v2.16.1)][[Diff](https://github.com/dubzzz/fast-check/compare/v2.16.0...v2.16.1)] | ||
## Fixes | ||
- ([PR#2421](https://github.com/dubzzz/fast-check/pull/2421)) Bug: Accept already cloneable values as output of `.map` | ||
# 2.16.0 | ||
@@ -117,4 +181,13 @@ | ||
--- | ||
--- | ||
# 2.15.1 | ||
_Fix regression when mapper returns an already cloneable value_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/v2.15.1)][[Diff](https://github.com/dubzzz/fast-check/compare/v2.15.0...v2.15.1)] | ||
## Fixes | ||
- ([PR#2421](https://github.com/dubzzz/fast-check/pull/2421)) Bug: Accept already cloneable values as output of `.map` | ||
# 2.15.0 | ||
@@ -121,0 +194,0 @@ |
@@ -64,3 +64,3 @@ "use strict"; | ||
} | ||
wrapper(itemsRaw, shrunkOnce, itemsRawLengthContext) { | ||
wrapper(itemsRaw, shrunkOnce, itemsRawLengthContext, startIndex) { | ||
const items = shrunkOnce ? this.preFilter(itemsRaw) : itemsRaw; | ||
@@ -85,2 +85,3 @@ let cloneable = false; | ||
itemsContexts, | ||
startIndex, | ||
}; | ||
@@ -95,8 +96,14 @@ return new NextValue_1.NextValue(vs, context); | ||
: this.generateNItems(targetSize, mrng, biasMeta.biasFactorItems); | ||
return this.wrapper(items, false, undefined); | ||
return this.wrapper(items, false, undefined, 0); | ||
} | ||
applyBias(mrng, biasFactor) { | ||
if (biasFactor === undefined || mrng.nextInt(1, biasFactor) !== 1) { | ||
if (biasFactor === undefined) { | ||
return { size: this.lengthArb.generate(mrng, undefined).value }; | ||
} | ||
if (this.minLength === this.maxLength) { | ||
return { size: this.lengthArb.generate(mrng, undefined).value, biasFactorItems: biasFactor }; | ||
} | ||
if (mrng.nextInt(1, biasFactor) !== 1) { | ||
return { size: this.lengthArb.generate(mrng, undefined).value }; | ||
} | ||
if (mrng.nextInt(1, biasFactor) !== 1 || this.minLength === this.maxLength) { | ||
@@ -124,2 +131,23 @@ return { size: this.lengthArb.generate(mrng, undefined).value, biasFactorItems: biasFactor }; | ||
} | ||
shrinkItemByItem(value, safeContext, endIndex) { | ||
let shrinks = Stream_1.Stream.nil(); | ||
for (let index = safeContext.startIndex; index < endIndex; ++index) { | ||
shrinks = shrinks.join((0, LazyIterableIterator_1.makeLazy)(() => this.arb | ||
.shrink(value[index], safeContext.itemsContexts[index]) | ||
.map((v) => { | ||
const beforeCurrent = value | ||
.slice(0, index) | ||
.map((v, i) => new NextValue_1.NextValue((0, symbols_1.cloneIfNeeded)(v), safeContext.itemsContexts[i])); | ||
const afterCurrent = value | ||
.slice(index + 1) | ||
.map((v, i) => new NextValue_1.NextValue((0, symbols_1.cloneIfNeeded)(v), safeContext.itemsContexts[i + index + 1])); | ||
return [ | ||
beforeCurrent.concat(v).concat(afterCurrent), | ||
undefined, | ||
index, | ||
]; | ||
}))); | ||
} | ||
return shrinks; | ||
} | ||
shrinkImpl(value, context) { | ||
@@ -131,3 +159,3 @@ if (value.length === 0) { | ||
? context | ||
: { shrunkOnce: false, lengthContext: undefined, itemsContexts: [] }; | ||
: { shrunkOnce: false, lengthContext: undefined, itemsContexts: [], startIndex: 0 }; | ||
return (this.lengthArb | ||
@@ -143,29 +171,32 @@ .shrink(value.length, safeContext.lengthContext) | ||
lengthValue.context, | ||
0, | ||
]; | ||
}) | ||
.join(this.arb.shrink(value[0], safeContext.itemsContexts[0]).map((v) => { | ||
return [ | ||
[v].concat(value.slice(1).map((v, index) => new NextValue_1.NextValue((0, symbols_1.cloneIfNeeded)(v), safeContext.itemsContexts[index + 1]))), | ||
undefined, | ||
]; | ||
})) | ||
.join((0, LazyIterableIterator_1.makeLazy)(() => value.length > this.minLength | ||
? this.shrinkItemByItem(value, safeContext, 1) | ||
: this.shrinkItemByItem(value, safeContext, value.length))) | ||
.join(value.length > this.minLength | ||
? (0, LazyIterableIterator_1.makeLazy)(() => this.shrinkImpl(value.slice(1), { | ||
shrunkOnce: false, | ||
lengthContext: undefined, | ||
itemsContexts: safeContext.itemsContexts.slice(1), | ||
? (0, LazyIterableIterator_1.makeLazy)(() => { | ||
const subContext = { | ||
shrunkOnce: false, | ||
lengthContext: undefined, | ||
itemsContexts: safeContext.itemsContexts.slice(1), | ||
startIndex: 0, | ||
}; | ||
return this.shrinkImpl(value.slice(1), subContext) | ||
.filter((v) => this.minLength <= v[0].length + 1) | ||
.map((v) => { | ||
return [ | ||
[new NextValue_1.NextValue((0, symbols_1.cloneIfNeeded)(value[0]), safeContext.itemsContexts[0])].concat(v[0]), | ||
undefined, | ||
0, | ||
]; | ||
}); | ||
}) | ||
.filter((v) => this.minLength <= v[0].length + 1) | ||
.map((v) => { | ||
return [ | ||
[new NextValue_1.NextValue((0, symbols_1.cloneIfNeeded)(value[0]), safeContext.itemsContexts[0])].concat(v[0]), | ||
undefined, | ||
]; | ||
})) | ||
: Stream_1.Stream.nil())); | ||
} | ||
shrink(value, context) { | ||
return this.shrinkImpl(value, context).map((contextualValue) => this.wrapper(contextualValue[0], true, contextualValue[1])); | ||
return this.shrinkImpl(value, context).map((contextualValue) => this.wrapper(contextualValue[0], true, contextualValue[1], contextualValue[2])); | ||
} | ||
} | ||
exports.ArrayArbitrary = ArrayArbitrary; |
@@ -28,3 +28,3 @@ "use strict"; | ||
if (warbs.length === 0) { | ||
throw new Error(`${label} expects at least one weigthed arbitrary`); | ||
throw new Error(`${label} expects at least one weighted arbitrary`); | ||
} | ||
@@ -31,0 +31,0 @@ let totalWeight = 0; |
@@ -7,3 +7,2 @@ "use strict"; | ||
const double_1 = require("../../double"); | ||
const maxSafeInteger_1 = require("../../maxSafeInteger"); | ||
function jsonConstraintsBuilder(stringArbitrary, constraints) { | ||
@@ -13,3 +12,2 @@ const key = stringArbitrary; | ||
(0, boolean_1.boolean)(), | ||
(0, maxSafeInteger_1.maxSafeInteger)(), | ||
(0, double_1.double)({ next: true, noDefaultInfinity: true, noNaN: true }), | ||
@@ -16,0 +14,0 @@ stringArbitrary, |
@@ -30,3 +30,3 @@ "use strict"; | ||
const positions = []; | ||
for (let idx = 0; idx !== chars.length; ++idx) { | ||
for (let idx = chars.length - 1; idx !== -1; --idx) { | ||
if (toggleCase(chars[idx]) !== chars[idx]) | ||
@@ -33,0 +33,0 @@ positions.push(idx); |
@@ -13,3 +13,3 @@ "use strict"; | ||
? v - 48 | ||
: v < 103 | ||
: v >= 97 && v < 103 | ||
? v - 97 + 10 | ||
@@ -16,0 +16,0 @@ : -1; |
"use strict"; | ||
var _a; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ConverterToNext = void 0; | ||
exports.ConverterToNext = exports.fromShrinkableToNextValue = void 0; | ||
const Stream_1 = require("../../../stream/Stream"); | ||
@@ -16,2 +16,3 @@ const ConverterFromNext_1 = require("./ConverterFromNext"); | ||
} | ||
exports.fromShrinkableToNextValue = fromShrinkableToNextValue; | ||
class ConverterToNext extends NextArbitrary_1.NextArbitrary { | ||
@@ -18,0 +19,0 @@ constructor(arb) { |
@@ -5,3 +5,6 @@ "use strict"; | ||
const genericTuple_1 = require("../../arbitrary/genericTuple"); | ||
const ConvertersProperty_1 = require("./ConvertersProperty"); | ||
const AsyncProperty_generic_1 = require("./AsyncProperty.generic"); | ||
const AlwaysShrinkableArbitrary_1 = require("../../arbitrary/_internals/AlwaysShrinkableArbitrary"); | ||
const Converters_1 = require("../arbitrary/definition/Converters"); | ||
function asyncProperty(...args) { | ||
@@ -12,4 +15,4 @@ if (args.length < 2) | ||
const p = args[args.length - 1]; | ||
return new AsyncProperty_generic_1.AsyncProperty((0, genericTuple_1.genericTuple)(arbs), t => p(...t)); | ||
return (0, ConvertersProperty_1.convertFromNextAsyncPropertyWithHooks)(new AsyncProperty_generic_1.AsyncProperty((0, genericTuple_1.genericTuple)(arbs.map(arb => (0, Converters_1.convertFromNext)(new AlwaysShrinkableArbitrary_1.AlwaysShrinkableArbitrary((0, Converters_1.convertToNext)(arb))))), t => p(...t))); | ||
} | ||
exports.asyncProperty = asyncProperty; |
@@ -7,8 +7,8 @@ "use strict"; | ||
const GlobalParameters_1 = require("../runner/configuration/GlobalParameters"); | ||
const ConverterFromNext_1 = require("../arbitrary/definition/ConverterFromNext"); | ||
const Stream_1 = require("../../stream/Stream"); | ||
const Converters_1 = require("../arbitrary/definition/Converters"); | ||
const NoUndefinedAsContext_1 = require("../../arbitrary/_internals/helpers/NoUndefinedAsContext"); | ||
class AsyncProperty { | ||
constructor(arb, predicate) { | ||
this.arb = arb; | ||
constructor(rawArb, predicate) { | ||
this.predicate = predicate; | ||
this.isAsync = () => true; | ||
const { asyncBeforeEach, asyncAfterEach, beforeEach, afterEach } = (0, GlobalParameters_1.readConfigureGlobal)() || {}; | ||
@@ -23,8 +23,17 @@ if (asyncBeforeEach !== undefined && beforeEach !== undefined) { | ||
this.afterEachHook = asyncAfterEach || afterEach || AsyncProperty.dummyHook; | ||
this.arb = (0, Converters_1.convertToNext)(rawArb); | ||
} | ||
isAsync() { | ||
return true; | ||
} | ||
generate(mrng, runId) { | ||
if (ConverterFromNext_1.ConverterFromNext.isConverterFromNext(this.arb)) { | ||
return this.arb.toShrinkable(this.arb.arb.generate(mrng, runId != null ? (0, IRawProperty_1.runIdToFrequency)(runId) : undefined)); | ||
const value = this.arb.generate(mrng, runId != null ? (0, IRawProperty_1.runIdToFrequency)(runId) : undefined); | ||
return (0, NoUndefinedAsContext_1.noUndefinedAsContext)(value); | ||
} | ||
shrink(value) { | ||
if (value.context === undefined && !this.arb.canShrinkWithoutContext(value.value_)) { | ||
return Stream_1.Stream.nil(); | ||
} | ||
return runId != null ? this.arb.withBias((0, IRawProperty_1.runIdToFrequency)(runId)).generate(mrng) : this.arb.generate(mrng); | ||
const safeContext = value.context !== NoUndefinedAsContext_1.UndefinedContextPlaceholder ? value.context : undefined; | ||
return this.arb.shrink(value.value_, safeContext).map(NoUndefinedAsContext_1.noUndefinedAsContext); | ||
} | ||
@@ -31,0 +40,0 @@ async run(v) { |
@@ -22,19 +22,26 @@ "use strict"; | ||
this.coveredCases = new Map(); | ||
this.isAsync = () => this.property.isAsync(); | ||
this.generate = (mrng, runId) => this.property.generate(mrng, runId); | ||
this.run = (v) => { | ||
const stringifiedValue = (0, stringify_1.stringify)(v); | ||
if (this.coveredCases.has(stringifiedValue)) { | ||
const lastOutput = this.coveredCases.get(stringifiedValue); | ||
if (!this.skipRuns) { | ||
return lastOutput; | ||
} | ||
return fromCachedUnsafe(lastOutput, this.property.isAsync()); | ||
} | ||
isAsync() { | ||
return this.property.isAsync(); | ||
} | ||
generate(mrng, runId) { | ||
return this.property.generate(mrng, runId); | ||
} | ||
shrink(value) { | ||
return this.property.shrink(value); | ||
} | ||
run(v) { | ||
const stringifiedValue = (0, stringify_1.stringify)(v); | ||
if (this.coveredCases.has(stringifiedValue)) { | ||
const lastOutput = this.coveredCases.get(stringifiedValue); | ||
if (!this.skipRuns) { | ||
return lastOutput; | ||
} | ||
const out = this.property.run(v); | ||
this.coveredCases.set(stringifiedValue, out); | ||
return out; | ||
}; | ||
return fromCachedUnsafe(lastOutput, this.property.isAsync()); | ||
} | ||
const out = this.property.run(v); | ||
this.coveredCases.set(stringifiedValue, out); | ||
return out; | ||
} | ||
} | ||
exports.IgnoreEqualValuesProperty = IgnoreEqualValuesProperty; |
@@ -5,3 +5,6 @@ "use strict"; | ||
const genericTuple_1 = require("../../arbitrary/genericTuple"); | ||
const ConvertersProperty_1 = require("./ConvertersProperty"); | ||
const Property_generic_1 = require("./Property.generic"); | ||
const AlwaysShrinkableArbitrary_1 = require("../../arbitrary/_internals/AlwaysShrinkableArbitrary"); | ||
const Converters_1 = require("../arbitrary/definition/Converters"); | ||
function property(...args) { | ||
@@ -12,4 +15,4 @@ if (args.length < 2) | ||
const p = args[args.length - 1]; | ||
return new Property_generic_1.Property((0, genericTuple_1.genericTuple)(arbs), t => p(...t)); | ||
return (0, ConvertersProperty_1.convertFromNextPropertyWithHooks)(new Property_generic_1.Property((0, genericTuple_1.genericTuple)(arbs.map(arb => (0, Converters_1.convertFromNext)(new AlwaysShrinkableArbitrary_1.AlwaysShrinkableArbitrary((0, Converters_1.convertToNext)(arb))))), t => p(...t))); | ||
} | ||
exports.property = property; |
@@ -7,8 +7,8 @@ "use strict"; | ||
const GlobalParameters_1 = require("../runner/configuration/GlobalParameters"); | ||
const ConverterFromNext_1 = require("../arbitrary/definition/ConverterFromNext"); | ||
const Converters_1 = require("../arbitrary/definition/Converters"); | ||
const Stream_1 = require("../../stream/Stream"); | ||
const NoUndefinedAsContext_1 = require("../../arbitrary/_internals/helpers/NoUndefinedAsContext"); | ||
class Property { | ||
constructor(arb, predicate) { | ||
this.arb = arb; | ||
constructor(rawArb, predicate) { | ||
this.predicate = predicate; | ||
this.isAsync = () => false; | ||
const { beforeEach = Property.dummyHook, afterEach = Property.dummyHook, asyncBeforeEach, asyncAfterEach, } = (0, GlobalParameters_1.readConfigureGlobal)() || {}; | ||
@@ -23,8 +23,17 @@ if (asyncBeforeEach !== undefined) { | ||
this.afterEachHook = afterEach; | ||
this.arb = (0, Converters_1.convertToNext)(rawArb); | ||
} | ||
isAsync() { | ||
return false; | ||
} | ||
generate(mrng, runId) { | ||
if (ConverterFromNext_1.ConverterFromNext.isConverterFromNext(this.arb)) { | ||
return this.arb.toShrinkable(this.arb.arb.generate(mrng, runId != null ? (0, IRawProperty_1.runIdToFrequency)(runId) : undefined)); | ||
const value = this.arb.generate(mrng, runId != null ? (0, IRawProperty_1.runIdToFrequency)(runId) : undefined); | ||
return (0, NoUndefinedAsContext_1.noUndefinedAsContext)(value); | ||
} | ||
shrink(value) { | ||
if (value.context === undefined && !this.arb.canShrinkWithoutContext(value.value_)) { | ||
return Stream_1.Stream.nil(); | ||
} | ||
return runId != null ? this.arb.withBias((0, IRawProperty_1.runIdToFrequency)(runId)).generate(mrng) : this.arb.generate(mrng); | ||
const safeContext = value.context !== NoUndefinedAsContext_1.UndefinedContextPlaceholder ? value.context : undefined; | ||
return this.arb.shrink(value.value_, safeContext).map(NoUndefinedAsContext_1.noUndefinedAsContext); | ||
} | ||
@@ -31,0 +40,0 @@ run(v) { |
@@ -10,19 +10,26 @@ "use strict"; | ||
this.interruptExecution = interruptExecution; | ||
this.isAsync = () => this.property.isAsync(); | ||
this.generate = (mrng, runId) => this.property.generate(mrng, runId); | ||
this.run = (v) => { | ||
if (this.getTime() >= this.skipAfterTime) { | ||
const preconditionFailure = new PreconditionFailure_1.PreconditionFailure(this.interruptExecution); | ||
if (this.isAsync()) { | ||
return Promise.resolve(preconditionFailure); | ||
} | ||
else { | ||
return preconditionFailure; | ||
} | ||
} | ||
return this.property.run(v); | ||
}; | ||
this.skipAfterTime = this.getTime() + timeLimit; | ||
} | ||
isAsync() { | ||
return this.property.isAsync(); | ||
} | ||
generate(mrng, runId) { | ||
return this.property.generate(mrng, runId); | ||
} | ||
shrink(value) { | ||
return this.property.shrink(value); | ||
} | ||
run(v) { | ||
if (this.getTime() >= this.skipAfterTime) { | ||
const preconditionFailure = new PreconditionFailure_1.PreconditionFailure(this.interruptExecution); | ||
if (this.isAsync()) { | ||
return Promise.resolve(preconditionFailure); | ||
} | ||
else { | ||
return preconditionFailure; | ||
} | ||
} | ||
return this.property.run(v); | ||
} | ||
} | ||
exports.SkipAfterProperty = SkipAfterProperty; |
@@ -20,7 +20,12 @@ "use strict"; | ||
this.timeMs = timeMs; | ||
this.isAsync = () => true; | ||
} | ||
isAsync() { | ||
return true; | ||
} | ||
generate(mrng, runId) { | ||
return this.property.generate(mrng, runId); | ||
} | ||
shrink(value) { | ||
return this.property.shrink(value); | ||
} | ||
async run(v) { | ||
@@ -27,0 +32,0 @@ const t = timeoutAfter(this.timeMs); |
@@ -7,7 +7,16 @@ "use strict"; | ||
this.property = property; | ||
this.isAsync = () => this.property.isAsync(); | ||
this.generate = (mrng, _runId) => this.property.generate(mrng); | ||
this.run = (v) => this.property.run(v); | ||
} | ||
isAsync() { | ||
return this.property.isAsync(); | ||
} | ||
generate(mrng, _runId) { | ||
return this.property.generate(mrng, undefined); | ||
} | ||
shrink(value) { | ||
return this.property.shrink(value); | ||
} | ||
run(v) { | ||
return this.property.run(v); | ||
} | ||
} | ||
exports.UnbiasedProperty = UnbiasedProperty; |
@@ -8,4 +8,5 @@ "use strict"; | ||
const IgnoreEqualValuesProperty_1 = require("../property/IgnoreEqualValuesProperty"); | ||
const ConvertersProperty_1 = require("../property/ConvertersProperty"); | ||
function decorateProperty(rawProperty, qParams) { | ||
let prop = rawProperty; | ||
let prop = (0, ConvertersProperty_1.convertToNextProperty)(rawProperty); | ||
if (rawProperty.isAsync() && qParams.timeout != null) { | ||
@@ -12,0 +13,0 @@ prop = new TimeoutProperty_1.TimeoutProperty(prop, qParams.timeout); |
@@ -5,3 +5,2 @@ "use strict"; | ||
const Stream_1 = require("../../stream/Stream"); | ||
const Shrinkable_1 = require("../arbitrary/definition/Shrinkable"); | ||
const GlobalParameters_1 = require("./configuration/GlobalParameters"); | ||
@@ -15,4 +14,4 @@ const QualifiedParameters_1 = require("./configuration/QualifiedParameters"); | ||
const RunDetailsFormatter_1 = require("./utils/RunDetailsFormatter"); | ||
function runIt(property, sourceValues, verbose, interruptedAsFailure) { | ||
const runner = new RunnerIterator_1.RunnerIterator(sourceValues, verbose, interruptedAsFailure); | ||
function runIt(property, shrink, sourceValues, verbose, interruptedAsFailure) { | ||
const runner = new RunnerIterator_1.RunnerIterator(sourceValues, shrink, verbose, interruptedAsFailure); | ||
for (const v of runner) { | ||
@@ -24,4 +23,4 @@ const out = property.run(v); | ||
} | ||
async function asyncRunIt(property, sourceValues, verbose, interruptedAsFailure) { | ||
const runner = new RunnerIterator_1.RunnerIterator(sourceValues, verbose, interruptedAsFailure); | ||
async function asyncRunIt(property, shrink, sourceValues, verbose, interruptedAsFailure) { | ||
const runner = new RunnerIterator_1.RunnerIterator(sourceValues, shrink, verbose, interruptedAsFailure); | ||
for (const v of runner) { | ||
@@ -33,3 +32,3 @@ const out = await property.run(v); | ||
} | ||
function runnerPathWalker(valueProducers, path) { | ||
function runnerPathWalker(valueProducers, shrink, path) { | ||
const pathPoints = path.split(':'); | ||
@@ -40,14 +39,9 @@ const pathStream = (0, Stream_1.stream)(valueProducers) | ||
const adaptedPath = ['0', ...pathPoints.slice(1)].join(':'); | ||
return (0, Stream_1.stream)((0, PathWalker_1.pathWalk)(adaptedPath, pathStream)).map((v) => () => v); | ||
return (0, Stream_1.stream)((0, PathWalker_1.pathWalk)(adaptedPath, pathStream, shrink)).map((v) => () => v); | ||
} | ||
function buildInitialValues(valueProducers, qParams) { | ||
const rawValues = qParams.path.length === 0 ? (0, Stream_1.stream)(valueProducers) : runnerPathWalker(valueProducers, qParams.path); | ||
if (!qParams.endOnFailure) | ||
return rawValues; | ||
return rawValues.map((shrinkableGen) => { | ||
return () => { | ||
const s = shrinkableGen(); | ||
return new Shrinkable_1.Shrinkable(s.value_); | ||
}; | ||
}); | ||
function buildInitialValues(valueProducers, shrink, qParams) { | ||
if (qParams.path.length === 0) { | ||
return (0, Stream_1.stream)(valueProducers); | ||
} | ||
return runnerPathWalker(valueProducers, shrink, qParams.path); | ||
} | ||
@@ -68,7 +62,9 @@ function check(rawProperty, params) { | ||
const maxSkips = qParams.numRuns * qParams.maxSkipsPerRun; | ||
const initialValues = buildInitialValues(generator, qParams); | ||
const shrink = property.shrink.bind(property); | ||
const initialValues = buildInitialValues(generator, shrink, qParams); | ||
const sourceValues = new SourceValuesIterator_1.SourceValuesIterator(initialValues, maxInitialIterations, maxSkips); | ||
const finalShrink = !qParams.endOnFailure ? shrink : Stream_1.Stream.nil; | ||
return property.isAsync() | ||
? asyncRunIt(property, sourceValues, qParams.verbose, qParams.markInterruptAsFailure).then((e) => e.toRunDetails(qParams.seed, qParams.path, maxSkips, qParams)) | ||
: runIt(property, sourceValues, qParams.verbose, qParams.markInterruptAsFailure).toRunDetails(qParams.seed, qParams.path, maxSkips, qParams); | ||
? asyncRunIt(property, finalShrink, sourceValues, qParams.verbose, qParams.markInterruptAsFailure).then((e) => e.toRunDetails(qParams.seed, qParams.path, maxSkips, qParams)) | ||
: runIt(property, finalShrink, sourceValues, qParams.verbose, qParams.markInterruptAsFailure).toRunDetails(qParams.seed, qParams.path, maxSkips, qParams); | ||
} | ||
@@ -75,0 +71,0 @@ exports.check = check; |
@@ -6,4 +6,5 @@ "use strict"; | ||
class RunnerIterator { | ||
constructor(sourceValues, verbose, interruptedAsFailure) { | ||
constructor(sourceValues, shrink, verbose, interruptedAsFailure) { | ||
this.sourceValues = sourceValues; | ||
this.shrink = shrink; | ||
this.runExecution = new RunExecution_1.RunExecution(verbose, interruptedAsFailure); | ||
@@ -21,3 +22,3 @@ this.currentIdx = -1; | ||
} | ||
this.currentShrinkable = nextValue.value; | ||
this.currentValue = nextValue.value; | ||
++this.currentIdx; | ||
@@ -28,9 +29,9 @@ return { done: false, value: nextValue.value.value_ }; | ||
if (result != null && typeof result === 'string') { | ||
this.runExecution.fail(this.currentShrinkable.value_, this.currentIdx, result); | ||
this.runExecution.fail(this.currentValue.value_, this.currentIdx, result); | ||
this.currentIdx = -1; | ||
this.nextValues = this.currentShrinkable.shrink(); | ||
this.nextValues = this.shrink(this.currentValue); | ||
} | ||
else if (result != null) { | ||
if (!result.interruptExecution) { | ||
this.runExecution.skip(this.currentShrinkable.value_); | ||
this.runExecution.skip(this.currentValue.value_); | ||
this.sourceValues.skippedOne(); | ||
@@ -43,3 +44,3 @@ } | ||
else { | ||
this.runExecution.success(this.currentShrinkable.value_); | ||
this.runExecution.success(this.currentValue.value_); | ||
} | ||
@@ -46,0 +47,0 @@ } |
@@ -5,2 +5,3 @@ "use strict"; | ||
const Stream_1 = require("../../stream/Stream"); | ||
const ConvertersProperty_1 = require("../property/ConvertersProperty"); | ||
const Property_generic_1 = require("../property/Property.generic"); | ||
@@ -15,3 +16,3 @@ const UnbiasedProperty_1 = require("../property/UnbiasedProperty"); | ||
? new Property_generic_1.Property(generator, () => true) | ||
: generator; | ||
: (0, ConvertersProperty_1.convertToNextProperty)(generator); | ||
return qParams.unbiased === true ? new UnbiasedProperty_1.UnbiasedProperty(prop) : prop; | ||
@@ -23,7 +24,9 @@ } | ||
const qParams = QualifiedParameters_1.QualifiedParameters.read(extendedParams); | ||
const tossedValues = (0, Stream_1.stream)((0, Tosser_1.toss)(toProperty(generator, qParams), qParams.seed, qParams.randomType, qParams.examples)); | ||
const nextProperty = toProperty(generator, qParams); | ||
const shrink = nextProperty.shrink.bind(nextProperty); | ||
const tossedValues = (0, Stream_1.stream)((0, Tosser_1.toss)(nextProperty, qParams.seed, qParams.randomType, qParams.examples)); | ||
if (qParams.path.length === 0) { | ||
return tossedValues.take(qParams.numRuns).map((s) => s().value_); | ||
} | ||
return (0, Stream_1.stream)((0, PathWalker_1.pathWalk)(qParams.path, tossedValues.map((s) => s()))) | ||
return (0, Stream_1.stream)((0, PathWalker_1.pathWalk)(qParams.path, tossedValues.map((s) => s()), shrink)) | ||
.take(qParams.numRuns) | ||
@@ -30,0 +33,0 @@ .map((s) => s.value_); |
@@ -6,4 +6,4 @@ "use strict"; | ||
const Random_1 = require("../../random/generator/Random"); | ||
const Shrinkable_1 = require("../arbitrary/definition/Shrinkable"); | ||
const PureRandom_1 = require("../../random/generator/PureRandom"); | ||
const NextValue_1 = require("../arbitrary/definition/NextValue"); | ||
function lazyGenerate(generator, rng, idx) { | ||
@@ -13,3 +13,3 @@ return () => generator.generate(new Random_1.Random(rng), idx); | ||
function* toss(generator, seed, random, examples) { | ||
yield* examples.map((e) => () => new Shrinkable_1.Shrinkable(e)); | ||
yield* examples.map((e) => () => new NextValue_1.NextValue(e, undefined)); | ||
let idx = 0; | ||
@@ -16,0 +16,0 @@ let rng = (0, PureRandom_1.convertToRandomGenerator)(random(seed)); |
@@ -5,3 +5,3 @@ "use strict"; | ||
const Stream_1 = require("../../../stream/Stream"); | ||
function pathWalk(path, initialValues) { | ||
function pathWalk(path, initialValues, shrink) { | ||
let values = (0, Stream_1.stream)(initialValues); | ||
@@ -20,3 +20,3 @@ const segments = path.split(':').map((text) => +text); | ||
} | ||
values = valueToShrink.shrink().drop(s); | ||
values = shrink(valueToShrink).drop(s); | ||
} | ||
@@ -23,0 +23,0 @@ return values; |
@@ -61,3 +61,3 @@ import { Stream } from '../../stream/Stream.js'; | ||
} | ||
wrapper(itemsRaw, shrunkOnce, itemsRawLengthContext) { | ||
wrapper(itemsRaw, shrunkOnce, itemsRawLengthContext, startIndex) { | ||
const items = shrunkOnce ? this.preFilter(itemsRaw) : itemsRaw; | ||
@@ -82,2 +82,3 @@ let cloneable = false; | ||
itemsContexts, | ||
startIndex, | ||
}; | ||
@@ -92,8 +93,14 @@ return new NextValue(vs, context); | ||
: this.generateNItems(targetSize, mrng, biasMeta.biasFactorItems); | ||
return this.wrapper(items, false, undefined); | ||
return this.wrapper(items, false, undefined, 0); | ||
} | ||
applyBias(mrng, biasFactor) { | ||
if (biasFactor === undefined || mrng.nextInt(1, biasFactor) !== 1) { | ||
if (biasFactor === undefined) { | ||
return { size: this.lengthArb.generate(mrng, undefined).value }; | ||
} | ||
if (this.minLength === this.maxLength) { | ||
return { size: this.lengthArb.generate(mrng, undefined).value, biasFactorItems: biasFactor }; | ||
} | ||
if (mrng.nextInt(1, biasFactor) !== 1) { | ||
return { size: this.lengthArb.generate(mrng, undefined).value }; | ||
} | ||
if (mrng.nextInt(1, biasFactor) !== 1 || this.minLength === this.maxLength) { | ||
@@ -121,2 +128,23 @@ return { size: this.lengthArb.generate(mrng, undefined).value, biasFactorItems: biasFactor }; | ||
} | ||
shrinkItemByItem(value, safeContext, endIndex) { | ||
let shrinks = Stream.nil(); | ||
for (let index = safeContext.startIndex; index < endIndex; ++index) { | ||
shrinks = shrinks.join(makeLazy(() => this.arb | ||
.shrink(value[index], safeContext.itemsContexts[index]) | ||
.map((v) => { | ||
const beforeCurrent = value | ||
.slice(0, index) | ||
.map((v, i) => new NextValue(cloneIfNeeded(v), safeContext.itemsContexts[i])); | ||
const afterCurrent = value | ||
.slice(index + 1) | ||
.map((v, i) => new NextValue(cloneIfNeeded(v), safeContext.itemsContexts[i + index + 1])); | ||
return [ | ||
beforeCurrent.concat(v).concat(afterCurrent), | ||
undefined, | ||
index, | ||
]; | ||
}))); | ||
} | ||
return shrinks; | ||
} | ||
shrinkImpl(value, context) { | ||
@@ -128,3 +156,3 @@ if (value.length === 0) { | ||
? context | ||
: { shrunkOnce: false, lengthContext: undefined, itemsContexts: [] }; | ||
: { shrunkOnce: false, lengthContext: undefined, itemsContexts: [], startIndex: 0 }; | ||
return (this.lengthArb | ||
@@ -140,28 +168,31 @@ .shrink(value.length, safeContext.lengthContext) | ||
lengthValue.context, | ||
0, | ||
]; | ||
}) | ||
.join(this.arb.shrink(value[0], safeContext.itemsContexts[0]).map((v) => { | ||
return [ | ||
[v].concat(value.slice(1).map((v, index) => new NextValue(cloneIfNeeded(v), safeContext.itemsContexts[index + 1]))), | ||
undefined, | ||
]; | ||
})) | ||
.join(makeLazy(() => value.length > this.minLength | ||
? this.shrinkItemByItem(value, safeContext, 1) | ||
: this.shrinkItemByItem(value, safeContext, value.length))) | ||
.join(value.length > this.minLength | ||
? makeLazy(() => this.shrinkImpl(value.slice(1), { | ||
shrunkOnce: false, | ||
lengthContext: undefined, | ||
itemsContexts: safeContext.itemsContexts.slice(1), | ||
? makeLazy(() => { | ||
const subContext = { | ||
shrunkOnce: false, | ||
lengthContext: undefined, | ||
itemsContexts: safeContext.itemsContexts.slice(1), | ||
startIndex: 0, | ||
}; | ||
return this.shrinkImpl(value.slice(1), subContext) | ||
.filter((v) => this.minLength <= v[0].length + 1) | ||
.map((v) => { | ||
return [ | ||
[new NextValue(cloneIfNeeded(value[0]), safeContext.itemsContexts[0])].concat(v[0]), | ||
undefined, | ||
0, | ||
]; | ||
}); | ||
}) | ||
.filter((v) => this.minLength <= v[0].length + 1) | ||
.map((v) => { | ||
return [ | ||
[new NextValue(cloneIfNeeded(value[0]), safeContext.itemsContexts[0])].concat(v[0]), | ||
undefined, | ||
]; | ||
})) | ||
: Stream.nil())); | ||
} | ||
shrink(value, context) { | ||
return this.shrinkImpl(value, context).map((contextualValue) => this.wrapper(contextualValue[0], true, contextualValue[1])); | ||
return this.shrinkImpl(value, context).map((contextualValue) => this.wrapper(contextualValue[0], true, contextualValue[1], contextualValue[2])); | ||
} | ||
} |
@@ -25,3 +25,3 @@ import { Stream } from '../../stream/Stream.js'; | ||
if (warbs.length === 0) { | ||
throw new Error(`${label} expects at least one weigthed arbitrary`); | ||
throw new Error(`${label} expects at least one weighted arbitrary`); | ||
} | ||
@@ -28,0 +28,0 @@ let totalWeight = 0; |
import { boolean } from '../../boolean.js'; | ||
import { constant } from '../../constant.js'; | ||
import { double } from '../../double.js'; | ||
import { maxSafeInteger } from '../../maxSafeInteger.js'; | ||
export function jsonConstraintsBuilder(stringArbitrary, constraints) { | ||
@@ -9,3 +8,2 @@ const key = stringArbitrary; | ||
boolean(), | ||
maxSafeInteger(), | ||
double({ next: true, noDefaultInfinity: true, noNaN: true }), | ||
@@ -12,0 +10,0 @@ stringArbitrary, |
@@ -25,3 +25,3 @@ export function countToggledBits(n) { | ||
const positions = []; | ||
for (let idx = 0; idx !== chars.length; ++idx) { | ||
for (let idx = chars.length - 1; idx !== -1; --idx) { | ||
if (toggleCase(chars[idx]) !== chars[idx]) | ||
@@ -28,0 +28,0 @@ positions.push(idx); |
@@ -10,3 +10,3 @@ import { buildCharacterArbitrary } from './_internals/builders/CharacterArbitraryBuilder.js'; | ||
? v - 48 | ||
: v < 103 | ||
: v >= 97 && v < 103 | ||
? v - 97 + 10 | ||
@@ -13,0 +13,0 @@ : -1; |
@@ -7,3 +7,3 @@ var _a; | ||
const identifier = '__ConverterToNext__'; | ||
function fromShrinkableToNextValue(g) { | ||
export function fromShrinkableToNextValue(g) { | ||
if (!g.hasToBeCloned) { | ||
@@ -10,0 +10,0 @@ return new NextValue(g.value_, g); |
import { genericTuple } from '../../arbitrary/genericTuple.js'; | ||
import { convertFromNextAsyncPropertyWithHooks } from './ConvertersProperty.js'; | ||
import { AsyncProperty } from './AsyncProperty.generic.js'; | ||
import { AlwaysShrinkableArbitrary } from '../../arbitrary/_internals/AlwaysShrinkableArbitrary.js'; | ||
import { convertFromNext, convertToNext } from '../arbitrary/definition/Converters.js'; | ||
function asyncProperty(...args) { | ||
@@ -8,4 +11,4 @@ if (args.length < 2) | ||
const p = args[args.length - 1]; | ||
return new AsyncProperty(genericTuple(arbs), t => p(...t)); | ||
return convertFromNextAsyncPropertyWithHooks(new AsyncProperty(genericTuple(arbs.map(arb => convertFromNext(new AlwaysShrinkableArbitrary(convertToNext(arb))))), t => p(...t))); | ||
} | ||
export { asyncProperty }; |
import { PreconditionFailure } from '../precondition/PreconditionFailure.js'; | ||
import { runIdToFrequency } from './IRawProperty.js'; | ||
import { readConfigureGlobal } from '../runner/configuration/GlobalParameters.js'; | ||
import { ConverterFromNext } from '../arbitrary/definition/ConverterFromNext.js'; | ||
import { Stream } from '../../stream/Stream.js'; | ||
import { convertToNext } from '../arbitrary/definition/Converters.js'; | ||
import { noUndefinedAsContext, UndefinedContextPlaceholder, } from '../../arbitrary/_internals/helpers/NoUndefinedAsContext.js'; | ||
export class AsyncProperty { | ||
constructor(arb, predicate) { | ||
this.arb = arb; | ||
constructor(rawArb, predicate) { | ||
this.predicate = predicate; | ||
this.isAsync = () => true; | ||
const { asyncBeforeEach, asyncAfterEach, beforeEach, afterEach } = readConfigureGlobal() || {}; | ||
@@ -19,8 +19,17 @@ if (asyncBeforeEach !== undefined && beforeEach !== undefined) { | ||
this.afterEachHook = asyncAfterEach || afterEach || AsyncProperty.dummyHook; | ||
this.arb = convertToNext(rawArb); | ||
} | ||
isAsync() { | ||
return true; | ||
} | ||
generate(mrng, runId) { | ||
if (ConverterFromNext.isConverterFromNext(this.arb)) { | ||
return this.arb.toShrinkable(this.arb.arb.generate(mrng, runId != null ? runIdToFrequency(runId) : undefined)); | ||
const value = this.arb.generate(mrng, runId != null ? runIdToFrequency(runId) : undefined); | ||
return noUndefinedAsContext(value); | ||
} | ||
shrink(value) { | ||
if (value.context === undefined && !this.arb.canShrinkWithoutContext(value.value_)) { | ||
return Stream.nil(); | ||
} | ||
return runId != null ? this.arb.withBias(runIdToFrequency(runId)).generate(mrng) : this.arb.generate(mrng); | ||
const safeContext = value.context !== UndefinedContextPlaceholder ? value.context : undefined; | ||
return this.arb.shrink(value.value_, safeContext).map(noUndefinedAsContext); | ||
} | ||
@@ -27,0 +36,0 @@ async run(v) { |
@@ -19,18 +19,25 @@ import { stringify } from '../../utils/stringify.js'; | ||
this.coveredCases = new Map(); | ||
this.isAsync = () => this.property.isAsync(); | ||
this.generate = (mrng, runId) => this.property.generate(mrng, runId); | ||
this.run = (v) => { | ||
const stringifiedValue = stringify(v); | ||
if (this.coveredCases.has(stringifiedValue)) { | ||
const lastOutput = this.coveredCases.get(stringifiedValue); | ||
if (!this.skipRuns) { | ||
return lastOutput; | ||
} | ||
return fromCachedUnsafe(lastOutput, this.property.isAsync()); | ||
} | ||
isAsync() { | ||
return this.property.isAsync(); | ||
} | ||
generate(mrng, runId) { | ||
return this.property.generate(mrng, runId); | ||
} | ||
shrink(value) { | ||
return this.property.shrink(value); | ||
} | ||
run(v) { | ||
const stringifiedValue = stringify(v); | ||
if (this.coveredCases.has(stringifiedValue)) { | ||
const lastOutput = this.coveredCases.get(stringifiedValue); | ||
if (!this.skipRuns) { | ||
return lastOutput; | ||
} | ||
const out = this.property.run(v); | ||
this.coveredCases.set(stringifiedValue, out); | ||
return out; | ||
}; | ||
return fromCachedUnsafe(lastOutput, this.property.isAsync()); | ||
} | ||
const out = this.property.run(v); | ||
this.coveredCases.set(stringifiedValue, out); | ||
return out; | ||
} | ||
} |
import { genericTuple } from '../../arbitrary/genericTuple.js'; | ||
import { convertFromNextPropertyWithHooks } from './ConvertersProperty.js'; | ||
import { Property } from './Property.generic.js'; | ||
import { AlwaysShrinkableArbitrary } from '../../arbitrary/_internals/AlwaysShrinkableArbitrary.js'; | ||
import { convertFromNext, convertToNext } from '../arbitrary/definition/Converters.js'; | ||
function property(...args) { | ||
@@ -8,4 +11,4 @@ if (args.length < 2) | ||
const p = args[args.length - 1]; | ||
return new Property(genericTuple(arbs), t => p(...t)); | ||
return convertFromNextPropertyWithHooks(new Property(genericTuple(arbs.map(arb => convertFromNext(new AlwaysShrinkableArbitrary(convertToNext(arb))))), t => p(...t))); | ||
} | ||
export { property }; |
import { PreconditionFailure } from '../precondition/PreconditionFailure.js'; | ||
import { runIdToFrequency } from './IRawProperty.js'; | ||
import { readConfigureGlobal } from '../runner/configuration/GlobalParameters.js'; | ||
import { ConverterFromNext } from '../arbitrary/definition/ConverterFromNext.js'; | ||
import { convertToNext } from '../arbitrary/definition/Converters.js'; | ||
import { Stream } from '../../stream/Stream.js'; | ||
import { noUndefinedAsContext, UndefinedContextPlaceholder, } from '../../arbitrary/_internals/helpers/NoUndefinedAsContext.js'; | ||
export class Property { | ||
constructor(arb, predicate) { | ||
this.arb = arb; | ||
constructor(rawArb, predicate) { | ||
this.predicate = predicate; | ||
this.isAsync = () => false; | ||
const { beforeEach = Property.dummyHook, afterEach = Property.dummyHook, asyncBeforeEach, asyncAfterEach, } = readConfigureGlobal() || {}; | ||
@@ -19,8 +19,17 @@ if (asyncBeforeEach !== undefined) { | ||
this.afterEachHook = afterEach; | ||
this.arb = convertToNext(rawArb); | ||
} | ||
isAsync() { | ||
return false; | ||
} | ||
generate(mrng, runId) { | ||
if (ConverterFromNext.isConverterFromNext(this.arb)) { | ||
return this.arb.toShrinkable(this.arb.arb.generate(mrng, runId != null ? runIdToFrequency(runId) : undefined)); | ||
const value = this.arb.generate(mrng, runId != null ? runIdToFrequency(runId) : undefined); | ||
return noUndefinedAsContext(value); | ||
} | ||
shrink(value) { | ||
if (value.context === undefined && !this.arb.canShrinkWithoutContext(value.value_)) { | ||
return Stream.nil(); | ||
} | ||
return runId != null ? this.arb.withBias(runIdToFrequency(runId)).generate(mrng) : this.arb.generate(mrng); | ||
const safeContext = value.context !== UndefinedContextPlaceholder ? value.context : undefined; | ||
return this.arb.shrink(value.value_, safeContext).map(noUndefinedAsContext); | ||
} | ||
@@ -27,0 +36,0 @@ run(v) { |
@@ -7,18 +7,25 @@ import { PreconditionFailure } from '../precondition/PreconditionFailure.js'; | ||
this.interruptExecution = interruptExecution; | ||
this.isAsync = () => this.property.isAsync(); | ||
this.generate = (mrng, runId) => this.property.generate(mrng, runId); | ||
this.run = (v) => { | ||
if (this.getTime() >= this.skipAfterTime) { | ||
const preconditionFailure = new PreconditionFailure(this.interruptExecution); | ||
if (this.isAsync()) { | ||
return Promise.resolve(preconditionFailure); | ||
} | ||
else { | ||
return preconditionFailure; | ||
} | ||
} | ||
return this.property.run(v); | ||
}; | ||
this.skipAfterTime = this.getTime() + timeLimit; | ||
} | ||
isAsync() { | ||
return this.property.isAsync(); | ||
} | ||
generate(mrng, runId) { | ||
return this.property.generate(mrng, runId); | ||
} | ||
shrink(value) { | ||
return this.property.shrink(value); | ||
} | ||
run(v) { | ||
if (this.getTime() >= this.skipAfterTime) { | ||
const preconditionFailure = new PreconditionFailure(this.interruptExecution); | ||
if (this.isAsync()) { | ||
return Promise.resolve(preconditionFailure); | ||
} | ||
else { | ||
return preconditionFailure; | ||
} | ||
} | ||
return this.property.run(v); | ||
} | ||
} |
@@ -17,7 +17,12 @@ const timeoutAfter = (timeMs) => { | ||
this.timeMs = timeMs; | ||
this.isAsync = () => true; | ||
} | ||
isAsync() { | ||
return true; | ||
} | ||
generate(mrng, runId) { | ||
return this.property.generate(mrng, runId); | ||
} | ||
shrink(value) { | ||
return this.property.shrink(value); | ||
} | ||
async run(v) { | ||
@@ -24,0 +29,0 @@ const t = timeoutAfter(this.timeMs); |
export class UnbiasedProperty { | ||
constructor(property) { | ||
this.property = property; | ||
this.isAsync = () => this.property.isAsync(); | ||
this.generate = (mrng, _runId) => this.property.generate(mrng); | ||
this.run = (v) => this.property.run(v); | ||
} | ||
isAsync() { | ||
return this.property.isAsync(); | ||
} | ||
generate(mrng, _runId) { | ||
return this.property.generate(mrng, undefined); | ||
} | ||
shrink(value) { | ||
return this.property.shrink(value); | ||
} | ||
run(v) { | ||
return this.property.run(v); | ||
} | ||
} |
@@ -5,4 +5,5 @@ import { SkipAfterProperty } from '../property/SkipAfterProperty.js'; | ||
import { IgnoreEqualValuesProperty } from '../property/IgnoreEqualValuesProperty.js'; | ||
import { convertToNextProperty } from '../property/ConvertersProperty.js'; | ||
export function decorateProperty(rawProperty, qParams) { | ||
let prop = rawProperty; | ||
let prop = convertToNextProperty(rawProperty); | ||
if (rawProperty.isAsync() && qParams.timeout != null) { | ||
@@ -9,0 +10,0 @@ prop = new TimeoutProperty(prop, qParams.timeout); |
@@ -1,3 +0,2 @@ | ||
import { stream } from '../../stream/Stream.js'; | ||
import { Shrinkable } from '../arbitrary/definition/Shrinkable.js'; | ||
import { Stream, stream } from '../../stream/Stream.js'; | ||
import { readConfigureGlobal } from './configuration/GlobalParameters.js'; | ||
@@ -11,4 +10,4 @@ import { QualifiedParameters } from './configuration/QualifiedParameters.js'; | ||
import { asyncReportRunDetails, reportRunDetails } from './utils/RunDetailsFormatter.js'; | ||
function runIt(property, sourceValues, verbose, interruptedAsFailure) { | ||
const runner = new RunnerIterator(sourceValues, verbose, interruptedAsFailure); | ||
function runIt(property, shrink, sourceValues, verbose, interruptedAsFailure) { | ||
const runner = new RunnerIterator(sourceValues, shrink, verbose, interruptedAsFailure); | ||
for (const v of runner) { | ||
@@ -20,4 +19,4 @@ const out = property.run(v); | ||
} | ||
async function asyncRunIt(property, sourceValues, verbose, interruptedAsFailure) { | ||
const runner = new RunnerIterator(sourceValues, verbose, interruptedAsFailure); | ||
async function asyncRunIt(property, shrink, sourceValues, verbose, interruptedAsFailure) { | ||
const runner = new RunnerIterator(sourceValues, shrink, verbose, interruptedAsFailure); | ||
for (const v of runner) { | ||
@@ -29,3 +28,3 @@ const out = await property.run(v); | ||
} | ||
function runnerPathWalker(valueProducers, path) { | ||
function runnerPathWalker(valueProducers, shrink, path) { | ||
const pathPoints = path.split(':'); | ||
@@ -36,14 +35,9 @@ const pathStream = stream(valueProducers) | ||
const adaptedPath = ['0', ...pathPoints.slice(1)].join(':'); | ||
return stream(pathWalk(adaptedPath, pathStream)).map((v) => () => v); | ||
return stream(pathWalk(adaptedPath, pathStream, shrink)).map((v) => () => v); | ||
} | ||
function buildInitialValues(valueProducers, qParams) { | ||
const rawValues = qParams.path.length === 0 ? stream(valueProducers) : runnerPathWalker(valueProducers, qParams.path); | ||
if (!qParams.endOnFailure) | ||
return rawValues; | ||
return rawValues.map((shrinkableGen) => { | ||
return () => { | ||
const s = shrinkableGen(); | ||
return new Shrinkable(s.value_); | ||
}; | ||
}); | ||
function buildInitialValues(valueProducers, shrink, qParams) { | ||
if (qParams.path.length === 0) { | ||
return stream(valueProducers); | ||
} | ||
return runnerPathWalker(valueProducers, shrink, qParams.path); | ||
} | ||
@@ -64,7 +58,9 @@ function check(rawProperty, params) { | ||
const maxSkips = qParams.numRuns * qParams.maxSkipsPerRun; | ||
const initialValues = buildInitialValues(generator, qParams); | ||
const shrink = property.shrink.bind(property); | ||
const initialValues = buildInitialValues(generator, shrink, qParams); | ||
const sourceValues = new SourceValuesIterator(initialValues, maxInitialIterations, maxSkips); | ||
const finalShrink = !qParams.endOnFailure ? shrink : Stream.nil; | ||
return property.isAsync() | ||
? asyncRunIt(property, sourceValues, qParams.verbose, qParams.markInterruptAsFailure).then((e) => e.toRunDetails(qParams.seed, qParams.path, maxSkips, qParams)) | ||
: runIt(property, sourceValues, qParams.verbose, qParams.markInterruptAsFailure).toRunDetails(qParams.seed, qParams.path, maxSkips, qParams); | ||
? asyncRunIt(property, finalShrink, sourceValues, qParams.verbose, qParams.markInterruptAsFailure).then((e) => e.toRunDetails(qParams.seed, qParams.path, maxSkips, qParams)) | ||
: runIt(property, finalShrink, sourceValues, qParams.verbose, qParams.markInterruptAsFailure).toRunDetails(qParams.seed, qParams.path, maxSkips, qParams); | ||
} | ||
@@ -71,0 +67,0 @@ function assert(property, params) { |
import { RunExecution } from './reporter/RunExecution.js'; | ||
export class RunnerIterator { | ||
constructor(sourceValues, verbose, interruptedAsFailure) { | ||
constructor(sourceValues, shrink, verbose, interruptedAsFailure) { | ||
this.sourceValues = sourceValues; | ||
this.shrink = shrink; | ||
this.runExecution = new RunExecution(verbose, interruptedAsFailure); | ||
@@ -17,3 +18,3 @@ this.currentIdx = -1; | ||
} | ||
this.currentShrinkable = nextValue.value; | ||
this.currentValue = nextValue.value; | ||
++this.currentIdx; | ||
@@ -24,9 +25,9 @@ return { done: false, value: nextValue.value.value_ }; | ||
if (result != null && typeof result === 'string') { | ||
this.runExecution.fail(this.currentShrinkable.value_, this.currentIdx, result); | ||
this.runExecution.fail(this.currentValue.value_, this.currentIdx, result); | ||
this.currentIdx = -1; | ||
this.nextValues = this.currentShrinkable.shrink(); | ||
this.nextValues = this.shrink(this.currentValue); | ||
} | ||
else if (result != null) { | ||
if (!result.interruptExecution) { | ||
this.runExecution.skip(this.currentShrinkable.value_); | ||
this.runExecution.skip(this.currentValue.value_); | ||
this.sourceValues.skippedOne(); | ||
@@ -39,5 +40,5 @@ } | ||
else { | ||
this.runExecution.success(this.currentShrinkable.value_); | ||
this.runExecution.success(this.currentValue.value_); | ||
} | ||
} | ||
} |
import { stream } from '../../stream/Stream.js'; | ||
import { convertToNextProperty } from '../property/ConvertersProperty.js'; | ||
import { Property } from '../property/Property.generic.js'; | ||
@@ -11,3 +12,3 @@ import { UnbiasedProperty } from '../property/UnbiasedProperty.js'; | ||
? new Property(generator, () => true) | ||
: generator; | ||
: convertToNextProperty(generator); | ||
return qParams.unbiased === true ? new UnbiasedProperty(prop) : prop; | ||
@@ -19,7 +20,9 @@ } | ||
const qParams = QualifiedParameters.read(extendedParams); | ||
const tossedValues = stream(toss(toProperty(generator, qParams), qParams.seed, qParams.randomType, qParams.examples)); | ||
const nextProperty = toProperty(generator, qParams); | ||
const shrink = nextProperty.shrink.bind(nextProperty); | ||
const tossedValues = stream(toss(nextProperty, qParams.seed, qParams.randomType, qParams.examples)); | ||
if (qParams.path.length === 0) { | ||
return tossedValues.take(qParams.numRuns).map((s) => s().value_); | ||
} | ||
return stream(pathWalk(qParams.path, tossedValues.map((s) => s()))) | ||
return stream(pathWalk(qParams.path, tossedValues.map((s) => s()), shrink)) | ||
.take(qParams.numRuns) | ||
@@ -26,0 +29,0 @@ .map((s) => s.value_); |
import { skipN } from 'pure-rand'; | ||
import { Random } from '../../random/generator/Random.js'; | ||
import { Shrinkable } from '../arbitrary/definition/Shrinkable.js'; | ||
import { convertToRandomGenerator } from '../../random/generator/PureRandom.js'; | ||
import { NextValue } from '../arbitrary/definition/NextValue.js'; | ||
function lazyGenerate(generator, rng, idx) { | ||
@@ -9,3 +9,3 @@ return () => generator.generate(new Random(rng), idx); | ||
export function* toss(generator, seed, random, examples) { | ||
yield* examples.map((e) => () => new Shrinkable(e)); | ||
yield* examples.map((e) => () => new NextValue(e, undefined)); | ||
let idx = 0; | ||
@@ -12,0 +12,0 @@ let rng = convertToRandomGenerator(random(seed)); |
import { stream } from '../../../stream/Stream.js'; | ||
export function pathWalk(path, initialValues) { | ||
export function pathWalk(path, initialValues, shrink) { | ||
let values = stream(initialValues); | ||
@@ -16,5 +16,5 @@ const segments = path.split(':').map((text) => +text); | ||
} | ||
values = valueToShrink.shrink().drop(s); | ||
values = shrink(valueToShrink).drop(s); | ||
} | ||
return values; | ||
} |
@@ -109,4 +109,4 @@ import { pre } from './check/precondition/Pre.js'; | ||
const __type = 'module'; | ||
const __version = '2.18.1'; | ||
const __commitHash = 'dd2135fb3b5d19c66e6370ad82f131a5f7739094'; | ||
const __version = '2.19.0'; | ||
const __commitHash = '099fdd7ab35a76cf2b2f5f4578a3da3fb67b2c83'; | ||
export { __type, __version, __commitHash, sample, statistics, check, assert, pre, PreconditionFailure, property, asyncProperty, boolean, falsy, float, double, integer, nat, maxSafeInteger, maxSafeNat, bigIntN, bigUintN, bigInt, bigUint, char, ascii, char16bits, unicode, fullUnicode, hexa, base64, mixedCase, string, asciiString, string16bits, stringOf, unicodeString, fullUnicodeString, hexaString, base64String, lorem, constant, constantFrom, clonedConstant, mapToConstant, option, oneof, frequency, clone, dedup, shuffledSubarray, subarray, array, sparseArray, infiniteStream, set, tuple, genericTuple, record, dictionary, anything, object, json, jsonObject, unicodeJson, unicodeJsonObject, letrec, memo, compareBooleanFunc, compareFunc, func, context, date, ipV4, ipV4Extended, ipV6, domain, webAuthority, webSegment, webFragments, webQueryParameters, webUrl, emailAddress, uuid, uuidV, int8Array, uint8Array, uint8ClampedArray, int16Array, uint16Array, int32Array, uint32Array, float32Array, float64Array, asyncModelRun, modelRun, scheduledModelRun, commands, scheduler, schedulerFor, Arbitrary, NextArbitrary, ArbitraryWithShrink, ArbitraryWithContextualShrink, Shrinkable, NextValue, cloneMethod, cloneIfNeeded, hasCloneMethod, convertFromNext, convertFromNextWithShrunkOnce, convertToNext, toStringMethod, hasToStringMethod, asyncToStringMethod, hasAsyncToStringMethod, stringify, asyncStringify, defaultReportMessage, asyncDefaultReportMessage, hash, VerbosityLevel, configureGlobal, readConfigureGlobal, resetConfigureGlobal, ExecutionStatus, Random, Stream, stream, }; |
@@ -240,5 +240,5 @@ "use strict"; | ||
exports.__type = __type; | ||
const __version = '2.18.1'; | ||
const __version = '2.19.0'; | ||
exports.__version = __version; | ||
const __commitHash = 'dd2135fb3b5d19c66e6370ad82f131a5f7739094'; | ||
const __commitHash = '099fdd7ab35a76cf2b2f5f4578a3da3fb67b2c83'; | ||
exports.__commitHash = __commitHash; |
@@ -127,3 +127,3 @@ import { pre } from './check/precondition/Pre'; | ||
/** | ||
* Version of fast-check used by your project (eg.: 2.18.1) | ||
* Version of fast-check used by your project (eg.: 2.19.0) | ||
* @remarks Since 1.22.0 | ||
@@ -134,3 +134,3 @@ * @public | ||
/** | ||
* Commit hash of the current code (eg.: dd2135fb3b5d19c66e6370ad82f131a5f7739094) | ||
* Commit hash of the current code (eg.: 099fdd7ab35a76cf2b2f5f4578a3da3fb67b2c83) | ||
* @remarks Since 2.7.0 | ||
@@ -137,0 +137,0 @@ * @public |
{ | ||
"name": "fast-check", | ||
"version": "2.18.1", | ||
"version": "2.19.0", | ||
"description": "Property based testing framework for JavaScript (like QuickCheck)", | ||
@@ -33,6 +33,6 @@ "type": "commonjs", | ||
"watch": "tsc -w", | ||
"test": "jest --config jest.unit.config.cjs --coverage", | ||
"test": "jest --config jest.unit.config.cjs --coverage --verbose", | ||
"test:watch": "jest --config jest.unit.config.cjs --watch", | ||
"test:debug": "node --inspect node_modules/jest/bin/jest.js --config jest.unit.config.cjs --watch --runInBand", | ||
"e2e": "jest --config jest.e2e.config.cjs --coverage", | ||
"e2e": "jest --config jest.e2e.config.cjs --coverage --verbose", | ||
"e2e:watch": "jest --config jest.e2e.config.cjs --watch", | ||
@@ -39,0 +39,0 @@ "update:examples": "cross-env UPDATE_CODE_SNIPPETS=true jest --config jest.examples.config.cjs", |
@@ -100,2 +100,3 @@ <h1 align="center"> | ||
- **Unique:** detect race conditions in your code \[[more](https://github.com/dubzzz/fast-check/blob/main/documentation/Tips.md#detect-race-conditions)\] - *shuffle the way your promises and async calls resolve using the power of property based testing to detect races* | ||
- **Unique:** simplify user definable corner cases \[[more](https://github.com/dubzzz/fast-check/blob/main/documentation/Tips.md#simplify-user-definable-corner-cases)\] - *simplify bug resolution by asking fast-check if it can find an even simpler corner case* | ||
@@ -102,0 +103,0 @@ For more details, refer to the documentation in the links above. |
959309
656
19582
175