tasty 1.5.3 → 1.5.4
raw patch · 22 files changed
+332/−166 lines, 22 filesdep −semigroups
Dependencies removed: semigroups
Files
- CHANGELOG.md +21/−1
- Control/Concurrent/Async.hs +40/−16
- README.md +21/−5
- Test/Tasty.hs +2/−0
- Test/Tasty/CmdLine.hs +1/−5
- Test/Tasty/Core.hs +136/−25
- Test/Tasty/Ingredients.hs +3/−3
- Test/Tasty/Ingredients/ConsoleReporter.hs +35/−11
- Test/Tasty/Ingredients/ListTests.hs +2/−3
- Test/Tasty/Options.hs +2/−2
- Test/Tasty/Options/Core.hs +12/−11
- Test/Tasty/Options/Env.hs +1/−6
- Test/Tasty/Parallel.hs +7/−2
- Test/Tasty/Patterns.hs +2/−4
- Test/Tasty/Patterns/Eval.hs +0/−4
- Test/Tasty/Patterns/Parser.hs +1/−1
- Test/Tasty/Providers.hs +2/−16
- Test/Tasty/Providers/ConsoleFormat.hs +3/−3
- Test/Tasty/Run.hs +18/−19
- Test/Tasty/Runners/Reducers.hs +1/−1
- Test/Tasty/Runners/Utils.hs +2/−5
- tasty.cabal +20/−23
CHANGELOG.md view
@@ -1,6 +1,26 @@ Changes ======= +Version 1.5.4+--------------++_2025-03-31_++* Fix display of `HasCallStack` backtraces when a test throws an error+ ([#472](https://github.com/UnkindPartition/tasty/pull/472)).+* Introduce `dependentTestGroup` and `inOrderTestGroup`,+ deprecate `sequentialTestGroup`+ ([#448](https://github.com/UnkindPartition/tasty/pull/448)).+* Add `instance IsTest t => IsTest (ContT () IO t)`+ ([#466](https://github.com/UnkindPartition/tasty/pull/466)).+* Limit maximum line length in console reporter+ ([#451](https://github.com/UnkindPartition/tasty/pull/451)).+* Make `-j` to entail `+RTS -N` automatically+ ([#457](https://github.com/UnkindPartition/tasty/pull/457)).+* Do not depend on `unbounded-delays` on `ppc64le` and `loongarch64`+ ([#460](https://github.com/UnkindPartition/tasty/pull/460),+ [#465](https://github.com/UnkindPartition/tasty/pull/465)).+ Version 1.5.3 -------------- @@ -521,7 +541,7 @@ * Better handling of exceptions that arise during resource creation or disposal * Expose the `AppMonoid` wrapper-* Add `askOption` and `inludingOptions`+* Add `askOption` and `includingOptions` Version 0.5.2.1 ---------------
Control/Concurrent/Async.hs view
@@ -36,7 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -} -{-# LANGUAGE DeriveDataTypeable, MagicHash, UnboxedTuples #-}+{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-} module Control.Concurrent.Async ( async, withAsync, wait, asyncThreadId, cancel, concurrently@@ -44,14 +44,40 @@ import Control.Concurrent.STM import Control.Exception+ ( BlockedIndefinitelyOnMVar(..)+ , BlockedIndefinitelyOnSTM(..)+ , Exception+ , SomeException+ , asyncExceptionFromException+ , asyncExceptionToException+ , catch+ , fromException+ , onException+ , toException+ , try+ ) import Control.Concurrent import Control.Monad import Data.IORef-import Data.Typeable import GHC.Conc (ThreadId(..)) import GHC.Exts import GHC.IO hiding (onException) +#if MIN_VERSION_base(4,21,0)+import Control.Exception (ExceptionWithContext, tryWithContext, catchNoPropagate, rethrowIO)+#else+type ExceptionWithContext x = x++catchNoPropagate :: IO a -> (ExceptionWithContext SomeException -> IO a) -> IO a+catchNoPropagate = catchAll++tryWithContext :: IO a -> IO (Either (ExceptionWithContext SomeException) a)+tryWithContext = try++rethrowIO :: ExceptionWithContext SomeException -> IO a+rethrowIO = throwIO+#endif+ -- | An asynchronous action spawned by 'async' or 'withAsync'. -- Asynchronous actions are executed in a separate thread, and -- operations are provided for waiting for asynchronous actions to@@ -59,9 +85,9 @@ -- data Async a = Async { asyncThreadId :: {-# UNPACK #-} !ThreadId- -- ^ Returns the 'ThreadId' of the thread running- -- the given 'Async'.- , _asyncWait :: STM (Either SomeException a)+ -- ^ Returns the t'ThreadId' of the thread running+ -- the given t'Async'.+ , _asyncWait :: STM (Either (ExceptionWithContext SomeException) a) } -- | Spawn an asynchronous action in a separate thread.@@ -103,11 +129,11 @@ withAsyncUsing doFork = \action inner -> do var <- newEmptyTMVarIO mask $ \restore -> do- t <- doFork $ try (restore action) >>= atomically . putTMVar var+ t <- doFork $ tryWithContext (restore action) >>= atomically . putTMVar var let a = Async t (readTMVar var)- r <- restore (inner a) `catchAll` \e -> do+ r <- restore (inner a) `catchNoPropagate` \e -> do uninterruptibleCancel a- throwIO e+ rethrowIO (e :: ExceptionWithContext SomeException) uninterruptibleCancel a return r @@ -131,7 +157,7 @@ -- > waitCatch = atomically . waitCatchSTM -- {-# INLINE waitCatch #-}-waitCatch :: Async a -> IO (Either SomeException a)+waitCatch :: Async a -> IO (Either (ExceptionWithContext SomeException) a) waitCatch = tryAgain . atomically . waitCatchSTM where -- See: https://github.com/simonmar/async/issues/14@@ -147,16 +173,16 @@ -- | A version of 'waitCatch' that can be used inside an STM transaction. -- {-# INLINE waitCatchSTM #-}-waitCatchSTM :: Async a -> STM (Either SomeException a)+waitCatchSTM :: Async a -> STM (Either (ExceptionWithContext SomeException) a) waitCatchSTM (Async _ w) = w -- | Cancel an asynchronous action by throwing the @AsyncCancelled@--- exception to it, and waiting for the `Async` thread to quit.--- Has no effect if the 'Async' has already completed.+-- exception to it, and waiting for the t'Async' thread to quit.+-- Has no effect if the t'Async' has already completed. -- -- > cancel a = throwTo (asyncThreadId a) AsyncCancelled <* waitCatch a ----- Note that 'cancel' will not terminate until the thread the 'Async'+-- Note that 'cancel' will not terminate until the thread the t'Async' -- refers to has terminated. This means that 'cancel' will block for -- as long said thread blocks when receiving an asynchronous exception. --@@ -172,13 +198,11 @@ -- | The exception thrown by `cancel` to terminate a thread. data AsyncCancelled = AsyncCancelled- deriving (Show, Eq, Typeable)+ deriving (Show, Eq) instance Exception AsyncCancelled where-#if __GLASGOW_HASKELL__ >= 708 fromException = asyncExceptionFromException toException = asyncExceptionToException-#endif -- | Cancel an asynchronous action --
README.md view
@@ -236,7 +236,7 @@ --quickcheck-max-size NUMBER Size of the biggest test cases quickcheck generates --quickcheck-max-ratio NUMBER- Maximum number of discared tests per successful test+ Maximum number of discarded tests per successful test before giving up --quickcheck-verbose Show the generated test cases --quickcheck-shrinks NUMBER@@ -703,14 +703,14 @@ If this parallelism is not desirable, you can declare *dependencies* between tests, so that one test will not start until certain other tests finish. -Dependencies are declared using the `after` or `sequentialTestGroup` combinator:+Dependencies are declared using the `after` or `dependentTestGroup` combinator: * `after AllFinish "pattern" my_tests` will execute the test tree `my_tests` only after all tests that match the pattern finish. * `after AllSucceed "pattern" my_tests` will execute the test tree `my_tests` only after all tests that match the pattern finish **and** only if they all succeed. If at least one dependency fails, then `my_tests` will be skipped.-* `sequentialTestGroup groupName dependencyType [tree1, tree2, ..]` will execute all tests+* `dependentTestGroup groupName dependencyType [tree1, tree2, ..]` will execute all tests in `tree1` first, after which it will execute all tests in `tree2`, and so forth. Like `after`, `dependencyType` can either be set to `AllFinish` or `AllSucceed`. @@ -723,7 +723,7 @@ -> TestTree -- ^ the subtree that depends on other tests -> TestTree -- ^ the subtree annotated with dependency information -sequentialTestGroup+dependentTestGroup :: TestName -- ^ name of the group -> DependencyType -- ^ whether to run the tests even if some of the dependencies fail -> [TestTree] -- ^ trees to execute sequentially@@ -792,7 +792,7 @@ test tree, searching for the next test to execute may also have an overhead quadratic in the number of tests. -Use `sequentialTestGroup` to mitigate these problems.+Use `dependentTestGroup` to mitigate these problems. ## FAQ@@ -828,6 +828,22 @@ bash directly to prevent this behaviour, or follow other suggestions from [Known Issues](https://github.com/git-for-windows/build-extra/blob/main/ReleaseNotes.md#known-issues).++## Migration from `test-framework`++`tasty` architecture is quite similar to `test-framework`, so a few mechanical changes are usually enough to migrate:++* Replace packages in `build-depends`:+ * `test-framework` -> `tasty`,+ * `test-framework-hunit` -> `tasty-hunit`,+ * `test-framework-quickcheck2` -> `tasty-quickcheck`.+* Replace module imports:+ * `Test.Framework` -> `Test.Tasty`,+ * `Test.Framework.Providers.HUnit` -> `Test.Tasty.HUnit`,+ * `Test.Framework.Providers.QuickCheck2` -> `Test.Tasty.QuickCheck`.+* Replace in type signatures:+ * `Test` -> `TestTree`.+* Replace `defaultMain tests` with `defaultMain (testGroup "All" tests)`. ## Press
Test/Tasty.hs view
@@ -33,7 +33,9 @@ TestName , TestTree , testGroup+ , dependentTestGroup , sequentialTestGroup+ , inOrderTestGroup -- * Running tests , defaultMain , defaultMainWithIngredients
Test/Tasty/CmdLine.hs view
@@ -8,7 +8,6 @@ ) where import Control.Arrow-import Control.Monad import Data.Maybe import Data.Proxy import Data.Typeable (typeRep)@@ -16,7 +15,6 @@ import Options.Applicative.Common (evalParser) import qualified Options.Applicative.Types as Applicative (Option(..)) import Options.Applicative.Types (Parser(..), OptProperties(..))-import Prelude -- Silence AMP and FTP import warnings import System.Exit import System.IO #if !MIN_VERSION_base(4,11,0)@@ -156,9 +154,7 @@ mapM_ (hPutStrLn stderr) warnings cmdlineOpts <- execParser $ info (helper <*> parser)- ( fullDesc <>- header "Mmm... tasty test suite"- )+ (header "Mmm... tasty test suite") envOpts <- suiteEnvOptions ins tree return $ envOpts <> cmdlineOpts
Test/Tasty/Core.hs view
@@ -1,8 +1,11 @@ -- | Core types and definitions {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ImplicitParams #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-} module Test.Tasty.Core ( FailureReason(..) , Outcome(..)@@ -18,9 +21,12 @@ , ResourceError(..) , DependencyType(..) , ExecutionMode(..)+ , Parallel(..) , TestTree(..) , testGroup , sequentialTestGroup+ , dependentTestGroup+ , inOrderTestGroup , after , after_ , TreeFold(..)@@ -28,11 +34,15 @@ , foldTestTree , foldTestTree0 , treeOptions+ , testFailed ) where import Control.Exception+import Control.Monad.Trans.Cont (ContT(..))+import Data.Coerce (coerce) import qualified Data.Map as Map import Data.Bifunctor (Bifunctor(second, bimap))+import Data.IORef (newIORef, readIORef, atomicModifyIORef') import Data.List (mapAccumR) import Data.Monoid (Any (getAny, Any)) import Data.Sequence ((|>))@@ -48,6 +58,10 @@ import Text.Printf import Text.Read (readMaybe) +#if MIN_VERSION_base(4,21,0) && !MIN_VERSION_base(4,22,0)+import Control.Exception.Context+#endif+ -- | If a test failed, 'FailureReason' describes why. -- -- @since 0.8@@ -156,16 +170,28 @@ Success -> True Failure {} -> False --- | Shortcut for creating a 'Result' that indicates exception+-- | Shortcut for creating a t'Result' that indicates exception exceptionResult :: SomeException -> Result exceptionResult e = Result { resultOutcome = Failure $ TestThrewException e- , resultDescription = "Exception: " ++ displayException e+ , resultDescription = "Exception: " ++ displayException' e , resultShortDescription = "FAIL" , resultTime = 0 , resultDetailsPrinter = noResultDetails } +displayException' :: SomeException -> String+#if MIN_VERSION_base(4,22,0)+displayException' = displayExceptionWithInfo+#elif MIN_VERSION_base(4,21,0)+displayException' (SomeException e) =+ displayException e ++ case displayExceptionContext ?exceptionContext of+ "" -> ""+ dc -> "\n\n" ++ dc+#else+displayException' = displayException+#endif+ -- | Test progress information. -- -- This may be used by a runner to provide some feedback to the user while@@ -201,7 +227,7 @@ -- | Run the test -- -- This method should cleanly catch any exceptions in the code to test, and- -- return them as part of the 'Result', see 'FailureReason' for an+ -- return them as part of the t'Result', see 'FailureReason' for an -- explanation. It is ok for 'run' to raise an exception if there is a -- problem with the test suite code itself (for example, if a file that -- should contain example data or expected output is not found).@@ -214,12 +240,43 @@ -- | The list of options that affect execution of tests of this type testOptions :: Tagged t [OptionDescription] +-- | @since 1.5.4+instance IsTest t => IsTest (ContT () IO t) where+ testOptions = coerce (testOptions @t)+ run opts (ContT k) yieldProgress = do+ resRef <- newIORef Nothing+ let runInIORef :: t -> IO ()+ runInIORef t = do+ res <- run opts t yieldProgress+ let err = testFailed "Continuation was called multiple times"+ atomicModifyIORef' resRef $ \prev ->+ (Just $ maybe res (const err) prev, ())+ k runInIORef+ maybeRes <- readIORef resRef+ pure $ case maybeRes of+ Nothing -> testFailed "Continuation was not called"+ Just r -> r++-- | t'Result' of a failed test.+--+-- @since 0.8+testFailed+ :: String -- ^ description+ -> Result+testFailed desc = Result+ { resultOutcome = Failure TestFailed+ , resultDescription = desc+ , resultShortDescription = "FAIL"+ , resultTime = 0+ , resultDetailsPrinter = noResultDetails+ }+ -- | The name of a test or a group of tests. -- -- @since 0.1 type TestName = String --- | 'ResourceSpec' describes how to acquire a resource (the first field)+-- | t'ResourceSpec' describes how to acquire a resource (the first field) -- and how to release it (the second field). -- -- @since 0.6@@ -230,7 +287,6 @@ = NotRunningTests | UnexpectedState String String | UseOutsideOfTest- deriving Typeable instance Show ResourceError where show NotRunningTests =@@ -264,19 +320,26 @@ -- | Determines mode of execution of a 'TestGroup' data ExecutionMode- = Sequential DependencyType- -- ^ Execute tests one after another- | Parallel- -- ^ Execute tests in parallel+ = Dependent DependencyType+ -- ^ Test have dependencies+ | Independent Parallel+ -- ^ Test have no dependencies deriving (Show, Read) +data Parallel+ = Parallel+ -- ^ Tests can be run in parallel+ | NonParallel+ -- ^ Tests should not be parallelized+ deriving (Show, Read)+ -- | Determines mode of execution of a 'TestGroup'. Note that this option is -- not exposed as a command line argument. instance IsOption ExecutionMode where- defaultValue = Parallel+ defaultValue = Independent Parallel parseValue = readMaybe optionName = Tagged "execution-mode"- optionHelp = Tagged "Whether to execute tests sequentially or in parallel"+ optionHelp = Tagged "Whether tests have dependencies or not" optionCLParser = mkOptionCLParser internal -- | The main data structure defining a test suite.@@ -316,20 +379,68 @@ -- @since 1.2 -- | Create a named group of test cases or other groups. Tests are executed in--- parallel. For sequential execution, see 'sequentialTestGroup'.+-- parallel. For sequential execution, see 'dependentTestGroup'. -- -- @since 0.1 testGroup :: TestName -> [TestTree] -> TestTree testGroup = TestGroup --- | Create a named group of test cases or other groups. Tests are executed in--- order. For parallel execution, see 'testGroup'.+{-# DEPRECATED sequentialTestGroup "Use dependentTestGroup instead" #-}+-- | Legacy name for 'dependentTestGroup'.+--+-- @since 1.5 sequentialTestGroup :: TestName -> DependencyType -> [TestTree] -> TestTree-sequentialTestGroup nm depType = setSequential . TestGroup nm . map setParallel+sequentialTestGroup = dependentTestGroup++-- | Create a named group of test cases or other groups. Tests are executed in+-- order and each test is considered a dependency of the next one.+-- If filtering by t'TestPattern' (@--pattern@) is in action,+-- any test matching the pattern also shields earlier tests from filtering out,+-- even if they themselves do not match the pattern.+--+-- For parallel execution, see 'testGroup'. For ordered test execution, but+-- with default filtering behavior, see 'inOrderTestGroup'.+--+-- Note that this is will only work when used with the default 'Test.Tasty.Ingredients.TestManager'.+-- If you use another manager, like @tasty-rerun@ for instance, sequentiality+-- might possibly be ignored.+--+-- @since 1.5.4+dependentTestGroup+ :: TestName+ -- ^ name of the group+ -> DependencyType+ -- ^ whether to run subsequent tests even if earlier ones have failed+ -> [TestTree]+ -- ^ tests to execute sequentially+ -> TestTree+dependentTestGroup nm depType = setDependent . TestGroup nm . map setParallel where- setParallel = PlusTestOptions (setOption Parallel)- setSequential = PlusTestOptions (setOption (Sequential depType))+ setParallel = PlusTestOptions (setOption $ Independent Parallel)+ setDependent = PlusTestOptions (setOption (Dependent depType)) ++-- | Create a named group of test cases that will be played sequentially,+-- in the exact order provided. Similarly to 'testGroup'+-- and in contrast to 'dependentTestGroup',+-- filtering by t'TestPattern' is applied uniformly.+--+-- Note that this is will only work when used with the default 'Test.Tasty.Ingredients.TestManager'.+-- If you use another manager, like @tasty-rerun@ for instance, the fact that+-- these tests should be run in the given order might possibly be ignored.+--+-- @since 1.5.4+inOrderTestGroup+ :: TestName+ -- ^ name of the group+ -> [TestTree]+ -- ^ tests to execute sequentially+ -> TestTree+inOrderTestGroup nm = setSequential . TestGroup nm . map setParallel+ where+ setParallel = PlusTestOptions (setOption $ Independent Parallel)+ setSequential = PlusTestOptions (setOption (Independent NonParallel))+ -- | Like 'after', but accepts the pattern as a syntax tree instead -- of a string. Useful for generating a test tree programmatically. --@@ -408,7 +519,7 @@ -- -- Instead of constructing fresh records, build upon `trivialFold` -- instead. This way your code won't break when new nodes/fields are--- indroduced.+-- introduced. -- -- @since 0.7 data TreeFold b = TreeFold@@ -450,7 +561,7 @@ -- a user's filter. This is used to force dependencies of a test to run. For -- example, if test @A@ depends on test @B@ and test @A@ is selected to run, test -- @B@ will be forced to match. Note that this only applies to dependencies--- specified using 'sequentialTestGroup'.+-- specified using 'dependentTestGroup'. type ForceTestMatch = Any -- | Fold a test tree into a single value.@@ -504,7 +615,7 @@ AnnWithResource opts res0 tree -> fResource opts res0 $ \res -> go (tree res) AnnAfter opts deptype dep tree -> fAfter opts deptype dep (go tree) --- | 'TestTree' with arbitrary annotations, e. g., evaluated 'OptionSet'.+-- | 'TestTree' with arbitrary annotations, e. g., evaluated t'OptionSet'. data AnnTestTree ann = AnnEmptyTestTree -- ^ Just an empty test tree (e. g., when everything has been filtered out).@@ -581,15 +692,15 @@ AnnTestGroup (opts, _) name trees -> case lookupOption opts of- Parallel ->+ Dependent _ ->+ second+ (mkGroup opts name)+ (mapAccumR go forceMatch trees)+ Independent _ -> bimap mconcat (mkGroup opts name) (unzip (map (go forceMatch) trees))- Sequential _ ->- second- (mkGroup opts name)- (mapAccumR go forceMatch trees) AnnWithResource (opts, _) res0 tree -> ( fst (go forceMatch (tree (throwIO NotRunningTests)))
Test/Tasty/Ingredients.hs view
@@ -36,7 +36,7 @@ -- which options it cares about, so that those options are presented to -- the user if the ingredient is included in the test suite. ----- An ingredient can choose, typically based on the 'OptionSet', whether to+-- An ingredient can choose, typically based on the t'OptionSet', whether to -- run. That's what the 'Maybe' is for. The first ingredient that agreed to -- run does its work, and the remaining ingredients are ignored. Thus, the -- order in which you arrange the ingredients may matter.@@ -87,7 +87,7 @@ -- | Try to run an 'Ingredient'. ----- If the ingredient refuses to run (usually based on the 'OptionSet'),+-- If the ingredient refuses to run (usually based on the t'OptionSet'), -- the function returns 'Nothing'. -- -- For a 'TestReporter', this function automatically starts running the@@ -117,7 +117,7 @@ -- -- Note that this isn't the same as simply pattern-matching on -- 'Ingredient'. E.g. options for a 'TestReporter' automatically include--- 'NumThreads'.+-- t'NumThreads'. -- -- @since 0.4 ingredientOptions :: Ingredient -> [OptionDescription]
Test/Tasty/Ingredients/ConsoleReporter.hs view
@@ -1,5 +1,5 @@ -- vim:fdm=marker-{-# LANGUAGE BangPatterns, ImplicitParams, MultiParamTypeClasses, DeriveDataTypeable, FlexibleContexts, CApiFFI, NamedFieldPuns #-}+{-# LANGUAGE BangPatterns, ImplicitParams, MultiParamTypeClasses, FlexibleContexts, CApiFFI, NamedFieldPuns #-} -- | Console reporter ingredient. -- -- @since 0.11.3@@ -66,6 +66,7 @@ #if !MIN_VERSION_base(4,11,0) import Data.Foldable (foldMap) #endif+import System.IO.Unsafe -------------------------------------------------- -- TestOutput base definitions@@ -124,7 +125,28 @@ type Level = Int --- | Build the 'TestOutput' for a 'TestTree' and 'OptionSet'. The @colors@+-- TODO before the next major release:+-- refactor this as an argument to 'buildTestOutput'+-- to avoid unsafePerformIO.+-- (We cannot add another argument to 'buildTestOutput'+-- in the middle of tasty-1.5 series, because it is exported)+terminalWidth :: Maybe Int+terminalWidth = unsafePerformIO $ do+ isTerminalStdin <- hIsTerminalDevice stdin+ if isTerminalStdin+ then fmap (fmap snd) getTerminalSize+ else pure Nothing+{-# NOINLINE terminalWidth #-}++-- | How wide could 'resultShortDescription' be (in non-extreme scenarios)?+-- Think of something like "OK", "FAIL (12.34s)", "TIMEOUT (100.00s)".+--+-- The field is freeform and test providers can put an arbitrarily long data,+-- so we just settle for a reasonable (over)approximation.+approxMaxResultShortDescriptionWidth :: Int+approxMaxResultShortDescriptionWidth = 20++-- | Build the 'TestOutput' for a 'TestTree' and t'OptionSet'. The @colors@ -- ImplicitParam controls whether the output is colored. -- -- @since 0.11.3@@ -132,7 +154,10 @@ buildTestOutput opts tree = let -- Do not retain the reference to the tree more than necessary- !alignment = computeAlignment opts tree+ !rawAlignment = computeAlignment opts tree+ !alignment = case terminalWidth of+ Nothing -> rawAlignment+ Just width -> min (width - approxMaxResultShortDescriptionWidth) rawAlignment MinDurationToReport{minDurationMicros} = lookupOption opts @@ -251,7 +276,7 @@ :: Monoid b => (String -> IO () -> IO Result -> (Result -> IO ()) -> b) -- ^ Eliminator for test cases. The @IO ()@ prints the testname. The- -- @IO Result@ blocks until the test is finished, returning it's 'Result'.+ -- @IO Result@ blocks until the test is finished, returning it's t'Result'. -- The @Result -> IO ()@ function prints the formatted output. -> (String -> IO () -> b -> b) -- ^ Eliminator for test groups. The @IO ()@ prints the test group's name.@@ -395,7 +420,7 @@ mappend = (Sem.<>) #endif --- | @computeStatistics@ computes a summary 'Statistics' for+-- | @computeStatistics@ computes a summary t'Statistics' for -- a given state of the 'StatusMap'. -- Useful in combination with 'printStatistics'. --@@ -597,7 +622,7 @@ -- -- @since 0.8 newtype Quiet = Quiet Bool- deriving (Eq, Ord, Typeable)+ deriving (Eq, Ord) instance IsOption Quiet where defaultValue = Quiet False parseValue = fmap Quiet . safeReadBool@@ -612,7 +637,7 @@ -- -- @since 0.8 newtype HideSuccesses = HideSuccesses Bool- deriving (Eq, Ord, Typeable)+ deriving (Eq, Ord) instance IsOption HideSuccesses where defaultValue = HideSuccesses False parseValue = fmap HideSuccesses . safeReadBool@@ -625,7 +650,7 @@ -- -- @since 1.5 newtype MinDurationToReport = MinDurationToReport { minDurationMicros :: Integer }- deriving (Eq, Ord, Typeable)+ deriving (Eq, Ord) instance IsOption MinDurationToReport where defaultValue = MinDurationToReport 10000 parseValue = fmap MinDurationToReport . parseDuration@@ -644,7 +669,7 @@ = Never | Always | Auto -- ^ Only if stdout is an ANSI color supporting terminal- deriving (Eq, Ord, Typeable)+ deriving (Eq, Ord) -- | Control color output instance IsOption UseColor where@@ -672,7 +697,6 @@ -- -- @since 1.3 newtype AnsiTricks = AnsiTricks { getAnsiTricks :: Bool }- deriving Typeable instance IsOption AnsiTricks where defaultValue = AnsiTricks True@@ -821,7 +845,7 @@ -- line or console detection. -- -- Can be used by providers that wish to provider specific result details printing,--- while re-using the tasty formats and coloring logic.+-- while reusing the tasty formats and coloring logic. -- -- @since 1.3.1 withConsoleFormat :: (?colors :: Bool) => ConsoleFormatPrinter
Test/Tasty/Ingredients/ListTests.hs view
@@ -1,5 +1,5 @@ -- | Ingredient for listing test names-{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, DeriveDataTypeable #-}+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-} module Test.Tasty.Ingredients.ListTests ( ListTests(..) , testsNames@@ -7,7 +7,6 @@ ) where import Data.Proxy-import Data.Typeable import Options.Applicative import Test.Tasty.Core@@ -19,7 +18,7 @@ -- -- @since 0.4 newtype ListTests = ListTests Bool- deriving (Eq, Ord, Typeable)+ deriving (Eq, Ord) instance IsOption ListTests where defaultValue = ListTests False parseValue = fmap ListTests . safeReadBool
Test/Tasty/Options.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable,+{-# LANGUAGE ScopedTypeVariables, ExistentialQuantification, GADTs, FlexibleInstances, UndecidableInstances, TypeOperators #-}@@ -135,7 +135,7 @@ changeOption :: forall v . IsOption v => (v -> v) -> OptionSet -> OptionSet changeOption f s = setOption (f $ lookupOption s) s --- | Create a singleton 'OptionSet'.+-- | Create a singleton t'OptionSet'. -- -- @since 0.8 singleOption :: IsOption v => v -> OptionSet
Test/Tasty/Options/Core.hs view
@@ -1,5 +1,5 @@ -- | Core options, i.e. the options used by tasty itself-{-# LANGUAGE CPP, DeriveDataTypeable, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-} {-# OPTIONS_GHC -fno-warn-type-defaults #-} -- for (^) module Test.Tasty.Options.Core ( NumThreads(..)@@ -14,13 +14,14 @@ import Control.Monad (mfilter) import Data.Proxy-import Data.Typeable import Data.Fixed import Options.Applicative hiding (str) import GHC.Conc #if !MIN_VERSION_base(4,11,0) import Data.Monoid #endif+import Control.Concurrent+import System.IO.Unsafe import Test.Tasty.Options import Test.Tasty.Patterns@@ -36,14 +37,15 @@ -- -- @since 0.1 newtype NumThreads = NumThreads { getNumThreads :: Int }- deriving (Eq, Ord, Num, Typeable)+ deriving (Eq, Ord, Num) instance IsOption NumThreads where- defaultValue = NumThreads numCapabilities+ defaultValue = unsafePerformIO $ NumThreads <$>+ if rtsSupportsBoundThreads then getNumProcessors else pure 1 parseValue = mfilter onlyPositive . fmap NumThreads . safeRead optionName = return "num-threads" optionHelp = return "Number of threads to use for tests execution" optionCLParser = mkOptionCLParser (short 'j' <> metavar "NUMBER")- showDefaultValue _ = Just "# of cores/capabilities"+ showDefaultValue _ = Just "Number of cores when using threaded RTS, 1 for non-threaded" -- | Filtering function to prevent non-positive number of threads onlyPositive :: NumThreads -> Bool@@ -60,15 +62,14 @@ | NoTimeout deriving ( Eq- -- ^ Auto-derived instance, just to allow storing in a 'Map' and such.+ -- ^ Auto-derived instance, just to allow storing in a 'Data.Map.Map' and such. -- -- @since 1.5.1 , Ord- -- ^ Auto-derived instance, just to allow storing in a 'Map' and such.+ -- ^ Auto-derived instance, just to allow storing in a 'Data.Map.Map' and such. -- -- @since 1.5.1 , Show- , Typeable ) instance IsOption Timeout where@@ -99,7 +100,7 @@ _ -> Nothing _ -> Nothing --- | A shortcut for creating 'Timeout' values.+-- | A shortcut for creating v'Timeout' values. -- -- @since 0.8 mkTimeout@@ -116,7 +117,7 @@ -- -- @since 1.5 newtype HideProgress = HideProgress { getHideProgress :: Bool }- deriving (Eq, Ord, Typeable)+ deriving (Eq, Ord) instance IsOption HideProgress where defaultValue = HideProgress False parseValue = fmap HideProgress . safeReadBool@@ -126,7 +127,7 @@ -- | The list of all core options, i.e. the options not specific to any -- provider or ingredient, but to tasty itself. Currently contains--- 'TestPattern' and 'Timeout'.+-- t'TestPattern', t'Timeout' and t'HideProgress'. -- -- @since 0.1 coreOptions :: [OptionDescription]
Test/Tasty/Options/Env.hs view
@@ -1,5 +1,5 @@ -- | Get options from the environment-{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}+{-# LANGUAGE ScopedTypeVariables #-} module Test.Tasty.Options.Env (getEnvOptions, suiteEnvOptions) where import Test.Tasty.Options@@ -8,14 +8,10 @@ import Test.Tasty.Runners.Reducers import System.Environment-import Data.Foldable import Data.Tagged import Data.Proxy import Data.Char-import Data.Typeable import Control.Exception-import Control.Applicative-import Prelude -- Silence AMP and FTP import warnings import Text.Printf data EnvOptionException@@ -23,7 +19,6 @@ String -- option name String -- variable name String -- value- deriving (Typeable) instance Show EnvOptionException where show (BadOption optName varName value) =
Test/Tasty/Parallel.hs view
@@ -1,5 +1,4 @@ -- | A helper module which takes care of parallelism-{-# LANGUAGE DeriveDataTypeable #-} module Test.Tasty.Parallel (ActionStatus(..), Action(..), runInParallel) where import Control.Monad@@ -8,7 +7,7 @@ import Control.Concurrent.STM import Foreign.StablePtr --- | What to do about an 'Action'?+-- | What to do about an t'Action'? data ActionStatus = ActionReady -- ^ the action is ready to be executed@@ -42,6 +41,12 @@ -- actions themselves. Any exceptions that reach this function or its -- threads are by definition unexpected. runInParallel nthreads actions = do+ -- When linked with threaded RTS, ensure we have enough Capabilities+ -- so that all Haskell worker threads can truly run in parallel.+ when rtsSupportsBoundThreads $ do+ ncap <- getNumCapabilities+ when (ncap < nthreads) $ setNumCapabilities nthreads+ callingThread <- myThreadId -- Don't let the main thread be garbage-collected
Test/Tasty/Patterns.hs view
@@ -1,6 +1,6 @@ -- | Test patterns -{-# LANGUAGE CPP, DeriveDataTypeable, TypeApplications #-}+{-# LANGUAGE CPP, TypeApplications #-} module Test.Tasty.Patterns ( TestPattern(..)@@ -21,7 +21,6 @@ import Data.Coerce (coerce) import Data.List.NonEmpty (nonEmpty) import Data.Maybe (catMaybes)-import Data.Typeable import Options.Applicative hiding (Success) #if !MIN_VERSION_base(4,11,0) import Data.Monoid@@ -33,8 +32,7 @@ TestPattern (Maybe Expr) deriving- ( Typeable- , Show -- ^ @since 1.1+ ( Show -- ^ @since 1.1 , Eq -- ^ @since 1.1 )
Test/Tasty/Patterns/Eval.hs view
@@ -12,10 +12,6 @@ import Data.Maybe import Data.Char import Test.Tasty.Patterns.Types-#if !MIN_VERSION_base(4,9,0)-import Control.Applicative-import Data.Traversable-#endif -- | @since 1.2 type Path = Seq.Seq String
Test/Tasty/Patterns/Parser.hs view
@@ -25,7 +25,7 @@ type Token = ReadP --- | A separate 'Parser' data type ensures that we don't forget to skip+-- | A separate t'Parser' data type ensures that we don't forget to skip -- spaces. -- -- @since 1.0
Test/Tasty/Providers.hs view
@@ -23,7 +23,7 @@ singleTest :: IsTest t => TestName -> t -> TestTree singleTest = SingleTest --- | 'Result' of a passed test.+-- | t'Result' of a passed test. -- -- @since 0.8 testPassed@@ -37,21 +37,7 @@ , resultDetailsPrinter = noResultDetails } --- | 'Result' of a failed test.------ @since 0.8-testFailed- :: String -- ^ description- -> Result-testFailed desc = Result- { resultOutcome = Failure TestFailed- , resultDescription = desc- , resultShortDescription = "FAIL"- , resultTime = 0- , resultDetailsPrinter = noResultDetails- }---- | 'Result' of a failed test with custom details printer+-- | t'Result' of a failed test with custom details printer -- -- @since 1.3.1 testFailedDetails
Test/Tasty/Providers/ConsoleFormat.hs view
@@ -1,5 +1,5 @@ -- | This module can be used by providers to perform colorful/formatted--- output and possibly re-use tasty's own output formats.+-- output and possibly reuse tasty's own output formats. -- -- @since 1.3.1 module Test.Tasty.Providers.ConsoleFormat@@ -68,13 +68,13 @@ infoFailFormat :: ConsoleFormat infoFailFormat = ConsoleFormat NormalIntensity Dull Red --- | Format used to display sucesses+-- | Format used to display successes -- -- @since 1.3.1 okFormat :: ConsoleFormat okFormat = ConsoleFormat NormalIntensity Dull Green --- | Format used to display additional information on sucesses+-- | Format used to display additional information on successes -- -- @since 1.3.1 infoOkFormat :: ConsoleFormat
Test/Tasty/Run.hs view
@@ -1,6 +1,6 @@ -- | Running tests {-# LANGUAGE ScopedTypeVariables, ExistentialQuantification, RankNTypes,- FlexibleContexts, CPP, DeriveDataTypeable, LambdaCase,+ FlexibleContexts, CPP, LambdaCase, RecordWildCards, NamedFieldPuns #-} module Test.Tasty.Run ( Status(..)@@ -18,7 +18,6 @@ import Data.List (intercalate) import Data.Graph (SCC(..), stronglyConnComp) import Data.Sequence (Seq, (|>), (<|), (><))-import Data.Typeable import Control.Monad (forever, guard, join, liftM) import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Reader (ReaderT(..), local, ask)@@ -27,11 +26,9 @@ import Control.Concurrent.STM import Control.Concurrent.Async import Control.Exception as E-import Control.Applicative import Control.Arrow import Data.Monoid (First(..)) import GHC.Conc (labelThread)-import Prelude -- Silence AMP and FTP import warnings #if MIN_VERSION_base(4,18,0) import Data.Traversable (mapAccumM)@@ -137,7 +134,7 @@ timed $ applyTimeout timeoutOpt $ do r <- wait asy -- Not only wait for the result to be returned, but make sure to- -- evalute it inside applyTimeout; see #280.+ -- evaluate it inside applyTimeout; see #280. evaluate $ resultOutcome r `seq` forceElements (resultDescription r) `seq`@@ -249,7 +246,6 @@ -- A finishes. Field lists detected cycles. -- -- @since 1.5- deriving (Typeable) instance Show DependencyException where show (DependencyLoop css) = "Test dependencies have cycles:\n" ++ showCycles css@@ -282,7 +278,7 @@ data Dependency = Dependency DependencyType DependencySpec deriving (Eq, Show) --- | Is given 'Dependency' a dependency that was introduced with 'After'?+-- | Is given t'Dependency' a dependency that was introduced with 'After'? isPatternDependency :: Dependency -> Bool isPatternDependency (Dependency _ (PatternDep {})) = True isPatternDependency _ = False@@ -291,7 +287,7 @@ -- The mapAccumM function behaves like a combination of mapM and mapAccumL that -- traverses the structure while evaluating the actions and passing an accumulating -- parameter from left to right. It returns a final value of this accumulator--- together with the new structure. The accummulator is often used for caching the+-- together with the new structure. The accumulator is often used for caching the -- intermediate results of a computation. mapAccumM :: Monad m => (acc -> x -> m (acc, y)) -> acc -> [x] -> m (acc, [y]) mapAccumM _ acc [] = return (acc, [])@@ -304,7 +300,7 @@ -- | An action with meta information data TestAction act = TestAction { testAction :: act- -- ^ Some action, typically 'UnresolvedAction', 'ResolvedAction', or 'Action'.+ -- ^ Some action, typically 'UnresolvedAction', 'ResolvedAction', or t'Action'. , testPath :: Path -- ^ Path pointing to this action (a series of group names + a test name) , testDeps :: Seq Dependency@@ -325,8 +321,8 @@ type Size = Int -- | Simplified version of 'TestTree' that only includes the tests to be run (as--- a 'TestAction') and the resources needed to run them (as 'Initializer's and--- 'Finalizer's).+-- a t'TestAction') and the resources needed to run them (as t'Initializer's and+-- t'Finalizer's). data TestActionTree act = TResource Initializer Finalizer (TestActionTree act) | TGroup Size [TestActionTree act]@@ -419,11 +415,14 @@ foldGroup opts name trees = fmap tGroup $ local (first (|> name)) $ case lookupOption opts of- Parallel ->- sequence trees- Sequential depType ->- snd <$> mapAccumM (goSeqGroup depType) mempty trees+ Independent Parallel -> sequence trees+ Independent NonParallel -> foldSequential AllFinish trees+ Dependent depType -> foldSequential depType trees + foldSequential :: DependencyType -> [Tr] -> ReaderT (Path, Seq Dependency) IO [TestActionTree UnresolvedAction]+ foldSequential depType =+ fmap snd . mapAccumM (goSeqGroup depType) mempty+ -- * Utility functions collectTests :: TestActionTree act -> [TestAction act] collectTests = \case@@ -577,7 +576,7 @@ FailedToCreate {} -> return $ return Nothing Destroyed -> return $ return Nothing --- While tasty allows to configure 'OptionSet' at any level of test tree,+-- While tasty allows to configure t'OptionSet' at any level of test tree, -- it often has any effect only on options of test providers (class IsTest). -- But test runners and reporters typically only look into the OptionSet -- they were given as an argument. This is not unreasonable: e. g., if an option@@ -586,9 +585,9 @@ -- a global option, without passing it via command line. -- -- 'applyTopLevelPlusTestOptions' allows for a compromise: unwrap top-level--- 'PlusTestOptions' from the 'TestTree' and apply them to the 'OptionSet'+-- 'PlusTestOptions' from the 'TestTree' and apply them to the t'OptionSet' -- from command line. This way a user can wrap their tests in--- 'adjustOption' / 'localOption' forcing, for instance, 'NumThreads' to 1.+-- 'adjustOption' / 'localOption' forcing, for instance, t'NumThreads' to 1. -- -- This function is not publicly exposed. applyTopLevelPlusTestOptions@@ -607,7 +606,7 @@ -- -- Once the callback returns, stop running the tests. ----- The number of test running threads is determined by the 'NumThreads'+-- The number of test running threads is determined by the t'NumThreads' -- option. -- -- @since 0.10
Test/Tasty/Runners/Reducers.hs view
@@ -41,8 +41,8 @@ module Test.Tasty.Runners.Reducers where +import Prelude hiding (Applicative(..)) import Control.Applicative-import Prelude -- Silence AMP import warnings import qualified Data.Semigroup as Sem -- | Monoid generated by '*>'.
Test/Tasty/Runners/Utils.hs view
@@ -4,11 +4,8 @@ module Test.Tasty.Runners.Utils where import Control.Exception-import Control.Applicative import Control.Concurrent (mkWeakThreadId, myThreadId) import Control.Monad (forM_)-import Data.Typeable (Typeable)-import Prelude -- Silence AMP import warnings import Text.Printf import Foreign.C (CInt) @@ -66,7 +63,7 @@ -- from https://ro-che.info/articles/2014-07-30-bracket -- | Install signal handlers so that e.g. the cursor is restored if the test--- suite is killed by SIGTERM. Upon a signal, a 'SignalException' will be+-- suite is killed by SIGTERM. Upon a signal, a t'SignalException' will be -- thrown to the thread that has executed this action. -- -- This function is called automatically from the @defaultMain*@ family of@@ -102,7 +99,7 @@ -- -- @since 1.2.1 newtype SignalException = SignalException CInt- deriving (Show, Typeable)+ deriving (Show) instance Exception SignalException -- | Measure the time taken by an 'IO' action to run.
tasty.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: tasty-version: 1.5.3+version: 1.5.4 synopsis: Modern and extensible testing framework description: Tasty is a modern testing framework for Haskell. It lets you combine your unit tests, golden@@ -29,12 +29,12 @@ library exposed-modules:- Test.Tasty,- Test.Tasty.Options,- Test.Tasty.Providers,- Test.Tasty.Providers.ConsoleFormat,+ Test.Tasty+ Test.Tasty.Options+ Test.Tasty.Providers+ Test.Tasty.Providers.ConsoleFormat Test.Tasty.Runners- Test.Tasty.Ingredients,+ Test.Tasty.Ingredients Test.Tasty.Ingredients.Basic Test.Tasty.Ingredients.ConsoleReporter @@ -45,36 +45,33 @@ Test.Tasty.Patterns.Eval other-modules: Control.Concurrent.Async- Test.Tasty.Parallel,- Test.Tasty.Core,- Test.Tasty.Options.Core,- Test.Tasty.Options.Env,- Test.Tasty.Patterns,- Test.Tasty.Patterns.Expr,- Test.Tasty.Run,- Test.Tasty.Runners.Reducers,- Test.Tasty.Runners.Utils,- Test.Tasty.CmdLine,+ Test.Tasty.Parallel+ Test.Tasty.Core+ Test.Tasty.Options.Core+ Test.Tasty.Options.Env+ Test.Tasty.Patterns+ Test.Tasty.Patterns.Expr+ Test.Tasty.Run+ Test.Tasty.Runners.Reducers+ Test.Tasty.Runners.Utils+ Test.Tasty.CmdLine Test.Tasty.Ingredients.ListTests Test.Tasty.Ingredients.IncludingOptions build-depends: base >= 4.9 && < 5, stm >= 2.3 && < 2.6,- containers >= 0.5.8 && < 0.8,+ containers >= 0.5.8 && < 0.9, transformers >= 0.5 && < 0.7, tagged >= 0.5 && < 0.9,- optparse-applicative >= 0.14 && < 0.19,+ optparse-applicative >= 0.14 && < 0.20, ansi-terminal >= 0.9 && < 1.2 -- No reason to depend on unbounded-delays on 64-bit architecture- if(!arch(x86_64) && !arch(aarch64) && !arch(ppc64) && !arch(s390x) && !arch(riscv64))+ if(!arch(x86_64) && !arch(aarch64) && !arch(ppc64le) && !arch(ppc64) && !arch(s390x) && !arch(riscv64) && !arch(loongarch64)) build-depends: unbounded-delays >= 0.1 && < 0.2 - if(!impl(ghc >= 8.0))- build-depends: semigroups < 0.21- if(!impl(ghc >= 8.4)) build-depends: time >= 1.4 && < 1.13 @@ -85,7 +82,7 @@ -- hs-source-dirs: default-language: Haskell2010- default-extensions: CPP, ScopedTypeVariables, DeriveDataTypeable+ default-extensions: CPP, ScopedTypeVariables ghc-options: -Wall -Wno-incomplete-uni-patterns