All files / src/arbitrary instances.ts

100% Statements 39/39
100% Branches 9/9
100% Functions 2/2
100% Lines 39/39

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        1x   1x   1x 1x                   1x 1x 1x 2867x 1x   1x 1x   1x 10719x 10719x 10719x 1x           1x 1x 1x 1x 1x 1x                 1x 21x 21x 21x 21x 21x 3214x 321202x     321202x 321202x   21x 1607x 1607x 1607x 1607x 1607x 21x  
/**
 * `@effect/typeclass` instances for the `fast-check` Arbitrary type.
 * @module
 */
import {Covariant as CO, FlatMap as FL, Monad as MD} from '@effect/typeclass'
import {Equivalence as EQ} from 'effect'
import {dual} from 'effect/Function'
import type {TypeLambda} from 'effect/HKT'
import fc from 'fast-check'
import {testUnaryEquivalence} from './equivalence.js'
 
/**
 * Type lambda for the `fc.Arbitrary` datatype.
 * @category type lambda
 */
export interface ArbitraryTypeLambda extends TypeLambda {
  readonly type: fc.Arbitrary<this['Target']>
}
 
const map: CO.Covariant<ArbitraryTypeLambda>['map'] = dual(
  2,
  <A, B>(self: fc.Arbitrary<A>, f: (a: A) => B): fc.Arbitrary<B> =>
    self.map(a => f(a)),
)
 
const flatMap: FL.FlatMap<ArbitraryTypeLambda>['flatMap'] = dual(
  2,
 
  <A, B>(
    self: fc.Arbitrary<A>,
    f: (a: A) => fc.Arbitrary<B>,
  ): fc.Arbitrary<B> => self.chain(a => f(a)),
)
 
/**
 * Monad instance for `fc.Arbitrary`.
 * @category fast-check
 */
export const Monad: MD.Monad<ArbitraryTypeLambda> = {
  map,
  imap: CO.imap<ArbitraryTypeLambda>(map),
  flatMap,
  of: fc.constant,
}
 
/**
 * Get an equivalence for `fc.Arbitrary<A>` from an equivalence of `A`.
 * Arbitraries are equal if they produce the same values for the same seeds.
 * Note this only means we were unable to find a counterexample to the
 * equivalence.
 * @category fast-check
 */
export const getEquivalence = <A>(
  equalsA: EQ.Equivalence<A>,
  parameters?: fc.Parameters<number>,
): EQ.Equivalence<fc.Arbitrary<A>> => {
  const sample =
    (arbitrary: fc.Arbitrary<A>) =>
    (seed: number): A => {
      const [result] = fc.sample(arbitrary, {seed, numRuns: 1})
      /* v8 ignore next 1 */
      if (result === undefined) throw new Error('Could not sample.')
      return result
    }
 
  return (self, that) =>
    testUnaryEquivalence(
      fc.integer(),
      equalsA,
      parameters,
    )(sample(self), sample(that))
}