UNPKG

effect-ts-laws

Version:
93 lines 3.53 kB
/** * @module law The Law type and functions for working with a single law. */ import { Option as OP, Predicate as PR } from 'effect'; import { tupled } from 'effect/Function'; import fc from 'fast-check'; /** * Build a law from a name, a predicate, an optional note, an arbitrary for the * predicate arguments, and optional `fast-check` runtime parameters. * The runtime parameters are * [documented here](https://fast-check.dev/api-reference/interfaces/Parameters.html). * @example * import {Law, checkLaw, tinyPositive} from 'effect-ts-laws' * import {Option as OP} from 'effect' * * export const law: Law<[number, number]> = Law( * 'sum of positives ≥ both', // • law name * '∀a,b in N, sum=a+b: sum≥a ∧ sum≥b', // • law note * tinyPositive, // • list of * tinyPositive, // arbitraries that * )( // are required for... * (x, y) => x + y >= x && x + y >= y, // • the law predicate * {numRuns: 10_000}, // • optional runtime config * ) * * assert.equal(law.name, 'sum of positives ≥ both') * assert.deepStrictEqual(checkLaw(law), OP.none()) * @typeParam Ts - Argument type of predicate. For example, if the law * predicate signature is `Predicate<[a: number, b: string]>`, then `T` * would be `[a: number, b: string]`. * @param name - Law name, shown as test label. * @param note - String note to be shown on failure or in verbose mode. * @param arbitraries - A tuple of arbitraries, one per predicate argument. * @category constructors */ export const Law = (name, note, ...arbitraries) => ( /** Law predicate. Its argument type is encoded in `Ts`. */ predicate, /** `fast-check` runtime parameters. */ parameters) => ({ name, note, predicate: tupled(predicate), arbitrary: fc.tuple(...arbitraries), /* v8 ignore next 1 */ ...(parameters !== undefined ? { parameters } : {}), }); /** * Return the given law but with its predicate negated. * @typeParam T - Argument type of law predicate. For example, if * the law predicate type is `Predicate<[number, number]>`, then * `T` would be `[number, string]`. * @param law - The law to be negated. * @returns A new `Law` object. * @category combinators */ export const negateLaw = ({ predicate, ...law }) => ({ ...law, predicate: PR.not(predicate) }); /** * Run the law and return either `None` on pass or `Some<string>` with the error * report on fail. * * See also {@link vitest.testLaw | testLaw}. * @category harness */ export const checkLaw = (law, parameters) => { let failMessage = undefined; try { asAssert(law, parameters); } catch (e) { /* v8 ignore next 2 */ if (!(e instanceof Error)) throw new Error(e); failMessage = e.message; } return OP.fromNullable(failMessage); }; /** * Convert the law into a `fast-check` assertion. * @typeParam Ts - Tuple type of law predicate arguments. * @category harness * @param law - The law to be converted. * @param overrides - `fast-check` runtime parameters. * @returns A void function that will throw on predicate failure. */ export const asAssert = ({ name, note, predicate, arbitrary, parameters }, overrides) => { fc.assert(fc.property(arbitrary, (args) => { if (predicate(args)) return true; throw new Error(`${name}: ${note}`); }), { ...parameters, ...overrides }); }; //# sourceMappingURL=law.js.map