All files / src/arbitrary function.ts

100% Statements 32/32
100% Branches 18/18
100% Functions 8/8
100% Lines 32/32

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        1x   1x       1x 1x 50366x 819224x                 1x   1x           1x 1x             1x 1x 231x 231x                 1x 1x 494x 494x   494x 494x               1x 1x     1x 1x               1x 1x 1x 1x   1x 1x           1x 131x  
/**
 * Arbitraries for various kinds of functions.
 * @module
 */
import {pipe, Predicate as PR} from 'effect'
import type {Kind, TypeLambda} from 'effect/HKT'
import fc from 'fast-check'
import type {LiftArbitrary} from './types.js'
 
// flipped “apply”
const applyF =
  <A, B>(f: (a: A) => B) =>
  (a: A): B =>
    f(a)
 
/**
 * Calls
 * [fc.function](https://fast-check.dev/docs/core-blocks/arbitraries/composites/function/#func)
 * but keeps only the first argument making it act as a function of a single
 * argument.
 * @category arbitraries
 */
export const unary: <A>() => <B>(
  b: fc.Arbitrary<B>,
) => fc.Arbitrary<(a: A) => B> = () => b => fc.func(b).map(applyF)
 
/**
 * An arbitrary function from `A` to `A`.
 * @category arbitraries
 */
export const endo = <A>(a: fc.Arbitrary<A>): fc.Arbitrary<(a: A) => A> =>
  fc.func(a).map(applyF)
 
/**
 * Build an arbitrary binary function of type `(a: A, b: B) => C` from an
 * arbitrary of `C`.
 * @category arbitraries
 */
export const binary =
  <A, B>() =>
  <C>(c: fc.Arbitrary<C>): fc.Arbitrary<(a: A, b: B) => C> =>
    fc.func(c).map(f => (a: A, b: B) => f(a, b))
 
/**
 * An arbitrary for a function from `A` to `F<B>`. Requires an
 * arbitrary of `B`, a function converting arbitraries of `A` to
 * arbitraries of `F<A>`, and the _type_ `A`.
 * @returns An arbitrary of type `(a: A) => F<B>`.
 * @category arbitraries
 */
export const unaryToKind =
  <A>() =>
  <F extends TypeLambda, R, O, E>(
    getArbitrary: LiftArbitrary<F, R, O, E>,
  ): (<B>(b: fc.Arbitrary<B>) => fc.Arbitrary<(a: A) => Kind<F, R, O, E, B>>) =>
  b =>
    pipe(b, getArbitrary, fc.func).map(applyF)
 
/**
 * An arbitrary for a function from `F<A>` to `B`. Requires an
 * arbitrary of `B` and specifying the kind type parameters.
 * @returns An arbitrary of type `(a: F<A>) => B`.
 * @category arbitraries
 */
export const unaryFromKind =
  <A, F extends TypeLambda, R = never, O = unknown, E = unknown>(): (<B>(
    b: fc.Arbitrary<B>,
  ) => fc.Arbitrary<(fa: Kind<F, R, O, E, A>) => B>) =>
  b =>
    fc.func(b).map(applyF)
 
/**
 * An arbitrary for the type `F<A⇒B>`. Requires an arbitrary of `B`, a
 * function lifting `A` to `F<A>`, and the _type_ `A`.
 * @returns An arbitrary of type `F<(a: A) => B>`.
 * @category arbitraries
 */
export const unaryInKind =
  <A>() =>
  <F extends TypeLambda, R = never, O = unknown, E = unknown>(
    of: <T>(t: T) => Kind<F, R, O, E, T>,
  ): (<B>(b: fc.Arbitrary<B>) => fc.Arbitrary<Kind<F, R, O, E, (a: A) => B>>) =>
  b =>
    unary<A>()(b).map(of)
 
/**
 * An arbitrary predicate of `A`.
 * @category arbitraries
 */
export const predicate = <A>(): fc.Arbitrary<PR.Predicate<A>> =>
  unary<A>()(fc.boolean())