Aktueller Stand

This commit is contained in:
2026-01-23 01:33:35 +01:00
parent 082dc5e110
commit 2766dd12c5
10109 changed files with 1578841 additions and 77685 deletions

View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decorateProperty = decorateProperty;
const SkipAfterProperty_1 = require("../property/SkipAfterProperty");
const TimeoutProperty_1 = require("../property/TimeoutProperty");
const UnbiasedProperty_1 = require("../property/UnbiasedProperty");
const IgnoreEqualValuesProperty_1 = require("../property/IgnoreEqualValuesProperty");
const safeDateNow = Date.now;
const safeSetTimeout = setTimeout;
const safeClearTimeout = clearTimeout;
function decorateProperty(rawProperty, qParams) {
let prop = rawProperty;
if (rawProperty.isAsync() && qParams.timeout != null) {
prop = new TimeoutProperty_1.TimeoutProperty(prop, qParams.timeout, safeSetTimeout, safeClearTimeout);
}
if (qParams.unbiased) {
prop = new UnbiasedProperty_1.UnbiasedProperty(prop);
}
if (qParams.skipAllAfterTimeLimit != null) {
prop = new SkipAfterProperty_1.SkipAfterProperty(prop, safeDateNow, qParams.skipAllAfterTimeLimit, false, safeSetTimeout, safeClearTimeout);
}
if (qParams.interruptAfterTimeLimit != null) {
prop = new SkipAfterProperty_1.SkipAfterProperty(prop, safeDateNow, qParams.interruptAfterTimeLimit, true, safeSetTimeout, safeClearTimeout);
}
if (qParams.skipEqualValues) {
prop = new IgnoreEqualValuesProperty_1.IgnoreEqualValuesProperty(prop, true);
}
if (qParams.ignoreEqualValues) {
prop = new IgnoreEqualValuesProperty_1.IgnoreEqualValuesProperty(prop, false);
}
return prop;
}

View File

@@ -0,0 +1,74 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.check = check;
exports.assert = assert;
const Stream_1 = require("../../stream/Stream");
const GlobalParameters_1 = require("./configuration/GlobalParameters");
const QualifiedParameters_1 = require("./configuration/QualifiedParameters");
const DecorateProperty_1 = require("./DecorateProperty");
const RunnerIterator_1 = require("./RunnerIterator");
const SourceValuesIterator_1 = require("./SourceValuesIterator");
const Tosser_1 = require("./Tosser");
const PathWalker_1 = require("./utils/PathWalker");
const RunDetailsFormatter_1 = require("./utils/RunDetailsFormatter");
const safeObjectAssign = Object.assign;
function runIt(property, shrink, sourceValues, verbose, interruptedAsFailure) {
const isModernProperty = property.runBeforeEach !== undefined && property.runAfterEach !== undefined;
const runner = new RunnerIterator_1.RunnerIterator(sourceValues, shrink, verbose, interruptedAsFailure);
for (const v of runner) {
if (isModernProperty) {
property.runBeforeEach();
}
const out = property.run(v, isModernProperty);
if (isModernProperty) {
property.runAfterEach();
}
runner.handleResult(out);
}
return runner.runExecution;
}
async function asyncRunIt(property, shrink, sourceValues, verbose, interruptedAsFailure) {
const isModernProperty = property.runBeforeEach !== undefined && property.runAfterEach !== undefined;
const runner = new RunnerIterator_1.RunnerIterator(sourceValues, shrink, verbose, interruptedAsFailure);
for (const v of runner) {
if (isModernProperty) {
await property.runBeforeEach();
}
const out = await property.run(v, isModernProperty);
if (isModernProperty) {
await property.runAfterEach();
}
runner.handleResult(out);
}
return runner.runExecution;
}
function check(rawProperty, params) {
if (rawProperty == null || rawProperty.generate == null)
throw new Error('Invalid property encountered, please use a valid property');
if (rawProperty.run == null)
throw new Error('Invalid property encountered, please use a valid property not an arbitrary');
const qParams = QualifiedParameters_1.QualifiedParameters.read(safeObjectAssign(safeObjectAssign({}, (0, GlobalParameters_1.readConfigureGlobal)()), params));
if (qParams.reporter !== null && qParams.asyncReporter !== null)
throw new Error('Invalid parameters encountered, reporter and asyncReporter cannot be specified together');
if (qParams.asyncReporter !== null && !rawProperty.isAsync())
throw new Error('Invalid parameters encountered, only asyncProperty can be used when asyncReporter specified');
const property = (0, DecorateProperty_1.decorateProperty)(rawProperty, qParams);
const maxInitialIterations = qParams.path.length === 0 || qParams.path.indexOf(':') === -1 ? qParams.numRuns : -1;
const maxSkips = qParams.numRuns * qParams.maxSkipsPerRun;
const shrink = (...args) => property.shrink(...args);
const initialValues = qParams.path.length === 0
? (0, Tosser_1.toss)(property, qParams.seed, qParams.randomType, qParams.examples)
: (0, PathWalker_1.pathWalk)(qParams.path, (0, Stream_1.stream)((0, Tosser_1.lazyToss)(property, qParams.seed, qParams.randomType, qParams.examples)), shrink);
const sourceValues = new SourceValuesIterator_1.SourceValuesIterator(initialValues, maxInitialIterations, maxSkips);
const finalShrink = !qParams.endOnFailure ? shrink : Stream_1.Stream.nil;
return property.isAsync()
? 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);
}
function assert(property, params) {
const out = check(property, params);
if (property.isAsync())
return out.then(RunDetailsFormatter_1.asyncReportRunDetails);
else
(0, RunDetailsFormatter_1.reportRunDetails)(out);
}

