{-# LANGUAGE TupleSections #-}
module Test.DejaFu
(
autocheck
, dejafu
, dejafus
, autocheckWay
, dejafuWay
, dejafusWay
, autocheckWithSettings
, dejafuWithSettings
, dejafusWithSettings
, module Test.DejaFu.Settings
, Result(..)
, runTest
, runTestWay
, runTestWithSettings
, Predicate
, ProPredicate(..)
, successful
, alwaysSame
, notAlwaysSame
, abortsNever
, abortsAlways
, abortsSometimes
, deadlocksNever
, deadlocksAlways
, deadlocksSometimes
, exceptionsNever
, exceptionsAlways
, exceptionsSometimes
, representative
, alwaysSameOn
, alwaysSameBy
, notAlwaysSameOn
, notAlwaysSameBy
, alwaysTrue
, somewhereTrue
, alwaysNothing
, somewhereNothing
, gives
, gives'
, Condition(..)
, isAbort
, isDeadlock
, isUncaughtException
, isInvariantFailure
, module Test.DejaFu.Refinement
, Program
, Basic
, ConcT
, ConcIO
, WithSetup
, WithSetupAndTeardown
, withSetup
, withTeardown
, withSetupAndTeardown
, Invariant
, registerInvariant
, inspectIORef
, inspectMVar
, inspectTVar
) where
import Control.Arrow (first)
import Control.DeepSeq (NFData(..))
import Control.Monad (unless, when)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Either (isLeft)
import Data.Function (on)
import Data.List (intercalate, intersperse, partition)
import Data.Maybe (catMaybes, isJust, isNothing, mapMaybe)
import Data.Profunctor (Profunctor(..))
import System.Environment (lookupEnv)
import Test.DejaFu.Conc
import Test.DejaFu.Internal
import Test.DejaFu.Refinement
import Test.DejaFu.SCT
import Test.DejaFu.Settings
import Test.DejaFu.Types
import Test.DejaFu.Utils
autocheck :: (MonadDejaFu n, MonadIO n, Eq a, Show a)
=> Program pty n a
-> n Bool
autocheck :: forall (n :: * -> *) a pty.
(MonadDejaFu n, MonadIO n, Eq a, Show a) =>
Program pty n a -> n Bool
autocheck = forall (n :: * -> *) a pty.
(MonadDejaFu n, MonadIO n, Eq a, Show a) =>
Settings n a -> Program pty n a -> n Bool
autocheckWithSettings forall (n :: * -> *) a. Applicative n => Settings n a
defaultSettings
autocheckWay :: (MonadDejaFu n, MonadIO n, Eq a, Show a)
=> Way
-> MemType
-> Program pty n a
-> n Bool
autocheckWay :: forall (n :: * -> *) a pty.
(MonadDejaFu n, MonadIO n, Eq a, Show a) =>
Way -> MemType -> Program pty n a -> n Bool
autocheckWay Way
way = forall (n :: * -> *) a pty.
(MonadDejaFu n, MonadIO n, Eq a, Show a) =>
Settings n a -> Program pty n a -> n Bool
autocheckWithSettings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: * -> *) a.
Applicative n =>
Way -> MemType -> Settings n a
fromWayAndMemType Way
way
autocheckWithSettings :: (MonadDejaFu n, MonadIO n, Eq a, Show a)
=> Settings n a
-> Program pty n a
-> n Bool
autocheckWithSettings :: forall (n :: * -> *) a pty.
(MonadDejaFu n, MonadIO n, Eq a, Show a) =>
Settings n a -> Program pty n a -> n Bool
autocheckWithSettings Settings n a
settings = forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Settings n a
-> [(String, ProPredicate a b)] -> Program pty n a -> n Bool
dejafusWithSettings Settings n a
settings
[ (String
"Successful", forall b a. Eq b => ProPredicate a b -> ProPredicate a b
representative forall a. Predicate a
successful)
, (String
"Deterministic", forall b a. Eq b => ProPredicate a b -> ProPredicate a b
representative forall a. Eq a => Predicate a
alwaysSame)
]
dejafu :: (MonadDejaFu n, MonadIO n, Show b)
=> String
-> ProPredicate a b
-> Program pty n a
-> n Bool
dejafu :: forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
String -> ProPredicate a b -> Program pty n a -> n Bool
dejafu = forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Settings n a
-> String -> ProPredicate a b -> Program pty n a -> n Bool
dejafuWithSettings forall (n :: * -> *) a. Applicative n => Settings n a
defaultSettings
dejafuWay :: (MonadDejaFu n, MonadIO n, Show b)
=> Way
-> MemType
-> String
-> ProPredicate a b
-> Program pty n a
-> n Bool
dejafuWay :: forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Way
-> MemType
-> String
-> ProPredicate a b
-> Program pty n a
-> n Bool
dejafuWay Way
way = forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Settings n a
-> String -> ProPredicate a b -> Program pty n a -> n Bool
dejafuWithSettings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: * -> *) a.
Applicative n =>
Way -> MemType -> Settings n a
fromWayAndMemType Way
way
dejafuWithSettings :: (MonadDejaFu n, MonadIO n, Show b)
=> Settings n a
-> String
-> ProPredicate a b
-> Program pty n a
-> n Bool
dejafuWithSettings :: forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Settings n a
-> String -> ProPredicate a b -> Program pty n a -> n Bool
dejafuWithSettings Settings n a
settings String
name ProPredicate a b
test =
forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Settings n a
-> [(String, ProPredicate a b)] -> Program pty n a -> n Bool
dejafusWithSettings Settings n a
settings [(String
name, ProPredicate a b
test)]
dejafus :: (MonadDejaFu n, MonadIO n, Show b)
=> [(String, ProPredicate a b)]
-> Program pty n a
-> n Bool
dejafus :: forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
[(String, ProPredicate a b)] -> Program pty n a -> n Bool
dejafus = forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Settings n a
-> [(String, ProPredicate a b)] -> Program pty n a -> n Bool
dejafusWithSettings forall (n :: * -> *) a. Applicative n => Settings n a
defaultSettings
dejafusWay :: (MonadDejaFu n, MonadIO n, Show b)
=> Way
-> MemType
-> [(String, ProPredicate a b)]
-> Program pty n a
-> n Bool
dejafusWay :: forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Way
-> MemType
-> [(String, ProPredicate a b)]
-> Program pty n a
-> n Bool
dejafusWay Way
way = forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Settings n a
-> [(String, ProPredicate a b)] -> Program pty n a -> n Bool
dejafusWithSettings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: * -> *) a.
Applicative n =>
Way -> MemType -> Settings n a
fromWayAndMemType Way
way
dejafusWithSettings :: (MonadDejaFu n, MonadIO n, Show b)
=> Settings n a
-> [(String, ProPredicate a b)]
-> Program pty n a
-> n Bool
dejafusWithSettings :: forall (n :: * -> *) b a pty.
(MonadDejaFu n, MonadIO n, Show b) =>
Settings n a
-> [(String, ProPredicate a b)] -> Program pty n a -> n Bool
dejafusWithSettings Settings n a
settings [(String, ProPredicate a b)]
tests Program pty n a
conc = do
[(Either Condition a, Trace)]
traces <- forall (n :: * -> *) a pty.
MonadDejaFu n =>
Settings n a -> Program pty n a -> n [(Either Condition a, Trace)]
runSCTWithSettings (forall s a. Lens' s a -> a -> s -> s
set forall (n :: * -> *) a.
Lens' (Settings n a) (Maybe (Either Condition a -> Maybe Discard))
ldiscard (forall a. a -> Maybe a
Just Either Condition a -> Maybe Discard
discarder) Settings n a
settings) Program pty n a
conc
[Bool]
results <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\(String
name, ProPredicate a b
test) -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => String -> Result a -> IO Bool
doTest String
name forall a b. (a -> b) -> a -> b
$ forall {a} {b}.
ProPredicate a b -> [(Either Condition a, Trace)] -> Result b
chk ProPredicate a b
test [(Either Condition a, Trace)]
traces) [(String, ProPredicate a b)]
tests
forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall (t :: * -> *). Foldable t => t Bool -> Bool
and [Bool]
results)
where
discarder :: Either Condition a -> Maybe Discard
discarder = forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. a -> a
id forall a.
(Either Condition a -> Maybe Discard)
-> (Either Condition a -> Maybe Discard)
-> Either Condition a
-> Maybe Discard
strengthenDiscard (forall s a. Lens' s a -> s -> a
get forall (n :: * -> *) a.
Lens' (Settings n a) (Maybe (Either Condition a -> Maybe Discard))
ldiscard Settings n a
settings) forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr
(forall a.
(Either Condition a -> Maybe Discard)
-> (Either Condition a -> Maybe Discard)
-> Either Condition a
-> Maybe Discard
weakenDiscard forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. ProPredicate a b -> Either Condition a -> Maybe Discard
pdiscard forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd)
(forall a b. a -> b -> a
const (forall a. a -> Maybe a
Just Discard
DiscardResultAndTrace))
[(String, ProPredicate a b)]
tests
chk :: ProPredicate a b -> [(Either Condition a, Trace)] -> Result b
chk ProPredicate a b
p [(Either Condition a, Trace)]
rs
| forall a. Int -> [a] -> Bool
moreThan Int
1 [(Either Condition a, Trace)]
rs =
let go :: (Either Condition a, [a]) -> Maybe (Either Condition a, [a])
go r :: (Either Condition a, [a])
r@(Either Condition a
efa, [a]
_) = case forall a b. ProPredicate a b -> Either Condition a -> Maybe Discard
pdiscard ProPredicate a b
p Either Condition a
efa of
Just Discard
DiscardResultAndTrace -> forall a. Maybe a
Nothing
Just Discard
DiscardTrace -> forall a. a -> Maybe a
Just (Either Condition a
efa, [])
Maybe Discard
Nothing -> forall a. a -> Maybe a
Just (Either Condition a, [a])
r
in forall {a} {b}.
ProPredicate a b -> [(Either Condition a, Trace)] -> Result b
peval ProPredicate a b
p (forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe forall {a}.
(Either Condition a, [a]) -> Maybe (Either Condition a, [a])
go [(Either Condition a, Trace)]
rs)
| Bool
otherwise = forall {a} {b}.
ProPredicate a b -> [(Either Condition a, Trace)] -> Result b
peval ProPredicate a b
p [(Either Condition a, Trace)]
rs
data Result a = Result
{ forall a. Result a -> Bool
_pass :: Bool
, forall a. Result a -> [(Either Condition a, Trace)]
_failures :: [(Either Condition a, Trace)]
, forall a. Result a -> String
_failureMsg :: String
} deriving (Result a -> Result a -> Bool
forall a. Eq a => Result a -> Result a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Result a -> Result a -> Bool
$c/= :: forall a. Eq a => Result a -> Result a -> Bool
== :: Result a -> Result a -> Bool
$c== :: forall a. Eq a => Result a -> Result a -> Bool
Eq, Int -> Result a -> ShowS
forall a. Show a => Int -> Result a -> ShowS
forall a. Show a => [Result a] -> ShowS
forall a. Show a => Result a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Result a] -> ShowS
$cshowList :: forall a. Show a => [Result a] -> ShowS
show :: Result a -> String
$cshow :: forall a. Show a => Result a -> String
showsPrec :: Int -> Result a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Result a -> ShowS
Show)
instance NFData a => NFData (Result a) where
rnf :: Result a -> ()
rnf Result a
r = forall a. NFData a => a -> ()
rnf ( forall a. Result a -> Bool
_pass Result a
r
, forall a. Result a -> [(Either Condition a, Trace)]
_failures Result a
r
, forall a. Result a -> String
_failureMsg Result a
r
)
defaultFail :: [(Either Condition a, Trace)] -> Result a
defaultFail :: forall a. [(Either Condition a, Trace)] -> Result a
defaultFail [(Either Condition a, Trace)]
failures = forall a.
Bool -> [(Either Condition a, Trace)] -> String -> Result a
Result Bool
False [(Either Condition a, Trace)]
failures String
""
defaultPass :: Result a
defaultPass :: forall a. Result a
defaultPass = forall a.
Bool -> [(Either Condition a, Trace)] -> String -> Result a
Result Bool
True [] String
""
instance Functor Result where
fmap :: forall a b. (a -> b) -> Result a -> Result b
fmap a -> b
f Result a
r = Result a
r { _failures :: [(Either Condition b, Trace)]
_failures = forall a b. (a -> b) -> [a] -> [b]
map (forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f) forall a b. (a -> b) -> a -> b
$ forall a. Result a -> [(Either Condition a, Trace)]
_failures Result a
r }
instance Foldable Result where
foldMap :: forall m a. Monoid m => (a -> m) -> Result a -> m
foldMap a -> m
f Result a
r = forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap a -> m
f [a
a | (Right a
a, Trace
_) <- forall a. Result a -> [(Either Condition a, Trace)]
_failures Result a
r]
runTest :: MonadDejaFu n
=> ProPredicate a b
-> Program pty n a
-> n (Result b)
runTest :: forall (n :: * -> *) a b pty.
MonadDejaFu n =>
ProPredicate a b -> Program pty n a -> n (Result b)
runTest = forall (n :: * -> *) a b pty.
MonadDejaFu n =>
Settings n a -> ProPredicate a b -> Program pty n a -> n (Result b)
runTestWithSettings forall (n :: * -> *) a. Applicative n => Settings n a
defaultSettings
runTestWay :: MonadDejaFu n
=> Way
-> MemType
-> ProPredicate a b
-> Program pty n a
-> n (Result b)
runTestWay :: forall (n :: * -> *) a b pty.
MonadDejaFu n =>
Way
-> MemType -> ProPredicate a b -> Program pty n a -> n (Result b)
runTestWay Way
way = forall (n :: * -> *) a b pty.
MonadDejaFu n =>
Settings n a -> ProPredicate a b -> Program pty n a -> n (Result b)
runTestWithSettings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: * -> *) a.
Applicative n =>
Way -> MemType -> Settings n a
fromWayAndMemType Way
way
runTestWithSettings :: MonadDejaFu n
=> Settings n a
-> ProPredicate a b
-> Program pty n a
-> n (Result b)
runTestWithSettings :: forall (n :: * -> *) a b pty.
MonadDejaFu n =>
Settings n a -> ProPredicate a b -> Program pty n a -> n (Result b)
runTestWithSettings Settings n a
settings ProPredicate a b
p Program pty n a
conc =
let discarder :: Either Condition a -> Maybe Discard
discarder = forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. a -> a
id forall a.
(Either Condition a -> Maybe Discard)
-> (Either Condition a -> Maybe Discard)
-> Either Condition a
-> Maybe Discard
strengthenDiscard (forall s a. Lens' s a -> s -> a
get forall (n :: * -> *) a.
Lens' (Settings n a) (Maybe (Either Condition a -> Maybe Discard))
ldiscard Settings n a
settings) (forall a b. ProPredicate a b -> Either Condition a -> Maybe Discard
pdiscard ProPredicate a b
p)
in forall {a} {b}.
ProPredicate a b -> [(Either Condition a, Trace)] -> Result b
peval ProPredicate a b
p forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (n :: * -> *) a pty.
MonadDejaFu n =>
Settings n a -> Program pty n a -> n [(Either Condition a, Trace)]
runSCTWithSettings (forall s a. Lens' s a -> a -> s -> s
set forall (n :: * -> *) a.
Lens' (Settings n a) (Maybe (Either Condition a -> Maybe Discard))
ldiscard (forall a. a -> Maybe a
Just Either Condition a -> Maybe Discard
discarder) Settings n a
settings) Program pty n a
conc
type Predicate a = ProPredicate a a
data ProPredicate a b = ProPredicate
{ forall a b. ProPredicate a b -> Either Condition a -> Maybe Discard
pdiscard :: Either Condition a -> Maybe Discard
, forall {a} {b}.
ProPredicate a b -> [(Either Condition a, Trace)] -> Result b
peval :: [(Either Condition a, Trace)] -> Result b
}
instance Profunctor ProPredicate where
dimap :: forall a b c d.
(a -> b) -> (c -> d) -> ProPredicate b c -> ProPredicate a d
dimap a -> b
f c -> d
g ProPredicate b c
p = ProPredicate
{ pdiscard :: Either Condition a -> Maybe Discard
pdiscard = forall a b. ProPredicate a b -> Either Condition a -> Maybe Discard
pdiscard ProPredicate b c
p forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f
, peval :: [(Either Condition a, Trace)] -> Result d
peval = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap c -> d
g forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {a} {b}.
ProPredicate a b -> [(Either Condition a, Trace)] -> Result b
peval ProPredicate b c
p forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f))
}
instance Functor (ProPredicate x) where
fmap :: forall a b. (a -> b) -> ProPredicate x a -> ProPredicate x b
fmap = forall (p :: * -> * -> *) a b c d.
Profunctor p =>
(a -> b) -> (c -> d) -> p b c -> p a d
dimap forall a. a -> a
id
representative :: Eq b => ProPredicate a b -> ProPredicate a b
representative :: forall b a. Eq b => ProPredicate a b -> ProPredicate a b
representative ProPredicate a b
p = ProPredicate a b
p
{ peval :: [(Either Condition a, Trace)] -> Result b
peval = \[(Either Condition a, Trace)]
xs ->
let result :: Result b
result = forall {a} {b}.
ProPredicate a b -> [(Either Condition a, Trace)] -> Result b
peval ProPredicate a b
p [(Either Condition a, Trace)]
xs
in Result b
result { _failures :: [(Either Condition b, Trace)]
_failures = forall x. (x -> x -> Bool) -> [(x, Trace)] -> [(x, Trace)]
simplestsBy forall a. Eq a => a -> a -> Bool
(==) (forall a. Result a -> [(Either Condition a, Trace)]
_failures Result b
result) }
}
successful :: Predicate a
successful :: forall a. Predicate a
successful = forall a. (Either Condition a -> Bool) -> Predicate a
alwaysTrue (forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a b. a -> b -> a
const Bool
False) (forall a b. a -> b -> a
const Bool
True))
abortsNever :: Predicate a
abortsNever :: forall a. Predicate a
abortsNever = forall a. (Either Condition a -> Bool) -> Predicate a
alwaysTrue (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a. Eq a => a -> a -> Bool
==Condition
Abort) (forall a b. a -> b -> a
const Bool
False))
abortsAlways :: Predicate a
abortsAlways :: forall a. Predicate a
abortsAlways = forall a. (Either Condition a -> Bool) -> Predicate a
alwaysTrue forall a b. (a -> b) -> a -> b
$ forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a. Eq a => a -> a -> Bool
==Condition
Abort) (forall a b. a -> b -> a
const Bool
False)
abortsSometimes :: Predicate a
abortsSometimes :: forall a. Predicate a
abortsSometimes = forall a. (Either Condition a -> Bool) -> Predicate a
somewhereTrue forall a b. (a -> b) -> a -> b
$ forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a. Eq a => a -> a -> Bool
==Condition
Abort) (forall a b. a -> b -> a
const Bool
False)
deadlocksNever :: Predicate a
deadlocksNever :: forall a. Predicate a
deadlocksNever = forall a. (Either Condition a -> Bool) -> Predicate a
alwaysTrue (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Condition -> Bool
isDeadlock (forall a b. a -> b -> a
const Bool
False))
deadlocksAlways :: Predicate a
deadlocksAlways :: forall a. Predicate a
deadlocksAlways = forall a. (Either Condition a -> Bool) -> Predicate a
alwaysTrue forall a b. (a -> b) -> a -> b
$ forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Condition -> Bool
isDeadlock (forall a b. a -> b -> a
const Bool
False)
deadlocksSometimes :: Predicate a
deadlocksSometimes :: forall a. Predicate a
deadlocksSometimes = forall a. (Either Condition a -> Bool) -> Predicate a
somewhereTrue forall a b. (a -> b) -> a -> b
$ forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Condition -> Bool
isDeadlock (forall a b. a -> b -> a
const Bool
False)
exceptionsNever :: Predicate a
exceptionsNever :: forall a. Predicate a
exceptionsNever = forall a. (Either Condition a -> Bool) -> Predicate a
alwaysTrue (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Condition -> Bool
isUncaughtException (forall a b. a -> b -> a
const Bool
False))
exceptionsAlways :: Predicate a
exceptionsAlways :: forall a. Predicate a
exceptionsAlways = forall a. (Either Condition a -> Bool) -> Predicate a
alwaysTrue forall a b. (a -> b) -> a -> b
$ forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Condition -> Bool
isUncaughtException (forall a b. a -> b -> a
const Bool
False)
exceptionsSometimes :: Predicate a
exceptionsSometimes :: forall a. Predicate a
exceptionsSometimes = forall a. (Either Condition a -> Bool) -> Predicate a
somewhereTrue forall a b. (a -> b) -> a -> b
$ forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Condition -> Bool
isUncaughtException (forall a b. a -> b -> a
const Bool
False)
alwaysSame :: Eq a => Predicate a
alwaysSame :: forall a. Eq a => Predicate a
alwaysSame = forall a. (a -> a -> Bool) -> Predicate a
alwaysSameBy forall a. Eq a => a -> a -> Bool
(==)
alwaysSameOn :: Eq b => (a -> b) -> Predicate a
alwaysSameOn :: forall b a. Eq b => (a -> b) -> Predicate a
alwaysSameOn a -> b
f = forall a. (a -> a -> Bool) -> Predicate a
alwaysSameBy (forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` a -> b
f)
alwaysSameBy :: (a -> a -> Bool) -> Predicate a
alwaysSameBy :: forall a. (a -> a -> Bool) -> Predicate a
alwaysSameBy a -> a -> Bool
f = ProPredicate
{ pdiscard :: Either Condition a -> Maybe Discard
pdiscard = forall a b. a -> b -> a
const forall a. Maybe a
Nothing
, peval :: [(Either Condition a, Trace)] -> Result a
peval = \[(Either Condition a, Trace)]
xs ->
let ([(Either Condition a, Trace)]
failures, [(Either Condition a, Trace)]
successes) = forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (forall a b. Either a b -> Bool
isLeft forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) [(Either Condition a, Trace)]
xs
simpleSuccesses :: [(Either Condition a, Trace)]
simpleSuccesses = forall x. (x -> x -> Bool) -> [(x, Trace)] -> [(x, Trace)]
simplestsBy (a -> a -> Bool
f forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall a b. HasCallStack => Either a b -> b
efromRight) [(Either Condition a, Trace)]
successes
simpleFailures :: [(Either Condition a, Trace)]
simpleFailures = forall x. (x -> x -> Bool) -> [(x, Trace)] -> [(x, Trace)]
simplestsBy (forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall a b. HasCallStack => Either a b -> a
efromLeft) [(Either Condition a, Trace)]
failures
in case ([(Either Condition a, Trace)]
simpleFailures, [(Either Condition a, Trace)]
simpleSuccesses) of
([], []) -> forall a. Result a
defaultPass
([], [(Either Condition a, Trace)
_]) -> forall a. Result a
defaultPass
([(Either Condition a, Trace)]
_, [(Either Condition a, Trace)]
_) -> forall a. [(Either Condition a, Trace)] -> Result a
defaultFail ([(Either Condition a, Trace)]
simpleFailures forall a. [a] -> [a] -> [a]
++ [(Either Condition a, Trace)]
simpleSuccesses)
}
notAlwaysSame :: Eq a => Predicate a
notAlwaysSame :: forall a. Eq a => Predicate a
notAlwaysSame = forall a. (a -> a -> Bool) -> Predicate a
notAlwaysSameBy forall a. Eq a => a -> a -> Bool
(==)
notAlwaysSameOn :: Eq b => (a -> b) -> Predicate a
notAlwaysSameOn :: forall b a. Eq b => (a -> b) -> Predicate a
notAlwaysSameOn a -> b
f = forall a. (a -> a -> Bool) -> Predicate a
notAlwaysSameBy (forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` a -> b
f)
notAlwaysSameBy :: (a -> a -> Bool) -> Predicate a
notAlwaysSameBy :: forall a. (a -> a -> Bool) -> Predicate a
notAlwaysSameBy a -> a -> Bool
f = ProPredicate
{ pdiscard :: Either Condition a -> Maybe Discard
pdiscard = forall a b. a -> b -> a
const forall a. Maybe a
Nothing
, peval :: [(Either Condition a, Trace)] -> Result a
peval = \[(Either Condition a, Trace)]
xs ->
let ([(Either Condition a, Trace)]
failures, [(Either Condition a, Trace)]
successes) = forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (forall a b. Either a b -> Bool
isLeft forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) [(Either Condition a, Trace)]
xs
simpleFailures :: [(Either Condition a, Trace)]
simpleFailures = forall x. (x -> x -> Bool) -> [(x, Trace)] -> [(x, Trace)]
simplestsBy (forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall a b. HasCallStack => Either a b -> a
efromLeft) [(Either Condition a, Trace)]
failures
in case [(Either Condition a, Trace)]
successes of
[(Either Condition a, Trace)
x] -> forall a. [(Either Condition a, Trace)] -> Result a
defaultFail ((Either Condition a, Trace)
x forall a. a -> [a] -> [a]
: [(Either Condition a, Trace)]
simpleFailures)
[(Either Condition a, Trace)]
_ ->
let res :: Result a
res = [(Either Condition a, Trace)] -> Result a -> Result a
go [(Either Condition a, Trace)]
successes (forall a. [(Either Condition a, Trace)] -> Result a
defaultFail [])
in case [(Either Condition a, Trace)]
failures of
[] -> Result a
res
[(Either Condition a, Trace)]
_ -> Result a
res { _failures :: [(Either Condition a, Trace)]
_failures = [(Either Condition a, Trace)]
simpleFailures forall a. [a] -> [a] -> [a]
++ forall a. Result a -> [(Either Condition a, Trace)]
_failures Result a
res, _pass :: Bool
_pass = Bool
False }
}
where
(Either a a, b)
y1 .*. :: (Either a a, b) -> (Either a a, b) -> Bool
.*. (Either a a, b)
y2 = Bool -> Bool
not (forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on a -> a -> Bool
f (forall a b. HasCallStack => Either a b -> b
efromRight forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) (Either a a, b)
y1 (Either a a, b)
y2)
go :: [(Either Condition a, Trace)] -> Result a -> Result a
go [(Either Condition a, Trace)
y1,(Either Condition a, Trace)
y2] Result a
res
| (Either Condition a, Trace)
y1 forall {a} {b}. (Either a a, b) -> (Either a a, b) -> Bool
.*. (Either Condition a, Trace)
y2 = Result a
res { _pass :: Bool
_pass = Bool
True }
| Bool
otherwise = Result a
res { _failures :: [(Either Condition a, Trace)]
_failures = (Either Condition a, Trace)
y1 forall a. a -> [a] -> [a]
: (Either Condition a, Trace)
y2 forall a. a -> [a] -> [a]
: forall a. Result a -> [(Either Condition a, Trace)]
_failures Result a
res }
go ((Either Condition a, Trace)
y1:(Either Condition a, Trace)
y2:[(Either Condition a, Trace)]
ys) Result a
res
| (Either Condition a, Trace)
y1 forall {a} {b}. (Either a a, b) -> (Either a a, b) -> Bool
.*. (Either Condition a, Trace)
y2 = [(Either Condition a, Trace)] -> Result a -> Result a
go ((Either Condition a, Trace)
y2forall a. a -> [a] -> [a]
:[(Either Condition a, Trace)]
ys) Result a
res { _pass :: Bool
_pass = Bool
True }
| Bool
otherwise = [(Either Condition a, Trace)] -> Result a -> Result a
go ((Either Condition a, Trace)
y2forall a. a -> [a] -> [a]
:[(Either Condition a, Trace)]
ys) Result a
res { _failures :: [(Either Condition a, Trace)]
_failures = (Either Condition a, Trace)
y1 forall a. a -> [a] -> [a]
: (Either Condition a, Trace)
y2 forall a. a -> [a] -> [a]
: forall a. Result a -> [(Either Condition a, Trace)]
_failures Result a
res }
go [(Either Condition a, Trace)]
_ Result a
res = Result a
res
alwaysNothing :: (Either Condition a -> Maybe (Either Condition b)) -> ProPredicate a b
alwaysNothing :: forall a b.
(Either Condition a -> Maybe (Either Condition b))
-> ProPredicate a b
alwaysNothing Either Condition a -> Maybe (Either Condition b)
f = ProPredicate
{ pdiscard :: Either Condition a -> Maybe Discard
pdiscard = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a. a -> Maybe a
Just Discard
DiscardResultAndTrace) (forall a b. a -> b -> a
const forall a. Maybe a
Nothing) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either Condition a -> Maybe (Either Condition b)
f
, peval :: [(Either Condition a, Trace)] -> Result b
peval = \[(Either Condition a, Trace)]
xs ->
let failures :: [(Either Condition b, Trace)]
failures = forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (\(Either Condition a
efa,Trace
trc) -> (,Trace
trc) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either Condition a -> Maybe (Either Condition b)
f Either Condition a
efa) [(Either Condition a, Trace)]
xs
in forall a.
Bool -> [(Either Condition a, Trace)] -> String -> Result a
Result (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Either Condition b, Trace)]
failures) [(Either Condition b, Trace)]
failures String
""
}
alwaysTrue :: (Either Condition a -> Bool) -> Predicate a
alwaysTrue :: forall a. (Either Condition a -> Bool) -> Predicate a
alwaysTrue Either Condition a -> Bool
p = forall a b.
(Either Condition a -> Maybe (Either Condition b))
-> ProPredicate a b
alwaysNothing (\Either Condition a
efa -> if Either Condition a -> Bool
p Either Condition a
efa then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just Either Condition a
efa)
somewhereNothing :: (Either Condition a -> Maybe (Either Condition b)) -> ProPredicate a b
somewhereNothing :: forall a b.
(Either Condition a -> Maybe (Either Condition b))
-> ProPredicate a b
somewhereNothing Either Condition a -> Maybe (Either Condition b)
f = ProPredicate
{ pdiscard :: Either Condition a -> Maybe Discard
pdiscard = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a. a -> Maybe a
Just Discard
DiscardTrace) (forall a b. a -> b -> a
const forall a. Maybe a
Nothing) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either Condition a -> Maybe (Either Condition b)
f
, peval :: [(Either Condition a, Trace)] -> Result b
peval = \[(Either Condition a, Trace)]
xs ->
let failures :: [Maybe (Either Condition b, Trace)]
failures = forall a b. (a -> b) -> [a] -> [b]
map (\(Either Condition a
efa,Trace
trc) -> (,Trace
trc) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either Condition a -> Maybe (Either Condition b)
f Either Condition a
efa) [(Either Condition a, Trace)]
xs
in forall a.
Bool -> [(Either Condition a, Trace)] -> String -> Result a
Result (forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any forall a. Maybe a -> Bool
isNothing [Maybe (Either Condition b, Trace)]
failures) (forall a. [Maybe a] -> [a]
catMaybes [Maybe (Either Condition b, Trace)]
failures) String
""
}
somewhereTrue :: (Either Condition a -> Bool) -> Predicate a
somewhereTrue :: forall a. (Either Condition a -> Bool) -> Predicate a
somewhereTrue Either Condition a -> Bool
p = forall a b.
(Either Condition a -> Maybe (Either Condition b))
-> ProPredicate a b
somewhereNothing (\Either Condition a
efa -> if Either Condition a -> Bool
p Either Condition a
efa then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just Either Condition a
efa)
gives :: (Eq a, Show a) => [Either Condition a] -> Predicate a
gives :: forall a. (Eq a, Show a) => [Either Condition a] -> Predicate a
gives [Either Condition a]
expected = ProPredicate
{ pdiscard :: Either Condition a -> Maybe Discard
pdiscard = \Either Condition a
efa -> if Either Condition a
efa forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Either Condition a]
expected then forall a. a -> Maybe a
Just Discard
DiscardTrace else forall a. Maybe a
Nothing
, peval :: [(Either Condition a, Trace)] -> Result a
peval = \[(Either Condition a, Trace)]
xs -> forall {a} {b} {a}.
(Eq a, Show a) =>
[a] -> [a] -> [(a, b)] -> Result a -> Result a
go [Either Condition a]
expected [] [(Either Condition a, Trace)]
xs forall a b. (a -> b) -> a -> b
$ forall a. [(Either Condition a, Trace)] -> Result a
defaultFail (forall {b}. [(Either Condition a, b)] -> [(Either Condition a, b)]
failures [(Either Condition a, Trace)]
xs)
}
where
go :: [a] -> [a] -> [(a, b)] -> Result a -> Result a
go [a]
waitingFor [a]
alreadySeen ((a
x, b
_):[(a, b)]
xs) Result a
res
| a
x forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [a]
waitingFor = [a] -> [a] -> [(a, b)] -> Result a -> Result a
go (forall a. (a -> Bool) -> [a] -> [a]
filter (forall a. Eq a => a -> a -> Bool
/=a
x) [a]
waitingFor) (a
xforall a. a -> [a] -> [a]
:[a]
alreadySeen) [(a, b)]
xs Result a
res
| a
x forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [a]
alreadySeen = [a] -> [a] -> [(a, b)] -> Result a -> Result a
go [a]
waitingFor [a]
alreadySeen [(a, b)]
xs Result a
res
| Bool
otherwise = Result a
res
go [] [a]
_ [] Result a
res = Result a
res { _pass :: Bool
_pass = Bool
True }
go [a]
es [a]
_ [] Result a
res = Result a
res { _failureMsg :: String
_failureMsg = [String] -> String
unlines forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (\a
e -> String
"Expected: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show a
e) [a]
es }
failures :: [(Either Condition a, b)] -> [(Either Condition a, b)]
failures = forall a. (a -> Bool) -> [a] -> [a]
filter (\(Either Condition a
r, b
_) -> Either Condition a
r forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Either Condition a]
expected)
gives' :: (Eq a, Show a) => [a] -> Predicate a
gives' :: forall a. (Eq a, Show a) => [a] -> Predicate a
gives' = forall a. (Eq a, Show a) => [Either Condition a] -> Predicate a
gives forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a b. b -> Either a b
Right
doTest :: Show a => String -> Result a -> IO Bool
doTest :: forall a. Show a => String -> Result a -> IO Bool
doTest String
name Result a
result = do
Bool
doctest <- forall a. Maybe a -> Bool
isJust forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO (Maybe String)
lookupEnv String
"DEJAFU_DOCTEST"
if forall a. Result a -> Bool
_pass Result a
result
then String -> IO ()
putStrLn (Bool -> String
passmsg Bool
doctest)
else do
String -> IO ()
putStrLn (Bool -> String
failmsg Bool
doctest)
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ forall a. Result a -> String
_failureMsg Result a
result) forall a b. (a -> b) -> a -> b
$
String -> IO ()
putStrLn forall a b. (a -> b) -> a -> b
$ forall a. Result a -> String
_failureMsg Result a
result
let failures :: [(Either Condition a, Trace)]
failures = forall a. Result a -> [(Either Condition a, Trace)]
_failures Result a
result
let output :: [IO ()]
output = forall a b. (a -> b) -> [a] -> [b]
map (\(Either Condition a
r, Trace
t) -> String -> IO ()
putStrLn forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
indent forall a b. (a -> b) -> a -> b
$ forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Condition -> String
showCondition forall a. Show a => a -> String
show Either Condition a
r forall a. [a] -> [a] -> [a]
++ String
" " forall a. [a] -> [a] -> [a]
++ Trace -> String
showTrace Trace
t) forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
take Int
5 [(Either Condition a, Trace)]
failures
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ forall a b. (a -> b) -> a -> b
$ forall a. a -> [a] -> [a]
intersperse (String -> IO ()
putStrLn String
"") [IO ()]
output
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall a. Int -> [a] -> Bool
moreThan Int
5 [(Either Condition a, Trace)]
failures) forall a b. (a -> b) -> a -> b
$
String -> IO ()
putStrLn (ShowS
indent String
"...")
forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a. Result a -> Bool
_pass Result a
result)
where
passmsg :: Bool -> String
passmsg Bool
True = String
"[pass] " forall a. [a] -> [a] -> [a]
++ String
name
passmsg Bool
False = String
"\27[32m[pass]\27[0m " forall a. [a] -> [a] -> [a]
++ String
name
failmsg :: Bool -> String
failmsg Bool
True = String
"[fail] " forall a. [a] -> [a] -> [a]
++ String
name
failmsg Bool
False = String
"\27[31m[fail]\27[0m " forall a. [a] -> [a] -> [a]
++ String
name
moreThan :: Int -> [a] -> Bool
moreThan :: forall a. Int -> [a] -> Bool
moreThan Int
n [] = Int
n forall a. Ord a => a -> a -> Bool
< Int
0
moreThan Int
0 [a]
_ = Bool
True
moreThan Int
n (a
_:[a]
rest) = forall a. Int -> [a] -> Bool
moreThan (Int
nforall a. Num a => a -> a -> a
-Int
1) [a]
rest
indent :: String -> String
indent :: ShowS
indent = forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (String
" "forall a. [a] -> [a] -> [a]
++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines