module Foundation.Check
( Gen
, Arbitrary(..)
, oneof
, elements
, frequency
, between
, Test(..)
, testName
, PropertyCheck
, Property(..)
, IsProperty(..)
, (===)
, propertyCompare
, propertyAnd
, propertyFail
, forAll
, Check
, validate
, pick
, iterateProperty
) where
import Basement.Imports
import Basement.Cast (cast)
import Basement.IntegralConv
import Basement.Types.OffsetSize
import Foundation.Check.Gen
import Foundation.Check.Arbitrary
import Foundation.Check.Property
import Foundation.Check.Types
import Foundation.Check.Print
import Foundation.Monad
import Foundation.Monad.State
import Foundation.Numerical
import Control.Exception (evaluate, SomeException)
validate :: IsProperty prop => String -> prop -> Check ()
validate propertyName prop = Check $ do
(genrng, params) <- withState $ \st -> ( (planRng st, planParams st)
, st { planValidations = planValidations st + 1 }
)
(r,nb) <- liftIO $ iterateProperty 100 params genrng (property prop)
case r of
PropertySuccess -> return ()
PropertyFailed failMsg -> do
withState $ \st -> ((), st { planFailures = PropertyResult propertyName nb (PropertyFailed failMsg) : planFailures st })
return ()
pick :: String -> IO a -> Check a
pick _ io = Check $ do
r <- liftIO io
pure r
iterateProperty :: CountOf TestResult -> GenParams -> (Word64 -> GenRng) -> Property -> IO (PropertyResult, CountOf TestResult)
iterateProperty limit genParams genRngIter prop = iterProp 1
where
iterProp !iter
| iter == limit = return (PropertySuccess, iter)
| otherwise = do
r <- liftIO toResult
case r of
(PropertyFailed e, _) -> return (PropertyFailed e, iter)
(PropertySuccess, cont) | cont -> iterProp (iter+1)
| otherwise -> return (PropertySuccess, iter)
where
iterW64 :: Word64
iterW64 = let (CountOf iter') = iter in cast (integralUpsize iter' :: Int64)
toResult :: IO (PropertyResult, Bool)
toResult = (propertyToResult <$> evaluate (runGen (unProp prop) (genRngIter iterW64) genParams))
`catch` (\(e :: SomeException) -> return (PropertyFailed (show e), False))