{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE CPP #-}
#ifndef NO_TYPEABLE
{-# LANGUAGE DeriveDataTypeable #-}
#endif
#ifndef NO_SAFE_HASKELL
{-# LANGUAGE Trustworthy #-}
#endif
module Test.QuickCheck.Test where
import Test.QuickCheck.Gen
import Test.QuickCheck.Property hiding ( Result( reason, theException, labels, classes, tables ), (.&.) )
import qualified Test.QuickCheck.Property as P
import Test.QuickCheck.Text
import Test.QuickCheck.State hiding (labels, classes, tables, requiredCoverage)
import qualified Test.QuickCheck.State as S
import Test.QuickCheck.Exception
import Test.QuickCheck.Random
import System.Random(split)
#if defined(MIN_VERSION_containers)
#if MIN_VERSION_containers(0,5,0)
import qualified Data.Map.Strict as Map
#else
import qualified Data.Map as Map
#endif
#else
import qualified Data.Map as Map
#endif
import qualified Data.Set as Set
import Data.Set(Set)
import Data.Map(Map)
import Data.Char
( isSpace
)
import Data.List
( sort
, sortBy
, group
, intersperse
)
import Data.Maybe(fromMaybe, isNothing, catMaybes)
import Data.Ord(comparing)
import Text.Printf(printf)
import Control.Monad
import Data.Bits
#ifndef NO_TYPEABLE
import Data.Typeable (Typeable)
#endif
data Args
= Args
{ Args -> Maybe (QCGen, Int)
replay :: Maybe (QCGen,Int)
, Args -> Int
maxSuccess :: Int
, Args -> Int
maxDiscardRatio :: Int
, Args -> Int
maxSize :: Int
, Args -> Bool
chatty :: Bool
, Args -> Int
maxShrinks :: Int
}
deriving ( Int -> Args -> ShowS
[Args] -> ShowS
Args -> String
(Int -> Args -> ShowS)
-> (Args -> String) -> ([Args] -> ShowS) -> Show Args
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Args] -> ShowS
$cshowList :: [Args] -> ShowS
show :: Args -> String
$cshow :: Args -> String
showsPrec :: Int -> Args -> ShowS
$cshowsPrec :: Int -> Args -> ShowS
Show, ReadPrec [Args]
ReadPrec Args
Int -> ReadS Args
ReadS [Args]
(Int -> ReadS Args)
-> ReadS [Args] -> ReadPrec Args -> ReadPrec [Args] -> Read Args
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Args]
$creadListPrec :: ReadPrec [Args]
readPrec :: ReadPrec Args
$creadPrec :: ReadPrec Args
readList :: ReadS [Args]
$creadList :: ReadS [Args]
readsPrec :: Int -> ReadS Args
$creadsPrec :: Int -> ReadS Args
Read
#ifndef NO_TYPEABLE
, Typeable
#endif
)
data Result
= Success
{ Result -> Int
numTests :: Int
, Result -> Int
numDiscarded :: Int
, Result -> Map [String] Int
labels :: !(Map [String] Int)
, Result -> Map String Int
classes :: !(Map String Int)
, Result -> Map String (Map String Int)
tables :: !(Map String (Map String Int))
, Result -> String
output :: String
}
| GaveUp
{ numTests :: Int
, numDiscarded :: Int
, labels :: !(Map [String] Int)
, classes :: !(Map String Int)
, tables :: !(Map String (Map String Int))
, output :: String
}
| Failure
{ numTests :: Int
, numDiscarded :: Int
, Result -> Int
numShrinks :: Int
, Result -> Int
numShrinkTries :: Int
, Result -> Int
numShrinkFinal :: Int
, Result -> QCGen
usedSeed :: QCGen
, Result -> Int
usedSize :: Int
, Result -> String
reason :: String
, Result -> Maybe AnException
theException :: Maybe AnException
, output :: String
, Result -> [String]
failingTestCase :: [String]
, Result -> [String]
failingLabels :: [String]
, Result -> Set String
failingClasses :: Set String
}
| NoExpectedFailure
{ numTests :: Int
, numDiscarded :: Int
, labels :: !(Map [String] Int)
, classes :: !(Map String Int)
, tables :: !(Map String (Map String Int))
, output :: String
}
deriving ( Int -> Result -> ShowS
[Result] -> ShowS
Result -> String
(Int -> Result -> ShowS)
-> (Result -> String) -> ([Result] -> ShowS) -> Show Result
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Result] -> ShowS
$cshowList :: [Result] -> ShowS
show :: Result -> String
$cshow :: Result -> String
showsPrec :: Int -> Result -> ShowS
$cshowsPrec :: Int -> Result -> ShowS
Show )
isSuccess :: Result -> Bool
isSuccess :: Result -> Bool
isSuccess Success{} = Bool
True
isSuccess _ = Bool
False
stdArgs :: Args
stdArgs :: Args
stdArgs = Args :: Maybe (QCGen, Int) -> Int -> Int -> Int -> Bool -> Int -> Args
Args
{ replay :: Maybe (QCGen, Int)
replay = Maybe (QCGen, Int)
forall a. Maybe a
Nothing
, maxSuccess :: Int
maxSuccess = 100
, maxDiscardRatio :: Int
maxDiscardRatio = 10
, maxSize :: Int
maxSize = 100
, chatty :: Bool
chatty = Bool
True
, maxShrinks :: Int
maxShrinks = Int
forall a. Bounded a => a
maxBound
}
quickCheck :: Testable prop => prop -> IO ()
quickCheck :: prop -> IO ()
quickCheck p :: prop
p = Args -> prop -> IO ()
forall prop. Testable prop => Args -> prop -> IO ()
quickCheckWith Args
stdArgs prop
p
quickCheckWith :: Testable prop => Args -> prop -> IO ()
quickCheckWith :: Args -> prop -> IO ()
quickCheckWith args :: Args
args p :: prop
p = Args -> prop -> IO Result
forall prop. Testable prop => Args -> prop -> IO Result
quickCheckWithResult Args
args prop
p IO Result -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
quickCheckResult :: Testable prop => prop -> IO Result
quickCheckResult :: prop -> IO Result
quickCheckResult p :: prop
p = Args -> prop -> IO Result
forall prop. Testable prop => Args -> prop -> IO Result
quickCheckWithResult Args
stdArgs prop
p
quickCheckWithResult :: Testable prop => Args -> prop -> IO Result
quickCheckWithResult :: Args -> prop -> IO Result
quickCheckWithResult a :: Args
a p :: prop
p =
Args -> (State -> IO Result) -> IO Result
forall a. Args -> (State -> IO a) -> IO a
withState Args
a (\s :: State
s -> State -> Property -> IO Result
test State
s (prop -> Property
forall prop. Testable prop => prop -> Property
property prop
p))
withState :: Args -> (State -> IO a) -> IO a
withState :: Args -> (State -> IO a) -> IO a
withState a :: Args
a test :: State -> IO a
test = (if Args -> Bool
chatty Args
a then (Terminal -> IO a) -> IO a
forall a. (Terminal -> IO a) -> IO a
withStdioTerminal else (Terminal -> IO a) -> IO a
forall a. (Terminal -> IO a) -> IO a
withNullTerminal) ((Terminal -> IO a) -> IO a) -> (Terminal -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \tm :: Terminal
tm -> do
QCGen
rnd <- case Args -> Maybe (QCGen, Int)
replay Args
a of
Nothing -> IO QCGen
newQCGen
Just (rnd :: QCGen
rnd,_) -> QCGen -> IO QCGen
forall (m :: * -> *) a. Monad m => a -> m a
return QCGen
rnd
State -> IO a
test $WMkState :: Terminal
-> Int
-> Int
-> Maybe Confidence
-> (Int -> Int -> Int)
-> Int
-> Int
-> Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> Map (Maybe String, String) Double
-> Bool
-> QCGen
-> Int
-> Int
-> Int
-> State
MkState{ terminal :: Terminal
terminal = Terminal
tm
, maxSuccessTests :: Int
maxSuccessTests = Args -> Int
maxSuccess Args
a
, coverageConfidence :: Maybe Confidence
coverageConfidence = Maybe Confidence
forall a. Maybe a
Nothing
, maxDiscardedRatio :: Int
maxDiscardedRatio = Args -> Int
maxDiscardRatio Args
a
, computeSize :: Int -> Int -> Int
computeSize = case Args -> Maybe (QCGen, Int)
replay Args
a of
Nothing -> Int -> Int -> Int
computeSize'
Just (_,s :: Int
s) -> Int -> Int -> Int
computeSize' (Int -> Int -> Int) -> Int -> Int -> Int -> Int
forall t t p.
(Eq t, Eq t, Num t, Num t) =>
(t -> t -> p) -> p -> t -> t -> p
`at0` Int
s
, numTotMaxShrinks :: Int
numTotMaxShrinks = Args -> Int
maxShrinks Args
a
, numSuccessTests :: Int
numSuccessTests = 0
, numDiscardedTests :: Int
numDiscardedTests = 0
, numRecentlyDiscardedTests :: Int
numRecentlyDiscardedTests = 0
, labels :: Map [String] Int
S.labels = Map [String] Int
forall k a. Map k a
Map.empty
, classes :: Map String Int
S.classes = Map String Int
forall k a. Map k a
Map.empty
, tables :: Map String (Map String Int)
S.tables = Map String (Map String Int)
forall k a. Map k a
Map.empty
, requiredCoverage :: Map (Maybe String, String) Double
S.requiredCoverage = Map (Maybe String, String) Double
forall k a. Map k a
Map.empty
, expected :: Bool
expected = Bool
True
, randomSeed :: QCGen
randomSeed = QCGen
rnd
, numSuccessShrinks :: Int
numSuccessShrinks = 0
, numTryShrinks :: Int
numTryShrinks = 0
, numTotTryShrinks :: Int
numTotTryShrinks = 0
}
where computeSize' :: Int -> Int -> Int
computeSize' n :: Int
n d :: Int
d
| Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`roundTo` Args -> Int
maxSize Args
a Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Args -> Int
maxSize Args
a Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Args -> Int
maxSuccess Args
a Bool -> Bool -> Bool
||
Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Args -> Int
maxSuccess Args
a Bool -> Bool -> Bool
||
Args -> Int
maxSuccess Args
a Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Args -> Int
maxSize Args
a Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0 = (Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Args -> Int
maxSize Args
a Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` 10) Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Args -> Int
maxSize Args
a
| Bool
otherwise =
((Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Args -> Int
maxSize Args
a) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Args -> Int
maxSize Args
a Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` (Args -> Int
maxSuccess Args
a Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Args -> Int
maxSize Args
a) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` 10) Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Args -> Int
maxSize Args
a
n :: a
n roundTo :: a -> a -> a
`roundTo` m :: a
m = (a
n a -> a -> a
forall a. Integral a => a -> a -> a
`div` a
m) a -> a -> a
forall a. Num a => a -> a -> a
* a
m
at0 :: (t -> t -> p) -> p -> t -> t -> p
at0 f :: t -> t -> p
f s :: p
s 0 0 = p
s
at0 f :: t -> t -> p
f s :: p
s n :: t
n d :: t
d = t -> t -> p
f t
n t
d
verboseCheck :: Testable prop => prop -> IO ()
verboseCheck :: prop -> IO ()
verboseCheck p :: prop
p = Property -> IO ()
forall prop. Testable prop => prop -> IO ()
quickCheck (prop -> Property
forall prop. Testable prop => prop -> Property
verbose prop
p)
verboseCheckWith :: Testable prop => Args -> prop -> IO ()
verboseCheckWith :: Args -> prop -> IO ()
verboseCheckWith args :: Args
args p :: prop
p = Args -> Property -> IO ()
forall prop. Testable prop => Args -> prop -> IO ()
quickCheckWith Args
args (prop -> Property
forall prop. Testable prop => prop -> Property
verbose prop
p)
verboseCheckResult :: Testable prop => prop -> IO Result
verboseCheckResult :: prop -> IO Result
verboseCheckResult p :: prop
p = Property -> IO Result
forall prop. Testable prop => prop -> IO Result
quickCheckResult (prop -> Property
forall prop. Testable prop => prop -> Property
verbose prop
p)
verboseCheckWithResult :: Testable prop => Args -> prop -> IO Result
verboseCheckWithResult :: Args -> prop -> IO Result
verboseCheckWithResult a :: Args
a p :: prop
p = Args -> Property -> IO Result
forall prop. Testable prop => Args -> prop -> IO Result
quickCheckWithResult Args
a (prop -> Property
forall prop. Testable prop => prop -> Property
verbose prop
p)
test :: State -> Property -> IO Result
test :: State -> Property -> IO Result
test st :: State
st f :: Property
f
| State -> Int
numSuccessTests State
st Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= State -> Int
maxSuccessTests State
st Bool -> Bool -> Bool
&& Maybe Confidence -> Bool
forall a. Maybe a -> Bool
isNothing (State -> Maybe Confidence
coverageConfidence State
st) =
State -> Property -> IO Result
doneTesting State
st Property
f
| State -> Int
numDiscardedTests State
st Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= State -> Int
maxDiscardedRatio State
st Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (State -> Int
numSuccessTests State
st) (State -> Int
maxSuccessTests State
st) =
State -> Property -> IO Result
giveUp State
st Property
f
| Bool
otherwise =
State -> Property -> IO Result
runATest State
st Property
f
doneTesting :: State -> Property -> IO Result
doneTesting :: State -> Property -> IO Result
doneTesting st :: State
st _f :: Property
_f
| State -> Bool
expected State
st Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
False = do
Terminal -> String -> IO ()
putPart (State -> Terminal
terminal State
st)
( ShowS
bold ("*** Failed!")
String -> ShowS
forall a. [a] -> [a] -> [a]
++ " Passed "
String -> ShowS
forall a. [a] -> [a] -> [a]
++ State -> String
showTestCount State
st
String -> ShowS
forall a. [a] -> [a] -> [a]
++ " (expected failure)"
)
(Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> Result)
-> IO Result
forall b.
(Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> b)
-> IO b
finished Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> Result
NoExpectedFailure
| Bool
otherwise = do
Terminal -> String -> IO ()
putPart (State -> Terminal
terminal State
st)
( "+++ OK, passed "
String -> ShowS
forall a. [a] -> [a] -> [a]
++ State -> String
showTestCount State
st
)
(Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> Result)
-> IO Result
forall b.
(Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> b)
-> IO b
finished Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> Result
Success
where
finished :: (Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> b)
-> IO b
finished k :: Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> b
k = do
State -> IO ()
success State
st
String
theOutput <- Terminal -> IO String
terminalOutput (State -> Terminal
terminal State
st)
b -> IO b
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> b
k (State -> Int
numSuccessTests State
st) (State -> Int
numDiscardedTests State
st) (State -> Map [String] Int
S.labels State
st) (State -> Map String Int
S.classes State
st) (State -> Map String (Map String Int)
S.tables State
st) String
theOutput)
giveUp :: State -> Property -> IO Result
giveUp :: State -> Property -> IO Result
giveUp st :: State
st _f :: Property
_f =
do
Terminal -> String -> IO ()
putPart (State -> Terminal
terminal State
st)
( ShowS
bold ("*** Gave up!")
String -> ShowS
forall a. [a] -> [a] -> [a]
++ " Passed only "
String -> ShowS
forall a. [a] -> [a] -> [a]
++ State -> String
showTestCount State
st
String -> ShowS
forall a. [a] -> [a] -> [a]
++ " tests"
)
State -> IO ()
success State
st
String
theOutput <- Terminal -> IO String
terminalOutput (State -> Terminal
terminal State
st)
Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return $WGaveUp :: Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> Result
GaveUp{ numTests :: Int
numTests = State -> Int
numSuccessTests State
st
, numDiscarded :: Int
numDiscarded = State -> Int
numDiscardedTests State
st
, labels :: Map [String] Int
labels = State -> Map [String] Int
S.labels State
st
, classes :: Map String Int
classes = State -> Map String Int
S.classes State
st
, tables :: Map String (Map String Int)
tables = State -> Map String (Map String Int)
S.tables State
st
, output :: String
output = String
theOutput
}
showTestCount :: State -> String
showTestCount :: State -> String
showTestCount st :: State
st =
Int -> ShowS
number (State -> Int
numSuccessTests State
st) "test"
String -> ShowS
forall a. [a] -> [a] -> [a]
++ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ "; " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (State -> Int
numDiscardedTests State
st) String -> ShowS
forall a. [a] -> [a] -> [a]
++ " discarded"
| State -> Int
numDiscardedTests State
st Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0
]
runATest :: State -> Property -> IO Result
runATest :: State -> Property -> IO Result
runATest st :: State
st f :: Property
f =
do
Terminal -> String -> IO ()
putTemp (State -> Terminal
terminal State
st)
( "("
String -> ShowS
forall a. [a] -> [a] -> [a]
++ State -> String
showTestCount State
st
String -> ShowS
forall a. [a] -> [a] -> [a]
++ ")"
)
let powerOfTwo :: a -> Bool
powerOfTwo n :: a
n = a
n a -> a -> a
forall a. Bits a => a -> a -> a
.&. (a
n a -> a -> a
forall a. Num a => a -> a -> a
- 1) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== 0
let f_or_cov :: Property
f_or_cov =
case State -> Maybe Confidence
coverageConfidence State
st of
Just confidence :: Confidence
confidence | (1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ State -> Int
numSuccessTests State
st) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` 100 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0 Bool -> Bool -> Bool
&& Int -> Bool
forall a. (Bits a, Num a) => a -> Bool
powerOfTwo ((1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ State -> Int
numSuccessTests State
st) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` 100) ->
Confidence -> State -> Property -> Property
addCoverageCheck Confidence
confidence State
st Property
f
_ -> Property
f
let size :: Int
size = State -> Int -> Int -> Int
computeSize State
st (State -> Int
numSuccessTests State
st) (State -> Int
numRecentlyDiscardedTests State
st)
MkRose res :: Result
res ts :: [Rose Result]
ts <- IO (Rose Result) -> IO (Rose Result)
protectRose (Rose Result -> IO (Rose Result)
reduceRose (Prop -> Rose Result
unProp (Gen Prop -> QCGen -> Int -> Prop
forall a. Gen a -> QCGen -> Int -> a
unGen (Property -> Gen Prop
unProperty Property
f_or_cov) QCGen
rnd1 Int
size)))
Result
res <- State -> Result -> IO Result
callbackPostTest State
st Result
res
let continue :: (State -> Property -> IO Result) -> State -> Property -> IO Result
continue break :: State -> Property -> IO Result
break st' :: State
st' | Result -> Bool
abort Result
res = State -> Property -> IO Result
break State
st'
| Bool
otherwise = State -> Property -> IO Result
test State
st'
let st' :: State
st' = State
st{ coverageConfidence :: Maybe Confidence
coverageConfidence = Result -> Maybe Confidence
maybeCheckCoverage Result
res Maybe Confidence -> Maybe Confidence -> Maybe Confidence
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` State -> Maybe Confidence
coverageConfidence State
st
, maxSuccessTests :: Int
maxSuccessTests = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe (State -> Int
maxSuccessTests State
st) (Result -> Maybe Int
maybeNumTests Result
res)
, labels :: Map [String] Int
S.labels = (Int -> Int -> Int)
-> [String] -> Int -> Map [String] Int -> Map [String] Int
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) (Result -> [String]
P.labels Result
res) 1 (State -> Map [String] Int
S.labels State
st)
, classes :: Map String Int
S.classes = (Int -> Int -> Int)
-> Map String Int -> Map String Int -> Map String Int
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) (State -> Map String Int
S.classes State
st) ([(String, Int)] -> Map String Int
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([String] -> [Int] -> [(String, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip (Result -> [String]
P.classes Result
res) (Int -> [Int]
forall a. a -> [a]
repeat 1)))
, tables :: Map String (Map String Int)
S.tables =
((String, String)
-> Map String (Map String Int) -> Map String (Map String Int))
-> Map String (Map String Int)
-> [(String, String)]
-> Map String (Map String Int)
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\(tab :: String
tab, x :: String
x) -> (Map String Int -> Map String Int -> Map String Int)
-> String
-> Map String Int
-> Map String (Map String Int)
-> Map String (Map String Int)
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith ((Int -> Int -> Int)
-> Map String Int -> Map String Int -> Map String Int
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+)) String
tab (String -> Int -> Map String Int
forall k a. k -> a -> Map k a
Map.singleton String
x 1))
(State -> Map String (Map String Int)
S.tables State
st) (Result -> [(String, String)]
P.tables Result
res)
, requiredCoverage :: Map (Maybe String, String) Double
S.requiredCoverage =
((Maybe String, String, Double)
-> Map (Maybe String, String) Double
-> Map (Maybe String, String) Double)
-> Map (Maybe String, String) Double
-> [(Maybe String, String, Double)]
-> Map (Maybe String, String) Double
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\(key :: Maybe String
key, value :: String
value, p :: Double
p) -> (Double -> Double -> Double)
-> (Maybe String, String)
-> Double
-> Map (Maybe String, String) Double
-> Map (Maybe String, String) Double
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith Double -> Double -> Double
forall a. Ord a => a -> a -> a
max (Maybe String
key, String
value) Double
p)
(State -> Map (Maybe String, String) Double
S.requiredCoverage State
st) (Result -> [(Maybe String, String, Double)]
P.requiredCoverage Result
res)
, expected :: Bool
expected = Result -> Bool
expect Result
res }
case Result
res of
MkResult{ok :: Result -> Maybe Bool
ok = Just True} ->
do (State -> Property -> IO Result) -> State -> Property -> IO Result
continue State -> Property -> IO Result
doneTesting
State
st'{ numSuccessTests :: Int
numSuccessTests = State -> Int
numSuccessTests State
st' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1
, numRecentlyDiscardedTests :: Int
numRecentlyDiscardedTests = 0
, randomSeed :: QCGen
randomSeed = QCGen
rnd2
} Property
f
MkResult{ok :: Result -> Maybe Bool
ok = Maybe Bool
Nothing, expect :: Result -> Bool
expect = Bool
expect, maybeNumTests :: Result -> Maybe Int
maybeNumTests = Maybe Int
mnt, maybeCheckCoverage :: Result -> Maybe Confidence
maybeCheckCoverage = Maybe Confidence
mcc} ->
do (State -> Property -> IO Result) -> State -> Property -> IO Result
continue State -> Property -> IO Result
giveUp
State
st{ numDiscardedTests :: Int
numDiscardedTests = State -> Int
numDiscardedTests State
st' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1
, numRecentlyDiscardedTests :: Int
numRecentlyDiscardedTests = State -> Int
numRecentlyDiscardedTests State
st' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1
, randomSeed :: QCGen
randomSeed = QCGen
rnd2
} Property
f
MkResult{ok :: Result -> Maybe Bool
ok = Just False} ->
do (numShrinks :: Int
numShrinks, totFailed :: Int
totFailed, lastFailed :: Int
lastFailed, res :: Result
res) <- State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
foundFailure State
st' Result
res [Rose Result]
ts
String
theOutput <- Terminal -> IO String
terminalOutput (State -> Terminal
terminal State
st')
if Bool -> Bool
not (Result -> Bool
expect Result
res) then
Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return $WSuccess :: Int
-> Int
-> Map [String] Int
-> Map String Int
-> Map String (Map String Int)
-> String
-> Result
Success{ labels :: Map [String] Int
labels = State -> Map [String] Int
S.labels State
st',
classes :: Map String Int
classes = State -> Map String Int
S.classes State
st',
tables :: Map String (Map String Int)
tables = State -> Map String (Map String Int)
S.tables State
st',
numTests :: Int
numTests = State -> Int
numSuccessTests State
st'Int -> Int -> Int
forall a. Num a => a -> a -> a
+1,
numDiscarded :: Int
numDiscarded = State -> Int
numDiscardedTests State
st',
output :: String
output = String
theOutput }
else do
[String]
testCase <- (String -> IO String) -> [String] -> IO [String]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> IO String
showCounterexample (Result -> [String]
P.testCase Result
res)
Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return Failure :: Int
-> Int
-> Int
-> Int
-> Int
-> QCGen
-> Int
-> String
-> Maybe AnException
-> String
-> [String]
-> [String]
-> Set String
-> Result
Failure{ usedSeed :: QCGen
usedSeed = State -> QCGen
randomSeed State
st'
, usedSize :: Int
usedSize = Int
size
, numTests :: Int
numTests = State -> Int
numSuccessTests State
st'Int -> Int -> Int
forall a. Num a => a -> a -> a
+1
, numDiscarded :: Int
numDiscarded = State -> Int
numDiscardedTests State
st'
, numShrinks :: Int
numShrinks = Int
numShrinks
, numShrinkTries :: Int
numShrinkTries = Int
totFailed
, numShrinkFinal :: Int
numShrinkFinal = Int
lastFailed
, output :: String
output = String
theOutput
, reason :: String
reason = Result -> String
P.reason Result
res
, theException :: Maybe AnException
theException = Result -> Maybe AnException
P.theException Result
res
, failingTestCase :: [String]
failingTestCase = [String]
testCase
, failingLabels :: [String]
failingLabels = Result -> [String]
P.labels Result
res
, failingClasses :: Set String
failingClasses = [String] -> Set String
forall a. Ord a => [a] -> Set a
Set.fromList (Result -> [String]
P.classes Result
res)
}
where
(rnd1 :: QCGen
rnd1,rnd2 :: QCGen
rnd2) = QCGen -> (QCGen, QCGen)
forall g. RandomGen g => g -> (g, g)
split (State -> QCGen
randomSeed State
st)
failureSummary :: State -> P.Result -> String
failureSummary :: State -> Result -> String
failureSummary st :: State
st res :: Result
res = (String, [String]) -> String
forall a b. (a, b) -> a
fst (State -> Result -> (String, [String])
failureSummaryAndReason State
st Result
res)
failureReason :: State -> P.Result -> [String]
failureReason :: State -> Result -> [String]
failureReason st :: State
st res :: Result
res = (String, [String]) -> [String]
forall a b. (a, b) -> b
snd (State -> Result -> (String, [String])
failureSummaryAndReason State
st Result
res)
failureSummaryAndReason :: State -> P.Result -> (String, [String])
failureSummaryAndReason :: State -> Result -> (String, [String])
failureSummaryAndReason st :: State
st res :: Result
res = (String
summary, [String]
full)
where
summary :: String
summary =
String
header String -> ShowS
forall a. [a] -> [a] -> [a]
++
Int -> ShowS
short 26 (ShowS
oneLine String
theReason String -> ShowS
forall a. [a] -> [a] -> [a]
++ " ") String -> ShowS
forall a. [a] -> [a] -> [a]
++
Bool -> String
count Bool
True String -> ShowS
forall a. [a] -> [a] -> [a]
++ "..."
full :: [String]
full =
(String
header String -> ShowS
forall a. [a] -> [a] -> [a]
++
(if String -> Bool
isOneLine String
theReason then String
theReason String -> ShowS
forall a. [a] -> [a] -> [a]
++ " " else "") String -> ShowS
forall a. [a] -> [a] -> [a]
++
Bool -> String
count Bool
False String -> ShowS
forall a. [a] -> [a] -> [a]
++ ":")String -> [String] -> [String]
forall a. a -> [a] -> [a]
:
if String -> Bool
isOneLine String
theReason then [] else String -> [String]
lines String
theReason
theReason :: String
theReason = Result -> String
P.reason Result
res
header :: String
header =
if Result -> Bool
expect Result
res then
ShowS
bold "*** Failed! "
else "+++ OK, failed as expected. "
count :: Bool -> String
count full :: Bool
full =
"(after " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> ShowS
number (State -> Int
numSuccessTests State
stInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) "test" String -> ShowS
forall a. [a] -> [a] -> [a]
++
[String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [
" and " String -> ShowS
forall a. [a] -> [a] -> [a]
++
Int -> String
forall a. Show a => a -> String
show (State -> Int
numSuccessShrinks State
st) String -> ShowS
forall a. [a] -> [a] -> [a]
++
[String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ "." String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (State -> Int
numTryShrinks State
st) | Bool
showNumTryShrinks ] String -> ShowS
forall a. [a] -> [a] -> [a]
++
" shrink" String -> ShowS
forall a. [a] -> [a] -> [a]
++
(if State -> Int
numSuccessShrinks State
st Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 1 Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
showNumTryShrinks then "" else "s")
| State -> Int
numSuccessShrinks State
st Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0 Bool -> Bool -> Bool
|| Bool
showNumTryShrinks ] String -> ShowS
forall a. [a] -> [a] -> [a]
++
")"
where
showNumTryShrinks :: Bool
showNumTryShrinks = Bool
full Bool -> Bool -> Bool
&& State -> Int
numTryShrinks State
st Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0
success :: State -> IO ()
success :: State -> IO ()
success st :: State
st = do
(String -> IO ()) -> [String] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Terminal -> String -> IO ()
putLine (Terminal -> String -> IO ()) -> Terminal -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ State -> Terminal
terminal State
st) ([[String]] -> [String]
paragraphs [[String]
short, [String]
long])
where
(short :: [String]
short, long :: [String]
long) =
case State -> ([String], [String])
labelsAndTables State
st of
([msg :: String
msg], long :: [String]
long) ->
([" (" String -> ShowS
forall a. [a] -> [a] -> [a]
++ (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace String
msg String -> ShowS
forall a. [a] -> [a] -> [a]
++ ")."], [String]
long)
([], long :: [String]
long) ->
(["."], [String]
long)
(short :: [String]
short, long :: [String]
long) ->
(":"String -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
short, [String]
long)
labelsAndTables :: State -> ([String], [String])
labelsAndTables :: State -> ([String], [String])
labelsAndTables st :: State
st = ([String]
theLabels, [String]
theTables)
where
theLabels :: [String]
theLabels :: [String]
theLabels =
[[String]] -> [String]
paragraphs ([[String]] -> [String]) -> [[String]] -> [String]
forall a b. (a -> b) -> a -> b
$
[ Int -> Maybe String -> Map String Int -> [String]
showTable (State -> Int
numSuccessTests State
st) Maybe String
forall a. Maybe a
Nothing Map String Int
m
| Map String Int
m <- State -> Map String Int
S.classes State
stMap String Int -> [Map String Int] -> [Map String Int]
forall a. a -> [a] -> [a]
:Map Int (Map String Int) -> [Map String Int]
forall k a. Map k a -> [a]
Map.elems Map Int (Map String Int)
numberedLabels ]
numberedLabels :: Map Int (Map String Int)
numberedLabels :: Map Int (Map String Int)
numberedLabels =
(Map String Int -> Map String Int -> Map String Int)
-> [(Int, Map String Int)] -> Map Int (Map String Int)
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith ((Int -> Int -> Int)
-> Map String Int -> Map String Int -> Map String Int
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+)) ([(Int, Map String Int)] -> Map Int (Map String Int))
-> [(Int, Map String Int)] -> Map Int (Map String Int)
forall a b. (a -> b) -> a -> b
$
[ (Int
i, String -> Int -> Map String Int
forall k a. k -> a -> Map k a
Map.singleton String
l Int
n)
| (labels :: [String]
labels, n :: Int
n) <- Map [String] Int -> [([String], Int)]
forall k a. Map k a -> [(k, a)]
Map.toList (State -> Map [String] Int
S.labels State
st),
(i :: Int
i, l :: String
l) <- [Int] -> [String] -> [(Int, String)]
forall a b. [a] -> [b] -> [(a, b)]
zip [0..] [String]
labels ]
theTables :: [String]
theTables :: [String]
theTables =
[[String]] -> [String]
paragraphs ([[String]] -> [String]) -> [[String]] -> [String]
forall a b. (a -> b) -> a -> b
$
[ Int -> Maybe String -> Map String Int -> [String]
showTable ([Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (Map String Int -> [Int]
forall k a. Map k a -> [a]
Map.elems Map String Int
m)) (String -> Maybe String
forall a. a -> Maybe a
Just String
table) Map String Int
m
| (table :: String
table, m :: Map String Int
m) <- Map String (Map String Int) -> [(String, Map String Int)]
forall k a. Map k a -> [(k, a)]
Map.toList (State -> Map String (Map String Int)
S.tables State
st) ] [[String]] -> [[String]] -> [[String]]
forall a. [a] -> [a] -> [a]
++
[[ (case Maybe String
mtable of Nothing -> "Only "; Just table :: String
table -> "Table '" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
table String -> ShowS
forall a. [a] -> [a] -> [a]
++ "' had only ")
String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Int -> String
forall a b. (Integral a, Integral b) => a -> b -> String
lpercent Int
n Int
tot String -> ShowS
forall a. [a] -> [a] -> [a]
++ " " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
label String -> ShowS
forall a. [a] -> [a] -> [a]
++ ", but expected " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Double -> Int -> String
forall a. Integral a => Double -> a -> String
lpercentage Double
p Int
tot
| (mtable :: Maybe String
mtable, label :: String
label, tot :: Int
tot, n :: Int
n, p :: Double
p) <- State -> [(Maybe String, String, Int, Int, Double)]
allCoverage State
st,
Maybe Integer -> Int -> Int -> Double -> Bool
insufficientlyCovered ((Confidence -> Integer) -> Maybe Confidence -> Maybe Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Confidence -> Integer
certainty (State -> Maybe Confidence
coverageConfidence State
st)) Int
tot Int
n Double
p ]]
showTable :: Int -> Maybe String -> Map String Int -> [String]
showTable :: Int -> Maybe String -> Map String Int -> [String]
showTable k :: Int
k mtable :: Maybe String
mtable m :: Map String Int
m =
[String
table String -> ShowS
forall a. [a] -> [a] -> [a]
++ " " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
total String -> ShowS
forall a. [a] -> [a] -> [a]
++ ":" | Just table :: String
table <- [Maybe String
mtable]] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
(((String, Int) -> String) -> [(String, Int)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, Int) -> String
forall a. Integral a => (String, a) -> String
format ([(String, Int)] -> [String])
-> ([(String, Int)] -> [(String, Int)])
-> [(String, Int)]
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
[(String, Int)] -> [(String, Int)]
forall a. [a] -> [a]
reverse ([(String, Int)] -> [(String, Int)])
-> ([(String, Int)] -> [(String, Int)])
-> [(String, Int)]
-> [(String, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String, Int) -> (String, Int) -> Ordering)
-> [(String, Int)] -> [(String, Int)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (((String, Int) -> Int)
-> (String, Int) -> (String, Int) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (String, Int) -> Int
forall a b. (a, b) -> b
snd) ([(String, Int)] -> [(String, Int)])
-> ([(String, Int)] -> [(String, Int)])
-> [(String, Int)]
-> [(String, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
[(String, Int)] -> [(String, Int)]
forall a. [a] -> [a]
reverse ([(String, Int)] -> [(String, Int)])
-> ([(String, Int)] -> [(String, Int)])
-> [(String, Int)]
-> [(String, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String, Int) -> (String, Int) -> Ordering)
-> [(String, Int)] -> [(String, Int)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (((String, Int) -> String)
-> (String, Int) -> (String, Int) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (String, Int) -> String
forall a b. (a, b) -> a
fst) ([(String, Int)] -> [String]) -> [(String, Int)] -> [String]
forall a b. (a -> b) -> a -> b
$ Map String Int -> [(String, Int)]
forall k a. Map k a -> [(k, a)]
Map.toList Map String Int
m)
where
format :: (String, a) -> String
format (key :: String
key, v :: a
v) =
a -> Int -> String
forall a b. (Integral a, Integral b) => a -> b -> String
rpercent a
v Int
k String -> ShowS
forall a. [a] -> [a] -> [a]
++ " " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
key
total :: String
total = String -> Int -> String
forall r. PrintfType r => String -> r
printf "(%d in total)" Int
k
foundFailure :: State -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int, P.Result)
foundFailure :: State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
foundFailure st :: State
st res :: Result
res ts :: [Rose Result]
ts =
do State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
localMin State
st{ numTryShrinks :: Int
numTryShrinks = 0 } Result
res [Rose Result]
ts
localMin :: State -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int, P.Result)
localMin :: State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
localMin st :: State
st res :: Result
res ts :: [Rose Result]
ts
| State -> Int
numSuccessShrinks State
st Int -> Int -> Int
forall a. Num a => a -> a -> a
+ State -> Int
numTotTryShrinks State
st Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= State -> Int
numTotMaxShrinks State
st =
State -> Result -> IO (Int, Int, Int, Result)
localMinFound State
st Result
res
localMin st :: State
st res :: Result
res ts :: [Rose Result]
ts = do
Either AnException ()
r <- IO () -> IO (Either AnException ())
forall a. IO a -> IO (Either AnException a)
tryEvaluateIO (IO () -> IO (Either AnException ()))
-> IO () -> IO (Either AnException ())
forall a b. (a -> b) -> a -> b
$
Terminal -> String -> IO ()
putTemp (State -> Terminal
terminal State
st) (State -> Result -> String
failureSummary State
st Result
res)
case Either AnException ()
r of
Left err :: AnException
err ->
State -> Result -> IO (Int, Int, Int, Result)
localMinFound State
st (String -> AnException -> Result
exception "Exception while printing status message" AnException
err) { callbacks :: [Callback]
callbacks = Result -> [Callback]
callbacks Result
res }
Right () -> do
Either AnException [Rose Result]
r <- [Rose Result] -> IO (Either AnException [Rose Result])
forall a. a -> IO (Either AnException a)
tryEvaluate [Rose Result]
ts
case Either AnException [Rose Result]
r of
Left err :: AnException
err ->
State -> Result -> IO (Int, Int, Int, Result)
localMinFound State
st
(String -> AnException -> Result
exception "Exception while generating shrink-list" AnException
err) { callbacks :: [Callback]
callbacks = Result -> [Callback]
callbacks Result
res }
Right ts' :: [Rose Result]
ts' -> State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
localMin' State
st Result
res [Rose Result]
ts'
localMin' :: State -> P.Result -> [Rose P.Result] -> IO (Int, Int, Int, P.Result)
localMin' :: State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
localMin' st :: State
st res :: Result
res [] = State -> Result -> IO (Int, Int, Int, Result)
localMinFound State
st Result
res
localMin' st :: State
st res :: Result
res (t :: Rose Result
t:ts :: [Rose Result]
ts) =
do
MkRose res' :: Result
res' ts' :: [Rose Result]
ts' <- IO (Rose Result) -> IO (Rose Result)
protectRose (Rose Result -> IO (Rose Result)
reduceRose Rose Result
t)
Result
res' <- State -> Result -> IO Result
callbackPostTest State
st Result
res'
if Result -> Maybe Bool
ok Result
res' Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
then State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
localMin State
st{ numSuccessShrinks :: Int
numSuccessShrinks = State -> Int
numSuccessShrinks State
st Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1,
numTryShrinks :: Int
numTryShrinks = 0 } Result
res' [Rose Result]
ts'
else State -> Result -> [Rose Result] -> IO (Int, Int, Int, Result)
localMin State
st{ numTryShrinks :: Int
numTryShrinks = State -> Int
numTryShrinks State
st Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1,
numTotTryShrinks :: Int
numTotTryShrinks = State -> Int
numTotTryShrinks State
st Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1 } Result
res [Rose Result]
ts
localMinFound :: State -> P.Result -> IO (Int, Int, Int, P.Result)
localMinFound :: State -> Result -> IO (Int, Int, Int, Result)
localMinFound st :: State
st res :: Result
res =
do [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ [ Terminal -> String -> IO ()
putLine (State -> Terminal
terminal State
st) String
msg | String
msg <- State -> Result -> [String]
failureReason State
st Result
res ]
State -> Result -> IO ()
callbackPostFinalFailure State
st Result
res
(Int, Int, Int, Result) -> IO (Int, Int, Int, Result)
forall (m :: * -> *) a. Monad m => a -> m a
return (State -> Int
numSuccessShrinks State
st, State -> Int
numTotTryShrinks State
st Int -> Int -> Int
forall a. Num a => a -> a -> a
- State -> Int
numTryShrinks State
st, State -> Int
numTryShrinks State
st, Result
res)
callbackPostTest :: State -> P.Result -> IO P.Result
callbackPostTest :: State -> Result -> IO Result
callbackPostTest st :: State
st res :: Result
res = (AnException -> Result) -> IO Result -> IO Result
forall a. (AnException -> a) -> IO a -> IO a
protect (String -> AnException -> Result
exception "Exception running callback") (IO Result -> IO Result) -> IO Result -> IO Result
forall a b. (a -> b) -> a -> b
$ do
[IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ [ State -> Result -> IO ()
f State
st Result
res | PostTest _ f :: State -> Result -> IO ()
f <- Result -> [Callback]
callbacks Result
res ]
Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return Result
res
callbackPostFinalFailure :: State -> P.Result -> IO ()
callbackPostFinalFailure :: State -> Result -> IO ()
callbackPostFinalFailure st :: State
st res :: Result
res = do
Either AnException ()
x <- IO () -> IO (Either AnException ())
forall a. IO a -> IO (Either AnException a)
tryEvaluateIO (IO () -> IO (Either AnException ()))
-> IO () -> IO (Either AnException ())
forall a b. (a -> b) -> a -> b
$ [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ [ State -> Result -> IO ()
f State
st Result
res | PostFinalFailure _ f :: State -> Result -> IO ()
f <- Result -> [Callback]
callbacks Result
res ]
case Either AnException ()
x of
Left err :: AnException
err -> do
Terminal -> String -> IO ()
putLine (State -> Terminal
terminal State
st) "*** Exception running callback: "
IO () -> IO (Either AnException ())
forall a. IO a -> IO (Either AnException a)
tryEvaluateIO (IO () -> IO (Either AnException ()))
-> IO () -> IO (Either AnException ())
forall a b. (a -> b) -> a -> b
$ Terminal -> String -> IO ()
putLine (State -> Terminal
terminal State
st) (AnException -> String
forall a. Show a => a -> String
show AnException
err)
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Right () -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
sufficientlyCovered :: Confidence -> Int -> Int -> Double -> Bool
sufficientlyCovered :: Confidence -> Int -> Int -> Double -> Bool
sufficientlyCovered confidence :: Confidence
confidence n :: Int
n k :: Int
k p :: Double
p =
Integer -> Integer -> Double -> Double
wilsonLow (Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
k) (Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n) (1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
err) Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
>= Double
tol Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
p
where
err :: Integer
err = Confidence -> Integer
certainty Confidence
confidence
tol :: Double
tol = Confidence -> Double
tolerance Confidence
confidence
insufficientlyCovered :: Maybe Integer -> Int -> Int -> Double -> Bool
insufficientlyCovered :: Maybe Integer -> Int -> Int -> Double -> Bool
insufficientlyCovered Nothing n :: Int
n k :: Int
k p :: Double
p =
Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
k Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
p Double -> Double -> Double
forall a. Num a => a -> a -> a
* Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
insufficientlyCovered (Just err :: Integer
err) n :: Int
n k :: Int
k p :: Double
p =
Integer -> Integer -> Double -> Double
wilsonHigh (Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
k) (Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n) (1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
err) Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
p
wilson :: Integer -> Integer -> Double -> Double
wilson :: Integer -> Integer -> Double -> Double
wilson k :: Integer
k n :: Integer
n z :: Double
z =
(Double
p Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
zDouble -> Double -> Double
forall a. Num a => a -> a -> a
*Double
zDouble -> Double -> Double
forall a. Fractional a => a -> a -> a
/(2Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
nf) Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
zDouble -> Double -> Double
forall a. Num a => a -> a -> a
*Double -> Double
forall a. Floating a => a -> a
sqrt (Double
pDouble -> Double -> Double
forall a. Num a => a -> a -> a
*(1Double -> Double -> Double
forall a. Num a => a -> a -> a
-Double
p)Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
nf Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
zDouble -> Double -> Double
forall a. Num a => a -> a -> a
*Double
zDouble -> Double -> Double
forall a. Fractional a => a -> a -> a
/(4Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
nfDouble -> Double -> Double
forall a. Num a => a -> a -> a
*Double
nf)))Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/(1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
zDouble -> Double -> Double
forall a. Num a => a -> a -> a
*Double
zDouble -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
nf)
where
nf :: Double
nf = Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
n
p :: Double
p = Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
k Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
n
wilsonLow :: Integer -> Integer -> Double -> Double
wilsonLow :: Integer -> Integer -> Double -> Double
wilsonLow k :: Integer
k n :: Integer
n a :: Double
a = Integer -> Integer -> Double -> Double
wilson Integer
k Integer
n (Double -> Double
invnormcdf (Double
aDouble -> Double -> Double
forall a. Fractional a => a -> a -> a
/2))
wilsonHigh :: Integer -> Integer -> Double -> Double
wilsonHigh :: Integer -> Integer -> Double -> Double
wilsonHigh k :: Integer
k n :: Integer
n a :: Double
a = Integer -> Integer -> Double -> Double
wilson Integer
k Integer
n (Double -> Double
invnormcdf (1Double -> Double -> Double
forall a. Num a => a -> a -> a
-Double
aDouble -> Double -> Double
forall a. Fractional a => a -> a -> a
/2))
invnormcdf :: Double -> Double
invnormcdf :: Double -> Double
invnormcdf p :: Double
p
| Double
p Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< 0 = 0Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/0
| Double
p Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> 1 = 0Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/0
| Double
p Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== 0 = -1Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/0
| Double
p Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== 1 = 1Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/0
| Double
p Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
p_low =
let
q :: Double
q = Double -> Double
forall a. Floating a => a -> a
sqrt(-2Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double -> Double
forall a. Floating a => a -> a
log(Double
p))
in
(((((Double
c1Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c2)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c3)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c4)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c5)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c6) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/
((((Double
d1Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
d2)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
d3)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
d4)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+1)
| Double
p Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
p_high =
let
q :: Double
q = Double
p Double -> Double -> Double
forall a. Num a => a -> a -> a
- 0.5
r :: Double
r = Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
*Double
q
in
(((((Double
a1Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
a2)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
a3)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
a4)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
a5)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
a6)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
q Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/
(((((Double
b1Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
b2)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
b3)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
b4)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
b5)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
rDouble -> Double -> Double
forall a. Num a => a -> a -> a
+1)
| Bool
otherwise =
let
q :: Double
q = Double -> Double
forall a. Floating a => a -> a
sqrt(-2Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double -> Double
forall a. Floating a => a -> a
log(1Double -> Double -> Double
forall a. Num a => a -> a -> a
-Double
p))
in
-(((((Double
c1Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c2)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c3)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c4)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c5)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
c6) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/
((((Double
d1Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
d2)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
d3)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
d4)Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
qDouble -> Double -> Double
forall a. Num a => a -> a -> a
+1)
where
a1 :: Double
a1 = -3.969683028665376e+01
a2 :: Double
a2 = 2.209460984245205e+02
a3 :: Double
a3 = -2.759285104469687e+02
a4 :: Double
a4 = 1.383577518672690e+02
a5 :: Double
a5 = -3.066479806614716e+01
a6 :: Double
a6 = 2.506628277459239e+00
b1 :: Double
b1 = -5.447609879822406e+01
b2 :: Double
b2 = 1.615858368580409e+02
b3 :: Double
b3 = -1.556989798598866e+02
b4 :: Double
b4 = 6.680131188771972e+01
b5 :: Double
b5 = -1.328068155288572e+01
c1 :: Double
c1 = -7.784894002430293e-03
c2 :: Double
c2 = -3.223964580411365e-01
c3 :: Double
c3 = -2.400758277161838e+00
c4 :: Double
c4 = -2.549732539343734e+00
c5 :: Double
c5 = 4.374664141464968e+00
c6 :: Double
c6 = 2.938163982698783e+00
d1 :: Double
d1 = 7.784695709041462e-03
d2 :: Double
d2 = 3.224671290700398e-01
d3 :: Double
d3 = 2.445134137142996e+00
d4 :: Double
d4 = 3.754408661907416e+00
p_low :: Double
p_low = 0.02425
p_high :: Double
p_high = 1 Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
p_low
addCoverageCheck :: Confidence -> State -> Property -> Property
addCoverageCheck :: Confidence -> State -> Property -> Property
addCoverageCheck confidence :: Confidence
confidence st :: State
st prop :: Property
prop
| [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and [ Confidence -> Int -> Int -> Double -> Bool
sufficientlyCovered Confidence
confidence Int
tot Int
n Double
p
| (_, _, tot :: Int
tot, n :: Int
n, p :: Double
p) <- State -> [(Maybe String, String, Int, Int, Double)]
allCoverage State
st ] =
Property -> Property
forall prop. Testable prop => prop -> Property
once Property
prop
| [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [ Maybe Integer -> Int -> Int -> Double -> Bool
insufficientlyCovered (Integer -> Maybe Integer
forall a. a -> Maybe a
Just (Confidence -> Integer
certainty Confidence
confidence)) Int
tot Int
n Double
p
| (_, _, tot :: Int
tot, n :: Int
n, p :: Double
p) <- State -> [(Maybe String, String, Int, Int, Double)]
allCoverage State
st ] =
let (theLabels :: [String]
theLabels, theTables :: [String]
theTables) = State -> ([String], [String])
labelsAndTables State
st in
(String -> Property -> Property)
-> Property -> [String] -> Property
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr String -> Property -> Property
forall prop. Testable prop => String -> prop -> Property
counterexample (Result -> Property
forall prop. Testable prop => prop -> Property
property Result
failed{reason :: String
P.reason = "Insufficient coverage"})
([[String]] -> [String]
paragraphs [[String]
theLabels, [String]
theTables])
| Bool
otherwise = Property
prop
allCoverage :: State -> [(Maybe String, String, Int, Int, Double)]
allCoverage :: State -> [(Maybe String, String, Int, Int, Double)]
allCoverage st :: State
st =
[ (Maybe String
key, String
value, Int
tot, Int
n, Double
p)
| ((key :: Maybe String
key, value :: String
value), p :: Double
p) <- Map (Maybe String, String) Double
-> [((Maybe String, String), Double)]
forall k a. Map k a -> [(k, a)]
Map.toList (State -> Map (Maybe String, String) Double
S.requiredCoverage State
st),
let tot :: Int
tot =
case Maybe String
key of
Just key :: String
key -> Int -> String -> Map String Int -> Int
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault 0 String
key Map String Int
totals
Nothing -> State -> Int
numSuccessTests State
st,
let n :: Int
n = Int -> String -> Map String Int -> Int
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault 0 String
value (Map String Int
-> Maybe String
-> Map (Maybe String) (Map String Int)
-> Map String Int
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault Map String Int
forall k a. Map k a
Map.empty Maybe String
key Map (Maybe String) (Map String Int)
combinedCounts) ]
where
combinedCounts :: Map (Maybe String) (Map String Int)
combinedCounts :: Map (Maybe String) (Map String Int)
combinedCounts =
Maybe String
-> Map String Int
-> Map (Maybe String) (Map String Int)
-> Map (Maybe String) (Map String Int)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Maybe String
forall a. Maybe a
Nothing (State -> Map String Int
S.classes State
st)
((String -> Maybe String)
-> Map String (Map String Int)
-> Map (Maybe String) (Map String Int)
forall k2 k1 a. Ord k2 => (k1 -> k2) -> Map k1 a -> Map k2 a
Map.mapKeys String -> Maybe String
forall a. a -> Maybe a
Just (State -> Map String (Map String Int)
S.tables State
st))
totals :: Map String Int
totals :: Map String Int
totals = (Map String Int -> Int)
-> Map String (Map String Int) -> Map String Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int)
-> (Map String Int -> [Int]) -> Map String Int -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map String Int -> [Int]
forall k a. Map k a -> [a]
Map.elems) (State -> Map String (Map String Int)
S.tables State
st)