{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | Tutorial: http://github.com/bennofs/quickcheck-property-monad/tree/master/README.md module Test.QuickCheck.Property.Monad ( PropM() , assert , failWith , generate , logMessage , logMessageLn ) where import Control.Applicative import Control.Monad import Control.Monad.Trans.Class import Control.Monad.Trans.Either import Control.Monad.Trans.Writer import Test.QuickCheck.Gen import Test.QuickCheck.Property -- | PropM is a monad for writing properties that depend on random -- data. This is especially useful if you have many invariants for -- your data and cannot simply write an 'Arbitrary' instance. newtype PropM a = PropM (EitherT String (WriterT String Gen) a) deriving (Functor, Applicative, Alternative, Monad, MonadPlus) instance Testable a => Testable (PropM a) where property (PropM m) = property $ do (r,w) <- runWriterT $ runEitherT m case r of Right r' -> return $ property r' Left err -> return $ printTestCase (w ++ "\n" ++ err) $ property False -- | Assert that a certain condition is true. If the condition is false, fail with the -- given error message. assert :: String -> Bool -> PropM () assert err cond = unless cond $ failWith $ "Assertion failed: " ++ err -- | Fail with the given error message. failWith :: String -> PropM () failWith err = PropM $ left err -- | Use the given generator to generate a value. generate :: Gen a -> PropM a generate = PropM . lift . lift -- | Log a message that will be printed when the test case fails. logMessage :: String -> PropM () logMessage = PropM . lift . tell -- | Like 'logMessage' but appends a line break after the message. logMessageLn :: String -> PropM () logMessageLn = logMessage . (++ "\n")