1 {-# LANGUAGE RecordWildCards #-}
3 -- | cabal-install CLI command: test
4 module Distribution
.Client
.CmdTest
5 ( -- * The @test@ CLI and action
9 -- * Internals exposed for testing
10 , isSubComponentProblem
13 , selectPackageTargets
14 , selectComponentTarget
17 import Distribution
.Client
.Compat
.Prelude
20 import Distribution
.Client
.CmdErrorMessages
23 , renderTargetProblemNoTargets
24 , renderTargetSelector
26 , targetSelectorFilter
27 , targetSelectorPluralPkgs
29 import Distribution
.Client
.NixStyleOptions
31 , defaultNixStyleFlags
34 import Distribution
.Client
.ProjectOrchestration
35 import Distribution
.Client
.Setup
39 import Distribution
.Client
.TargetProblem
42 import Distribution
.Client
.Utils
45 import Distribution
.Simple
.Command
49 import Distribution
.Simple
.Flag
52 import Distribution
.Simple
.Setup
56 import Distribution
.Simple
.Utils
62 import Distribution
.Verbosity
66 import qualified System
.Exit
(exitSuccess
)
68 import Distribution
.Client
.Errors
69 import GHC
.Environment
73 testCommand
:: CommandUI
(NixStyleFlags
())
76 { commandName
= "v2-test"
77 , commandSynopsis
= "Run test-suites."
78 , commandUsage
= usageAlternatives
"v2-test" ["[TARGETS] [FLAGS]"]
79 , commandDescription
= Just
$ \_
->
81 "Runs the specified test-suites, first ensuring they are up to "
83 ++ "Any test-suite in any package in the project can be specified. "
84 ++ "A package can be specified in which case all the test-suites in the "
85 ++ "package are run. The default is to run all the test-suites in the "
86 ++ "package in the current directory.\n\n"
87 ++ "Dependencies are built or rebuilt as necessary. Additional "
88 ++ "configuration flags can be specified on the command line and these "
89 ++ "extend the project configuration from the 'cabal.project', "
90 ++ "'cabal.project.local' and other files.\n\n"
91 ++ "To pass command-line arguments to a test suite, see the "
93 , commandNotes
= Just
$ \pname
->
98 ++ " Run all the test-suites in the package in the current directory\n"
101 ++ " v2-test pkgname\n"
102 ++ " Run all the test-suites in the package named pkgname\n"
105 ++ " v2-test cname\n"
106 ++ " Run the test-suite named cname\n"
109 ++ " v2-test cname --enable-coverage\n"
110 ++ " Run the test-suite built with code coverage (including local libs used)\n"
111 , commandDefaultFlags
= defaultNixStyleFlags
()
112 , commandOptions
= nixStyleOptions
(const [])
115 -- | The @test@ command is very much like @build@. It brings the install plan
116 -- up to date, selects that part of the plan needed by the given or implicit
117 -- test target(s) and then executes the plan.
119 -- Compared to @build@ the difference is that there's also test targets
120 -- which are ephemeral.
122 -- For more details on how this works, see the module
123 -- "Distribution.Client.ProjectOrchestration"
124 testAction
:: NixStyleFlags
() -> [String] -> GlobalFlags
-> IO ()
125 testAction flags
@NixStyleFlags
{..} targetStrings globalFlags
= do
126 baseCtx
<- establishProjectBaseContext verbosity cliConfig OtherCommand
129 either (reportTargetSelectorProblems verbosity
) return
130 =<< readTargetSelectors
(localPackages baseCtx
) (Just TestKind
) targetStrings
133 runProjectPreBuildPhase verbosity baseCtx
$ \elaboratedPlan
-> do
134 when (buildSettingOnlyDeps
(buildSettings baseCtx
)) $
135 dieWithException verbosity TestCommandDoesn
'tSupport
137 fullArgs
<- getFullArgs
138 when ("+RTS" `
elem` fullArgs
) $
140 giveRTSWarning
"test"
142 -- Interpret the targets on the command line as test targets
143 -- (as opposed to say build or haddock targets).
145 either (reportTargetProblems verbosity failWhenNoTestSuites
) return $
148 selectComponentTarget
153 let elaboratedPlan
' =
154 pruneInstallPlanToTargets
158 return (elaboratedPlan
', targets
)
160 printPlan verbosity baseCtx buildCtx
162 buildOutcomes
<- runProjectBuildPhase verbosity baseCtx buildCtx
163 runProjectPostBuildPhase verbosity baseCtx buildCtx buildOutcomes
165 failWhenNoTestSuites
= testFailWhenNoTestSuites testFlags
166 verbosity
= fromFlagOrDefault normal
(configVerbosity configFlags
)
167 cliConfig
= commandLineFlagsToProjectConfig globalFlags flags mempty
-- ClientInstallFlags
169 -- | This defines what a 'TargetSelector' means for the @test@ command.
170 -- It selects the 'AvailableTarget's that the 'TargetSelector' refers to,
171 -- or otherwise classifies the problem.
173 -- For the @test@ command we select all buildable test-suites,
174 -- or fail if there are no test-suites or no buildable test-suites.
177 -> [AvailableTarget k
]
178 -> Either TestTargetProblem
[k
]
179 selectPackageTargets targetSelector targets
180 -- If there are any buildable test-suite targets then we select those
181 |
not (null targetsTestsBuildable
) =
182 Right targetsTestsBuildable
183 -- If there are test-suites but none are buildable then we report those
184 |
not (null targetsTests
) =
185 Left
(TargetProblemNoneEnabled targetSelector targetsTests
)
186 -- If there are no test-suite but some other targets then we report that
187 |
not (null targets
) =
188 Left
(noTestsProblem targetSelector
)
189 -- If there are no targets at all then we report that
191 Left
(TargetProblemNoTargets targetSelector
)
193 targetsTestsBuildable
=
194 selectBuildableTargets
195 . filterTargetsKind TestKind
200 . filterTargetsKind TestKind
203 -- | For a 'TargetComponent' 'TargetSelector', check if the component can be
206 -- For the @test@ command we just need to check it is a test-suite, in addition
207 -- to the basic checks on being buildable etc.
208 selectComponentTarget
209 :: SubComponentTarget
211 -> Either TestTargetProblem k
212 selectComponentTarget subtarget
@WholeComponent t
213 | CTestName _
<- availableTargetComponentName t
=
215 selectComponentTargetBasic subtarget t
219 (availableTargetPackageId t
)
220 (availableTargetComponentName t
)
222 selectComponentTarget subtarget t
=
224 ( isSubComponentProblem
225 (availableTargetPackageId t
)
226 (availableTargetComponentName t
)
230 -- | The various error conditions that can occur when matching a
231 -- 'TargetSelector' against 'AvailableTarget's for the @test@ command.
233 = -- | The 'TargetSelector' matches targets but no test-suites
234 TargetProblemNoTests TargetSelector
235 |
-- | The 'TargetSelector' refers to a component that is not a test-suite
236 TargetProblemComponentNotTest PackageId ComponentName
237 |
-- | Asking to test an individual file or module is not supported
238 TargetProblemIsSubComponent PackageId ComponentName SubComponentTarget
241 type TestTargetProblem
= TargetProblem TestProblem
243 noTestsProblem
:: TargetSelector
-> TargetProblem TestProblem
244 noTestsProblem
= CustomTargetProblem
. TargetProblemNoTests
246 notTestProblem
:: PackageId
-> ComponentName
-> TargetProblem TestProblem
247 notTestProblem pkgid name
= CustomTargetProblem
$ TargetProblemComponentNotTest pkgid name
249 isSubComponentProblem
252 -> SubComponentTarget
253 -> TargetProblem TestProblem
254 isSubComponentProblem pkgid name subcomponent
=
255 CustomTargetProblem
$
256 TargetProblemIsSubComponent pkgid name subcomponent
258 reportTargetProblems
:: Verbosity
-> Flag
Bool -> [TestTargetProblem
] -> IO a
259 reportTargetProblems verbosity failWhenNoTestSuites problems
=
260 case (failWhenNoTestSuites
, problems
) of
261 (Flag
True, [CustomTargetProblem
(TargetProblemNoTests _
)]) ->
262 dieWithException verbosity
$ ReportTargetProblems problemsMessage
263 (_
, [CustomTargetProblem
(TargetProblemNoTests selector
)]) -> do
264 notice verbosity
(renderAllowedNoTestsProblem selector
)
265 System
.Exit
.exitSuccess
266 (_
, _
) -> dieWithException verbosity
$ ReportTargetProblems problemsMessage
268 problemsMessage
= unlines . map renderTestTargetProblem
$ problems
270 -- | Unless @--test-fail-when-no-test-suites@ flag is passed, we don't
271 -- @die@ when the target problem is 'TargetProblemNoTests'.
272 -- Instead, we display a notice saying that no tests have run and
273 -- indicate how this behaviour was enabled.
274 renderAllowedNoTestsProblem
:: TargetSelector
-> String
275 renderAllowedNoTestsProblem selector
=
276 "No tests to run for " ++ renderTargetSelector selector
278 renderTestTargetProblem
:: TestTargetProblem
-> String
279 renderTestTargetProblem
(TargetProblemNoTargets targetSelector
) =
280 case targetSelectorFilter targetSelector
of
282 | kind
/= TestKind
->
283 "The test command is for running test suites, but the target '"
284 ++ showTargetSelector targetSelector
286 ++ renderTargetSelector targetSelector
289 ++ show targetSelector
290 _
-> renderTargetProblemNoTargets
"test" targetSelector
291 renderTestTargetProblem problem
=
292 renderTargetProblem
"test" renderTestProblem problem
294 renderTestProblem
:: TestProblem
-> String
295 renderTestProblem
(TargetProblemNoTests targetSelector
) =
296 "Cannot run tests for the target '"
297 ++ showTargetSelector targetSelector
298 ++ "' which refers to "
299 ++ renderTargetSelector targetSelector
301 ++ plural
(targetSelectorPluralPkgs targetSelector
) "it does" "they do"
302 ++ " not contain any test suites."
303 renderTestProblem
(TargetProblemComponentNotTest pkgid cname
) =
304 "The test command is for running test suites, but the target '"
305 ++ showTargetSelector targetSelector
307 ++ renderTargetSelector targetSelector
308 ++ " from the package "
312 targetSelector
= TargetComponent pkgid cname WholeComponent
313 renderTestProblem
(TargetProblemIsSubComponent pkgid cname subtarget
) =
314 "The test command can only run test suites as a whole, "
315 ++ "not files or modules within them, but the target '"
316 ++ showTargetSelector targetSelector
318 ++ renderTargetSelector targetSelector
321 targetSelector
= TargetComponent pkgid cname subtarget