{-# LANGUAGE RecordWildCards, GeneralizedNewtypeDeriving #-}

module Test.Util(
    Test, withTests,
    passed, failed, progress,
    ) where

import Idea
import Control.Monad
import Control.Monad.Trans.Reader
import Control.Monad.IO.Class
import Data.IORef

data S = S
    {S -> Int
failures :: !Int
    ,S -> Int
total :: !Int
    ,S -> [[Idea]]
ideas :: [[Idea]]
    }

newtype Test a = Test (ReaderT (IORef S) IO a)
    deriving (forall a b. a -> Test b -> Test a
forall a b. (a -> b) -> Test a -> Test b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> Test b -> Test a
$c<$ :: forall a b. a -> Test b -> Test a
fmap :: forall a b. (a -> b) -> Test a -> Test b
$cfmap :: forall a b. (a -> b) -> Test a -> Test b
Functor, Functor Test
forall a. a -> Test a
forall a b. Test a -> Test b -> Test a
forall a b. Test a -> Test b -> Test b
forall a b. Test (a -> b) -> Test a -> Test b
forall a b c. (a -> b -> c) -> Test a -> Test b -> Test c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b. Test a -> Test b -> Test a
$c<* :: forall a b. Test a -> Test b -> Test a
*> :: forall a b. Test a -> Test b -> Test b
$c*> :: forall a b. Test a -> Test b -> Test b
liftA2 :: forall a b c. (a -> b -> c) -> Test a -> Test b -> Test c
$cliftA2 :: forall a b c. (a -> b -> c) -> Test a -> Test b -> Test c
<*> :: forall a b. Test (a -> b) -> Test a -> Test b
$c<*> :: forall a b. Test (a -> b) -> Test a -> Test b
pure :: forall a. a -> Test a
$cpure :: forall a. a -> Test a
Applicative, Applicative Test
forall a. a -> Test a
forall a b. Test a -> Test b -> Test b
forall a b. Test a -> (a -> Test b) -> Test b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> Test a
$creturn :: forall a. a -> Test a
>> :: forall a b. Test a -> Test b -> Test b
$c>> :: forall a b. Test a -> Test b -> Test b
>>= :: forall a b. Test a -> (a -> Test b) -> Test b
$c>>= :: forall a b. Test a -> (a -> Test b) -> Test b
Monad, Monad Test
forall a. IO a -> Test a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: forall a. IO a -> Test a
$cliftIO :: forall a. IO a -> Test a
MonadIO)

-- | Returns the number of failing tests.
withTests :: Test a -> IO (Int, a)
withTests :: forall a. Test a -> IO (Int, a)
withTests (Test ReaderT (IORef S) IO a
act) = do
    IORef S
ref <- forall a. a -> IO (IORef a)
newIORef forall a b. (a -> b) -> a -> b
$ Int -> Int -> [[Idea]] -> S
S Int
0 Int
0 []
    a
res <- forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT (IORef S) IO a
act IORef S
ref
    S{Int
[[Idea]]
ideas :: [[Idea]]
total :: Int
failures :: Int
ideas :: S -> [[Idea]]
total :: S -> Int
failures :: S -> Int
..} <- forall a. IORef a -> IO a
readIORef IORef S
ref
    String -> IO ()
putStrLn String
""
    String -> IO ()
putStrLn forall a b. (a -> b) -> a -> b
$ if Int
failures forall a. Eq a => a -> a -> Bool
== Int
0
        then String
"Tests passed (" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
total forall a. [a] -> [a] -> [a]
++ String
")"
        else String
"Tests failed (" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
failures forall a. [a] -> [a] -> [a]
++ String
" of " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
total forall a. [a] -> [a] -> [a]
++ String
")"
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
failures, a
res)

progress :: Test ()
progress :: Test ()
progress = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Char -> IO ()
putChar Char
'.'

passed :: Test ()
passed :: Test ()
passed = do
    IORef S
ref <- forall a. ReaderT (IORef S) IO a -> Test a
Test forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' IORef S
ref forall a b. (a -> b) -> a -> b
$ \S
s -> S
s{total :: Int
total=S -> Int
total S
sforall a. Num a => a -> a -> a
+Int
1}

failed :: [String] -> Test ()
failed :: [String] -> Test ()
failed [String]
xs = do
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
xs) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ String -> IO ()
putStrLn forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines forall a b. (a -> b) -> a -> b
$ String
"" forall a. a -> [a] -> [a]
: [String]
xs
    IORef S
ref <- forall a. ReaderT (IORef S) IO a -> Test a
Test forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' IORef S
ref forall a b. (a -> b) -> a -> b
$ \S
s -> S
s{total :: Int
total=S -> Int
total S
sforall a. Num a => a -> a -> a
+Int
1, failures :: Int
failures=S -> Int
failures S
sforall a. Num a => a -> a -> a
+Int
1}