View File

@@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunnerIterator = void 0;
const PreconditionFailure_1 = require("../precondition/PreconditionFailure");
const RunExecution_1 = require("./reporter/RunExecution");
class RunnerIterator {
constructor(sourceValues, shrink, verbose, interruptedAsFailure) {
this.sourceValues = sourceValues;
this.shrink = shrink;
this.runExecution = new RunExecution_1.RunExecution(verbose, interruptedAsFailure);
this.currentIdx = -1;
this.nextValues = sourceValues;
}
[Symbol.iterator]() {
return this;
}
next() {
const nextValue = this.nextValues.next();
if (nextValue.done || this.runExecution.interrupted) {
return { done: true, value: undefined };
}
this.currentValue = nextValue.value;
++this.currentIdx;
return { done: false, value: nextValue.value.value_ };
}
handleResult(result) {
if (result != null && typeof result === 'object' && !PreconditionFailure_1.PreconditionFailure.isFailure(result)) {
this.runExecution.fail(this.currentValue.value_, this.currentIdx, result);
this.currentIdx = -1;
this.nextValues = this.shrink(this.currentValue);
}
else if (result != null) {
if (!result.interruptExecution) {
this.runExecution.skip(this.currentValue.value_);
this.sourceValues.skippedOne();
}
else {
this.runExecution.interrupt();
}
}
else {
this.runExecution.success(this.currentValue.value_);
}
}
}
exports.RunnerIterator = RunnerIterator;

View File

