Skip to content

Commit b16a443

Browse files
committed
Update tests, adding more assertions
- Improve test descriptions - Mention [package:][ctype:]component - Don't repeat [package:][ctype:]component - Lift validatedTargets, rename r as replFlags - Don't use -XRecordWildCards for configFlags - Add a one.project one pkg test - Remove target string manipulation - Make reportProjectNoTarget a function - Redo ReplProjectTarget tests - Redo ReplProjectNoneTarget tests - Satisfy fix-whitespace - Error whether or not project has packages - Guard against triggering an assertion if targets are null
1 parent af52211 commit b16a443

File tree

16 files changed

+193
-117
lines changed

16 files changed

+193
-117
lines changed

cabal-install/src/Distribution/Client/CmdRepl.hs

Lines changed: 82 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ import Distribution.Simple.Compiler
106106
)
107107
import Distribution.Simple.Program.GHC
108108
import Distribution.Simple.Setup
109-
( ReplOptions (..)
109+
( Flag
110+
, ReplOptions (..)
110111
, commonSetupTempFileOptions
111112
)
112113
import Distribution.Simple.Utils
@@ -157,7 +158,6 @@ import Distribution.Utils.Generic
157158
import Distribution.Verbosity
158159
( lessVerbose
159160
, normal
160-
, silent
161161
)
162162
import Language.Haskell.Extension
163163
( Language (..)
@@ -197,7 +197,6 @@ import System.FilePath
197197
, (</>)
198198
)
199199
import Text.PrettyPrint hiding ((<>))
200-
import qualified Text.PrettyPrint as Pretty
201200

202201
replCommand :: CommandUI (NixStyleFlags ReplFlags)
203202
replCommand =
@@ -284,22 +283,7 @@ multiReplDecision ctx compiler flags =
284283
-- For more details on how this works, see the module
285284
-- "Distribution.Client.ProjectOrchestration"
286285
replAction :: NixStyleFlags ReplFlags -> [String] -> GlobalFlags -> IO ()
287-
replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings' globalFlags = do
288-
-- NOTE: The REPL will work with no targets in the context of a project if a
289-
-- single package is in the same directory as the project file. To have the
290-
-- same behaviour when the package is somewhere else we adjust the targets.
291-
targetStrings <-
292-
if null targetStrings'
293-
then withCtx silent targetStrings' $ \targetCtx ctx _ ->
294-
return . fromMaybe [] $ case targetCtx of
295-
ProjectContext ->
296-
let pkgs = projectPackages $ projectConfig ctx
297-
in if length pkgs == 1
298-
then pure <$> listToMaybe pkgs
299-
else Nothing
300-
_ -> Nothing
301-
else return targetStrings'
302-
286+
replAction flags@NixStyleFlags{extraFlags = replFlags@ReplFlags{..}, configFlags} targetStrings globalFlags = do
303287
withCtx verbosity targetStrings $ \targetCtx ctx targetSelectors -> do
304288
when (buildSettingOnlyDeps (buildSettings ctx)) $
305289
dieWithException verbosity ReplCommandDoesn'tSupport
@@ -308,25 +292,11 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings'
308292

309293
baseCtx <- case targetCtx of
310294
ProjectContext -> do
311-
let pkgs = projectPackages $ projectConfig ctx
312-
when (null targetStrings && length pkgs /= 1) $
313-
let singleTarget = text "With a project, the REPL command requires a single target"
314-
project = case projectConfigProjectFile . projectConfigShared $ projectConfig ctx of
315-
Flag projectName -> comma <+> (quotes (text projectName))
316-
_ -> Pretty.empty
317-
msg =
318-
if null pkgs
319-
then
320-
(singleTarget <> comma)
321-
<+> (text "but there are no packages in this project" <> project <> comma)
322-
<+> text "to choose a package (library) or other component from"
323-
<+> "as the target for this command."
324-
else
325-
(singleTarget <> (char '.'))
326-
<+> (text "The packages in this project" <> project <> comma)
327-
<+> (text "are" <> colon)
328-
$+$ nest 1 (vcat [text "-" <+> text pkg | pkg <- sort pkgs])
329-
in dieWithException verbosity $ RenderReplTargetProblem [render msg]
295+
when (null targetSelectors) $ do
296+
let projectFile = projectConfigProjectFile . projectConfigShared $ projectConfig ctx
297+
let pkgs = projectPackages $ projectConfig ctx
298+
dieWithException verbosity $
299+
RenderReplTargetProblem [render (reportProjectNoTarget projectFile pkgs)]
330300
return ctx
331301
GlobalContext -> do
332302
unless (null targetStrings) $
@@ -398,7 +368,7 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings'
398368
-- especially in the no-project case.
399369
withInstallPlan (lessVerbose verbosity) baseCtx' $ \elaboratedPlan sharedConfig -> do
400370
-- targets should be non-empty map, but there's no NonEmptyMap yet.
401-
targets <- validatedTargets (projectConfigShared (projectConfig ctx)) (pkgConfigCompiler sharedConfig) elaboratedPlan targetSelectors
371+
targets <- validatedTargets' (projectConfigShared (projectConfig ctx)) (pkgConfigCompiler sharedConfig) elaboratedPlan targetSelectors
402372

403373
let
404374
(unitId, _) = fromMaybe (error "panic: targets should be non-empty") $ safeHead $ Map.toList targets
@@ -422,14 +392,19 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings'
422392
let ProjectBaseContext{..} = baseCtx''
423393

424394
-- Recalculate with updated project.
425-
targets <- validatedTargets (projectConfigShared projectConfig) (pkgConfigCompiler elaboratedShared') elaboratedPlan targetSelectors
395+
targets <- validatedTargets' (projectConfigShared projectConfig) (pkgConfigCompiler elaboratedShared') elaboratedPlan targetSelectors
426396

427397
let
428398
elaboratedPlan' =
429-
pruneInstallPlanToTargets
430-
TargetActionRepl
431-
targets
432-
elaboratedPlan
399+
-- Guard against pruning with empty targets and failing an assertion
400+
-- within pruneInstallPlanToTargets.
401+
if null targets
402+
then elaboratedPlan
403+
else
404+
pruneInstallPlanToTargets
405+
TargetActionRepl
406+
targets
407+
elaboratedPlan
433408
includeTransitive = fromFlagOrDefault True (envIncludeTransitive replEnvFlags)
434409

435410
pkgsBuildStatus <-
@@ -561,28 +536,7 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings'
561536
verbosity = cfgVerbosity normal flags
562537
tempFileOptions = commonSetupTempFileOptions $ configCommonFlags configFlags
563538

564-
validatedTargets ctx compiler elaboratedPlan targetSelectors = do
565-
let multi_repl_enabled = multiReplDecision ctx compiler r
566-
-- Interpret the targets on the command line as repl targets
567-
-- (as opposed to say build or haddock targets).
568-
targets <-
569-
either (reportTargetProblems verbosity) return $
570-
resolveTargetsFromSolver
571-
(selectPackageTargets multi_repl_enabled)
572-
selectComponentTarget
573-
elaboratedPlan
574-
Nothing
575-
targetSelectors
576-
577-
-- Reject multiple targets, or at least targets in different
578-
-- components. It is ok to have two module/file targets in the
579-
-- same component, but not two that live in different components.
580-
when (Set.size (distinctTargetComponents targets) > 1 && not (useMultiRepl multi_repl_enabled)) $
581-
reportTargetProblems
582-
verbosity
583-
[multipleTargetsProblem multi_repl_enabled targets]
584-
585-
return targets
539+
validatedTargets' = validatedTargets verbosity replFlags
586540

587541
-- | Create a constraint which requires a later version of Cabal.
588542
-- This is used for commands which require a specific feature from the Cabal library
@@ -595,6 +549,68 @@ requireCabal version source =
595549
, source
596550
)
597551

