Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | 1x 1x 1x 1x 1x 936x 936x 936x 936x 936x 936x 936x 936x 936x 936x 936x 936x 1x 4x 4x 4x 1x 125x 125x 125x 125x 125x 125x 125x 43x 125x 125x 1x 881x 881x 881x 881x 881x 80367x 43x 881x 881x 881x 881x | /** * @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' /** * A paper-thin wrapper over a fast-check property and its runtime * configuration adding: * 1. `Law ≡ property + assert + test` - Testing a law will run the * _fast-check_ property inside an assertion inside * [a vitest](https://vitest.dev/guide/features.html) * `test(() => {...})` block. This means you can call * [testLaw](https://middle-ages.github.io/effect-ts-laws-docs/functions/testLaw.html) * and/or * [testLaws](https://middle-ages.github.io/effect-ts-laws-docs/functions/testLaws.html) * from inside a `describe(() => {...})` block, or even from the * top level of your test file, but _not_ inside a * `test(() => {...})` block. * - The law can also be _checked_, instead of _tested_ using `checkLaw`. * This exactly the same as `testLaw`, except in a pure function that * returns the test results without using any `vitest` blocks. * 2. One or more Laws can be grouped under a single label into a `LawSet`. * Useful for testing units that require multiple laws, for example * typeclasses. Besides its child _laws_, a `LawSet` can includes other * `LawSets` as requirements to be run as a guard before testing its own * laws. * 3. A law has a name, just like the `fc.Property` it is wrapping, but also * a field for a note. It is shown only on failure or when the `fast-check` * runtime parameter `verbose` is true. * A law can be converted into a `fast-check` property and tested. * @typeParam Ts - Tuple whose elements are the predicate arguments. * @category model */ export interface Law<Ts extends UnknownArgs> { /** * Law name to be used as test name. You can include a description of the * unit under test or anything else you wish to appear in the test name, * for example: `MyList.map:associative`. */ name: string /** A note shown only on failure or in verbose mode. */ note: string /** * Predicate to be tested. Its arguments will appear in a single tuple. */ predicate: PR.Predicate<Ts> /** Arbitrary for the arguments tuple of the predicate. */ arbitrary: fc.Arbitrary<Ts> /** * `fast-check` configuration * [parameters](https://fast-check.dev/api-reference/interfaces/Parameters.html). * This configuration will override global fast-check configuration, but test * parameters may override this configuration. */ parameters?: ParameterOverrides } /** * 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 = <Ts extends UnknownArgs>( name: string, note: string, ...arbitraries: {[K in keyof Ts]: fc.Arbitrary<Ts[K]>} ) => ( /** Law predicate. Its argument type is encoded in `Ts`. */ predicate: (...args: Ts) => boolean, /** `fast-check` runtime parameters. */ parameters?: ParameterOverrides, ): Law<Ts> => ({ name, note, predicate: tupled(predicate), arbitrary: fc.tuple<Ts>(...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 = <Ts extends UnknownArgs>({ predicate, ...law }: Law<Ts>): Law<Ts> => ({...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 = <Ts extends UnknownArgs>( law: Law<Ts>, parameters?: ParameterOverrides, ): OP.Option<string> => { let failMessage: string | undefined = undefined try { asAssert(law, parameters) } catch (e) { /* v8 ignore next 2 */ if (!(e instanceof Error)) throw new Error(e as string) 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 = <Ts extends UnknownArgs>( {name, note, predicate, arbitrary, parameters}: Law<Ts>, overrides?: ParameterOverrides, ): void => { fc.assert( fc.property<[Ts]>(arbitrary, (args: Ts) => { if (predicate(args)) return true throw new Error(`${name}: ${note}`) }), {...parameters, ...overrides}, ) } /** * A base type for law predicate argument types. * @category model * @internal */ export type UnknownArgs = [unknown, ...unknown[]] /** * When you need to work with laws but do not need to preserve the predicate * argument types. * @category model * @internal */ export type UnknownLaw = Law<any> /** * `fast-check` runtime * [parameters](https://fast-check.dev/api-reference/interfaces/Parameters.html). * Fields with a type that depends on the property argument list * are omitted here and must be set on individual law tests. * @category fast-check */ export type ParameterOverrides = Omit< fc.Parameters, // These are all fields we must omit from to lose the type parameter. 'reporter' | 'asyncReporter' | 'examples' > |