{-# LANGUAGE BangPatterns #-}
module Test.Tasty.Runners.Utils where
import Control.Exception
import Control.Applicative
import Control.Concurrent (mkWeakThreadId, myThreadId)
import Control.Monad (forM_)
#ifndef VERSION_clock
import Data.Time.Clock.POSIX (getPOSIXTime)
#endif
import Data.Typeable (Typeable)
import Prelude
import Text.Printf
import Foreign.C (CInt)
#ifdef VERSION_clock
import qualified System.Clock as Clock
#endif
#ifdef VERSION_unix
#define INSTALL_HANDLERS 1
#else
#define INSTALL_HANDLERS 0
#endif
#if INSTALL_HANDLERS
import System.Posix.Signals
import System.Mem.Weak (deRefWeak)
#endif
import Test.Tasty.Core (Time)
formatMessage :: String -> IO String
formatMessage :: String -> IO String
formatMessage = Int -> String -> IO String
go Int
3
where
go :: Int -> String -> IO String
go :: Int -> String -> IO String
go Int
0 String
_ = forall (m :: * -> *) a. Monad m => a -> m a
return String
"exceptions keep throwing other exceptions!"
go Int
recLimit String
msg = do
Either SomeException ()
mbStr <- forall e a. Exception e => IO a -> IO (Either e a)
try forall a b. (a -> b) -> a -> b
$ forall a. a -> IO a
evaluate forall a b. (a -> b) -> a -> b
$ forall a. [a] -> ()
forceElements String
msg
case Either SomeException ()
mbStr of
Right () -> forall (m :: * -> *) a. Monad m => a -> m a
return String
msg
Left SomeException
e' -> forall r. PrintfType r => String -> r
printf String
"message threw an exception: %s" forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> String -> IO String
go (Int
recLimitforall a. Num a => a -> a -> a
-Int
1) (forall a. Show a => a -> String
show (SomeException
e' :: SomeException))
forceElements :: [a] -> ()
forceElements :: forall a. [a] -> ()
forceElements = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr seq :: forall a b. a -> b -> b
seq ()
installSignalHandlers :: IO ()
installSignalHandlers :: IO ()
installSignalHandlers = do
#if INSTALL_HANDLERS
ThreadId
main_thread_id <- IO ThreadId
myThreadId
Weak ThreadId
weak_tid <- ThreadId -> IO (Weak ThreadId)
mkWeakThreadId ThreadId
main_thread_id
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [ CInt
sigHUP, CInt
sigTERM, CInt
sigUSR1, CInt
sigUSR2, CInt
sigXCPU, CInt
sigXFSZ ] forall a b. (a -> b) -> a -> b
$ \CInt
sig ->
CInt -> Handler -> Maybe SignalSet -> IO Handler
installHandler CInt
sig (IO () -> Handler
Catch forall a b. (a -> b) -> a -> b
$ Weak ThreadId -> CInt -> IO ()
send_exception Weak ThreadId
weak_tid CInt
sig) forall a. Maybe a
Nothing
where
send_exception :: Weak ThreadId -> CInt -> IO ()
send_exception Weak ThreadId
weak_tid CInt
sig = do
Maybe ThreadId
m <- forall v. Weak v -> IO (Maybe v)
deRefWeak Weak ThreadId
weak_tid
case Maybe ThreadId
m of
Maybe ThreadId
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just ThreadId
tid -> forall e. Exception e => ThreadId -> e -> IO ()
throwTo ThreadId
tid (forall e. Exception e => e -> SomeException
toException forall a b. (a -> b) -> a -> b
$ CInt -> SignalException
SignalException CInt
sig)
#else
return ()
#endif
newtype SignalException = SignalException CInt
deriving (Int -> SignalException -> String -> String
[SignalException] -> String -> String
SignalException -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [SignalException] -> String -> String
$cshowList :: [SignalException] -> String -> String
show :: SignalException -> String
$cshow :: SignalException -> String
showsPrec :: Int -> SignalException -> String -> String
$cshowsPrec :: Int -> SignalException -> String -> String
Show, Typeable)
instance Exception SignalException
timed :: IO a -> IO (Time, a)
timed :: forall a. IO a -> IO (Time, a)
timed IO a
t = do
Time
start <- IO Time
getTime
!a
r <- IO a
t
Time
end <- IO Time
getTime
forall (m :: * -> *) a. Monad m => a -> m a
return (Time
endforall a. Num a => a -> a -> a
-Time
start, a
r)
#ifdef VERSION_clock
getTime :: IO Time
getTime :: IO Time
getTime = do
TimeSpec
t <- Clock -> IO TimeSpec
Clock.getTime Clock
Clock.Monotonic
let ns :: Time
ns = forall a b. (Real a, Fractional b) => a -> b
realToFrac forall a b. (a -> b) -> a -> b
$
#if MIN_VERSION_clock(0,7,1)
TimeSpec -> Integer
Clock.toNanoSecs TimeSpec
t
#else
Clock.timeSpecAsNanoSecs t
#endif
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Time
ns forall a. Fractional a => a -> a -> a
/ Time
10 forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
9 :: Int)
#else
getTime :: IO Time
getTime = realToFrac <$> getPOSIXTime
#endif