All files / src/arbitrary instances.ts

100% Statements 14/14
100% Branches 0/0
100% Functions 8/8
100% Lines 12/12

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                                      45x     552139x     45x           73410x             45x                           45x       21x 3214x   321202x     321202x     21x 1607x            
/**
 * `@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))
}