{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module SafeBufferMonadSpec where
import Control.Monad.State
import Data.Functor.Identity
import SafeBuffer
import Test.Hspec
spec :: Spec
spec =
describe "SafeBufferMonad" $
it "is mockable" $
runIdentity (runBufferMock someFunction) `shouldBe` (6, [1,2,3])
where
someFunction :: SafeBufferMonad [Int] m => m Int
someFunction = do
writeBuffer [1]
writeBuffer [2]
writeBuffer [3]
buffer <- readBuffer
pure (sum buffer)
-- an instance of SafeBufferMonad that doesn't rely on IO
-- (but doesn't handle exceptions either) for testing
newtype SafeBufferMockT s m a = SafeBufferMockT { run :: StateT s m a }
deriving (Functor, Applicative, Monad, MonadTrans)
instance (Monad m, Monoid s) => SafeBufferMonad s (SafeBufferMockT s m) where
readBuffer = SafeBufferMockT get
writeBuffer msg = modifyBuffer (`mappend` msg)
clearBuffer = SafeBufferMockT $ do
s <- get
put mempty
pure s
modifyBuffer f = SafeBufferMockT $ modify' f
runBufferMock :: Monoid s => SafeBufferMockT s m a -> m (a, s)
runBufferMock sb = runStateT (run sb) mempty