{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Test.Framework.CmdlineOptions (
CmdlineOptions(..), defaultCmdlineOptions, parseTestArgs, helpString,
testConfigFromCmdlineOptions
) where
import Test.Framework.TestReporter
import Test.Framework.TestTypes
import Test.Framework.History
import Test.Framework.Utils
#ifndef MIN_VERSION_base
#define MIN_VERSION_base(a,b,c) 1
#endif
#if !MIN_VERSION_base(4,6,0)
import Prelude hiding ( catch )
#endif
import Control.Exception
import Data.Char (toLower)
import Data.Maybe
import System.IO
import System.Environment hiding (getEnv)
import System.Directory
import System.Console.GetOpt
import qualified Text.Regex as R
#ifndef mingw32_HOST_OS
import System.Posix.Terminal
import System.Posix.IO (stdOutput)
import System.Posix.Env
#endif
#ifdef __GLASGOW_HASKELL__
import GHC.Conc ( numCapabilities )
#endif
import qualified Data.ByteString as BS
import Control.Monad
data CmdlineOptions = CmdlineOptions {
CmdlineOptions -> Bool
opts_quiet :: Bool
, CmdlineOptions -> TestFilter
opts_filter :: TestFilter
, CmdlineOptions -> Bool
opts_help :: Bool
, CmdlineOptions -> [String]
opts_negated :: [String]
, CmdlineOptions -> Maybe Int
opts_threads :: Maybe Int
, CmdlineOptions -> Bool
opts_shuffle :: Bool
, CmdlineOptions -> Bool
opts_machineOutput :: Bool
, CmdlineOptions -> Maybe String
opts_machineOutputXml :: Maybe FilePath
, CmdlineOptions -> Maybe Bool
opts_useColors :: Maybe Bool
, CmdlineOptions -> Maybe String
opts_outputFile :: Maybe FilePath
, CmdlineOptions -> Bool
opts_listTests :: Bool
, CmdlineOptions -> Bool
opts_split :: Bool
, CmdlineOptions -> Maybe String
opts_historyFile :: Maybe FilePath
, CmdlineOptions -> Bool
opts_failFast :: Bool
, CmdlineOptions -> Bool
opts_sortByPrevTime :: Bool
, CmdlineOptions -> Maybe Int
opts_maxPrevTimeMs :: Maybe Milliseconds
, CmdlineOptions -> Maybe Int
opts_maxCurTimeMs :: Maybe Milliseconds
, CmdlineOptions -> Maybe Double
opts_prevFactor :: Maybe Double
, CmdlineOptions -> Bool
opts_timeoutIsSuccess :: Bool
, CmdlineOptions -> Int
opts_repeat :: Int
}
defaultCmdlineOptions :: CmdlineOptions
defaultCmdlineOptions :: CmdlineOptions
defaultCmdlineOptions = CmdlineOptions {
opts_quiet :: Bool
opts_quiet = Bool
False
, opts_filter :: TestFilter
opts_filter = Bool -> TestFilter
forall a b. a -> b -> a
const Bool
True
, opts_help :: Bool
opts_help = Bool
False
, opts_negated :: [String]
opts_negated = []
, opts_threads :: Maybe Int
opts_threads = Maybe Int
forall a. Maybe a
Nothing
, opts_shuffle :: Bool
opts_shuffle = Bool
False
, opts_machineOutput :: Bool
opts_machineOutput = Bool
False
, opts_machineOutputXml :: Maybe String
opts_machineOutputXml = Maybe String
forall a. Maybe a
Nothing
, opts_useColors :: Maybe Bool
opts_useColors = Maybe Bool
forall a. Maybe a
Nothing
, opts_outputFile :: Maybe String
opts_outputFile = Maybe String
forall a. Maybe a
Nothing
, opts_listTests :: Bool
opts_listTests = Bool
False
, opts_split :: Bool
opts_split = Bool
False
, opts_historyFile :: Maybe String
opts_historyFile = Maybe String
forall a. Maybe a
Nothing
, opts_failFast :: Bool
opts_failFast = Bool
False
, opts_sortByPrevTime :: Bool
opts_sortByPrevTime = Bool
False
, opts_maxPrevTimeMs :: Maybe Int
opts_maxPrevTimeMs = Maybe Int
forall a. Maybe a
Nothing
, opts_maxCurTimeMs :: Maybe Int
opts_maxCurTimeMs = Maybe Int
forall a. Maybe a
Nothing
, opts_prevFactor :: Maybe Double
opts_prevFactor = Maybe Double
forall a. Maybe a
Nothing
, opts_timeoutIsSuccess :: Bool
opts_timeoutIsSuccess = Bool
False
, opts_repeat :: Int
opts_repeat = Int
1
}
processorCount :: Int
#ifdef __GLASGOW_HASKELL__
processorCount :: Int
processorCount = Int
numCapabilities
#else
processorCount = 1
#endif
optionDescriptions :: [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
optionDescriptions :: [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
optionDescriptions =
[ String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [Char
'q'] [String
"quiet"]
((CmdlineOptions -> Either String CmdlineOptions)
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. a -> ArgDescr a
NoArg (\CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_quiet = True }))
String
"Only display errors."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [Char
'n'] [String
"not"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_negated = s : (opts_negated o) }) String
"PATTERN")
String
"Tests to exclude."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [Char
'l'] [String
"list"]
((CmdlineOptions -> Either String CmdlineOptions)
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. a -> ArgDescr a
NoArg (\CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_listTests = True }))
String
"List all matching tests."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [Char
'j'] [String
"threads"]
((Maybe String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (Maybe String -> a) -> String -> ArgDescr a
OptArg (\Maybe String
ms CmdlineOptions
o -> Maybe String -> Either String Int
parseThreads Maybe String
ms Either String Int
-> (Int -> Either String CmdlineOptions)
-> Either String CmdlineOptions
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Int
i -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_threads = Just i }) String
"N")
(String
"Run N tests in parallel, default N=" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
processorCount String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".")
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"shuffle"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> String -> Either String Bool
forall {a}. String -> Either a Bool
parseBool String
s Either String Bool
-> (Bool -> Either String CmdlineOptions)
-> Either String CmdlineOptions
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
b -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_shuffle = b }) String
"BOOL")
String
"Shuffle test order. Default: false"
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [Char
'o'] [String
"output-file"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_outputFile = Just s }) String
"FILE")
String
"Name of output file."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"json"]
((CmdlineOptions -> Either String CmdlineOptions)
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. a -> ArgDescr a
NoArg (\CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_machineOutput = True }))
String
"Output results in machine-readable JSON format (incremental)."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"xml"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_machineOutputXml = Just s }) String
"FILE")
String
"Output results in junit-style XML format."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"split"]
((CmdlineOptions -> Either String CmdlineOptions)
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. a -> ArgDescr a
NoArg (\CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_split = True }))
String
"Splits results in separate files to avoid file locking (requires -o/--output-file)."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"colors"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> String -> Either String Bool
forall {a}. String -> Either a Bool
parseBool String
s Either String Bool
-> (Bool -> Either String CmdlineOptions)
-> Either String CmdlineOptions
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
b -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_useColors = Just b }) String
"BOOL")
String
"Use colors or not."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"history"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_historyFile = Just s }) String
"FILE")
String
"Path to the history file. Default: ./.HTF/<ProgramName>.history"
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"fail-fast"]
((CmdlineOptions -> Either String CmdlineOptions)
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. a -> ArgDescr a
NoArg (\CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_failFast = True }))
String
"Fail and abort test run as soon as the first test fails."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"sort-by-prev-time"]
((CmdlineOptions -> Either String CmdlineOptions)
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. a -> ArgDescr a
NoArg (\CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_sortByPrevTime = True }))
String
"Sort tests ascending by their execution of the previous test run (if available). Default: false"
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"max-prev-ms"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> String -> String -> Either String Int
forall {b}. Read b => String -> String -> Either String b
parseRead String
"--max-prev-ms" String
s Either String Int
-> (Int -> Either String CmdlineOptions)
-> Either String CmdlineOptions
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(Int
ms::Int) -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_maxPrevTimeMs = Just ms }) String
"MILLISECONDS")
String
"Do not try to execute tests that had a execution time greater than MILLISECONDS in a previous test run."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"max-cur-ms"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> String -> String -> Either String Int
forall {b}. Read b => String -> String -> Either String b
parseRead String
"--max-cur-ms" String
s Either String Int
-> (Int -> Either String CmdlineOptions)
-> Either String CmdlineOptions
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(Int
ms::Int) ->
CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_maxCurTimeMs = Just ms }) String
"MILLISECONDS")
String
"Abort a test that runs more than MILLISECONDS."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"prev-factor"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> String -> String -> Either String Double
forall {b}. Read b => String -> String -> Either String b
parseRead String
"--prev-factor" String
s Either String Double
-> (Double -> Either String CmdlineOptions)
-> Either String CmdlineOptions
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(Double
ms::Double) ->
CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_prevFactor = Just ms }) String
"DOUBLE")
String
"Abort a test that runs more than DOUBLE times slower than in a previous run."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"timeout-is-success"]
((CmdlineOptions -> Either String CmdlineOptions)
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. a -> ArgDescr a
NoArg (\CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_timeoutIsSuccess = True }))
String
"Do not regard a test timeout as an error."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [] [String
"repeat"]
((String -> CmdlineOptions -> Either String CmdlineOptions)
-> String
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
s CmdlineOptions
o -> String -> String -> Either String Int
forall {b}. Read b => String -> String -> Either String b
parseRead String
"--repeat" String
s Either String Int
-> (Int -> Either String CmdlineOptions)
-> Either String CmdlineOptions
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(Int
i::Int) ->
CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_repeat = i}) String
"NUMBER")
String
"Execute the tests selected on the command line NUMBER times."
, String
-> [String]
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
-> String
-> OptDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option [Char
'h'] [String
"help"]
((CmdlineOptions -> Either String CmdlineOptions)
-> ArgDescr (CmdlineOptions -> Either String CmdlineOptions)
forall a. a -> ArgDescr a
NoArg (\CmdlineOptions
o -> CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions -> Either String CmdlineOptions)
-> CmdlineOptions -> Either String CmdlineOptions
forall a b. (a -> b) -> a -> b
$ CmdlineOptions
o { opts_help = True }))
String
"Display this message."
]
where
parseThreads :: Maybe String -> Either String Int
parseThreads Maybe String
Nothing = Int -> Either String Int
forall a b. b -> Either a b
Right Int
processorCount
parseThreads (Just String
s) =
case String -> Maybe Int
forall (m :: * -> *) a. (MonadFail m, Read a) => String -> m a
readM String
s of
Just Int
i -> Int -> Either String Int
forall a b. b -> Either a b
Right Int
i
Maybe Int
Nothing -> String -> Either String Int
forall a b. a -> Either a b
Left (String
"invalid number of threads: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s)
parseBool :: String -> Either a Bool
parseBool String
s =
Bool -> Either a Bool
forall a b. b -> Either a b
Right (Bool -> Either a Bool) -> Bool -> Either a Bool
forall a b. (a -> b) -> a -> b
$
if (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String
"1", String
"true", String
"yes", String
"on"] then Bool
True else Bool
False
parseRead :: String -> String -> Either String b
parseRead String
opt String
s =
case String -> Maybe b
forall (m :: * -> *) a. (MonadFail m, Read a) => String -> m a
readM String
s of
Just b
i -> b -> Either String b
forall a b. b -> Either a b
Right b
i
Maybe b
Nothing -> String -> Either String b
forall a b. a -> Either a b
Left (String
"invalid value for option " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
opt String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s)
parseTestArgs :: [String] -> Either String CmdlineOptions
parseTestArgs :: [String] -> Either String CmdlineOptions
parseTestArgs [String]
args =
case ArgOrder (CmdlineOptions -> Either String CmdlineOptions)
-> [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
-> [String]
-> ([CmdlineOptions -> Either String CmdlineOptions], [String],
[String])
forall a.
ArgOrder a -> [OptDescr a] -> [String] -> ([a], [String], [String])
getOpt ArgOrder (CmdlineOptions -> Either String CmdlineOptions)
forall a. ArgOrder a
Permute [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
optionDescriptions [String]
args of
([CmdlineOptions -> Either String CmdlineOptions]
optTrans, [String]
tests, []) ->
do CmdlineOptions
opts <- (CmdlineOptions
-> (CmdlineOptions -> Either String CmdlineOptions)
-> Either String CmdlineOptions)
-> CmdlineOptions
-> [CmdlineOptions -> Either String CmdlineOptions]
-> Either String CmdlineOptions
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (\CmdlineOptions
o CmdlineOptions -> Either String CmdlineOptions
f -> CmdlineOptions -> Either String CmdlineOptions
f CmdlineOptions
o) CmdlineOptions
defaultCmdlineOptions [CmdlineOptions -> Either String CmdlineOptions]
optTrans
Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (CmdlineOptions -> Bool
opts_shuffle CmdlineOptions
opts Bool -> Bool -> Bool
&& CmdlineOptions -> Bool
opts_sortByPrevTime CmdlineOptions
opts) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$
String -> Either String ()
forall a b. a -> Either a b
Left (String
"Options --shuffle=true and --sort-by-prev-time are in conflict. " String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
"Can only use one of both.\n\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
-> [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
-> String
forall a. String -> [OptDescr a] -> String
usageInfo String
usageHeader [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
optionDescriptions)
case (CmdlineOptions -> Maybe String
opts_outputFile CmdlineOptions
opts, CmdlineOptions -> Bool
opts_split CmdlineOptions
opts) of
(Maybe String
Nothing, Bool
True) -> String -> Either String CmdlineOptions
forall a b. a -> Either a b
Left (String
"Option --split requires -o or --output-file\n\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
-> [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
-> String
forall a. String -> [OptDescr a] -> String
usageInfo String
usageHeader [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
optionDescriptions)
(Maybe String, Bool)
_ -> let posStrs :: [String]
posStrs = [String]
tests
negStrs :: [String]
negStrs = CmdlineOptions -> [String]
opts_negated CmdlineOptions
opts
pos :: [Regex]
pos = (String -> Regex) -> [String] -> [Regex]
forall a b. (a -> b) -> [a] -> [b]
map String -> Regex
mkRegex [String]
posStrs
neg :: [Regex]
neg = (String -> Regex) -> [String] -> [Regex]
forall a b. (a -> b) -> [a] -> [b]
map String -> Regex
mkRegex [String]
negStrs
pred :: GenFlatTest a -> Bool
pred (FlatTest TestSort
_ TestPath
path Maybe Location
_ a
_) =
let flat :: String
flat = TestPath -> String
flatName TestPath
path
in if ((Regex -> Bool) -> [Regex] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Regex
s -> Regex
s Regex -> String -> Bool
`matches` String
flat) [Regex]
neg)
then Bool
False
else [Regex] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Regex]
pos Bool -> Bool -> Bool
|| (Regex -> Bool) -> [Regex] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Regex
s -> Regex
s Regex -> String -> Bool
`matches` String
flat) [Regex]
pos
in CmdlineOptions -> Either String CmdlineOptions
forall a b. b -> Either a b
Right (CmdlineOptions
opts { opts_filter = pred })
([CmdlineOptions -> Either String CmdlineOptions]
_,[String]
_,[String]
errs) ->
String -> Either String CmdlineOptions
forall a b. a -> Either a b
Left ([String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String]
errs String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
-> [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
-> String
forall a. String -> [OptDescr a] -> String
usageInfo String
usageHeader [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
optionDescriptions)
where
matches :: Regex -> String -> Bool
matches Regex
r String
s = Maybe [String] -> Bool
forall a. Maybe a -> Bool
isJust (Maybe [String] -> Bool) -> Maybe [String] -> Bool
forall a b. (a -> b) -> a -> b
$ Regex -> String -> Maybe [String]
R.matchRegex Regex
r String
s
mkRegex :: String -> Regex
mkRegex String
s = String -> Bool -> Bool -> Regex
R.mkRegexWithOpts String
s Bool
True Bool
False
usageHeader :: String
= (String
"USAGE: COMMAND [OPTION ...] PATTERN ...\n\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
" where PATTERN is a posix regular expression matching\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
" the names of the tests to run.\n")
helpString :: String
helpString :: String
helpString = String
-> [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
-> String
forall a. String -> [OptDescr a] -> String
usageInfo String
usageHeader [OptDescr (CmdlineOptions -> Either String CmdlineOptions)]
optionDescriptions
testConfigFromCmdlineOptions :: CmdlineOptions -> IO TestConfig
testConfigFromCmdlineOptions :: CmdlineOptions -> IO TestConfig
testConfigFromCmdlineOptions CmdlineOptions
opts =
do (TestOutput
output, Bool
colors) <-
case (CmdlineOptions -> Maybe String
opts_outputFile CmdlineOptions
opts, CmdlineOptions -> Bool
opts_split CmdlineOptions
opts) of
(Just String
fname, Bool
True) -> (TestOutput, Bool) -> IO (TestOutput, Bool)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> TestOutput
TestOutputSplitted String
fname, Bool
False)
(Maybe String, Bool)
_ -> do (Handle
outputHandle, Bool
closeOutput, Maybe Fd
mOutputFd) <- IO (Handle, Bool, Maybe Fd)
openOutputFile
Bool
colors <- Maybe Fd -> IO Bool
checkColors Maybe Fd
mOutputFd
(TestOutput, Bool) -> IO (TestOutput, Bool)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Handle -> Bool -> TestOutput
TestOutputHandle Handle
outputHandle Bool
closeOutput, Bool
colors)
let threads :: Maybe Int
threads = CmdlineOptions -> Maybe Int
opts_threads CmdlineOptions
opts
reporters :: [TestReporter]
reporters = IsParallel -> IsJsonOutput -> IsXmlOutput -> [TestReporter]
defaultTestReporters (Bool -> IsParallel
isParallelFromBool (Bool -> IsParallel) -> Bool -> IsParallel
forall a b. (a -> b) -> a -> b
$ Maybe Int -> Bool
forall a. Maybe a -> Bool
isJust Maybe Int
threads)
(if CmdlineOptions -> Bool
opts_machineOutput CmdlineOptions
opts then IsJsonOutput
JsonOutput else IsJsonOutput
NoJsonOutput)
(if Maybe String -> Bool
forall a. Maybe a -> Bool
isJust (CmdlineOptions -> Maybe String
opts_machineOutputXml CmdlineOptions
opts) then IsXmlOutput
XmlOutput else IsXmlOutput
NoXmlOutput)
String
historyFile <- IO String
getHistoryFile
TestHistory
history <- String -> IO TestHistory
getHistory String
historyFile
TestConfig -> IO TestConfig
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (TestConfig -> IO TestConfig) -> TestConfig -> IO TestConfig
forall a b. (a -> b) -> a -> b
$ TestConfig { tc_quiet :: Bool
tc_quiet = CmdlineOptions -> Bool
opts_quiet CmdlineOptions
opts
, tc_threads :: Maybe Int
tc_threads = Maybe Int
threads
, tc_shuffle :: Bool
tc_shuffle = CmdlineOptions -> Bool
opts_shuffle CmdlineOptions
opts
, tc_output :: TestOutput
tc_output = TestOutput
output
, tc_outputXml :: Maybe String
tc_outputXml = CmdlineOptions -> Maybe String
opts_machineOutputXml CmdlineOptions
opts
, tc_reporters :: [TestReporter]
tc_reporters = [TestReporter]
reporters
, tc_filter :: TestFilter
tc_filter = CmdlineOptions -> TestFilter
opts_filter CmdlineOptions
opts TestFilter -> TestFilter -> TestFilter
forall {t}. (t -> Bool) -> (t -> Bool) -> t -> Bool
`mergeFilters` (TestHistory -> TestFilter
forall {a}. TestHistory -> GenFlatTest a -> Bool
historicFilter TestHistory
history)
, tc_useColors :: Bool
tc_useColors = Bool
colors
, tc_historyFile :: String
tc_historyFile = String
historyFile
, tc_history :: TestHistory
tc_history = TestHistory
history
, tc_sortByPrevTime :: Bool
tc_sortByPrevTime = CmdlineOptions -> Bool
opts_sortByPrevTime CmdlineOptions
opts
, tc_failFast :: Bool
tc_failFast = CmdlineOptions -> Bool
opts_failFast CmdlineOptions
opts
, tc_maxSingleTestTime :: Maybe Int
tc_maxSingleTestTime = CmdlineOptions -> Maybe Int
opts_maxCurTimeMs CmdlineOptions
opts
, tc_prevFactor :: Maybe Double
tc_prevFactor = CmdlineOptions -> Maybe Double
opts_prevFactor CmdlineOptions
opts
, tc_timeoutIsSuccess :: Bool
tc_timeoutIsSuccess = CmdlineOptions -> Bool
opts_timeoutIsSuccess CmdlineOptions
opts
, tc_repeat :: Int
tc_repeat = CmdlineOptions -> Int
opts_repeat CmdlineOptions
opts
}
where
#ifdef mingw32_HOST_OS
openOutputFile =
case opts_outputFile opts of
Nothing -> return (stdout, False, Nothing)
Just fname ->
do f <- openFile fname WriteMode
return (f, True, Nothing)
checkColors mOutputFd =
case opts_useColors opts of
Just b -> return b
Nothing -> return False
#else
openOutputFile :: IO (Handle, Bool, Maybe Fd)
openOutputFile =
case CmdlineOptions -> Maybe String
opts_outputFile CmdlineOptions
opts of
Maybe String
Nothing -> (Handle, Bool, Maybe Fd) -> IO (Handle, Bool, Maybe Fd)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Handle
stdout, Bool
False, Fd -> Maybe Fd
forall a. a -> Maybe a
Just Fd
stdOutput)
Just String
fname ->
do Handle
f <- String -> IOMode -> IO Handle
openFile String
fname IOMode
WriteMode
(Handle, Bool, Maybe Fd) -> IO (Handle, Bool, Maybe Fd)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Handle
f, Bool
True, Maybe Fd
forall a. Maybe a
Nothing)
checkColors :: Maybe Fd -> IO Bool
checkColors Maybe Fd
mOutputFd =
case CmdlineOptions -> Maybe Bool
opts_useColors CmdlineOptions
opts of
Just Bool
b -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
b
Maybe Bool
Nothing ->
do Maybe String
mterm <- String -> IO (Maybe String)
getEnv String
"TERM"
case Maybe String
mterm of
Maybe String
Nothing -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
Just String
s | (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"dumb" -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
Maybe String
_ -> do Maybe String
mx <- String -> IO (Maybe String)
getEnv String
"HTF_NO_COLORS"
case Maybe String
mx of
Just String
s | (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String
"", String
"1", String
"y", String
"yes", String
"true"] -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
Maybe String
_ -> case Maybe Fd
mOutputFd of
Just Fd
fd -> Fd -> IO Bool
queryTerminal Fd
fd
Maybe Fd
_ -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
#endif
getHistoryFile :: IO String
getHistoryFile =
case CmdlineOptions -> Maybe String
opts_historyFile CmdlineOptions
opts of
Just String
fp -> String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return String
fp
Maybe String
Nothing ->
do String
progName <- IO String
getProgName
let x :: String
x = if String
progName String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"<interactive>" then String
"interactive" else String
progName
String
curDir <- IO String
getCurrentDirectory
let dir :: String
dir = String
curDir String -> String -> String
</> String
".HTF"
Bool -> String -> IO ()
createDirectoryIfMissing Bool
False String
dir
String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ String
dir String -> String -> String
</> (String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".history")
getHistory :: String -> IO TestHistory
getHistory String
fp =
do Bool
b <- String -> IO Bool
doesFileExist String
fp
if Bool -> Bool
not Bool
b
then TestHistory -> IO TestHistory
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return TestHistory
emptyTestHistory
else do ByteString
bs <- String -> IO ByteString
BS.readFile String
fp
case ByteString -> Either String TestHistory
deserializeTestHistory ByteString
bs of
Right TestHistory
history -> TestHistory -> IO TestHistory
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return TestHistory
history
Left String
err ->
do Handle -> String -> IO ()
hPutStrLn Handle
stderr (String
"Error deserializing content of HTF history file " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
fp String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
err)
TestHistory -> IO TestHistory
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return TestHistory
emptyTestHistory
IO TestHistory -> (IOException -> IO TestHistory) -> IO TestHistory
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` (\(IOException
e::IOException) ->
do Handle -> String -> IO ()
hPutStrLn Handle
stderr (String
"Error reading HTF history file " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
fp String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ IOException -> String
forall a. Show a => a -> String
show IOException
e)
TestHistory -> IO TestHistory
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return TestHistory
emptyTestHistory)
mergeFilters :: (t -> Bool) -> (t -> Bool) -> t -> Bool
mergeFilters t -> Bool
f1 t -> Bool
f2 t
t =
t -> Bool
f1 t
t Bool -> Bool -> Bool
&& t -> Bool
f2 t
t
historicFilter :: TestHistory -> GenFlatTest a -> Bool
historicFilter TestHistory
history GenFlatTest a
t =
case CmdlineOptions -> Maybe Int
opts_maxPrevTimeMs CmdlineOptions
opts of
Maybe Int
Nothing -> Bool
True
Just Int
ms ->
case Maybe Int -> Maybe Int -> Maybe Int
forall a. Ord a => a -> a -> a
max ((HistoricTestResult -> Int)
-> Maybe HistoricTestResult -> Maybe Int
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap HistoricTestResult -> Int
htr_timeMs (Text -> TestHistory -> Maybe HistoricTestResult
findHistoricTestResult (GenFlatTest a -> Text
forall a. GenFlatTest a -> Text
historyKey GenFlatTest a
t) TestHistory
history))
((HistoricTestResult -> Int)
-> Maybe HistoricTestResult -> Maybe Int
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap HistoricTestResult -> Int
htr_timeMs (Text -> TestHistory -> Maybe HistoricTestResult
findHistoricSuccessfulTestResult (GenFlatTest a -> Text
forall a. GenFlatTest a -> Text
historyKey GenFlatTest a
t) TestHistory
history))
of
Maybe Int
Nothing -> Bool
True
Just Int
t -> Int
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
ms