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
79 | -> (Report Progress -> m ())
80 | -> m (Report Result)
81 | checkReport cfg si0 se0 test updateUI =
82 | let (conf, MkTagged numTests, initSz) := unCriteria cfg.terminationCriteria
83 | in loop numTests 0 (fromMaybe initSz si0) se0 neutral conf
91 | -> Coverage CoverCount
93 | -> m (Report Result)
94 | loop n tests si se cover conf = do
95 | updateUI (MkReport tests cover Running)
99 | pure $
report False tests si se cover conf
101 | if abortEarly cfg.terminationCriteria tests cover conf
105 | pure $
report True tests si se cover conf
108 | let (s0,s1) := split se
109 | tr := runGen si s0 $
runTestT test
110 | nextSize = if si < maxSize then (si + 1) else 0
111 | in case tr.value of
114 | let upd := updateUI . MkReport (tests+1) cover
115 | in map (MkReport (tests+1) cover) $
116 | takeSmallest si se cfg.shrinkLimit upd tr
120 | (Right x, journal) =>
121 | let cover1 := journalCoverage journal <+> cover
122 | in loop k (tests + 1) nextSize s1 cover1 conf
125 | {auto _ : HasTerminal m}
126 | -> {auto _ : Monad m}
129 | -> Maybe PropertyName
133 | -> m (Report Result)
134 | checkTerm term color name si se prop = do
135 | result <- checkReport {m} prop.config si se prop.test $
137 | when (multOf100 prog.tests) $
138 | let ppprog := renderProgress color name prog
139 | in case prog.status of
140 | Running => putTmp term ppprog
141 | Shrinking _ => putTmp term ppprog
143 | putOut term (renderResult color name result)
147 | {auto _ : CanInitSeed StdGen m}
148 | -> {auto _ : HasTerminal m}
149 | -> {auto _ : Monad m}
152 | -> Maybe PropertyName
154 | -> m (Report Result)
155 | checkWith term color name prop =
156 | initSeed >>= \se => checkTerm term color name Nothing se prop
161 | {auto _ : CanInitSeed StdGen m}
162 | -> {auto _ : HasConfig m}
163 | -> {auto _ : HasTerminal m}
164 | -> {auto _ : Monad m}
168 | checkNamed name prop = do
169 | color <- detectColor
171 | rep <- checkWith term color (Just name) prop
172 | pure $
rep.status == OK
177 | {auto _ : CanInitSeed StdGen m}
178 | -> {auto _ : HasConfig m}
179 | -> {auto _ : HasTerminal m}
180 | -> {auto _ : Monad m}
184 | color <- detectColor
186 | rep <- checkWith term color Nothing prop
187 | pure $
rep.status == OK
192 | {auto _ : HasConfig m}
193 | -> {auto _ : HasTerminal m}
194 | -> {auto _ : Monad m}
199 | recheck si se prop = do
200 | color <- detectColor
202 | let prop = noVerifiedTermination $
withTests 1 prop
203 | _ <- checkTerm term color Nothing (Just si) se prop
207 | {auto _ : CanInitSeed StdGen m}
208 | -> {auto _ : HasTerminal m}
209 | -> {auto _ : Monad m}
212 | -> List (PropertyName, Property)
214 | checkGroupWith term color = run neutral
217 | run : Summary -> List (PropertyName, Property) -> m Summary
219 | run s ((pn,p) :: ps) = do
220 | rep <- checkWith term color (Just pn) p
221 | run (s <+> fromResult rep.status) ps
225 | {auto _ : CanInitSeed StdGen m}
226 | -> {auto _ : HasConfig m}
227 | -> {auto _ : HasTerminal m}
228 | -> {auto _ : Monad m}
231 | checkGroup (MkGroup group props) = do
233 | putOut term $
"━━━ " ++ unTag group ++ " ━━━\n"
234 | color <- detectColor
235 | summary <- checkGroupWith term color props
236 | putOut term (renderSummary color summary)
237 | pure $
summary.failed == 0
261 | test : HasIO io => List Group -> io ()
264 | Right c <- pure $
applyArgs args
266 | putStrLn "Errors when parsing command line args:"
267 | traverse_ putStrLn errs
270 | then putStrLn info >> exitSuccess
272 | let gs2 := map (applyConfig c) gs
274 | res <- foldlM (\b,g => map (b &&) (checkGroup g)) True gs2
277 | else putStrLn "\n\nSome tests failed" >> exitFailure