552+
reportProjectNoTarget :: Flag FilePath -> [String] -> Doc
553+
reportProjectNoTarget projectFile pkgs =
554+
case (null pkgs, projectName) of
555+
(True, Just project) ->
556+
text "There are no packages in"
557+
<+> (project <> char '.')
558+
<+> text "Please add a package to the project and"
559+
<+> pickComponent
560+
(True, Nothing) ->
561+
text "Please add a package to the project and" <+> pickComponent
562+
(False, Just project) ->
563+
text "Please"
564+
<+> pickComponent
565+
<+> text "The packages in"
566+
<+> project
567+
<+> (text "from which to select a component target are" <> colon)
568+
$+$ nest 1 (vcat [text "-" <+> text pkg | pkg <- sort pkgs])
569+
(False, Nothing) ->
570+
text "Please"
571+
<+> pickComponent
572+
<+> (text "The packages from which to select a component in 'cabal.project'" <> comma)
573+
<+> (text "the implicit default as if `--project-file=cabal.project` was added as a command option" <> comma)
574+
<+> (text "are" <> colon)
575+
$+$ nest 1 (vcat [text "-" <+> text pkg | pkg <- sort pkgs])
576+
where
577+
projectName = case projectFile of
578+
Flag "" -> Nothing
579+
Flag n -> Just $ quotes (text n)
580+
_ -> Nothing
581+
pickComponent = text "pick a single [package:][ctype:]component as target for the REPL command."
582+
583+
validatedTargets
584+
:: Verbosity
585+
-> ReplFlags
586+
-> ProjectConfigShared
587+
-> Compiler
588+
-> ElaboratedInstallPlan
589+
-> [TargetSelector]
590+
-> IO TargetsMap
591+
validatedTargets verbosity replFlags ctx compiler elaboratedPlan targetSelectors = do
592+
let multi_repl_enabled = multiReplDecision ctx compiler replFlags
593+
-- Interpret the targets on the command line as repl targets (as opposed to
594+
-- say build or haddock targets).
595+
targets <-
596+
either (reportTargetProblems verbosity) return $
597+
resolveTargetsFromSolver
598+
(selectPackageTargets multi_repl_enabled)
599+
selectComponentTarget
600+
elaboratedPlan
601+
Nothing
602+
targetSelectors
603+
604+
-- Reject multiple targets, or at least targets in different components. It is
605+
-- ok to have two module/file targets in the same component, but not two that
606+
-- live in different components.
607+
when (Set.size (distinctTargetComponents targets) > 1 && not (useMultiRepl multi_repl_enabled)) $
608+
reportTargetProblems
609+
verbosity
610+
[multipleTargetsProblem multi_repl_enabled targets]
611+
612+
return targets
613+
598614
-- | First version of GHC which supports multiple home packages
599615
minMultipleHomeUnitsVersion :: Version
600616
minMultipleHomeUnitsVersion = mkVersion [9, 4]
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
# cabal clean
22
# cabal v2-repl
3-
Configuration is affected by the following files:
4-
- alt.project
5-
Resolving dependencies...
6-
Build profile: -w ghc-<GHCVER> -O1
7-
In order, the following will be built:
8-
- alt-0.1 (interactive) (lib) (first run)
9-
Configuring library for alt-0.1...
10-
Preprocessing library for alt-0.1...
3+
Error: [Cabal-7076]
4+
Please pick a single [package:][ctype:]component as target for the REPL command. The packages in 'alt.project' from which to select a component target are:
5+
- alt
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
# cabal clean
22
# cabal v2-repl
3-
Configuration is affected by the following files:
4-
- alt.project
5-
Resolving dependencies...
6-
Build profile: -w ghc-<GHCVER> -O1
7-
In order, the following will be built:
8-
- alt-0.1 (interactive) (lib) (first run)
9-
Configuring library for alt-0.1...
10-
Preprocessing library for alt-0.1...
3+
Error: [Cabal-7076]
4+
Please pick a single [package:][ctype:]component as target for the REPL command. The packages in 'alt.project' from which to select a component target are:
5+
- alt