@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sample = sample;
exports.statistics = statistics;
const Stream_1 = require("../../stream/Stream");
const Property_generic_1 = require("../property/Property.generic");
const UnbiasedProperty_1 = require("../property/UnbiasedProperty");
const GlobalParameters_1 = require("./configuration/GlobalParameters");
const QualifiedParameters_1 = require("./configuration/QualifiedParameters");
const Tosser_1 = require("./Tosser");
const PathWalker_1 = require("./utils/PathWalker");
function toProperty(generator, qParams) {
const prop = !Object.prototype.hasOwnProperty.call(generator, 'isAsync')
? new Property_generic_1.Property(generator, () => true)
: generator;
return qParams.unbiased === true ? new UnbiasedProperty_1.UnbiasedProperty(prop) : prop;
}
function streamSample(generator, params) {
const extendedParams = typeof params === 'number'
? Object.assign(Object.assign({}, (0, GlobalParameters_1.readConfigureGlobal)()), { numRuns: params }) : Object.assign(Object.assign({}, (0, GlobalParameters_1.readConfigureGlobal)()), params);
const qParams = QualifiedParameters_1.QualifiedParameters.read(extendedParams);
const nextProperty = toProperty(generator, qParams);
const shrink = nextProperty.shrink.bind(nextProperty);
const tossedValues = qParams.path.length === 0
? (0, Stream_1.stream)((0, Tosser_1.toss)(nextProperty, qParams.seed, qParams.randomType, qParams.examples))
: (0, PathWalker_1.pathWalk)(qParams.path, (0, Stream_1.stream)((0, Tosser_1.lazyToss)(nextProperty, qParams.seed, qParams.randomType, qParams.examples)), shrink);
return tossedValues.take(qParams.numRuns).map((s) => s.value_);
}
function sample(generator, params) {
return [...streamSample(generator, params)];
}
function round2(n) {
return (Math.round(n * 100) / 100).toFixed(2);
}
function statistics(generator, classify, params) {
const extendedParams = typeof params === 'number'
? Object.assign(Object.assign({}, (0, GlobalParameters_1.readConfigureGlobal)()), { numRuns: params }) : Object.assign(Object.assign({}, (0, GlobalParameters_1.readConfigureGlobal)()), params);
const qParams = QualifiedParameters_1.QualifiedParameters.read(extendedParams);
const recorded = {};
for (const g of streamSample(generator, params)) {
const out = classify(g);
const categories = Array.isArray(out) ? out : [out];
for (const c of categories) {
recorded[c] = (recorded[c] || 0) + 1;
}
}
const data = Object.entries(recorded)
.sort((a, b) => b[1] - a[1])
.map((i) => [i[0], `${round2((i[1] * 100.0) / qParams.numRuns)}%`]);
const longestName = data.map((i) => i[0].length).reduce((p, c) => Math.max(p, c), 0);
const longestPercent = data.map((i) => i[1].length).reduce((p, c) => Math.max(p, c), 0);
for (const item of data) {
qParams.logger(`${item[0].padEnd(longestName, '.')}..${item[1].padStart(longestPercent, '.')}`);
}
}

View File

@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SourceValuesIterator = void 0;
class SourceValuesIterator {
constructor(initialValues, maxInitialIterations, remainingSkips) {
this.initialValues = initialValues;
this.maxInitialIterations = maxInitialIterations;
this.remainingSkips = remainingSkips;
}
[Symbol.iterator]() {
return this;
}
next() {
if (--this.maxInitialIterations !== -1 && this.remainingSkips >= 0) {
const n = this.initialValues.next();
if (!n.done)
return { value: n.value, done: false };
}
return { value: undefined, done: true };
}
skippedOne() {
--this.remainingSkips;
++this.maxInitialIterations;
}
}
exports.SourceValuesIterator = SourceValuesIterator;

View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.toss = toss;
exports.lazyToss = lazyToss;
const pure_rand_1 = require("pure-rand");
const Random_1 = require("../../random/generator/Random");
const Value_1 = require("../arbitrary/definition/Value");
const globals_1 = require("../../utils/globals");
function tossNext(generator, rng, index) {
rng.unsafeJump();
return generator.generate(new Random_1.Random(rng), index);
}
function* toss(generator, seed, random, examples) {
for (let idx = 0; idx !== examples.length; ++idx) {
yield new Value_1.Value(examples[idx], undefined);
}
for (let idx = 0, rng = random(seed);; ++idx) {
yield tossNext(generator, rng, idx);
}
}
function lazyGenerate(generator, rng, idx) {
return () => generator.generate(new Random_1.Random(rng), idx);
}
function* lazyToss(generator, seed, random, examples) {
yield* (0, globals_1.safeMap)(examples, (e) => () => new Value_1.Value(e, undefined));
let idx = 0;
let rng = random(seed);
for (;;) {
rng = rng.jump ? rng.jump() : (0, pure_rand_1.skipN)(rng, 42);
yield lazyGenerate(generator, rng, idx++);
}
}

