@firfi/quint-connect
Version:
Model-based testing framework connecting Quint specifications to TypeScript implementations
62 lines • 3.22 kB
JavaScript
import { Effect, Schema, SchemaGetter } from "effect";
import { QuintError } from "./errors.js";
import { DEFAULT_MAX_SAMPLES, DEFAULT_MAX_STEPS, DEFAULT_N_TRACES } from "./run-options.js";
const RANDOM_SEED_HEX_LENGTH = 16;
const HEX_RADIX = 16;
const MIN_EVALUATOR_THREADS = 2;
const RuntimeFields = Schema.Struct({
nruns: Schema.optional(Schema.Number),
nsteps: Schema.optional(Schema.Number),
ntraces: Schema.optional(Schema.Number),
nthreads: Schema.optional(Schema.Number)
});
const CompiledEvaluatorInputValue = Schema.Struct({
source: Schema.String,
runtime: RuntimeFields
});
const runtimeInteger = (source, pattern) => {
const value = pattern.exec(source)?.[1];
return value === undefined ? undefined : Number(value);
};
const CompiledEvaluatorInput = Schema.String.pipe(Schema.decodeTo(Schema.toType(CompiledEvaluatorInputValue), {
decode: SchemaGetter.transform((source) => ({
source,
runtime: {
nruns: runtimeInteger(source, /"nruns":\s*(\d+)/),
nsteps: runtimeInteger(source, /"nsteps":\s*(\d+)/),
ntraces: runtimeInteger(source, /"ntraces":\s*(\d+)/),
nthreads: runtimeInteger(source, /"nthreads":\s*(\d+)/)
}
})),
encode: SchemaGetter.transform((input) => input.source)
}));
export const decodeCompiledEvaluatorInput = (input) => Schema.decodeUnknownEffect(CompiledEvaluatorInput)(input).pipe(Effect.mapError((error) => new QuintError({ message: `Invalid compiled evaluator input: ${error}` })));
const parseSeed = BigInt;
export const makeRandomSeedHex = () => Array.from({ length: RANDOM_SEED_HEX_LENGTH }, () => Math.floor(Math.random() * HEX_RADIX).toString(HEX_RADIX)).join("");
export const patchCompiledEvaluatorInput = (compiledInput, opts, cpuCount, randomSeedHex) => {
const nTraces = opts.nTraces ?? DEFAULT_N_TRACES;
const maxSamples = opts.maxSamples ?? DEFAULT_MAX_SAMPLES;
const maxSteps = opts.maxSteps ?? DEFAULT_MAX_STEPS;
const nThreads = Math.max(MIN_EVALUATOR_THREADS, Math.min(maxSamples, cpuCount));
let patchedInput = compiledInput.source;
if (compiledInput.runtime.nruns !== undefined) {
patchedInput = patchedInput.replace(/"nruns":\s*\d+/, `"nruns":${maxSamples}`);
}
if (compiledInput.runtime.nsteps !== undefined) {
patchedInput = patchedInput.replace(/"nsteps":\s*\d+/, `"nsteps":${maxSteps}`);
}
if (compiledInput.runtime.ntraces !== undefined) {
patchedInput = patchedInput.replace(/"ntraces":\s*\d+/, `"ntraces":${nTraces}`);
}
if (compiledInput.runtime.nthreads !== undefined) {
patchedInput = patchedInput.replace(/"nthreads":\s*\d+/, `"nthreads":${nThreads}`);
}
const seedBigint = opts.seed !== undefined ? parseSeed(opts.seed) : BigInt(`0x${randomSeedHex}`);
const seedHex = `0x${seedBigint.toString(HEX_RADIX)}`;
const seedReplaced = patchedInput.replace(/"seed":\s*(?:null|undefined|\d+)/, `"seed":${seedBigint}`);
patchedInput = seedReplaced === patchedInput
? patchedInput.replace(/}\s*$/, `,"seed":${seedBigint}}`)
: seedReplaced;
return { input: patchedInput, seedHex };
};
//# sourceMappingURL=compiled-evaluator-input.js.map