All files / src/arbitrary time.ts

100% Statements 46/46
100% Branches 15/15
100% Functions 2/2
100% Lines 46/46

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          1x 1x 1x 1x   1x           1x 1x 1x 1x 1x 1x 1x 1x           1x   1x 1x 1x 101x 101x 101x 101x 101x 101x   101x 101x 101x 101x 1x 1x               1x 1x 1x 1x 1x           1x 2x 2x 2x 2x 2x           1x 1x   1x 1x 1x 1x  
/**
 * Arbitraries for basic effect-ts temporal datatypes.
 * @module
 */
import {Bounded as BU} from '@effect/typeclass'
import {DateTime as DT, Duration as DU, pipe} from 'effect'
import fc from 'fast-check'
import {tinyInteger} from './data.js'
import {Monad as arbitraryMonad} from './instances.js'
 
const {flatMap, map} = arbitraryMonad
 
/**
 * Finite `Duration` arbitrary.
 * @category arbitraries
 */
export const duration: fc.Arbitrary<DU.Duration> = fc.oneof(
  tinyInteger.map(_ => DU.millis(_)),
  tinyInteger.map(_ => DU.seconds(_)),
  tinyInteger.map(_ => DU.minutes(_)),
  tinyInteger.map(_ => DU.hours(_)),
  tinyInteger.map(_ => DU.days(_)),
  tinyInteger.map(_ => DU.weeks(_)),
)
 
/**
 * Arbitrary for a duration and its bounds.
 * @category arbitraries
 */
export const boundedDuration: fc.Arbitrary<
  [fc.Arbitrary<DU.Duration>, BU.Bounded<DU.Duration>]
> = pipe(
  fc.tuple(tinyInteger, tinyInteger),
  flatMap(([first, second]) => {
    const [min, max] = first < second ? [first, second] : [second, first]
    const bounded: fc.Arbitrary<BU.Bounded<DU.Duration>> = fc.constant({
      compare: DU.Order,
      maxBound: DU.millis(min),
      minBound: DU.millis(max),
    })
 
    return fc.tuple(
      fc.constant(map(fc.integer({min, max}), i => DU.millis(i))),
      bounded,
    )
  }),
)
 
/**
 * `DateTime.TimeZone.Offset` arbitrary. The offset is clamped between -14hrs
 * and 14hrs, allowing for a maximum 28hrs offset between any two points on
 * earth.
 * @category arbitraries
 */
export const offsetTimezone: fc.Arbitrary<DT.TimeZone.Offset> = pipe(
  {min: -14, max: 14},
  fc.integer,
  map(offset => DT.zoneMakeOffset(offset)),
)
 
/**
 * `DateTime.Utc` arbitrary. Only valid dates are generated.
 * @category arbitraries
 */
export const utc = (constraints?: fc.DateConstraints): fc.Arbitrary<DT.Utc> =>
  pipe(
    {noInvalidDate: true, ...constraints},
    fc.date,
    map(date => DT.unsafeFromDate(date)),
  )
 
/**
 * `DateTime.Zoned` arbitrary. Only valid dates are generated.
 * @category arbitraries
 */
export const zoned = (
  constraints?: fc.DateConstraints,
): fc.Arbitrary<DT.Zoned> =>
  pipe(
    fc.tuple(utc(constraints), offsetTimezone),
    map(([utc, zone]) => DT.setZone(utc, zone)),
  )