Skip to content

Commit 628ddc8

Browse files
authored
Merge pull request #10427 from 9999years/cabal-testsuite-pattern-arg
Make `cabal-testsuite` filterable with `--pattern`
2 parents 6bfdbfd + 33b7678 commit 628ddc8

File tree

3 files changed

+77
-22
lines changed

3 files changed

+77
-22
lines changed

cabal-testsuite/README.md

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
cabal-testsuite is a suite of integration tests for Cabal-based
22
frameworks.
33

4-
How to run
5-
----------
4+
# How to run
65

76
1. Build `cabal-testsuite` (`cabal build cabal-testsuite:cabal-tests`)
87
2. Run the `cabal-tests` executable. It will scan for all tests
98
in your current directory and subdirectories and run them.
10-
To run a specific set of tests, use `cabal-tests --with-cabal=CABALBIN PATH ...`.
11-
(e.g. `cabal run cabal-testsuite:cabal-tests -- --with-cabal=cabal cabal-testsuite/PackageTests/TestOptions/setup.test.hs`)
12-
You can control parallelism using the `-j` flag.
139

1410
There are a few useful flags:
1511

12+
* To run a specific set of tests, pass the path to a `.test.hs` file to run or
13+
use the `-p`/`--pattern` flag to filter tests.
14+
15+
See the ["Selecting tests"](#selecting-tests) section below for more details.
16+
17+
* `-j INT` controls the number of threads used for running tests.
18+
1619
* `--with-cabal PATH` can be used to specify the path of a
1720
`cabal-install` executable. IF YOU DO NOT SPECIFY THIS FLAG,
1821
CABAL INSTALL TESTS WILL NOT RUN.
@@ -28,6 +31,28 @@ There are a few useful flags:
2831
* `--keep-tmp-files` can be used to keep the temporary directories that tests
2932
are run in.
3033

34+
## Selecting tests
35+
36+
To run a specific set of tests, use `cabal-tests --with-cabal=CABALBIN PATH ...`, e.g.:
37+
38+
```
39+
cabal run cabal-testsuite:cabal-tests -- \
40+
--with-cabal=cabal \
41+
cabal-testsuite/PackageTests/TestOptions/setup.test.hs
42+
```
43+
44+
Alternatively, use `-p`/`--pattern` to select tests dynamically:
45+
46+
```
47+
cabal run cabal-testsuite:cabal-tests -- \
48+
--with-cabal=cabal \
49+
--pattern "/TestOptions/"
50+
```
51+
52+
See [the documentation for Tasty pattern
53+
syntax](https://hackage.haskell.org/package/tasty#patterns) for more
54+
information.
55+
3156
## Which Cabal library version do cabal-install tests use?
3257

3358
By default the `cabal-install` tests will use the `Cabal` library which comes with
@@ -74,8 +99,7 @@ components have broken doctests
7499
our CI currently checks that `Cabal-syntax` and `Cabal` doctests pass via
75100
`make doctest-install && make doctest` (you can use this `make`-based workflow too).
76101

77-
How to write
78-
------------
102+
# How to write
79103

80104
If you learn better by example, just look at the tests that live
81105
in `cabal-testsuite/PackageTests`; if you `git log -p`, you can
@@ -155,8 +179,7 @@ allow multiple tests to be defined in one file but run in parallel;
155179
at the moment, these just indicate long running tests that should
156180
be run early (to avoid straggling).
157181

158-
Frequently asked questions
159-
--------------------------
182+
# Frequently asked questions
160183

161184
For all of these answers, to see examples of the functions in
162185
question, grep the test suite.
@@ -223,8 +246,7 @@ long before editing a file, in order for file system timestamp
223246
resolution to pick it up. Use `withDelay` and `delay` prior to
224247
making a modification.
225248

226-
Hermetic tests
227-
--------------
249+
# Hermetic tests
228250

229251
Tests are run in a fresh temporary system directory. This attempts to isolate the
230252
tests from anything specific to do with your directory structure. In particular
@@ -235,8 +257,7 @@ tests from anything specific to do with your directory structure. In particular
235257
* You must `git add` all files which are relevant to the test, otherwise
236258
they will not be copied.
237259

238-
Design notes
239-
------------
260+
# Design notes
240261

241262
This is the second rewrite of the integration testing framework. The
242263
primary goal was to use Haskell as the test language (letting us take
@@ -296,8 +317,7 @@ figure out how to get out the threading setting, and then spawn
296317
that many GHCi servers to service the running threads. Improvements
297318
welcome.
298319

299-
Expect tests
300-
------------
320+
# Expect tests
301321

302322
An expect test (aka _golden test_)
303323
is a test where we read out the output of the test
@@ -366,8 +386,7 @@ Some other notes:
366386
on the output for the string you're looking for. Try to be
367387
deterministic, but sometimes it's not (easily) possible.
368388

369-
Non-goals
370-
---------
389+
# Non-goals
371390

372391
Here are some things we do not currently plan on supporting:
373392

cabal-testsuite/cabal-testsuite.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ executable cabal-tests
105105
-- dependencies specific to exe:cabal-tests
106106
, clock ^>= 0.7.2 || ^>=0.8
107107
, directory
108+
, tasty
109+
, containers
108110

109111
build-tool-depends: cabal-testsuite:setup
110112
default-extensions: TypeOperators

cabal-testsuite/main/cabal-tests.hs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,19 @@ import Control.Exception
2323
import Control.Monad
2424
import GHC.Conc (numCapabilities)
2525
import Data.List
26+
import Data.Proxy (Proxy(Proxy))
27+
import qualified Data.Sequence as Seq (fromList)
2628
import Text.Printf
29+
import qualified Test.Tasty.Options as Tasty
30+
( OptionSet
31+
, OptionDescription (Option)
32+
, lookupOption
33+
)
34+
import qualified Test.Tasty.Runners as Tasty
35+
( optionParser
36+
, TestPattern
37+
, testPatternMatches
38+
)
2739
import qualified System.Clock as Clock
2840
import System.IO
2941
import System.FilePath
@@ -72,7 +84,8 @@ data MainArgs = MainArgs {
7284
mainArgQuiet :: Bool,
7385
mainArgDistDir :: Maybe FilePath,
7486
mainArgCabalSpec :: Maybe CabalLibSpec,
75-
mainCommonArgs :: CommonArgs
87+
mainCommonArgs :: CommonArgs,
88+
mainTastyArgs :: Tasty.OptionSet
7689
}
7790

7891
data CabalLibSpec = BootCabalLib | InTreeCabalLib FilePath FilePath | SpecificCabalLib String FilePath
@@ -117,6 +130,17 @@ mainArgParser = MainArgs
117130
<> metavar "DIR"))
118131
<*> optional cabalLibSpecParser
119132
<*> commonArgParser
133+
<*> tastyArgParser
134+
135+
tastyArgParser :: Parser Tasty.OptionSet
136+
tastyArgParser =
137+
let (warnings, parser) =
138+
Tasty.optionParser
139+
[ Tasty.Option (Proxy @Tasty.TestPattern)
140+
]
141+
in if null warnings
142+
then parser
143+
else error $ unlines ("Failed to create parser for Tasty CLI options:" : warnings)
120144

121145
-- Unpack and build a specific released version of Cabal and Cabal-syntax libraries
122146
buildCabalLibsProject :: String -> Verbosity -> Maybe FilePath -> FilePath -> IO [FilePath]
@@ -184,6 +208,7 @@ main = do
184208
-- Parse arguments. N.B. 'helper' adds the option `--help`.
185209
args <- execParser $ info (mainArgParser <**> helper) mempty
186210
let verbosity = if mainArgVerbose args then verbose else normal
211+
testPattern = Tasty.lookupOption @Tasty.TestPattern (mainTastyArgs args)
187212

188213
pkg_dbs <-
189214
-- Not path to cabal-install so we're not going to run cabal-install tests so we
@@ -264,7 +289,7 @@ main = do
264289
-- NB: getDirectoryContentsRecursive is lazy IO, but it
265290
-- doesn't handle directories disappearing gracefully. Fix
266291
-- this!
267-
(single_tests, multi_tests) <- evaluate (partitionTests test_scripts)
292+
(single_tests, multi_tests) <- evaluate (partitionTests testPattern test_scripts)
268293
let all_tests = multi_tests ++ single_tests
269294
margin = maximum (map length all_tests) + 2
270295
hPutStrLn stderr $ "tests to run: " ++ show (length all_tests)
@@ -381,10 +406,19 @@ main = do
381406
findTests :: IO [FilePath]
382407
findTests = getDirectoryContentsRecursive "."
383408

384-
partitionTests :: [FilePath] -> ([FilePath], [FilePath])
385-
partitionTests = go [] []
409+
-- | Partition a list of paths into a tuple of test paths and multi-test paths.
410+
--
411+
-- Non-test paths and test paths that don't match the given `Tasty.TestPattern` are dropped.
412+
partitionTests :: Tasty.TestPattern -> [FilePath] -> ([FilePath], [FilePath])
413+
partitionTests testPattern paths =
414+
go [] [] paths
386415
where
387-
go ts ms [] = (ts, ms)
416+
-- Filter a list, keeping only paths that match the @pattern@.
417+
keepPatternMatches = filter (Tasty.testPatternMatches testPattern . toTastyPath)
418+
419+
toTastyPath path = Seq.fromList $ splitDirectories path
420+
421+
go ts ms [] = (keepPatternMatches ts, keepPatternMatches ms)
388422
go ts ms (f:fs) =
389423
-- NB: Keep this synchronized with isTestFile
390424
case takeExtensions f of

0 commit comments

Comments
 (0)