cron-0.7.2: test/SpecHelper.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module SpecHelper
( module X
, module SpecHelper
) where
-------------------------------------------------------------------------------
import Control.Applicative as X
import Data.Attoparsec.Text as X (Parser, parseOnly)
import qualified Data.List.NonEmpty as NE
import Data.Maybe as X
import Data.Monoid as X
import Data.Text (Text)
import Data.Time.Calendar as X (Day (..), fromGregorian,
toGregorian)
import Data.Time.Clock as X (DiffTime, UTCTime (..), addUTCTime,
diffUTCTime, picosecondsToDiffTime,
secondsToDiffTime)
import qualified Data.Time.Clock.POSIX as POSIX
import Data.Time.LocalTime as X
import Debug.Trace as X
import GHC.Generics (Generic)
import qualified GHC.Generics as G
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Test.Tasty as X
import Test.Tasty.Hedgehog as X
import Test.Tasty.HUnit as X
-------------------------------------------------------------------------------
import System.Cron as X
-------------------------------------------------------------------------------
-- | A necessary evil for generators that can generically make sure
-- all constructors of your sum type are covered. The tradeoff is that
-- you have no control over the range at the per-test level, so use
-- this sparingly where full coverage is more valuable than
-- fine-tuning generators.
class HasGen a where
gen :: Gen a
default gen :: (Generic a, GHasGen (G.Rep a)) => Gen a
gen = Gen.choice (fmap G.to <$> ggen)
class GHasGen f where
ggen :: [Gen (f a)]
instance GHasGen G.U1 where
ggen = [pure G.U1]
instance (HasGen a) => GHasGen (G.K1 i a) where
ggen = [G.K1 <$> gen]
instance (GHasGen a, GHasGen b) => GHasGen (a G.:*: b) where
ggen = [ (G.:*:) <$> f <*> g | f <- ggen, g <- ggen]
instance (GHasGen a, GHasGen b) => GHasGen (a G.:+: b) where
ggen = (fmap G.L1 <$> ggen) <> (fmap G.R1 <$> ggen)
-- we don't care about metadata, lift over it
instance (GHasGen c) => GHasGen (G.M1 _a _b c) where
ggen = fmap G.M1 <$> ggen
instance HasGen BaseField
instance HasGen SpecificField
instance HasGen RangeField
instance HasGen Int where
gen = Gen.int Range.linearBounded
instance HasGen Text where
gen = genAlpha
instance HasGen CronField
instance HasGen a => HasGen (NE.NonEmpty a) where
gen = Gen.nonEmpty (Range.linear 1 50) gen
instance HasGen a => HasGen [a] where
gen = Gen.list (Range.linear 0 50) gen
instance HasGen StepField where
gen = Gen.just (mkStepField <$> gen <*> gen)
instance HasGen CronSchedule
instance HasGen Crontab
instance HasGen CronCommand where
gen = CronCommand <$> genAlpha
instance HasGen CrontabEntry
instance HasGen MinuteSpec where
gen = Gen.just (mkMinuteSpec <$> gen)
instance HasGen HourSpec where
gen = Gen.just (mkHourSpec <$> gen)
instance HasGen DayOfMonthSpec where
gen = Gen.just (mkDayOfMonthSpec <$> gen)
instance HasGen DayOfWeekSpec where
gen = Gen.just (mkDayOfWeekSpec <$> gen)
instance HasGen MonthSpec where
gen = Gen.just (mkMonthSpec <$> gen)
instance HasGen UTCTime where
gen = genUTCTime
genAlpha :: Gen Text
genAlpha = Gen.text (Range.linear 1 50) Gen.alpha
genUTCTime :: Gen UTCTime
genUTCTime = genUTCTime' (Range.linear 0 maxBound)
-- | genUTCTime with a range of posix seconds
genUTCTime' :: Range.Range Int -> Gen UTCTime
genUTCTime' = fmap POSIX.posixSecondsToUTCTime . genPOSIXTime
genPOSIXTime :: Range.Range Int -> Gen POSIX.POSIXTime
genPOSIXTime rnge = fromInteger . toInteger <$> Gen.int rnge
mkMinuteSpec' :: CronField -> MinuteSpec
mkMinuteSpec' = fromJust . mkMinuteSpec
mkHourSpec' :: CronField -> HourSpec
mkHourSpec' = fromJust . mkHourSpec
mkDayOfMonthSpec' :: CronField -> DayOfMonthSpec
mkDayOfMonthSpec' = fromJust . mkDayOfMonthSpec
mkMonthSpec' :: CronField -> MonthSpec
mkMonthSpec' = fromJust . mkMonthSpec
mkDayOfWeekSpec' :: CronField -> DayOfWeekSpec
mkDayOfWeekSpec' = fromJust . mkDayOfWeekSpec
mkRangeField' :: Int -> Int -> RangeField
mkRangeField' a = fromJust . mkRangeField a
mkSpecificField' :: Int -> SpecificField
mkSpecificField' = fromJust . mkSpecificField
mkStepField' :: BaseField -> Int -> StepField
mkStepField' a = fromJust . mkStepField a
-------------------------------------------------------------------------------
isLeft :: Either a b -> Bool
isLeft (Left _) = True
isLeft _ = False