@@ -33,16 +33,22 @@ module Test.QuickCheck
3333
3434import Prelude
3535
36- import Control.Monad.Eff (Eff ())
37- import Control.Monad.Eff.Console (CONSOLE (), log )
38- import Control.Monad.Eff.Exception (EXCEPTION (), throwException , error )
39- import Control.Monad.Eff.Random (RANDOM ())
40-
41- import Data.List (List (..))
36+ import Control.Monad.Eff (Eff )
37+ import Control.Monad.Eff.Console (CONSOLE , log )
38+ import Control.Monad.Eff.Exception (EXCEPTION , throwException , error )
39+ import Control.Monad.Eff.Random (RANDOM )
40+ import Control.Monad.Rec.Class (Step (..), tailRec )
41+
42+ import Data.Foldable (for_ )
43+ import Data.List (List )
44+ import Data.Maybe (Maybe (..))
45+ import Data.Maybe.First (First (..))
46+ import Data.Monoid (mempty )
47+ import Data.Tuple (Tuple (..))
4248import Data.Unfoldable (replicateA )
4349
4450import Test.QuickCheck.Arbitrary (class Arbitrary , arbitrary )
45- import Test.QuickCheck.Gen (Gen , evalGen )
51+ import Test.QuickCheck.Gen (Gen , evalGen , runGen )
4652import Test.QuickCheck.LCG (Seed , randomSeed )
4753
4854-- | A type synonym which represents the effects used by the `quickCheck` function.
@@ -52,36 +58,52 @@ type QC eff a = Eff (console :: CONSOLE, random :: RANDOM, err :: EXCEPTION | ef
5258-- |
5359-- | This function generates a new random seed, runs 100 tests and
5460-- | prints the test results to the console.
55- quickCheck :: forall eff prop . ( Testable prop ) => prop -> QC eff Unit
61+ quickCheck :: forall eff prop . Testable prop => prop -> QC eff Unit
5662quickCheck prop = quickCheck' 100 prop
5763
5864-- | A variant of the `quickCheck` function which accepts an extra parameter
5965-- | representing the number of tests which should be run.
60- quickCheck' :: forall eff prop . ( Testable prop ) => Int -> prop -> QC eff Unit
66+ quickCheck' :: forall eff prop . Testable prop => Int -> prop -> QC eff Unit
6167quickCheck' n prop = do
6268 seed <- randomSeed
63- let results = quickCheckPure seed n prop
64- let successes = countSuccesses results
65- log $ show successes <> " /" <> show n <> " test(s) passed."
66- throwOnFirstFailure one results
67-
69+ let result = tailRec loop { seed, index: 0 , successes: 0 , firstFailure: mempty }
70+ log $ show result.successes <> " /" <> show n <> " test(s) passed."
71+ for_ result.firstFailure \{ index, message } ->
72+ throwException $ error $ " Test " <> show (index + 1 ) <> " failed: \n " <> message
6873 where
69-
70- throwOnFirstFailure :: Int -> List Result -> QC eff Unit
71- throwOnFirstFailure _ Nil = pure unit
72- throwOnFirstFailure n (Cons (Failed msg) _) = throwException $ error $ " Test " <> show n <> " failed: \n " <> msg
73- throwOnFirstFailure n (Cons _ rest) = throwOnFirstFailure (n + one) rest
74-
75- countSuccesses :: List Result -> Int
76- countSuccesses Nil = zero
77- countSuccesses (Cons Success rest) = one + countSuccesses rest
78- countSuccesses (Cons _ rest) = countSuccesses rest
74+ loop :: LoopState -> Step LoopState (LoopResult ())
75+ loop { seed, index, successes, firstFailure }
76+ | index == n = Done { successes, firstFailure }
77+ | otherwise =
78+ case runGen (test prop) { newSeed: seed, size: 10 } of
79+ Tuple Success s ->
80+ Loop
81+ { seed: s.newSeed
82+ , index: index + 1
83+ , successes: successes + 1
84+ , firstFailure
85+ }
86+ Tuple (Failed message) s ->
87+ Loop
88+ { seed: s.newSeed
89+ , index: index + 1
90+ , successes
91+ , firstFailure: firstFailure <> First (Just { index, message })
92+ }
93+
94+ type LoopResult r =
95+ { successes :: Int
96+ , firstFailure :: First { index :: Int , message :: String }
97+ | r
98+ }
99+
100+ type LoopState = LoopResult (seed :: Seed , index :: Int )
79101
80102-- | Test a property, returning all test results as an array.
81103-- |
82104-- | The first argument is the _random seed_ to be passed to the random generator.
83105-- | The second argument is the number of tests to run.
84- quickCheckPure :: forall prop . ( Testable prop ) => Seed -> Int -> prop -> List Result
106+ quickCheckPure :: forall prop . Testable prop => Seed -> Int -> prop -> List Result
85107quickCheckPure s n prop = evalGen (replicateA n (test prop)) { newSeed: s, size: 10 }
86108
87109-- | The `Testable` class represents _testable properties_.
0 commit comments