fb-util-0.1.0.1: Util/Testing.hs
{-
Copyright (c) Meta Platforms, Inc. and affiliates.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree.
-}
{-# LANGUAGE NamedFieldPuns #-}
module Util.Testing
( assertProperty
, assertPropertyWithArgs
, QC.stdArgs
, QC.Args(..)
, skip
, skipTest
, skipTestIf
, skipTestIfRtsIsProfiled
, skipIf
) where
import Control.Exception
import GHC.Stack (HasCallStack)
import System.Environment (lookupEnv)
import System.IO
import Test.HUnit
import Test.HUnit.Lang (HUnitFailure)
import Util.Control.Exception
import qualified Test.QuickCheck as QC
skip :: String -> IO ()
skip msg = hPutStr stderr $ unlines [msg, "***SKIP***"]
skipIf :: (SomeException -> Bool) -> IO () -> IO ()
skipIf f = handleAll $ \e -> if f e then skip (show e) else throw e
skipTestIf :: (SomeException -> Bool) -> Test -> Test
skipTestIf f (TestCase tc) = TestCase $ skipIf f tc
skipTestIf f (TestList ts) = TestList $ map (skipTestIf f) ts
skipTestIf f (TestLabel l t) = TestLabel l $ skipTestIf f t
skipTest :: Test -> Test
skipTest = skipTestIf $ const True
skipTestIfRtsIsProfiled :: Test -> Test
skipTestIfRtsIsProfiled = skipTestIf $ const (rtsIsProfiled /= 0)
assertProperty
:: (HasCallStack, QC.Testable prop) => String -> prop -> Assertion
assertProperty msg prop =
assertPropertyWithArgs msg QC.stdArgs prop
assertPropertyWithArgs
:: (HasCallStack, QC.Testable prop) => String -> QC.Args -> prop -> Assertion
assertPropertyWithArgs msg qcArgs prop = do
size <- maybe (QC.maxSize qcArgs) read <$> lookupEnv "QUICKCHECK_SIZE"
success <-
maybe (QC.maxSuccess qcArgs) read <$> lookupEnv "QUICKCHECK_RUNS"
mbSeed <- lookupEnv "QUICKCHECK_SEED"
let args = qcArgs {
QC.maxSize = size,
QC.maxSuccess = success,
QC.replay = (,size) . read <$> mbSeed
}
case QC.replay args of
Just r -> putStrLn $ "Running with replay: " <> show r
_ -> pure ()
result <- QC.quickCheckWithResult args prop
case result of
QC.Success{} -> return ()
QC.Failure{theException = Just e}
| Just (he :: HUnitFailure) <- fromException e -> throwIO he
QC.Failure{usedSeed, usedSize}
-> assertFailure $ unlines $
[ msg
, "To reproduce, set:"
, "- QUICKCHECK_SEED=" <> show (show usedSeed)
] <>
[ "- QUICKCHECK_SIZE=" <> show usedSize
| usedSize /= QC.maxSize QC.stdArgs
]
_ -> assertFailure msg
foreign import ccall unsafe "rts_isProfiled" rtsIsProfiled :: Int