View File

@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.configureGlobal = configureGlobal;
exports.readConfigureGlobal = readConfigureGlobal;
exports.resetConfigureGlobal = resetConfigureGlobal;
let globalParameters = {};
function configureGlobal(parameters) {
globalParameters = parameters;
}
function readConfigureGlobal() {
return globalParameters;
}
function resetConfigureGlobal() {
globalParameters = {};
}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,144 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QualifiedParameters = void 0;
const pure_rand_1 = require("pure-rand");
const VerbosityLevel_1 = require("./VerbosityLevel");
const safeDateNow = Date.now;
const safeMathMin = Math.min;
const safeMathRandom = Math.random;
class QualifiedParameters {
constructor(op) {
const p = op || {};
this.seed = QualifiedParameters.readSeed(p);
this.randomType = QualifiedParameters.readRandomType(p);
this.numRuns = QualifiedParameters.readNumRuns(p);
this.verbose = QualifiedParameters.readVerbose(p);
this.maxSkipsPerRun = QualifiedParameters.readOrDefault(p, 'maxSkipsPerRun', 100);
this.timeout = QualifiedParameters.safeTimeout(QualifiedParameters.readOrDefault(p, 'timeout', null));
this.skipAllAfterTimeLimit = QualifiedParameters.safeTimeout(QualifiedParameters.readOrDefault(p, 'skipAllAfterTimeLimit', null));
this.interruptAfterTimeLimit = QualifiedParameters.safeTimeout(QualifiedParameters.readOrDefault(p, 'interruptAfterTimeLimit', null));
this.markInterruptAsFailure = QualifiedParameters.readBoolean(p, 'markInterruptAsFailure');
this.skipEqualValues = QualifiedParameters.readBoolean(p, 'skipEqualValues');
this.ignoreEqualValues = QualifiedParameters.readBoolean(p, 'ignoreEqualValues');
this.logger = QualifiedParameters.readOrDefault(p, 'logger', (v) => {
console.log(v);
});
this.path = QualifiedParameters.readOrDefault(p, 'path', '');
this.unbiased = QualifiedParameters.readBoolean(p, 'unbiased');
this.examples = QualifiedParameters.readOrDefault(p, 'examples', []);
this.endOnFailure = QualifiedParameters.readBoolean(p, 'endOnFailure');
this.reporter = QualifiedParameters.readOrDefault(p, 'reporter', null);
this.asyncReporter = QualifiedParameters.readOrDefault(p, 'asyncReporter', null);
this.errorWithCause = QualifiedParameters.readBoolean(p, 'errorWithCause');
}
toParameters() {
const orUndefined = (value) => (value !== null ? value : undefined);
const parameters = {
seed: this.seed,
randomType: this.randomType,
numRuns: this.numRuns,
maxSkipsPerRun: this.maxSkipsPerRun,
timeout: orUndefined(this.timeout),
skipAllAfterTimeLimit: orUndefined(this.skipAllAfterTimeLimit),
interruptAfterTimeLimit: orUndefined(this.interruptAfterTimeLimit),
markInterruptAsFailure: this.markInterruptAsFailure,
skipEqualValues: this.skipEqualValues,
ignoreEqualValues: this.ignoreEqualValues,
path: this.path,
logger: this.logger,
unbiased: this.unbiased,
verbose: this.verbose,
examples: this.examples,
endOnFailure: this.endOnFailure,
reporter: orUndefined(this.reporter),
asyncReporter: orUndefined(this.asyncReporter),
errorWithCause: this.errorWithCause,
};
return parameters;
}
static read(op) {
return new QualifiedParameters(op);
}
}
exports.QualifiedParameters = QualifiedParameters;
QualifiedParameters.createQualifiedRandomGenerator = (random) => {
return (seed) => {
const rng = random(seed);
if (rng.unsafeJump === undefined) {
rng.unsafeJump = () => (0, pure_rand_1.unsafeSkipN)(rng, 42);
}
return rng;
};
};
QualifiedParameters.readSeed = (p) => {
if (p.seed == null)
return safeDateNow() ^ (safeMathRandom() * 0x100000000);
const seed32 = p.seed | 0;
if (p.seed === seed32)
return seed32;
const gap = p.seed - seed32;
return seed32 ^ (gap * 0x100000000);
};
QualifiedParameters.readRandomType = (p) => {
if (p.randomType == null)
return pure_rand_1.default.xorshift128plus;
if (typeof p.randomType === 'string') {
switch (p.randomType) {
case 'mersenne':
return QualifiedParameters.createQualifiedRandomGenerator(pure_rand_1.default.mersenne);
case 'congruential':
case 'congruential32':
return QualifiedParameters.createQualifiedRandomGenerator(pure_rand_1.default.congruential32);
case 'xorshift128plus':
return pure_rand_1.default.xorshift128plus;
case 'xoroshiro128plus':
return pure_rand_1.default.xoroshiro128plus;
default:
throw new Error(`Invalid random specified: '${p.randomType}'`);
}
}
const mrng = p.randomType(0);
if ('min' in mrng && mrng.min !== -0x80000000) {
throw new Error(`Invalid random number generator: min must equal -0x80000000, got ${String(mrng.min)}`);
}
if ('max' in mrng && mrng.max !== 0x7fffffff) {
throw new Error(`Invalid random number generator: max must equal 0x7fffffff, got ${String(mrng.max)}`);
}
if ('unsafeJump' in mrng) {
return p.randomType;
}
return QualifiedParameters.createQualifiedRandomGenerator(p.randomType);
};
QualifiedParameters.readNumRuns = (p) => {
const defaultValue = 100;
if (p.numRuns != null)
return p.numRuns;
if (p.num_runs != null)
return p.num_runs;
return defaultValue;
};
QualifiedParameters.readVerbose = (p) => {
if (p.verbose == null)
return VerbosityLevel_1.VerbosityLevel.None;
if (typeof p.verbose === 'boolean') {
return p.verbose === true ? VerbosityLevel_1.VerbosityLevel.Verbose : VerbosityLevel_1.VerbosityLevel.None;
}
if (p.verbose <= VerbosityLevel_1.VerbosityLevel.None) {
return VerbosityLevel_1.VerbosityLevel.None;
}
if (p.verbose >= VerbosityLevel_1.VerbosityLevel.VeryVerbose) {
return VerbosityLevel_1.VerbosityLevel.VeryVerbose;
}
return p.verbose | 0;
};
QualifiedParameters.readBoolean = (p, key) => p[key] === true;
QualifiedParameters.readOrDefault = (p, key, defaultValue) => {
const value = p[key];
return value != null ? value : defaultValue;
};
QualifiedParameters.safeTimeout = (value) => {
if (value === null) {
return null;
}
return safeMathMin(value, 0x7fffffff);
};

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VerbosityLevel = void 0;
var VerbosityLevel;
(function (VerbosityLevel) {
VerbosityLevel[VerbosityLevel["None"] = 0] = "None";
VerbosityLevel[VerbosityLevel["Verbose"] = 1] = "Verbose";
VerbosityLevel[VerbosityLevel["VeryVerbose"] = 2] = "VeryVerbose";
})(VerbosityLevel || (exports.VerbosityLevel = VerbosityLevel = {}));

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExecutionStatus = void 0;
var ExecutionStatus;
(function (ExecutionStatus) {
ExecutionStatus[ExecutionStatus["Success"] = 0] = "Success";
ExecutionStatus[ExecutionStatus["Skipped"] = -1] = "Skipped";
ExecutionStatus[ExecutionStatus["Failure"] = 1] = "Failure";
})(ExecutionStatus || (exports.ExecutionStatus = ExecutionStatus = {}));

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,118 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunExecution = void 0;
const VerbosityLevel_1 = require("../configuration/VerbosityLevel");
const ExecutionStatus_1 = require("./ExecutionStatus");
const globals_1 = require("../../../utils/globals");
class RunExecution {
constructor(verbosity, interruptedAsFailure) {
this.verbosity = verbosity;
this.interruptedAsFailure = interruptedAsFailure;
this.isSuccess = () => this.pathToFailure == null;
this.firstFailure = () => (this.pathToFailure ? +(0, globals_1.safeSplit)(this.pathToFailure, ':')[0] : -1);
this.numShrinks = () => (this.pathToFailure ? (0, globals_1.safeSplit)(this.pathToFailure, ':').length - 1 : 0);
this.rootExecutionTrees = [];
this.currentLevelExecutionTrees = this.rootExecutionTrees;
this.failure = null;
this.numSkips = 0;
this.numSuccesses = 0;
this.interrupted = false;
}
appendExecutionTree(status, value) {
const currentTree = { status, value, children: [] };
this.currentLevelExecutionTrees.push(currentTree);
return currentTree;
}
fail(value, id, failure) {
if (this.verbosity >= VerbosityLevel_1.VerbosityLevel.Verbose) {
const currentTree = this.appendExecutionTree(ExecutionStatus_1.ExecutionStatus.Failure, value);
this.currentLevelExecutionTrees = currentTree.children;
}
if (this.pathToFailure == null)
this.pathToFailure = `${id}`;
else
this.pathToFailure += `:${id}`;
this.value = value;
this.failure = failure;
}
skip(value) {
if (this.verbosity >= VerbosityLevel_1.VerbosityLevel.VeryVerbose) {
this.appendExecutionTree(ExecutionStatus_1.ExecutionStatus.Skipped, value);
}
if (this.pathToFailure == null) {
++this.numSkips;
}
}
success(value) {
if (this.verbosity >= VerbosityLevel_1.VerbosityLevel.VeryVerbose) {
this.appendExecutionTree(ExecutionStatus_1.ExecutionStatus.Success, value);
}
if (this.pathToFailure == null) {
++this.numSuccesses;
}
}
interrupt() {
this.interrupted = true;
}
extractFailures() {
if (this.isSuccess()) {
return [];
}
const failures = [];
let cursor = this.rootExecutionTrees;
while (cursor.length > 0 && cursor[cursor.length - 1].status === ExecutionStatus_1.ExecutionStatus.Failure) {
const failureTree = cursor[cursor.length - 1];
failures.push(failureTree.value);
cursor = failureTree.children;
}
return failures;
}
toRunDetails(seed, basePath, maxSkips, qParams) {
if (!this.isSuccess()) {
return {
failed: true,
interrupted: this.interrupted,
numRuns: this.firstFailure() + 1 - this.numSkips,
numSkips: this.numSkips,
numShrinks: this.numShrinks(),
seed,
counterexample: this.value,
counterexamplePath: RunExecution.mergePaths(basePath, this.pathToFailure),
error: this.failure.errorMessage,
errorInstance: this.failure.error,
failures: this.extractFailures(),
executionSummary: this.rootExecutionTrees,
verbose: this.verbosity,
runConfiguration: qParams.toParameters(),
};
}
const considerInterruptedAsFailure = this.interruptedAsFailure || this.numSuccesses === 0;
const failed = this.numSkips > maxSkips || (this.interrupted && considerInterruptedAsFailure);
const out = {
failed,
interrupted: this.interrupted,
numRuns: this.numSuccesses,
numSkips: this.numSkips,
numShrinks: 0,
seed,
counterexample: null,
counterexamplePath: null,
error: null,
errorInstance: null,
failures: [],
executionSummary: this.rootExecutionTrees,
verbose: this.verbosity,
runConfiguration: qParams.toParameters(),
};
return out;
}
}
exports.RunExecution = RunExecution;
RunExecution.mergePaths = (offsetPath, path) => {
if (offsetPath.length === 0)
return path;
const offsetItems = offsetPath.split(':');
const remainingItems = path.split(':');
const middle = +offsetItems[offsetItems.length - 1] + +remainingItems[0];
return [...offsetItems.slice(0, offsetItems.length - 1), `${middle}`, ...remainingItems.slice(1)].join(':');
};