cabal-testsuite/PackageTests/ReplOptions/cabal.test.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ main = do
1313
cabalTest' "alt-single-repl-options" $ do
1414
cabal' "clean" []
1515
-- Can we 'cabal repl' without a target when the project has a single package?
16-
void $ cabalWithStdin "v2-repl" (altProject singleOpts) ":set"
16+
void . fails $ cabalWithStdin "v2-repl" (altProject singleOpts) ":set"
1717

1818
cabalTest' "multiple-repl-options" $ do
1919
cabal' "clean" []
@@ -25,7 +25,7 @@ main = do
2525
cabalTest' "alt-multiple-repl-options" $ do
2626
cabal' "clean" []
2727
-- Can we 'cabal repl' without a target when the project has a single package?
28-
void $ cabalWithStdin "v2-repl" (altProject multiOpts) ":set"
28+
void . fails $ cabalWithStdin "v2-repl" (altProject multiOpts) ":set"
2929

3030
cabalTest' "single-repl-options-multiple-flags" $ do
3131
cabal' "clean" []
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# checking repl command with a missing project
2+
# cabal repl
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Test.Cabal.Prelude
2+
3+
main = cabalTest . recordMode RecordMarked $ do
4+
let log = recordHeader . pure
5+
6+
-- Triggers "Assertion failed"
7+
-- log "checking repl command with no project and --ignore-project"
8+
-- _ <- fails $ cabal' "repl" ["--ignore-project"]
9+
10+
-- Triggers "Assertion failed"
11+
-- log "checking repl command with no project and no project options"
12+
-- _ <- fails $ cabal' "repl" []
13+
14+
log "checking repl command with a missing project"
15+
missing <- fails $ cabal' "repl" [ "--project-file=missing.project" ]
16+
assertOutputContains "The given project file 'missing.project' does not exist." missing
17+
18+
return ()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: pkg-one
2+
version: 0.1
3+
license: BSD3
4+
cabal-version: >= 1.2
5+
build-type: Simple
6+
7+
library
8+
exposed-modules: Foo
9+
build-depends: base
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: pkg-one
2+
version: 0.1
3+
license: BSD3
4+
cabal-version: >= 1.2
5+
build-type: Simple
6+
7+
library
8+
exposed-modules: Foo
9+
build-depends: base
Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
1-
# checking repl command with a project using an implicit default 'cabal.project'
1+
# checking repl command with a 'cabal.project' and no project options
22
# cabal repl
3-
Configuration is affected by the following files:
4-
- cabal.project
53
Error: [Cabal-7076]
6-
With a project, the REPL command requires a single target. The packages in this project are:
4+
Please pick a single [package:][ctype:]component as target for the REPL command. The packages from which to select a component in 'cabal.project', the implicit default as if `--project-file=cabal.project` was added as a command option, are:
75
- pkg-one
86
- pkg-two
9-
# checking repl command with a project using an explicit 'cabal.project'
7+
# checking repl command using an explicit 'some.project'
108
# cabal repl
11-
Configuration is affected by the following files:
12-
- some.project
139
Error: [Cabal-7076]
14-
With a project, the REPL command requires a single target. The packages in this project, 'some.project', are:
10+
Please pick a single [package:][ctype:]component as target for the REPL command. The packages in 'some.project' from which to select a component target are:
1511
- pkg-one
1612
- pkg-two
17-
# checking repl command with a project listing packages in reverse order
13+
# checking repl command using an explicit 'reverse.project', listing packages in reverse order
1814
# cabal repl
19-
Configuration is affected by the following files:
20-
- reverse.project
2115
Error: [Cabal-7076]
22-
With a project, the REPL command requires a single target. The packages in this project, 'reverse.project', are:
16+
Please pick a single [package:][ctype:]component as target for the REPL command. The packages in 'reverse.project' from which to select a component target are:
2317
- pkg-one
2418
- pkg-two
25-
# checking repl command with a project with no packages
19+
# checking repl command with an 'empty.project' with no packages
2620
# cabal repl
27-
Configuration is affected by the following files:
28-
- empty.project
2921
Warning: There are no packages or optional-packages in the project
3022
Error: [Cabal-7076]
31-
With a project, the REPL command requires a single target but there are no packages in this project, 'empty.project', to choose a package (library) or other component from as the target for this command.
32-
# checking repl command with a missing project
23+
There are no packages in 'empty.project'. Please add a package to the project and pick a single [package:][ctype:]component as target for the REPL command.
24+
# checking repl command with a missing 'missing.project'
25+
# cabal repl
26+
# checking repl command with a missing 'missing.project'
3327
# cabal repl

0 commit comments

Comments
 (0)