quickcheck-dynamic-3.4.1: test/Spec/DynamicLogic/Counters.hs
{-# LANGUAGE NamedFieldPuns #-}
-- | Define several variant models of /counters/ which are useful to
-- test or use examples for various behaviours of the runtime.
module Spec.DynamicLogic.Counters where
import Control.Monad.Reader
import Data.IORef
import Test.QuickCheck
import Test.QuickCheck.StateModel
-- A very simple model with a single action that always succeed in
-- predictable way. This model is useful for testing the runtime.
newtype SimpleCounter = SimpleCounter {count :: Int}
deriving (Eq, Show, Generic)
deriving instance Eq (Action SimpleCounter a)
deriving instance Show (Action SimpleCounter a)
instance HasVariables (Action SimpleCounter a) where
getAllVariables _ = mempty
instance StateModel SimpleCounter where
data Action SimpleCounter a where
IncSimple :: Action SimpleCounter Int
arbitraryAction _ _ = pure $ Some IncSimple
initialState = SimpleCounter 0
nextState SimpleCounter{count} IncSimple _ = SimpleCounter (count + 1)
instance RunModel SimpleCounter (ReaderT (IORef Int) IO) where
perform _ IncSimple _ = do
ref <- ask
lift $ atomicModifyIORef' ref (\count -> (succ count, count))
-- A very simple model with a single action whose postcondition fails in a
-- predictable way. This model is useful for testing the runtime.
newtype FailingCounter = FailingCounter {failingCount :: Int}
deriving (Eq, Show, Generic)
deriving instance Eq (Action FailingCounter a)
deriving instance Show (Action FailingCounter a)
instance HasVariables (Action FailingCounter a) where
getAllVariables _ = mempty
instance StateModel FailingCounter where
data Action FailingCounter a where
Inc' :: Action FailingCounter Int
arbitraryAction _ _ = pure $ Some Inc'
initialState = FailingCounter 0
nextState FailingCounter{failingCount} Inc' _ = FailingCounter (failingCount + 1)
instance RunModel FailingCounter (ReaderT (IORef Int) IO) where
perform _ Inc' _ = do
ref <- ask
lift $ atomicModifyIORef' ref (\count -> (succ count, count))
postcondition (_, FailingCounter{failingCount}) _ _ _ = pure $ failingCount < 4
-- A generic but simple counter model
data Counter = Counter Int
deriving (Show, Generic)
deriving instance Show (Action Counter a)
deriving instance Eq (Action Counter a)
instance HasVariables (Action Counter a) where
getAllVariables _ = mempty
instance StateModel Counter where
data Action Counter a where
Inc :: Action Counter ()
Reset :: Action Counter Int
initialState = Counter 0
arbitraryAction _ _ = frequency [(5, pure $ Some Inc), (1, pure $ Some Reset)]
nextState (Counter n) Inc _ = Counter (n + 1)
nextState _ Reset _ = Counter 0
instance RunModel Counter (ReaderT (IORef Int) IO) where
perform _ Inc _ = do
ref <- ask
lift $ modifyIORef ref succ
perform _ Reset _ = do
ref <- ask
lift $ do
n <- readIORef ref
writeIORef ref 0
pure n
postcondition (Counter n, _) Reset _ res = pure $ n == res
postcondition _ _ _ _ = pure True