mockcat-1.4.1.0: src/Test/MockCat/Internal/Types.hs
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wno-missing-export-lists #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use null" #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Test.MockCat.Internal.Types where
import Control.Monad (ap)
import Control.Concurrent.STM (TVar)
import Data.Maybe (listToMaybe)
import Data.Dynamic (Dynamic)
import GHC.IO (unsafePerformIO)
import Prelude hiding (lookup)
import Control.Monad.State ( State, MonadState, execState, modify )
type AssociationList k a = [(k, a)]
type MockName = String
data InvocationRecorder params = InvocationRecorder
{ invocationRef :: TVar (InvocationRecord params)
, functionNature :: FunctionNature
}
-- | Result of building a mock: function plus its recorder.
data BuiltMock fn params = BuiltMock
{ builtMockFn :: fn
, builtMockRecorder :: InvocationRecorder params
}
data ResolvedMock params = ResolvedMock {
resolvedMockName :: Maybe MockName,
resolvedMockRecorder :: InvocationRecorder params
}
data FunctionNature
= PureConstant
| IOConstant
| ParametricFunction
deriving (Eq, Show)
type InvocationList params = [params]
type InvocationCounts params = AssociationList params Int
data InvocationRecord params = InvocationRecord {
invocations :: InvocationList params,
invocationCounts :: InvocationCounts params
}
deriving (Eq, Show)
data CountVerifyMethod
= Equal Int
| LessThanEqual Int
| GreaterThanEqual Int
| LessThan Int
| GreaterThan Int
deriving (Eq)
instance Show CountVerifyMethod where
show (Equal e) = show e
show (LessThanEqual e) = "<= " <> show e
show (LessThan e) = "< " <> show e
show (GreaterThanEqual e) = ">= " <> show e
show (GreaterThan e) = "> " <> show e
newtype Cases a b = Cases (State [a] b)
instance Functor (Cases a) where
fmap f (Cases s) = Cases (fmap f s)
instance Applicative (Cases a) where
pure x = Cases $ pure x
(<*>) = ap
instance Monad (Cases a) where
(Cases m) >>= f = Cases $ do
result <- m
let (Cases newState) = f result
newState
newtype VerifyFailed = VerifyFailed Message
data VerifyOrderMethod
= ExactlySequence
| PartiallySequence
deriving (Show, Eq)
data VerifyOrderResult a = VerifyOrderResult
{ index :: Int,
calledValue :: a,
expectedValue :: a
}
type Message = String
data VerifyMatchType a = MatchAny a | MatchAll a
safeIndex :: [a] -> Int -> Maybe a
safeIndex xs n
| n < 0 = Nothing
| otherwise = listToMaybe (drop n xs)
{-# NOINLINE perform #-}
perform :: IO a -> a
perform = unsafePerformIO
-- | Mock expectation context holds verification actions to run at the end
-- of the `withMock` block, and a recorder list for local registration.
-- - contextVerifications: stores verification actions
-- - contextRecorders: stores mock recorders (for expects to retrieve)
data WithMockContext = WithMockContext
{ contextVerifications :: TVar [IO ()]
, contextRecorders :: TVar [(Maybe MockName, Dynamic)]
}
-- | Expectation specification
data Expectation params where
-- | Count expectation with specific arguments
CountExpectation :: CountVerifyMethod -> params -> Expectation params
-- | Count expectation without arguments (any arguments)
CountAnyExpectation :: CountVerifyMethod -> Expectation params
-- | Order expectation
OrderExpectation :: VerifyOrderMethod -> [params] -> Expectation params
-- | Simple expectation (at least once) with arguments
SimpleExpectation :: params -> Expectation params
-- | Simple expectation (at least once) without arguments
AnyExpectation :: Expectation params
deriving (Show, Eq)
-- | Expectations builder (Monad instance for do syntax)
newtype Expectations params a = Expectations (State [Expectation params] a)
deriving (Functor, Applicative, Monad, MonadState [Expectation params])
-- | Run the Expectations monad to get a list of Expectation
runExpectations :: Expectations params () -> [Expectation params]
runExpectations (Expectations s) = execState s []
-- | Add an expectation to the list
addExpectation :: Expectation params -> Expectations params ()
addExpectation e = modify (++ [e])