{-# LANGUAGE DeriveDataTypeable #-} import Prelude hiding (catch) import Test.Framework (defaultMain, testGroup, Test) import Test.Framework.Providers.HUnit import Test.HUnit hiding (Test) import Control.Exception.Peel import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Peel (MonadPeelIO) import Data.IORef import Data.Maybe import Data.Typeable (Typeable) import Control.Monad.Trans.Identity import Control.Monad.Trans.List import Control.Monad.Trans.Maybe import Control.Monad.Trans.Reader import Control.Monad.Trans.Writer import Control.Monad.Trans.Error import Control.Monad.Trans.State import qualified Control.Monad.Trans.RWS as RWS main :: IO () main = defaultMain [ testSuite "IdentityT" runIdentityT , testSuite "ListT" $ fmap head . runListT , testSuite "MaybeT" $ fmap fromJust . runMaybeT , testSuite "ReaderT" $ flip runReaderT "reader state" , testSuite "WriterT" runWriterT' , testSuite "ErrorT" runErrorT' , testSuite "StateT" $ flip evalStateT "state state" , testSuite "RWST" $ \m -> runRWST' m "RWS in" "RWS state" , testCase "ErrorT throwError" case_throwError , testCase "WriterT tell" case_tell ] where runWriterT' :: Functor m => WriterT [Int] m a -> m a runWriterT' = fmap fst . runWriterT runErrorT' :: Functor m => ErrorT String m () -> m () runErrorT' = fmap (either (const ()) id) . runErrorT runRWST' :: (Monad m, Functor m) => RWS.RWST r [Int] s m a -> r -> s -> m a runRWST' m r s = fmap fst $ RWS.evalRWST m r s testSuite :: MonadPeelIO m => String -> (m () -> IO ()) -> Test testSuite s run = testGroup s [ testCase "finally" $ case_finally run , testCase "catch" $ case_catch run , testCase "bracket" $ case_bracket run , testCase "bracket_" $ case_bracket_ run , testCase "onException" $ case_onException run ] ignore :: IO () -> IO () ignore x = catch x go where go :: SomeException -> IO () go _ = return () data Exc = Exc deriving (Show, Typeable) instance Exception Exc one :: Int one = 1 case_finally :: MonadPeelIO m => (m () -> IO ()) -> Assertion case_finally run = do i <- newIORef one ignore (run $ (do liftIO $ writeIORef i 2 error "error") `finally` (liftIO $ writeIORef i 3)) j <- readIORef i j @?= 3 case_catch :: MonadPeelIO m => (m () -> IO ()) -> Assertion case_catch run = do i <- newIORef one run $ (do liftIO $ writeIORef i 2 throw Exc) `catch` (\Exc -> liftIO $ writeIORef i 3) j <- readIORef i j @?= 3 case_bracket :: MonadPeelIO m => (m () -> IO ()) -> Assertion case_bracket run = do i <- newIORef one ignore $ run $ bracket (liftIO $ writeIORef i 2) (\() -> liftIO $ writeIORef i 4) (\() -> liftIO $ writeIORef i 3) j <- readIORef i j @?= 4 case_bracket_ :: MonadPeelIO m => (m () -> IO ()) -> Assertion case_bracket_ run = do i <- newIORef one ignore $ run $ bracket_ (liftIO $ writeIORef i 2) (liftIO $ writeIORef i 4) (liftIO $ writeIORef i 3) j <- readIORef i j @?= 4 case_onException :: MonadPeelIO m => (m () -> IO ()) -> Assertion case_onException run = do i <- newIORef one ignore $ run $ onException (liftIO (writeIORef i 2) >> error "ignored") (liftIO $ writeIORef i 3) j <- readIORef i j @?= 3 ignore $ run $ onException (liftIO $ writeIORef i 4) (liftIO $ writeIORef i 5) k <- readIORef i k @?= 4 case_throwError :: Assertion case_throwError = do i <- newIORef one Left "throwError" <- runErrorT $ (liftIO (writeIORef i 2) >> throwError "throwError") `finally` (liftIO $ writeIORef i 3) j <- readIORef i j @?= 3 case_tell :: Assertion case_tell = do i <- newIORef one ((), w) <- runWriterT $ bracket_ (liftIO (writeIORef i 2) >> tell [1]) (liftIO (writeIORef i 4) >> tell [3]) (liftIO (writeIORef i 3) >> tell [2]) j <- readIORef i j @?= 4 w @?= [2] ((), w') <- runWriterT $ bracket (liftIO (writeIORef i 5) >> tell [5]) (const $ liftIO (writeIORef i 7) >> tell [7]) (const $ liftIO (writeIORef i 6) >> tell [6]) j' <- readIORef i j' @?= 7 w' @?= [5, 6]