{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE DeriveGeneric #-} import Data.Default import Data.Int import Data.Word import Data.Monoid import Data.Complex import qualified Data.Sequence as Seq import qualified Data.Map as M import qualified Data.Set as S import qualified Data.IntMap as IM import qualified Data.IntSet as IS import Data.Tree (Tree(..)) import Data.Functor.Identity import Control.Applicative import Data.Proxy #if MIN_VERSION_base(4, 16, 0) import Data.Tuple #endif import GHC.Generics import Foreign.C.Types import Foreign.Ptr #if MIN_VERSION_base(4, 18, 0) import Foreign.C.ConstPtr #endif import Control.Monad (when, join) import Control.Monad.Reader import Data.IORef import System.Exit (exitFailure) import System.IO data TestState = TestState { testState_count :: !(IORef Int) , testState_ok :: !(IORef Bool) } newtype Test a = Test{ unTest :: ReaderT TestState IO a } deriving (Functor, Applicative, Monad, MonadIO, MonadReader TestState) runTest :: (MonadIO m) => Test a -> m a runTest t = liftIO $ do hSetBuffering stdout LineBuffering rc <- newIORef 0 rk <- newIORef True x <- runReaderT (unTest t) TestState{ testState_count = rc, testState_ok = rk } c <- readIORef rc putStrLn $ "1.." ++ show c k <- readIORef rk when (not k) exitFailure pure x instance (Default a) => Default (Test a) where def = return def withRef :: (IORef Int -> IO () -> IO a) -> Test a withRef f = do TestState rc rk <- ask liftIO (f rc (atomicWriteIORef rk False)) ok :: Bool -> String -> Test () ok b s = withRef $ \ref lose -> do c <- atomicModifyIORef' ref (join (,) . succ) putStrLn $ (if b then "" else "not ") ++ "ok " ++ show c ++ " - " ++ s when (not b) lose is {-, isNot-} :: (Show a, Eq a) => a -> a -> Test () is x y = ok (x == y) (show x ++ " == " ++ show y) -- isNot x y = ok (x /= y) (show x ++ " /= " ++ show y) -- diag :: String -> Test () -- diag s = liftIO $ do -- putStrLn $ "# " ++ s data T0 a b = C0 a a | C1 | C2 b deriving (Eq, Show, Generic) instance (Default a) => Default (T0 a b) main :: IO () main = runTest $ do is def () is def (Nothing :: Maybe (Int, Ordering, [Float])) is def "" is def (S.empty :: S.Set ()) is def (M.empty :: M.Map () ()) is def IS.empty is def (IM.empty :: IM.IntMap ()) is def (Seq.empty :: Seq.Seq ()) is def (Node (0 :: Complex Float) []) is def EQ is def (Any False) is def (All True) is def (Last Nothing :: Last ()) is def (First Nothing :: First ()) is def (Sum (0 :: Integer)) is def (Product (1 :: Rational)) is def (Identity ()) is def (Const 0 :: Const Int Char) is def (Proxy :: Proxy Char) #if MIN_VERSION_base(4, 16, 0) is def (pure () :: Solo ()) #endif is def False is def (0 :: Int) is def (0 :: Integer) is def (0 :: Float) is def (0 :: Double) is def (0 :: Rational) is def (0 :: Complex Double) is def (0 :: Int8) is def (0 :: Int16) is def (0 :: Int32) is def (0 :: Int64) is def (0 :: Word) is def (0 :: Word8) is def (0 :: Word16) is def (0 :: Word32) is def (0 :: Word64) is def (0 :: CShort) is def (0 :: CUShort) is def (0 :: CInt) is def (0 :: CUInt) is def (0 :: CLong) is def (0 :: CULong) is def (0 :: CLLong) is def (0 :: CULLong) is def (0 :: CPtrdiff) is def (0 :: CSize) is def (0 :: CSigAtomic) is def (0 :: CIntPtr) is def (0 :: CUIntPtr) is def (0 :: CIntMax) is def (0 :: CUIntMax) is def (0 :: CClock) is def (0 :: CTime) is def (0 :: CUSeconds) is def (0 :: CSUSeconds) is def (0 :: CFloat) is def (0 :: CDouble) is def (0 :: IntPtr) is def (0 :: WordPtr) #if MIN_VERSION_base(4, 10, 0) is def (0 :: CBool) #endif is def nullPtr is def nullFunPtr #if MIN_VERSION_base(4, 18, 0) is def (ConstPtr nullPtr) #endif is def ((def, def) :: ((), Maybe ((), ()))) is def ((def, def, def) :: ((), Maybe ((), ()), [Ordering])) is def ((def, def, def, def) :: ((), Maybe ((), ()), [Ordering], Float)) is def ((def, def, def, def, def, def, def) :: ((), (), (), (), (), (), ())) is def (C0 0 0 :: T0 Int Char)