{-# LANGUAGE RankNTypes #-} module Test.Utils ( -- * Property runners monadicSim , runSimGen -- * Function composition , (..:) -- * Invariants , Invariant (..) , noInvariant , trivialInvariant , whnfInvariant ) where import Control.Monad.IOSim (IOSim, runSimOrThrow) import Data.Typeable (Typeable) import NoThunks.Class (OnlyCheckWhnf (..), unsafeNoThunks) import Test.QuickCheck (Arbitrary (..), Gen, Property, Testable (..), elements) import Test.QuickCheck.Gen.Unsafe (Capture (..), capture) import Test.QuickCheck.Monadic (PropertyM, monadic') {------------------------------------------------------------------------------- Property runners (copied from "Ouroboros.Network.Testing.QuickCheck") -------------------------------------------------------------------------------} runSimGen :: (forall s. Gen (IOSim s a)) -> Gen a runSimGen f = do Capture eval <- capture return $ runSimOrThrow (eval f) monadicSim :: Testable a => (forall s. PropertyM (IOSim s) a) -> Property monadicSim m = property (runSimGen (monadic' m)) {------------------------------------------------------------------------------- Function composition -------------------------------------------------------------------------------} infixr 9 ..: (..:) :: (y -> z) -> (x0 -> x1 -> x2 -> y) -> (x0 -> x1 -> x2 -> z) (..:) g f x0 x1 x2 = g (f x0 x1 x2) {------------------------------------------------------------------------------- Invariants -------------------------------------------------------------------------------} -- | Invariants -- -- Testing with @'Invariant' (const Nothing)'@ /should/ be the same as testing -- with 'NoInvariant'. data Invariant a = NoInvariant | Invariant String (a -> Maybe String) instance Show (Invariant a) where show NoInvariant = "NoInvariant" show (Invariant name _) = "Invariant " <> name instance Typeable a => Arbitrary (Invariant a) where arbitrary = elements [ noInvariant , whnfInvariant , trivialInvariant ] noInvariant :: Invariant a noInvariant = NoInvariant whnfInvariant :: Typeable a => Invariant a whnfInvariant = Invariant "WHNF" $ fmap show . unsafeNoThunks . OnlyCheckWhnf trivialInvariant :: Invariant a trivialInvariant = Invariant "Trivial" $ const Nothing