View File

@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.pathWalk = pathWalk;
function produce(producer) {
return producer();
}
function pathWalk(path, initialProducers, shrink) {
const producers = initialProducers;
const segments = path.split(':').map((text) => +text);
if (segments.length === 0) {
return producers.map(produce);
}
if (!segments.every((v) => !Number.isNaN(v))) {
throw new Error(`Unable to replay, got invalid path=${path}`);
}
let values = producers.drop(segments[0]).map(produce);
for (const s of segments.slice(1)) {
const valueToShrink = values.getNthOrLast(0);
if (valueToShrink === null) {
throw new Error(`Unable to replay, got wrong path=${path}`);
}
values = shrink(valueToShrink).drop(s);
}
return values;
}

View File

@@ -0,0 +1,166 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.reportRunDetails = reportRunDetails;
exports.asyncReportRunDetails = asyncReportRunDetails;
exports.defaultReportMessage = defaultReportMessage;
exports.asyncDefaultReportMessage = asyncDefaultReportMessage;
const globals_1 = require("../../../utils/globals");
const stringify_1 = require("../../../utils/stringify");
const VerbosityLevel_1 = require("../configuration/VerbosityLevel");
const ExecutionStatus_1 = require("../reporter/ExecutionStatus");
const safeObjectAssign = Object.assign;
function formatHints(hints) {
if (hints.length === 1) {
return `Hint: ${hints[0]}`;
}
return hints.map((h, idx) => `Hint (${idx + 1}): ${h}`).join('\n');
}
function formatFailures(failures, stringifyOne) {
return `Encountered failures were:\n- ${failures.map(stringifyOne).join('\n- ')}`;
}
function formatExecutionSummary(executionTrees, stringifyOne) {
const summaryLines = [];
const remainingTreesAndDepth = [];
for (const tree of executionTrees.slice().reverse()) {
remainingTreesAndDepth.push({ depth: 1, tree });
}
while (remainingTreesAndDepth.length !== 0) {
const currentTreeAndDepth = remainingTreesAndDepth.pop();
const currentTree = currentTreeAndDepth.tree;
const currentDepth = currentTreeAndDepth.depth;
const statusIcon = currentTree.status === ExecutionStatus_1.ExecutionStatus.Success
? '\x1b[32m\u221A\x1b[0m'
: currentTree.status === ExecutionStatus_1.ExecutionStatus.Failure
? '\x1b[31m\xD7\x1b[0m'
: '\x1b[33m!\x1b[0m';
const leftPadding = Array(currentDepth).join('. ');
summaryLines.push(`${leftPadding}${statusIcon} ${stringifyOne(currentTree.value)}`);
for (const tree of currentTree.children.slice().reverse()) {
remainingTreesAndDepth.push({ depth: currentDepth + 1, tree });
}
}
return `Execution summary:\n${summaryLines.join('\n')}`;
}
function preFormatTooManySkipped(out, stringifyOne) {
const message = `Failed to run property, too many pre-condition failures encountered\n{ seed: ${out.seed} }\n\nRan ${out.numRuns} time(s)\nSkipped ${out.numSkips} time(s)`;
let details = null;
const hints = [
'Try to reduce the number of rejected values by combining map, flatMap and built-in arbitraries',
'Increase failure tolerance by setting maxSkipsPerRun to an higher value',
];
if (out.verbose >= VerbosityLevel_1.VerbosityLevel.VeryVerbose) {
details = formatExecutionSummary(out.executionSummary, stringifyOne);
}
else {
(0, globals_1.safePush)(hints, 'Enable verbose mode at level VeryVerbose in order to check all generated values and their associated status');
}
return { message, details, hints };
}
function preFormatFailure(out, stringifyOne) {
const noErrorInMessage = out.runConfiguration.errorWithCause;
const messageErrorPart = noErrorInMessage ? '' : `\nGot ${(0, globals_1.safeReplace)(out.error, /^Error: /, 'error: ')}`;
const message = `Property failed after ${out.numRuns} tests\n{ seed: ${out.seed}, path: "${out.counterexamplePath}", endOnFailure: true }\nCounterexample: ${stringifyOne(out.counterexample)}\nShrunk ${out.numShrinks} time(s)${messageErrorPart}`;
let details = null;
const hints = [];
if (out.verbose >= VerbosityLevel_1.VerbosityLevel.VeryVerbose) {
details = formatExecutionSummary(out.executionSummary, stringifyOne);
}
else if (out.verbose === VerbosityLevel_1.VerbosityLevel.Verbose) {
details = formatFailures(out.failures, stringifyOne);
}
else {
(0, globals_1.safePush)(hints, 'Enable verbose mode in order to have the list of all failing values encountered during the run');
}
return { message, details, hints };
}
function preFormatEarlyInterrupted(out, stringifyOne) {
const message = `Property interrupted after ${out.numRuns} tests\n{ seed: ${out.seed} }`;
let details = null;
const hints = [];
if (out.verbose >= VerbosityLevel_1.VerbosityLevel.VeryVerbose) {
details = formatExecutionSummary(out.executionSummary, stringifyOne);
}
else {
(0, globals_1.safePush)(hints, 'Enable verbose mode at level VeryVerbose in order to check all generated values and their associated status');
}
return { message, details, hints };
}
function defaultReportMessageInternal(out, stringifyOne) {
if (!out.failed)
return;
const { message, details, hints } = out.counterexamplePath === null
? out.interrupted
? preFormatEarlyInterrupted(out, stringifyOne)
: preFormatTooManySkipped(out, stringifyOne)
: preFormatFailure(out, stringifyOne);
let errorMessage = message;
if (details != null)
errorMessage += `\n\n${details}`;
if (hints.length > 0)
errorMessage += `\n\n${formatHints(hints)}`;
return errorMessage;
}
function defaultReportMessage(out) {
return defaultReportMessageInternal(out, stringify_1.stringify);
}
async function asyncDefaultReportMessage(out) {
const pendingStringifieds = [];
function stringifyOne(value) {
const stringified = (0, stringify_1.possiblyAsyncStringify)(value);
if (typeof stringified === 'string') {
return stringified;
}
pendingStringifieds.push(Promise.all([value, stringified]));
return '\u2026';
}
const firstTryMessage = defaultReportMessageInternal(out, stringifyOne);
if (pendingStringifieds.length === 0) {
return firstTryMessage;
}
const registeredValues = new globals_1.Map(await Promise.all(pendingStringifieds));
function stringifySecond(value) {
const asyncStringifiedIfRegistered = (0, globals_1.safeMapGet)(registeredValues, value);
if (asyncStringifiedIfRegistered !== undefined) {
return asyncStringifiedIfRegistered;
}
return (0, stringify_1.stringify)(value);
}
return defaultReportMessageInternal(out, stringifySecond);
}
function buildError(errorMessage, out) {
if (!out.runConfiguration.errorWithCause) {
throw new globals_1.Error(errorMessage);
}
const ErrorWithCause = globals_1.Error;
const error = new ErrorWithCause(errorMessage, { cause: out.errorInstance });
if (!('cause' in error)) {
safeObjectAssign(error, { cause: out.errorInstance });
}
return error;
}
function throwIfFailed(out) {
if (!out.failed)
return;
throw buildError(defaultReportMessage(out), out);
}
async function asyncThrowIfFailed(out) {
if (!out.failed)
return;
throw buildError(await asyncDefaultReportMessage(out), out);
}
function reportRunDetails(out) {
if (out.runConfiguration.asyncReporter)
return out.runConfiguration.asyncReporter(out);
else if (out.runConfiguration.reporter)
return out.runConfiguration.reporter(out);
else
return throwIfFailed(out);
}
async function asyncReportRunDetails(out) {
if (out.runConfiguration.asyncReporter)
return out.runConfiguration.asyncReporter(out);
else if (out.runConfiguration.reporter)
return out.runConfiguration.reporter(out);
else
return asyncThrowIfFailed(out);
}