0 | module Hedgehog.Internal.Runner
5 | import Hedgehog.Internal.Config
6 | import Hedgehog.Internal.Gen
7 | import Hedgehog.Internal.Options
8 | import Hedgehog.Internal.Property
9 | import Hedgehog.Internal.Range
10 | import Hedgehog.Internal.Report
11 | import Hedgehog.Internal.Terminal
13 | import System.Random.Pure.StdGen
19 | TestRes = (Either Failure (), Journal)
26 | shrink : Monad m => Nat -> Coforest a -> b -> (Nat -> a -> m (Maybe b)) -> m b
27 | shrink _ [] b _ = pure b
28 | shrink 0 _ b _ = pure b
29 | shrink (S k) (t :: ts) b f = do
30 | Just b2 <- f (S k) t.value | Nothing => shrink k ts b f
31 | shrink k t.forest b2 f
38 | -> (Progress -> m ())
41 | takeSmallest si se (MkTagged slimit) updateUI t = do
42 | res <- run 0 t.value
44 | then shrink slimit t.forest res runMaybe
50 | calcShrinks : Nat -> ShrinkCount
51 | calcShrinks rem = MkTagged $
(slimit `minus` rem) + 1
53 | run : ShrinkCount -> TestRes -> m Result
56 | (Left $
MkFailure err diff, MkJournal logs) =>
57 | let fail = mkFailure si se shrinks Nothing err diff (reverse logs)
58 | in updateUI (Shrinking fail) $> Failed fail
60 | (Right x, _) => pure OK
62 | runMaybe : Nat -> TestRes -> m (Maybe Result)
63 | runMaybe shrinksLeft testRes = do
64 | res <- run (calcShrinks shrinksLeft) testRes
65 | if isFailure res then pure (Just res) else pure Nothing
78 | -> (Report Progress -> m ())
79 | -> m (Report Result)
80 | checkReport cfg si0 se0 test updateUI =
81 | let (conf, MkTagged numTests, initSz) := unCriteria cfg.terminationCriteria
82 | in loop numTests 0 (fromMaybe initSz si0) se0 neutral conf
90 | -> Coverage CoverCount
92 | -> m (Report Result)
93 | loop n tests si se cover conf = do
94 | updateUI (MkReport tests cover Running)
98 | pure $
report False tests si se cover conf
100 | if abortEarly cfg.terminationCriteria tests cover conf
104 | pure $
report True tests si se cover conf
107 | let (s0,s1) := split se
108 | tr := runGen si s0 $
runTestT test
109 | nextSize = if si < maxSize then (si + 1) else 0
110 | in case tr.value of
113 | let upd := updateUI . MkReport (tests+1) cover
114 | in map (MkReport (tests+1) cover) $
115 | takeSmallest si se cfg.shrinkLimit upd tr
119 | (Right x, journal) =>
120 | let cover1 := journalCoverage journal <+> cover
121 | in loop k (tests + 1) nextSize s1 cover1 conf
124 | {auto _ : HasTerminal m}
125 | -> {auto _ : Monad m}
128 | -> Maybe PropertyName
132 | -> m (Report Result)
133 | checkTerm term color name si se prop = do
134 | result <- checkReport {m} prop.config si se prop.test $
136 | when (multOf100 prog.tests) $
137 | let ppprog := renderProgress color name prog
138 | in case prog.status of
139 | Running => putTmp term ppprog
140 | Shrinking _ => putTmp term ppprog
142 | putOut term (renderResult color name result)
146 | {auto _ : CanInitSeed StdGen m}
147 | -> {auto _ : HasTerminal m}
148 | -> {auto _ : Monad m}
151 | -> Maybe PropertyName
153 | -> m (Report Result)
154 | checkWith term color name prop =
155 | initSeed >>= \se => checkTerm term color name Nothing se prop
160 | {auto _ : CanInitSeed StdGen m}
161 | -> {auto _ : HasConfig m}
162 | -> {auto _ : HasTerminal m}
163 | -> {auto _ : Monad m}
167 | checkNamed name prop = do
168 | color <- detectColor
170 | rep <- checkWith term color (Just name) prop
171 | pure $
rep.status == OK
176 | {auto _ : CanInitSeed StdGen m}
177 | -> {auto _ : HasConfig m}
178 | -> {auto _ : HasTerminal m}
179 | -> {auto _ : Monad m}
183 | color <- detectColor
185 | rep <- checkWith term color Nothing prop
186 | pure $
rep.status == OK
191 | {auto _ : HasConfig m}
192 | -> {auto _ : HasTerminal m}
193 | -> {auto _ : Monad m}
198 | recheck si se prop = do
199 | color <- detectColor
201 | let prop = noVerifiedTermination $
withTests 1 prop
202 | _ <- checkTerm term color Nothing (Just si) se prop
206 | {auto _ : CanInitSeed StdGen m}
207 | -> {auto _ : HasTerminal m}
208 | -> {auto _ : Monad m}
211 | -> List (PropertyName, Property)
213 | checkGroupWith term color = run neutral
216 | run : Summary -> List (PropertyName, Property) -> m Summary
218 | run s ((pn,p) :: ps) = do
219 | rep <- checkWith term color (Just pn) p
220 | run (s <+> fromResult rep.status) ps
224 | {auto _ : CanInitSeed StdGen m}
225 | -> {auto _ : HasConfig m}
226 | -> {auto _ : HasTerminal m}
227 | -> {auto _ : Monad m}
230 | checkGroup (MkGroup group props) = do
232 | putOut term $
"━━━ " ++ unTag group ++ " ━━━\n"
233 | color <- detectColor
234 | summary <- checkGroupWith term color props
235 | putOut term (renderSummary color summary)
236 | pure $
summary.failed == 0
260 | test : HasIO io => List Group -> io ()
263 | Right c <- pure $
applyArgs args
265 | putStrLn "Errors when parsing command line args:"
266 | traverse_ putStrLn errs
269 | then putStrLn info >> exitSuccess
271 | let gs2 := map (applyConfig c) gs
273 | res <- foldlM (\b,g => map (b &&) (checkGroup g)) True gs2
276 | else putStrLn "\n\nSome tests failed" >> exitFailure