packages feed

genvalidity-time-1.0.0.1: src/Data/GenValidity/Time/Calendar.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}

module Data.GenValidity.Time.Calendar where

import Data.GenValidity
import Data.Time.Calendar
import Data.Validity.Time.Calendar ()
import Test.QuickCheck

instance GenValid Day where
  genValid = uniformlyOneHundredYearsAround2020
  shrinkValid (ModifiedJulianDay i) = ModifiedJulianDay <$> shrinkValid i

uniformlyOneHundredYearsAround2020 :: Gen Day
uniformlyOneHundredYearsAround2020 = do
  y <- choose (1970, 2070)
  m <- choose (1, 12)
  d <- choose (1, 31)
  pure $ fromGregorian y m d

genSmartDayAround :: Day -> Gen Day
genSmartDayAround d = oneof [genValid, genDayAround d, genDayCloselyAround d]

-- We cannot put this in 'GenValid Day' around 'today' because that would break reproducability
genDayAround :: Day -> Gen Day
genDayAround today = do
  let (thisYear, _, _) = toGregorian today
  y <- choose (pred thisYear, succ thisYear)
  m <- choose (1, 12)
  d <- choose (1, 31)
  pure $ fromGregorian y m d

genDayCloselyAround :: Day -> Gen Day
genDayCloselyAround today = sized $ \s -> do
  diff <- choose (-s, s)
  pure $ addDays (fromIntegral diff) today

instance GenValid CalendarDiffDays where
  genValid = CalendarDiffDays <$> genValid <*> genValid
  shrinkValid (CalendarDiffDays m d) = [CalendarDiffDays m' d' | (m', d') <- shrinkValid (m, d)]

instance GenValid DayOfWeek where
  genValid =
    elements
      [ Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
      ]

  -- It's hard to know how to shrink this, because there is no official start of the week.
  -- However, just as we would shrink MonthOfYear to January, we will shrink the days of the week to monday
  shrinkValid Monday = []
  shrinkValid Tuesday = [Monday]
  shrinkValid Wednesday = [Monday, Tuesday]
  shrinkValid Thursday = [Monday, Tuesday, Wednesday]
  shrinkValid Friday = [Monday, Tuesday, Wednesday, Thursday]
  shrinkValid Saturday = [Monday, Tuesday, Wednesday, Thursday, Friday]
  shrinkValid Sunday = [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]