packages feed

tasty 1.2.3 → 1.3

raw patch · 12 files changed

+201/−80 lines, 12 filesdep +semigroupsdep −ghc-primdep ~base

Dependencies added: semigroups

Dependencies removed: ghc-prim

Dependency ranges changed: base

Files

CHANGELOG.md view
@@ -1,6 +1,23 @@ Changes ======= +Version 1.3+-----------++* `IsOption` has a new method `showDefaultValue` for customizing how+  `defaultValue`s are rendered in the `--help` output.+* Drop support for GHCs older than 5 years+* Do not install handlers for the signals that dump core+* Export the `AnsiTricks` type/option+* In addition to a `Parser`, `optionParser` and `suiteOptionParser` now return+  a `[String]` representing warning messages:+  * A warning is emitted if an `IsOption` instance defines multiple options in+    the implementation of `optionCLParser`.+  * An warning is emitted if an `IsOption` instance's `optionCLParser`+    implementation assigns a default value (e.g., with+    `Options.Applicative.value`), as this interferes with `tasty`'s ability to+    read environment variable arguments.+ Version 1.2.3 ------------- 
README.md view
@@ -181,10 +181,11 @@  Usage: test [-p|--pattern PATTERN] [-t|--timeout DURATION] [-l|--list-tests]             [-j|--num-threads NUMBER] [-q|--quiet] [--hide-successes]-            [--color never|always|auto] [--quickcheck-tests NUMBER]+            [--color never|always|auto] [--ansi-tricks ARG]+            [--smallcheck-depth NUMBER] [--quickcheck-tests NUMBER]             [--quickcheck-replay SEED] [--quickcheck-show-replay]             [--quickcheck-max-size NUMBER] [--quickcheck-max-ratio NUMBER]-            [--quickcheck-verbose] [--smallcheck-depth NUMBER]+            [--quickcheck-verbose] [--quickcheck-shrinks NUMBER]  Available options:   -h,--help                Show this help text@@ -194,11 +195,16 @@                            default: s)   -l,--list-tests          Do not run the tests; just print their names   -j,--num-threads NUMBER  Number of threads to use for tests execution+                           (default: # of cores/capabilities)   -q,--quiet               Do not produce any output; indicate success only by                            the exit code   --hide-successes         Do not print tests that passed successfully   --color never|always|auto                            When to use colored output (default: 'auto')+  --ansi-tricks ARG        Enable various ANSI terminal tricks. Can be set to+                           'true' (default) or 'false'.+  --smallcheck-depth NUMBER+                           Depth to use for smallcheck tests   --quickcheck-tests NUMBER                            Number of test cases for QuickCheck to generate   --quickcheck-replay SEED Random seed to use for replaying a previous test run@@ -210,8 +216,9 @@                            Maximum number of discared tests per successful test                            before giving up   --quickcheck-verbose     Show the generated test cases-  --smallcheck-depth NUMBER-                           Depth to use for smallcheck tests+  --quickcheck-shrinks NUMBER+                           Number of shrinks allowed before QuickCheck will fail+                           a test ```  Every option can be passed via environment. To obtain the environment variable@@ -728,7 +735,7 @@  Here are some caveats to keep in mind regarding dependencies in Tasty: -1. If Test B depends on Test A, remember that either of the may be filtered out+1. If Test B depends on Test A, remember that either of them may be filtered out    using the `--pattern` option. Collecting the dependency info happens *after*    filtering. Therefore, if Test A is filtered out, Test B will run    unconditionally, and if Test B is filtered out, it simply won't run.@@ -800,6 +807,10 @@ [custom-options-article]: https://ro-che.info/articles/2013-12-20-tasty-custom-options.html [awk-patterns-article]: https://ro-che.info/articles/2018-01-08-tasty-new-patterns [tasty-directories]: https://nmattia.com/posts/2018-04-30-tasty-test-names.html++## GHC version support policy++We only support the GHC/base versions [from the last 5 years](https://wiki.haskell.org/Base_package#Versions).  Maintainers -----------
Test/Tasty/CmdLine.hs view
@@ -7,16 +7,21 @@   , defaultMainWithIngredients   ) where -import Options.Applicative-import Data.Monoid ((<>))+import Control.Arrow+import Control.Monad+import Data.Maybe import Data.Proxy-import Data.Foldable (foldMap)+import Data.Typeable (typeRep)+import Options.Applicative+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,9,0)+#if !MIN_VERSION_base(4,11,0) import Data.Monoid+import Data.Foldable (foldMap) #endif  import Test.Tasty.Core@@ -26,15 +31,108 @@ import Test.Tasty.Options.Env import Test.Tasty.Runners.Reducers --- | Generate a command line parser from a list of option descriptions-optionParser :: [OptionDescription] -> Parser OptionSet-optionParser = getApp . foldMap toSet where-  toSet :: OptionDescription -> Ap Parser OptionSet-  toSet (Option (Proxy :: Proxy v)) = Ap $-    (singleOption <$> (optionCLParser :: Parser v)) <|> pure mempty+-- | Generate a command line parser from a list of option descriptions,+-- alongside any related warning messages.+optionParser :: [OptionDescription] -> ([String], Parser OptionSet)+optionParser = second getApp . foldMap toSet where+  toSet :: OptionDescription -> ([String], Ap Parser OptionSet)+  toSet (Option p) = second+    (\parser -> Ap $ (singleOption <$> parser) <|> pure mempty)+    (finalizeCLParser p optionCLParser) --- | The command line parser for the test suite-suiteOptionParser :: [Ingredient] -> TestTree -> Parser OptionSet+-- Do two things:+--+-- 1. Replace an `optionCLParser`'s 'propShowDefault' with 'showDefaultValue'+--    from the 'IsOption' class.+-- 2. Generate warning messages if the 'optionCLParser' does anything+--    suspicious. Currently, the only suspicious things we check for are+--    (a) if the 'Parser' defines multiple options and, (b) if the 'Parser'+--    assigns a default value outside of 'defaultValue'.+finalizeCLParser :: forall proxy v . IsOption v+                 => proxy v -> Parser v -> ([String], Parser v)+finalizeCLParser _ p = (warnings, setCLParserShowDefaultValue mbDef p)+  where+    mbDef :: Maybe String+    mbDef = showDefaultValue (defaultValue :: v)++    warnings :: [String]+    warnings = catMaybes [multipleOptPsWarning, badDefaultWarning]++    -- Warn if a Parser defines multiple options, as this breaks an assumption+    -- that setCLParserShowDefaultValue relies on.+    multipleOptPsWarning :: Maybe String+    multipleOptPsWarning+      | numOptPs p > 1+      = Just $ unlines+        [ prov+        , "optionCLParser defines multiple options. Consider only defining"+        , "a single option here, as defining multiple options does not play"+        , "well with how tasty displays default values."+        ]+      | otherwise+      = Nothing++    -- Warning if a Parser has a default value (outside of IsOption's+    -- defaultValue method, that is), as this interferes with tasty's ability+    -- to read arguments from environment variables. For more on this point,+    -- see the Haddocks for optionCLParser.+    badDefaultWarning :: Maybe String+    badDefaultWarning+      -- evalParser will only return Just if has a default value declared with+      -- e.g. the Options.Applicative.value function.+      | isJust (evalParser p)+      = Just $ unlines+        [ prov+        , "Using default values (e.g., with Options.Applicative.value) in"+        , "optionCLParser is prohibited, as it interferes with tasty's ability"+        , "to read environment variable options properly. Moreover, assigning"+        , "default values is unnecessary, as their functionality is subsumed"+        , "by the defaultValue method of IsOption."+        ]+      | otherwise+      = Nothing++    prov :: String+    prov = "WARNING (in the IsOption instance for "+             ++ show (typeRep (Proxy :: Proxy v)) ++ "):"++-- Replace an `optionCLParser`'s 'propShowDefault' with 'showDefaultValue' from+-- the 'IsOption' class. It's tempting to try doing this when constructing the+-- 'Parser' itself using 'optionMod', but @optparse-applicative@'s 'mkParser'+-- function always overrides the result of 'optionMod'. Ugh.+setCLParserShowDefaultValue :: Maybe String -> Parser a -> Parser a+setCLParserShowDefaultValue mbDef = go+  where+    go :: Parser a -> Parser a+    -- Note that we /always/ replace the Option's optProps, regardless of+    -- what type it may have. This can produce unexpected results if an+    -- optionCLParser defines multiple options, which is why we emit a warning+    -- (in finalizeCLParser) if a Parser does this.+    go (OptP o)      = OptP o{Applicative.optProps =+                              modifyDefault (Applicative.optProps o)}+    go p@NilP{}      = p+    go (MultP p1 p2) = MultP (go p1) (go p2)+    go (AltP  p1 p2) = AltP  (go p1) (go p2)+    go (BindP p1 p2) = BindP (go p1) (fmap go p2)++    modifyDefault :: OptProperties -> OptProperties+    modifyDefault op = op{propShowDefault = mbDef}++-- Note: this is a conservative estimate, since we cannot count the number+-- of OptPs in the continuation argument of BindP. But BindP is really only+-- used for ParserM purposes, and since ParserM is an internal+-- optparse-applicative definition, most optionCLParser instances are+-- unlikely to use it in practice.+numOptPs :: Parser a -> Int+numOptPs OptP{} = 1+numOptPs NilP{} = 0+numOptPs (MultP p1  p2) = numOptPs p1 + numOptPs p2+numOptPs (AltP  p1  p2) = numOptPs p1 + numOptPs p2+numOptPs (BindP p1 _p2) = numOptPs p1++-- | The command line parser for the test suite, alongside any related+-- warnings.+suiteOptionParser :: [Ingredient] -> TestTree -> ([String], Parser OptionSet) suiteOptionParser ins tree = optionParser $ suiteOptions ins tree  -- | Parse the command-line and environment options passed to tasty.@@ -48,8 +146,10 @@ -- pass 'defaultIngredients'. parseOptions :: [Ingredient] -> TestTree -> IO OptionSet parseOptions ins tree = do+  let (warnings, parser) = suiteOptionParser ins tree+  mapM_ (hPutStrLn stderr) warnings   cmdlineOpts <- execParser $-    info (helper <*> suiteOptionParser ins tree)+    info (helper <*> parser)     ( fullDesc <>       header "Mmm... tasty test suite"     )
Test/Tasty/Ingredients/Basic.hs view
@@ -9,6 +9,7 @@     consoleTestReporter   , Quiet(..)   , HideSuccesses(..)+  , AnsiTricks(..)     -- ** Listing tests   , listingTests   , ListTests(..)
Test/Tasty/Ingredients/ConsoleReporter.hs view
@@ -1,4 +1,4 @@--- vim:fdm=marker:foldtext=foldtext()+-- vim:fdm=marker {-# LANGUAGE BangPatterns, ImplicitParams, MultiParamTypeClasses, DeriveDataTypeable, FlexibleContexts #-} -- | Console reporter ingredient module Test.Tasty.Ingredients.ConsoleReporter@@ -48,15 +48,11 @@ import Options.Applicative hiding (str, Success, Failure) import System.IO import System.Console.ANSI-#if !MIN_VERSION_base(4,8,0)-import Data.Proxy-import Data.Foldable hiding (concatMap,elem,sequence_)-#endif-#if MIN_VERSION_base(4,9,0)+#if !MIN_VERSION_base(4,11,0) import Data.Semigroup (Semigroup) import qualified Data.Semigroup (Semigroup((<>)))-#else import Data.Monoid+import Data.Foldable (foldMap) #endif  --------------------------------------------------@@ -86,10 +82,8 @@ instance Monoid TestOutput where   mempty = Skip   mappend = Seq-#if MIN_VERSION_base(4,9,0) instance Semigroup TestOutput where   (<>) = mappend-#endif  type Level = Int @@ -283,10 +277,8 @@ instance Monoid Statistics where   Statistics t1 f1 `mappend` Statistics t2 f2 = Statistics (t1 + t2) (f1 + f2)   mempty = Statistics 0 0-#if MIN_VERSION_base(4,9,0) instance Semigroup Statistics where   (<>) = mappend-#endif  -- | @computeStatistics@ computes a summary 'Statistics' for -- a given state of the 'StatusMap'.@@ -466,8 +458,9 @@   defaultValue = Auto   parseValue = parseUseColor   optionName = return "color"-  optionHelp = return "When to use colored output (default: 'auto')"+  optionHelp = return "When to use colored output"   optionCLParser = mkOptionCLParser $ metavar "never|always|auto"+  showDefaultValue = Just . displayUseColor  -- | By default, when the option @--hide-successes@ is given and the output -- goes to an ANSI-capable terminal, we employ some ANSI terminal tricks to@@ -483,7 +476,7 @@ -- -- When that happens, this option can be used to disable the tricks. In -- that case, the test name will be printed only once the test fails.-newtype AnsiTricks = AnsiTricks Bool+newtype AnsiTricks = AnsiTricks { getAnsiTricks :: Bool }   deriving Typeable  instance IsOption AnsiTricks where@@ -493,8 +486,15 @@   optionHelp = return $     -- Multiline literals don't work because of -XCPP.     "Enable various ANSI terminal tricks. " ++-    "Can be set to 'true' (default) or 'false'."+    "Can be set to 'true' or 'false'."+  showDefaultValue = Just . displayBool . getAnsiTricks +displayBool :: Bool -> String+displayBool b =+  case b of+    False -> "false"+    True  -> "true"+ -- | @useColor when isTerm@ decides if colors should be used, --   where @isTerm@ indicates whether @stdout@ is a terminal device. --@@ -514,6 +514,13 @@     "auto"   -> return Auto     _        -> Nothing +displayUseColor :: UseColor -> String+displayUseColor uc =+  case uc of+    Never  -> "never"+    Always -> "always"+    Auto   -> "auto"+ -- }}}  --------------------------------------------------@@ -574,10 +581,8 @@   Maximum a `mappend` Maximum b = Maximum (a `max` b)   MinusInfinity `mappend` a = a   a `mappend` MinusInfinity = a-#if MIN_VERSION_base(4,9,0) instance Ord a => Semigroup (Maximum a) where   (<>) = mappend-#endif  -- | Compute the amount of space needed to align \"OK\"s and \"FAIL\"s computeAlignment :: OptionSet -> TestTree -> Int
Test/Tasty/Options.hs view
@@ -25,6 +25,7 @@  import qualified Data.Map as Map import Data.Map (Map)+import Data.Maybe import Data.Char (toLower) import Data.Tagged import Data.Proxy@@ -33,7 +34,7 @@ import Data.Foldable import Prelude hiding (mod) -- Silence FTP import warnings import Options.Applicative-#if MIN_VERSION_base(4,9,0)+#if !MIN_VERSION_base(4,11,0) import Data.Semigroup (Semigroup) import qualified Data.Semigroup (Semigroup((<>))) #endif@@ -52,6 +53,12 @@   -- | The option description or help string. This can be an arbitrary   -- string.   optionHelp :: Tagged v String+  -- | How a 'defaultValue' should be displayed in the help string. 'Nothing'+  -- (the default implementation) will result in nothing being displayed, while+  -- @'Just' def@ will result in @def@ being advertised as the default in the+  -- help string.+  showDefaultValue :: v -> Maybe String+  showDefaultValue _ = Nothing   -- | A command-line option parser.   --   -- It has a default implementation in terms of the other methods.@@ -62,11 +69,14 @@   -- Even if you override this, you still should implement all the methods   -- above, to allow alternative interfaces.   ---  -- Do not supply a default value here for this parser!-  -- This is because if no value was provided on the command line we may-  -- lookup the option e.g. in the environment. But if the parser always-  -- succeeds, we have no way to tell whether the user really provided the-  -- option on the command line.+  -- Do not supply a default value (e.g., with the 'value' function) here+  -- for this parser! This is because if no value was provided on the command+  -- line we may lookup the option e.g. in the environment. But if the parser+  -- always succeeds, we have no way to tell whether the user really provided+  -- the option on the command line.+  --+  -- Similarly, do not use 'showDefaultWith' here, as it will be ignored. Use+  -- the 'showDefaultValue' method of 'IsOption' instead.    -- (If we don't specify a default, the option becomes mandatory.   -- So, when we build the complete parser for OptionSet, we turn a@@ -88,10 +98,8 @@   mempty = OptionSet mempty   OptionSet a `mappend` OptionSet b =     OptionSet $ Map.unionWith (flip const) a b-#if MIN_VERSION_base(4,9,0) instance Semigroup OptionSet where   (<>) = mappend-#endif  -- | Set the option value setOption :: IsOption v => v -> OptionSet -> OptionSet
Test/Tasty/Options/Core.hs view
@@ -37,6 +37,7 @@   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"  -- | Filtering function to prevent non-positive number of threads onlyPositive :: NumThreads -> Bool
Test/Tasty/Patterns/Eval.hs view
@@ -10,7 +10,7 @@ import Data.Maybe import Data.Char import Test.Tasty.Patterns.Types-#if !MIN_VERSION_base(4,8,0)+#if !MIN_VERSION_base(4,9,0) import Control.Applicative import Data.Traversable #endif
Test/Tasty/Patterns/Parser.hs view
@@ -28,16 +28,6 @@ newtype Parser a = Parser (ReadP a)   deriving (Functor, Applicative, Alternative, Monad, MonadPlus) -#if !MIN_VERSION_base(4,6,0)-instance Applicative ReadP where-  pure = return-  (<*>) = ap-instance Alternative ReadP where-  empty = mzero-  (<|>) = mplus-#endif-- data ParseResult a = Success a | Invalid | Ambiguous [a]   deriving Show 
Test/Tasty/Runners/Reducers.hs view
@@ -43,10 +43,9 @@  import Control.Applicative import Prelude  -- Silence AMP import warnings-#if MIN_VERSION_base(4,9,0)+#if !MIN_VERSION_base(4,11,0) import Data.Semigroup (Semigroup) import qualified Data.Semigroup (Semigroup((<>)))-#else import Data.Monoid #endif @@ -55,10 +54,8 @@ instance Applicative f => Monoid (Traversal f) where   mempty = Traversal $ pure ()   Traversal f1 `mappend` Traversal f2 = Traversal $ f1 *> f2-#if MIN_VERSION_base(4,9,0) instance Applicative f => Semigroup (Traversal f) where   (<>) = mappend-#endif  -- | Monoid generated by @'liftA2' ('<>')@ --@@ -69,7 +66,5 @@ instance (Applicative f, Monoid a) => Monoid (Ap f a) where   mempty = pure mempty   mappend = liftA2 mappend-#if MIN_VERSION_base(4,9,0) instance (Applicative f, Monoid a) => Semigroup (Ap f a) where   (<>) = mappend-#endif
Test/Tasty/Runners/Utils.hs view
@@ -5,6 +5,8 @@  import Control.Exception import Control.Applicative+import Control.Concurrent (mkWeakThreadId, myThreadId)+import Control.Monad (forM_) #ifndef VERSION_clock import Data.Time.Clock.POSIX (getPOSIXTime) #endif@@ -16,22 +18,16 @@ import qualified System.Clock as Clock #endif -import Test.Tasty.Core (Time)---- We install handlers only on UNIX (obviously) and on GHC >= 7.6.--- GHC 7.4 lacks mkWeakThreadId (see #181), and this is not important--- enough to look for an alternative implementation, so we just disable it--- there.-#define INSTALL_HANDLERS defined __UNIX__ && MIN_VERSION_base(4,6,0)+-- Install handlers only on UNIX+#define INSTALL_HANDLERS defined __UNIX__  #if INSTALL_HANDLERS-import Control.Concurrent (mkWeakThreadId, myThreadId)-import Control.Exception (Exception(..), throwTo)-import Control.Monad (forM_) import System.Posix.Signals import System.Mem.Weak (deRefWeak) #endif +import Test.Tasty.Core (Time)+ -- | Catch possible exceptions that may arise when evaluating a string. -- For normal (total) strings, this is a no-op. --@@ -71,8 +67,7 @@ #if INSTALL_HANDLERS   main_thread_id <- myThreadId   weak_tid <- mkWeakThreadId main_thread_id-  forM_ [ sigABRT, sigBUS, sigFPE, sigHUP, sigILL, sigQUIT, sigSEGV,-          sigSYS, sigTERM, sigUSR1, sigUSR2, sigXCPU, sigXFSZ ] $ \sig ->+  forM_ [ sigHUP, sigTERM, sigUSR1, sigUSR2, sigXCPU, sigXFSZ ] $ \sig ->     installHandler sig (Catch $ send_exception weak_tid sig) Nothing   where     send_exception weak_tid sig = do
tasty.cabal view
@@ -2,7 +2,7 @@ --  see http://haskell.org/cabal/users-guide/  name:                tasty-version:             1.2.3+version:             1.3 synopsis:            Modern and extensible testing framework description:         Tasty is a modern testing framework for Haskell.                      It lets you combine your unit tests, golden@@ -14,7 +14,7 @@ maintainer:          Roman Cheplyaka <roma@ro-che.info> homepage:            https://github.com/feuerbach/tasty bug-reports:         https://github.com/feuerbach/tasty/issues--- copyright:           +-- copyright: category:            Testing build-type:          Simple extra-source-files:  CHANGELOG.md, README.md@@ -58,7 +58,7 @@     Test.Tasty.Ingredients.ListTests     Test.Tasty.Ingredients.IncludingOptions   build-depends:-    base >= 4.5 && < 5,+    base >= 4.7 && < 5,     stm >= 2.3,     containers,     mtl >= 2.1.3.1,@@ -67,22 +67,20 @@     unbounded-delays >= 0.1,     async >= 2.0,     ansi-terminal >= 0.9+  if(!impl(ghc >= 8.0))+    build-depends: semigroups    if flag(clock)     build-depends: clock >= 0.4.4.0   else     build-depends: time >= 1.4 -  if impl(ghc < 7.6)-    -- for GHC.Generics-    build-depends: ghc-prim-   if !os(windows) && !impl(ghcjs)     build-depends: unix,                    wcwidth     cpp-options: -D__UNIX__ -  -- hs-source-dirs:      +  -- hs-source-dirs:   default-language:    Haskell2010   default-extensions:  CPP, ScopedTypeVariables, DeriveDataTypeable   ghc-options: -Wall