2 {-# LANGUAGE ScopedTypeVariables #-}
5 module Test
.Cabal
.Monad
(
6 -- * High-level runners
18 hackageRepoToolProgram
,
26 -- * The test environment
32 -- * Derived values from 'TestEnv'
44 testUserCabalConfigFile
,
50 -- * Known broken tests
53 -- whenHasSharedLibraries,
54 -- * Arguments (TODO: move me)
58 -- * Version Constants
62 import Test
.Cabal
.Script
63 import Test
.Cabal
.Plan
64 import Test
.Cabal
.OutputNormalizer
65 import Test
.Cabal
.TestCode
67 import Distribution
.Pretty
(prettyShow
)
68 import Distribution
.Simple
.Compiler
69 ( PackageDBStack
, PackageDB
(..), compilerFlavor
70 , Compiler
, compilerVersion
, showCompilerIdWithAbi
)
71 import Distribution
.System
72 import Distribution
.Simple
.Program
.Db
73 import Distribution
.Simple
.Program
74 import Distribution
.Simple
.Configure
76 import qualified Distribution
.Simple
.Utils
as U
(cabalVersion
)
77 import Distribution
.Text
79 import Test
.Utils
.TempTestDir
(removeDirectoryRecursiveHack
)
80 import Distribution
.Verbosity
81 import Distribution
.Version
83 #if !MIN_VERSION_base
(4,11,0)
84 import Data
.Monoid
((<>))
86 import Data
.Monoid
(mempty
)
87 import qualified Control
.Exception
as E
89 import Control
.Monad
.Trans
.Reader
90 import Control
.Monad
.IO.Class
92 import Control
.Applicative
93 import System
.Directory
95 import System
.FilePath
97 import System
.IO.Error
(isDoesNotExistError)
98 import Distribution
.Simple
.Utils
hiding (info
)
99 import System
.Process
hiding (env
)
100 import Options
.Applicative
101 import Test
.Cabal
.Run
102 import qualified Data
.ByteString
.Char8
as C
106 data CommonArgs
= CommonArgs
{
107 argCabalInstallPath
:: Maybe FilePath,
108 argGhcPath
:: Maybe FilePath,
109 argHackageRepoToolPath
:: Maybe FilePath,
110 argHaddockPath
:: Maybe FilePath,
111 argKeepTmpFiles
:: Bool,
113 argSkipSetupTests
:: Bool
116 commonArgParser
:: Parser CommonArgs
117 commonArgParser
= CommonArgs
118 <$> optional
(option str
119 ( help
"Path to cabal-install executable to test. If omitted, tests involving cabal-install are skipped!"
123 <*> optional
(option str
124 ( help
"GHC to ask Cabal to use via --with-ghc flag"
129 <*> optional
(option str
130 ( help
"Path to hackage-repo-tool to use for repository manipulation"
131 <> long
"with-hackage-repo-tool"
134 <*> optional
(option str
135 ( help
"Path to haddock to use for --with-haddock flag"
136 <> long
"with-haddock"
140 ( long
"keep-tmp-files"
141 <> help
"Keep temporary files"
145 <> help
"Accept output"
147 <*> switch
(long
"skip-setup-tests" <> help
"Skip setup tests")
149 renderCommonArgs
:: CommonArgs
-> [String]
150 renderCommonArgs args
=
151 maybe [] (\x
-> ["--with-cabal", x
]) (argCabalInstallPath args
) ++
152 maybe [] (\x
-> ["--with-ghc", x
]) (argGhcPath args
) ++
153 maybe [] (\x
-> ["--with-haddock", x
]) (argHaddockPath args
) ++
154 maybe [] (\x
-> ["--with-hackage-repo-tool", x
]) (argHackageRepoToolPath args
) ++
155 (if argAccept args
then ["--accept"] else []) ++
156 (if argKeepTmpFiles args
then ["--keep-tmp-files"] else []) ++
157 (if argSkipSetupTests args
then ["--skip-setup-tests"] else [])
159 data TestArgs
= TestArgs
{
160 testArgDistDir
:: FilePath,
161 testArgPackageDb
:: [FilePath],
162 testArgScriptPath
:: FilePath,
163 testCommonArgs
:: CommonArgs
166 testArgParser
:: Parser TestArgs
167 testArgParser
= TestArgs
169 ( help
"Build directory of cabal-testsuite"
173 ( help
"Package DB which contains Cabal and Cabal-syntax"
174 <> long
"extra-package-db"
176 <*> argument str
( metavar
"FILE")
179 skip
:: String -> TestM
()
180 skip reason
= liftIO
$ do
181 putStrLn ("SKIP " ++ reason
)
182 E
.throwIO
(TestCodeSkip reason
)
184 skipIf
:: String -> Bool -> TestM
()
185 skipIf reason b
= when b
(skip reason
)
187 skipUnless
:: String -> Bool -> TestM
()
188 skipUnless reason b
= unless b
(skip reason
)
190 expectedBroken
:: TestM
()
191 expectedBroken
= liftIO
$ do
192 putStrLn "EXPECTED FAIL"
193 E
.throwIO TestCodeKnownFail
195 unexpectedSuccess
:: TestM
()
196 unexpectedSuccess
= liftIO
$ do
197 putStrLn "UNEXPECTED OK"
198 E
.throwIO TestCodeUnexpectedOk
201 trySkip
:: IO a
-> IO (Either String a
)
202 trySkip m
= fmap Right m `E
.catch`
\e
-> case e
of
203 TestCodeSkip msg
-> return (Left msg
)
206 setupAndCabalTest
:: TestM
() -> IO ()
207 setupAndCabalTest m
= do
208 r1
<- trySkip
(setupTest m
)
209 r2
<- trySkip
(cabalTest
' "cabal" m
)
211 (Left msg1
, Left msg2
) -> E
.throwIO
(TestCodeSkip
(msg1
++ "; " ++ msg2
))
214 setupTest
:: TestM
() -> IO ()
215 setupTest m
= runTestM
"" $ do
217 skipIf
"setup test" (testSkipSetupTests env
)
220 cabalTest
:: TestM
() -> IO ()
221 cabalTest
= cabalTest
' ""
223 cabalTest
' :: String -> TestM
() -> IO ()
224 cabalTest
' mode m
= runTestM mode
$ do
225 skipUnless
"no cabal-install" =<< isAvailableProgram cabalProgram
226 withReaderT
(\nenv
-> nenv
{ testCabalInstallAsSetup
= True }) m
228 type TestM
= ReaderT TestEnv
IO
230 gitProgram
:: Program
231 gitProgram
= simpleProgram
"git"
233 hackageRepoToolProgram
:: Program
234 hackageRepoToolProgram
= simpleProgram
"hackage-repo-tool"
236 cabalProgram
:: Program
237 cabalProgram
= (simpleProgram
"cabal") {
238 -- Do NOT search for executable named cabal, it's probably
239 -- not the one you were intending to test
240 programFindLocation
= \_ _
-> return Nothing
243 diffProgram
:: Program
244 diffProgram
= simpleProgram
"diff"
246 python3Program
:: Program
247 python3Program
= simpleProgram
"python3"
249 -- | Run a test in the test monad according to program's arguments.
250 runTestM
:: String -> TestM a
-> IO a
252 liftIO
$ (canonicalizePath
=<< getTemporaryDirectory
) >>= \systemTmpDir
->
253 -- canonicalizePath: cabal-install is inconsistent w.r.t. looking through
254 -- symlinks. We canonicalize here to avoid such issues when the temporary
255 -- directory contains symlinks. See #9763.
256 execParser
(info testArgParser Data
.Monoid
.mempty
) >>= \args
->
257 withTempDirectoryEx verbosity
(defaultTempFileOptions
{ optKeepTempFiles
= argKeepTmpFiles
(testCommonArgs args
) })
259 "cabal-testsuite" $ \tmp_dir
-> do
260 let dist_dir
= testArgDistDir args
261 (script_dir0
, script_filename
) = splitFileName
(testArgScriptPath args
)
263 stripped
= stripExtension
".test.hs" script_filename
264 <|
> stripExtension
".multitest.hs" script_filename
265 script_base
= fromMaybe (dropExtensions script_filename
) stripped
267 -- Canonicalize this so that it is stable across working directory changes
268 script_dir
<- canonicalizePath script_dir0
269 senv
<- mkScriptEnv verbosity
270 -- Add test suite specific programs
273 ([gitProgram
, hackageRepoToolProgram
, cabalProgram
, diffProgram
, python3Program
] ++ builtinPrograms
)
274 (runnerProgramDb senv
)
275 -- Reconfigure according to user flags
276 let cargs
= testCommonArgs args
279 (comp
, platform
, program_db2
) <- case argGhcPath cargs
of
280 Nothing
-> return (runnerCompiler senv
, runnerPlatform senv
, program_db0
)
282 -- All the things that get updated paths from
283 -- configCompilerEx. The point is to make sure
284 -- we reconfigure these when we need them.
285 let program_db1
= unconfigureProgram
"ghc"
286 . unconfigureProgram
"ghc-pkg"
287 . unconfigureProgram
"hsc2hs"
288 . unconfigureProgram
"haddock"
289 . unconfigureProgram
"hpc"
290 . unconfigureProgram
"runghc"
291 . unconfigureProgram
"gcc"
292 . unconfigureProgram
"ld"
293 . unconfigureProgram
"ar"
294 . unconfigureProgram
"strip"
296 -- TODO: this actually leaves a pile of things unconfigured.
297 -- Optimal strategy for us is to lazily configure them, so
298 -- we don't pay for things we don't need. A bit difficult
299 -- to do in the current design.
301 (Just
(compilerFlavor
(runnerCompiler senv
)))
307 (configuredGhcProg
, _
) <- requireProgram verbosity ghcProgram program_db2
310 reconfigurePrograms verbosity
311 ([("cabal", p
) | p
<- maybeToList (argCabalInstallPath cargs
)] ++
312 [("hackage-repo-tool", p
)
313 | p
<- maybeToList (argHackageRepoToolPath cargs
)] ++
314 [("haddock", p
) | p
<- maybeToList (argHaddockPath cargs
)])
315 [] -- --prog-options not supported ATM
317 -- configCompilerEx only marks some programs as known, so to pick
318 -- them up we must configure them
319 program_db
<- configureAllKnownPrograms verbosity program_db3
321 let db_stack
= [GlobalPackageDB
]
323 testSourceDir
= script_dir
,
324 testTmpDir
= tmp_dir
,
325 testSubName
= script_base
,
327 testProgramDb
= program_db
,
328 testPlatform
= platform
,
330 testCompilerPath
= programPath configuredGhcProg
,
331 testPackageDBStack
= db_stack
,
332 testVerbosity
= verbosity
,
333 testMtimeChangeDelay
= Nothing
,
334 testScriptEnv
= senv
,
335 testSetupPath
= dist_dir
</> "build" </> "setup" </> "setup",
336 testPackageDbPath
= case testArgPackageDb args
of [] -> Nothing
; xs
-> Just xs
,
337 testSkipSetupTests
= argSkipSetupTests
(testCommonArgs args
),
338 testHaveCabalShared
= runnerWithSharedLib senv
,
340 -- Try to avoid Unicode output
341 [ ("LC_ALL", Just
"C")
342 -- Hermetic builds (knot-tied)
343 , ("HOME", Just
(testHomeDir env
))
344 -- Set CABAL_DIR in addition to HOME, since HOME has no
345 -- effect on Windows.
346 , ("CABAL_DIR", Just
(testCabalDir env
))
347 , ("CABAL_CONFIG", Just
(testUserCabalConfigFile env
))
349 testShouldFail
= False,
350 testRelativeCurrentDir
= ".",
351 testHavePackageDb
= False,
352 testHaveRepo
= False,
353 testCabalInstallAsSetup
= False,
354 testCabalProjectFile
= Nothing
,
356 testRecordDefaultMode
= DoNotRecord
,
357 testRecordUserMode
= Nothing
,
358 testMaybeStoreDir
= Nothing
361 r
<- withSourceCopy m
362 check_expect
(argAccept
(testCommonArgs args
))
366 verbosity
= normal
-- TODO: configurable
370 onlyIfExists
. removeDirectoryRecursiveHack verbosity
$ testWorkDir env
371 -- NB: it's important to initialize this ourselves, as
372 -- the default configuration hardcodes Hackage, which we do
373 -- NOT want to assume for these tests (no test should
375 liftIO
$ createDirectoryIfMissing
True (testCabalDir env
)
376 ghc_path
<- programPathM ghcProgram
377 liftIO
$ writeFile (testUserCabalConfigFile env
)
378 $ unlines [ "with-compiler: " ++ ghc_path
]
380 check_expect accept
= do
382 actual_raw
<- liftIO
$ readFileOrEmpty
(testActualFile env
)
383 expect
<- liftIO
$ readFileOrEmpty
(testExpectFile env
)
384 norm_env
<- mkNormalizerEnv
385 let actual
= normalizeOutput norm_env actual_raw
386 when (words actual
/= words expect
) $ do
387 -- First try whitespace insensitive diff
388 let actual_fp
= testNormalizedActualFile env
389 expect_fp
= testNormalizedExpectFile env
390 liftIO
$ writeFile actual_fp actual
391 liftIO
$ writeFile expect_fp expect
392 liftIO
$ putStrLn "Actual output differs from expected:"
393 b
<- diff
["-uw"] expect_fp actual_fp
394 unless b
. void
$ diff
["-u"] expect_fp actual_fp
396 then do liftIO
$ putStrLn "Accepting new output."
397 liftIO
$ writeFileNoCR
(testExpectFile env
) actual
398 else liftIO
$ exitWith (ExitFailure
1)
400 readFileOrEmpty
:: FilePath -> IO String
401 readFileOrEmpty f
= readFile f `E
.catch`
\e
->
402 if isDoesNotExistError e
406 -- | Run an IO action, and suppress a "does not exist" error.
407 onlyIfExists
:: MonadIO m
=> IO () -> m
()
409 liftIO
$ E
.catch m
$ \(e
:: IOError) ->
410 unless (isDoesNotExistError e
) $ E
.throwIO e
412 -- | Make a hermetic copy of the test directory.
414 -- This requires the test repository to be a Git checkout, because
415 -- we use the Git metadata to figure out what files to copy into the
417 withSourceCopy
:: TestM a
-> TestM a
418 withSourceCopy m
= do
421 let curdir
= testSourceDir env
422 dest
= testSourceCopyDir env
425 (error (unlines [ "withSourceCopy: No files to copy from " ++ curdir
426 , "You need to \"git add\" any files before they are copied by the testsuite."]))
428 unless (isTestFile f
) $ liftIO
$ do
429 putStrLn ("Copying " ++ (curdir
</> f
) ++ " to " ++ (dest
</> f
))
430 createDirectoryIfMissing
True (takeDirectory
(dest
</> f
))
431 d
<- liftIO
$ doesDirectoryExist (curdir
</> f
)
434 copyDirectoryRecursive normal
(curdir
</> f
) (dest
</> f
)
436 copyFile
(curdir
</> f
) (dest
</> f
)
440 -- NB: Keep this synchronized with partitionTests
441 isTestFile
:: FilePath -> Bool
443 case takeExtensions f
of
445 ".multitest.hs" -> True
449 initWorkDir
:: TestM
()
452 liftIO
$ createDirectoryIfMissing
True (testWorkDir env
)
456 getSourceFiles
:: TestM
[FilePath]
459 configured_prog
<- requireProgramM gitProgram
460 r
<- liftIO
$ run
(testVerbosity env
)
461 (Just
$ testSourceDir env
)
462 (testEnvironment env
)
463 (programPath configured_prog
)
464 ["ls-files", "--cached", "--modified"]
467 _
<- requireSuccess r
468 return (lines $ resultOutput r
)
470 recordLog
:: Result
-> TestM
()
473 let mode
= testRecordMode env
475 liftIO
$ C
.appendFile (testWorkDir env
</> "test.log")
476 (C
.pack
$ "+ " ++ resultCommand res
++ "\n"
477 ++ resultOutput res
++ "\n\n")
478 liftIO
. C
.appendFile (testActualFile env
) . C
.pack
$
480 RecordAll
-> unlines (lines (resultOutput res
))
481 RecordMarked
-> getMarkedOutput
(resultOutput res
)
484 ------------------------------------------------------------------------
485 -- * Subprocess run results
487 requireSuccess
:: Result
-> TestM Result
488 requireSuccess r
@Result
{ resultCommand
= cmd
489 , resultExitCode
= exitCode
490 , resultOutput
= output
} = withFrozenCallStack
$ do
492 when (exitCode
/= ExitSuccess
&& not (testShouldFail env
)) $
493 assertFailure
$ "Command " ++ cmd
++ " failed.\n" ++
494 "Output:\n" ++ output
++ "\n"
495 when (exitCode
== ExitSuccess
&& testShouldFail env
) $
496 assertFailure
$ "Command " ++ cmd
++ " succeeded.\n" ++
497 "Output:\n" ++ output
++ "\n"
500 assertFailure
:: String -> m
()
501 assertFailure msg
= withFrozenCallStack
$ error msg
505 -- | Runs 'diff' with some arguments on two files, outputting the
506 -- diff to stderr, and returning true if the two files differ
507 diff
:: [String] -> FilePath -> FilePath -> TestM
Bool
508 diff args path1 path2
= do
509 diff_path
<- programPathM diffProgram
510 (_
,_
,_
,h
) <- liftIO
$
511 createProcess
(proc diff_path
(args
++ [path1
, path2
])) {
512 std_out
= UseHandle
stderr
514 r
<- liftIO
$ waitForProcess h
515 return (r
/= ExitSuccess
)
517 -- | Write a file with no CRs, always.
518 writeFileNoCR
:: FilePath -> String -> IO ()
520 withFile f WriteMode
$ \h
-> do
521 hSetNewlineMode h noNewlineTranslation
524 mkNormalizerEnv
:: TestM NormalizerEnv
527 ghc_pkg_program
<- requireProgramM ghcPkgProgram
528 -- Arguably we should use Cabal's APIs but I am too lazy
529 -- to remember what it is
530 list_out
<- liftIO
$ readProcess
(programPath ghc_pkg_program
)
531 ["list", "--global", "--simple-output"] ""
532 tmpDir
<- liftIO
$ getTemporaryDirectory
534 canonicalizedTestTmpDir
<- liftIO
$ canonicalizePath
(testTmpDir env
)
536 -- 'cabal' is configured in the package-db, but doesn't specify how to find the program version
537 -- Thus we find the program location, if it exists, and query for the program version for
538 -- output normalisation.
540 cabalProgM
<- needProgramM
"cabal"
542 Nothing
-> pure Nothing
544 liftIO
(findProgramVersion
"--numeric-version" id (testVerbosity env
) (programPath cabalProg
))
546 return NormalizerEnv
{
548 = addTrailingPathSeparator
(testSourceDir env
),
550 = addTrailingPathSeparator
(testTmpDir env
),
551 normalizerCanonicalTmpDir
552 = addTrailingPathSeparator canonicalizedTestTmpDir
,
554 = addTrailingPathSeparator tmpDir
,
556 = compilerVersion
(testCompiler env
),
558 = testCompilerPath env
,
559 normalizerKnownPackages
560 = mapMaybe simpleParse
(words list_out
),
563 normalizerCabalVersion
564 = cabalVersionLibrary
,
565 normalizerCabalInstallVersion
569 cabalVersionLibrary
:: Version
570 cabalVersionLibrary
= U
.cabalVersion
572 requireProgramM
:: Program
-> TestM ConfiguredProgram
573 requireProgramM program
= do
575 (configured_program
, _
) <- liftIO
$
576 requireProgram
(testVerbosity env
) program
(testProgramDb env
)
577 return configured_program
579 needProgramM
:: String -> TestM
(Maybe ConfiguredProgram
)
580 needProgramM program
= do
582 return $ lookupProgramByName program
(testProgramDb env
)
584 programPathM
:: Program
-> TestM
FilePath
585 programPathM program
= do
586 fmap programPath
(requireProgramM program
)
588 isAvailableProgram
:: Program
-> TestM
Bool
589 isAvailableProgram program
= do
591 case lookupProgram program
(testProgramDb env
) of
592 Just _
-> return True
594 -- It might not have been configured. Try to configure.
595 progdb
<- liftIO
$ configureProgram
(testVerbosity env
) program
(testProgramDb env
)
596 case lookupProgram program progdb
of
597 Just _
-> return True
598 Nothing
-> return False
601 getMarkedOutput
:: String -> String -- trailing newline
602 getMarkedOutput out
= unlines (go
(lines out
) False)
606 |
"-----END CABAL OUTPUT-----" `
isPrefixOf` x
608 |
otherwise = x
: go xs
True
610 -- NB: Windows has extra goo at the end
611 |
"-----BEGIN CABAL OUTPUT-----" `
isPrefixOf` x
613 |
otherwise = go xs
False
616 data TestEnv
= TestEnv
620 -- | Path to the test directory, as specified by path to test
622 testSourceDir
:: FilePath
623 -- | Somewhere to stow temporary files needed by the test.
624 , testTmpDir
:: FilePath
626 -- | Test sub-name, used to qualify dist/database directory to avoid
628 , testSubName
:: String
629 -- | Test mode, further qualifies multiple invocations of the
630 -- same test source code.
632 -- | Program database to use when we want ghc, ghc-pkg, etc.
633 , testProgramDb
:: ProgramDb
634 -- | Compiler we are running tests for
635 , testCompiler
:: Compiler
636 , testCompilerPath
:: FilePath
637 -- | Platform we are running tests on
638 , testPlatform
:: Platform
639 -- | Package database stack (actually this changes lol)
640 , testPackageDBStack
:: PackageDBStack
641 -- | How verbose to be
642 , testVerbosity
:: Verbosity
643 -- | How long we should 'threadDelay' to make sure the file timestamp is
644 -- updated correctly for recompilation tests. Nothing if we haven't
646 , testMtimeChangeDelay
:: Maybe Int
647 -- | Script environment for runghc
648 , testScriptEnv
:: ScriptEnv
649 -- | Setup script path
650 , testSetupPath
:: FilePath
651 -- | Setup package-db path which contains Cabal and Cabal-syntax for cabal-install to
652 -- use when compiling custom setups, plus the store with possible dependencies of those setup packages.
653 , testPackageDbPath
:: Maybe [FilePath]
654 -- | Skip Setup tests?
655 , testSkipSetupTests
:: Bool
656 -- | Do we have shared libraries for the Cabal-under-tests?
657 -- This is used for example to determine whether we can build
658 -- detailed-0.9 tests dynamically, since they link against Cabal-under-test.
659 , testHaveCabalShared
:: Bool
663 -- | Environment override
664 , testEnvironment
:: [(String, Maybe String)]
665 -- | When true, we invert the meaning of command execution failure
666 , testShouldFail
:: Bool
667 -- | The current working directory, relative to 'testSourceDir'
668 , testRelativeCurrentDir
:: FilePath
669 -- | Says if we've initialized the per-test package DB
670 , testHavePackageDb
:: Bool
671 -- | Says if we've setup a repository
672 , testHaveRepo
:: Bool
673 -- | Says if we're testing cabal-install as setup
674 , testCabalInstallAsSetup
:: Bool
675 -- | Says what cabal.project file to use (probed)
676 , testCabalProjectFile
:: Maybe FilePath
677 -- | Cached record of the plan metadata from a new-build
678 -- invocation; controlled by 'withPlan'.
679 , testPlan
:: Maybe Plan
680 -- | If user mode is not set, this is the record mode we default to.
681 , testRecordDefaultMode
:: RecordMode
682 -- | User explicitly set record mode. Not implemented ATM.
683 , testRecordUserMode
:: Maybe RecordMode
684 -- | Path to the storedir used by the test, if not the default
685 , testMaybeStoreDir
:: Maybe FilePath
689 testRecordMode
:: TestEnv
-> RecordMode
690 testRecordMode env
= fromMaybe (testRecordDefaultMode env
) (testRecordUserMode env
)
692 data RecordMode
= DoNotRecord | RecordMarked | RecordAll
693 deriving (Show, Eq
, Ord
)
695 getTestEnv
:: TestM TestEnv
698 ------------------------------------------------------------------------
701 -- | The absolute path to the root of the package directory; it's
702 -- where the Cabal file lives. This is what you want the CWD of cabal
704 testCurrentDir
:: TestEnv
-> FilePath
705 testCurrentDir env
= testSourceCopyDir env
</> testRelativeCurrentDir env
707 testName
:: TestEnv
-> String
708 testName env
= testSubName env
<.> testMode env
710 -- | The absolute path to the directory containing all the
711 -- files for ALL tests associated with a test (respecting
712 -- subtests.) To clean, you ONLY need to delete this directory.
713 testWorkDir
:: TestEnv
-> FilePath
714 testWorkDir env
= testTmpDir env
</> (testName env
<.> "dist")
716 -- | The absolute prefix where installs go.
717 testPrefixDir
:: TestEnv
-> FilePath
718 testPrefixDir env
= testWorkDir env
</> "usr"
720 -- | The absolute path where library installs go.
721 testLibInstallDir
:: TestEnv
-> FilePath
722 testLibInstallDir env
= libDir
</> compilerDir
724 platform
@(Platform _ os
) = testPlatform env
726 Windows
-> testPrefixDir env
727 _
-> testPrefixDir env
</> "lib"
728 compilerDir
= prettyShow platform
++ "-" ++ showCompilerIdWithAbi
(testCompiler env
)
730 -- | The absolute path to the build directory that should be used
731 -- for the current package in a test.
732 testDistDir
:: TestEnv
-> FilePath
733 testDistDir env
= testWorkDir env
</> "work" </> testRelativeCurrentDir env
</> "dist"
735 -- | The absolute path to the shared package database that should
736 -- be used by all packages in this test.
737 testPackageDbDir
:: TestEnv
-> FilePath
738 testPackageDbDir env
= testWorkDir env
</> "packagedb"
740 -- | The absolute prefix where our simulated HOME directory is.
741 testHomeDir
:: TestEnv
-> FilePath
742 testHomeDir env
= testWorkDir env
</> "home"
744 -- | The absolute prefix of our local secure repository, which we
745 -- use to simulate "external" packages
746 testRepoDir
:: TestEnv
-> FilePath
747 testRepoDir env
= testWorkDir env
</> "repo"
749 -- | The absolute prefix of keys for the test.
750 testKeysDir
:: TestEnv
-> FilePath
751 testKeysDir env
= testWorkDir env
</> "keys"
753 -- | If 'withSourceCopy' is used, where the source files go.
754 testSourceCopyDir
:: TestEnv
-> FilePath
755 testSourceCopyDir env
= testTmpDir env
757 -- | The user cabal directory
758 testCabalDir
:: TestEnv
-> FilePath
759 testCabalDir env
= testHomeDir env
</> ".cabal"
761 testStoreDir
:: TestEnv
-> FilePath
762 testStoreDir env
= case testMaybeStoreDir env
of
764 Nothing
-> testCabalDir env
</> "store"
766 -- | The user cabal config file
767 testUserCabalConfigFile
:: TestEnv
-> FilePath
768 testUserCabalConfigFile env
= testCabalDir env
</> "config"
770 -- | The file where the expected output of the test lives
771 testExpectFile
:: TestEnv
-> FilePath
772 testExpectFile env
= testSourceDir env
</> testName env
<.> "out"
774 -- | Where we store the actual output
775 testActualFile
:: TestEnv
-> FilePath
776 testActualFile env
= testWorkDir env
</> testName env
<.> "comp.out"
778 -- | Where we will write the normalized actual file (for diffing)
779 testNormalizedActualFile
:: TestEnv
-> FilePath
780 testNormalizedActualFile env
= testActualFile env
<.> "normalized"
782 -- | Where we will write the normalized expected file (for diffing)
783 testNormalizedExpectFile
:: TestEnv
-> FilePath
784 testNormalizedExpectFile env
= testWorkDir env
</> testName env
<.> "out.normalized"