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 2836x 1x   1x 1x   1x 10719x 10719x 10719x 1x           1x 1x 1x 1x 1x 1x                 1x 21x 21x 21x 21x 21x 3200x 319802x     319802x 319802x   21x 1600x 1600x 1600x 1600x 1600x 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))
}