-
Notifications
You must be signed in to change notification settings - Fork 704
/
Copy pathExeV10.hs
193 lines (161 loc) · 6.94 KB
/
ExeV10.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
module Distribution.Simple.Test.ExeV10
( runTest
) where
import Prelude ()
import Distribution.Compat.Prelude
import Distribution.Types.UnqualComponentName
import Distribution.Compat.CreatePipe
import Distribution.Compat.Environment
import qualified Distribution.PackageDescription as PD
import Distribution.Simple.Build.PathsModule
import Distribution.Simple.BuildPaths
import Distribution.Simple.Compiler
import Distribution.Simple.Hpc
import Distribution.Simple.InstallDirs
import qualified Distribution.Simple.LocalBuildInfo as LBI
import qualified Distribution.Types.LocalBuildInfo as LBI
import Distribution.Simple.Setup
import Distribution.Simple.Test.Log
import Distribution.Simple.Utils
import Distribution.System
import Distribution.TestSuite
import Distribution.Pretty
import Distribution.Verbosity
import System.Directory
( createDirectoryIfMissing, doesDirectoryExist, doesFileExist
, getCurrentDirectory, removeDirectoryRecursive )
import System.FilePath ( (</>), (<.>) )
import System.IO ( stdout, stderr )
import qualified Data.ByteString.Lazy as LBS
runTest :: PD.PackageDescription
-> LBI.LocalBuildInfo
-> LBI.ComponentLocalBuildInfo
-> TestFlags
-> PD.TestSuite
-> IO TestSuiteLog
runTest pkg_descr lbi clbi flags suite = do
let isCoverageEnabled = LBI.testCoverage lbi
way = guessWay lbi
tixDir_ = tixDir distPref way testName'
pwd <- getCurrentDirectory
existingEnv <- getEnvironment
let cmd = LBI.buildDir lbi </> testName'
</> testName' <.> exeExtension (LBI.hostPlatform lbi)
-- Check that the test executable exists.
exists <- doesFileExist cmd
unless exists $ die' verbosity $ "Error: Could not find test program \"" ++ cmd
++ "\". Did you build the package first?"
-- Remove old .tix files if appropriate.
unless (fromFlag $ testKeepTix flags) $ do
exists' <- doesDirectoryExist tixDir_
when exists' $ removeDirectoryRecursive tixDir_
-- Create directory for HPC files.
createDirectoryIfMissing True tixDir_
-- Write summary notices indicating start of test suite
notice verbosity $ summarizeSuiteStart $ testName'
-- Run the test executable
let opts = map (testOption pkg_descr lbi suite)
(testOptions flags)
dataDirPath = pwd </> PD.dataDir pkg_descr
tixFile = pwd </> tixFilePath distPref way (testName')
pkgPathEnv = (pkgPathEnvVar pkg_descr "datadir", dataDirPath)
: existingEnv
shellEnv = [("HPCTIXFILE", tixFile) | isCoverageEnabled] ++ pkgPathEnv
-- Add (DY)LD_LIBRARY_PATH if needed
shellEnv' <- if LBI.withDynExe lbi
then do let (Platform _ os) = LBI.hostPlatform lbi
paths <- LBI.depLibraryPaths True False lbi clbi
return (addLibraryPath os paths shellEnv)
else return shellEnv
-- Output logger
(wOut, wErr, getLogText) <- case details of
Direct -> return (stdout, stderr, return LBS.empty)
_ -> do
(rOut, wOut) <- createPipe
return $ (,,) wOut wOut $ do
-- Read test executables' output
logText <- LBS.hGetContents rOut
-- '--show-details=streaming': print the log output in another thread
when (details == Streaming) $ LBS.putStr logText
-- drain the output.
evaluate (force logText)
(exit, logText) <- case testWrapper flags of
Flag path -> rawSystemIOWithEnvAndAction
verbosity path (cmd:opts) Nothing (Just shellEnv')
getLogText
-- these handles are automatically closed
Nothing (Just wOut) (Just wErr)
NoFlag -> rawSystemIOWithEnvAndAction
verbosity cmd opts Nothing (Just shellEnv')
getLogText
-- these handles are automatically closed
Nothing (Just wOut) (Just wErr)
-- Generate TestSuiteLog from executable exit code and a machine-
-- readable test log.
let suiteLog = buildLog exit
-- Write summary notice to log file indicating start of test suite
appendFile (logFile suiteLog) $ summarizeSuiteStart testName'
-- Append contents of temporary log file to the final human-
-- readable log file
LBS.appendFile (logFile suiteLog) logText
-- Write end-of-suite summary notice to log file
appendFile (logFile suiteLog) $ summarizeSuiteFinish suiteLog
-- Show the contents of the human-readable log file on the terminal
-- if there is a failure and/or detailed output is requested
let whenPrinting = when $
( details == Always ||
details == Failures && not (suitePassed $ testLogs suiteLog))
-- verbosity overrides show-details
&& verbosity >= normal
whenPrinting $ do
LBS.putStr logText
putChar '\n'
-- Write summary notice to terminal indicating end of test suite
notice verbosity $ summarizeSuiteFinish suiteLog
when isCoverageEnabled $
case PD.library pkg_descr of
Nothing ->
die' verbosity "Error: test coverage is only supported for packages with a library component"
Just library ->
markupTest verbosity lbi distPref (prettyShow $ PD.package pkg_descr) suite library
return suiteLog
where
testName' = unUnqualComponentName $ PD.testName suite
distPref = fromFlag $ testDistPref flags
verbosity = fromFlag $ testVerbosity flags
details = fromFlag $ testShowDetails flags
testLogDir = distPref </> "test"
buildLog exit =
let r = case exit of
ExitSuccess -> Pass
ExitFailure c -> Fail $ "exit code: " ++ show c
--n = unUnqualComponentName $ PD.testName suite
l = TestLog
{ testName = testName'
, testOptionsReturned = []
, testResult = r
}
in TestSuiteLog
{ testSuiteName = PD.testName suite
, testLogs = l
, logFile =
testLogDir
</> testSuiteLogPath (fromFlag $ testHumanLog flags)
pkg_descr lbi testName' l
}
-- TODO: This is abusing the notion of a 'PathTemplate'. The result isn't
-- necessarily a path.
testOption :: PD.PackageDescription
-> LBI.LocalBuildInfo
-> PD.TestSuite
-> PathTemplate
-> String
testOption pkg_descr lbi suite template =
fromPathTemplate $ substPathTemplate env template
where
env = initialPathTemplateEnv
(PD.package pkg_descr) (LBI.localUnitId lbi)
(compilerInfo $ LBI.compiler lbi) (LBI.hostPlatform lbi) ++
[(TestSuiteNameVar, toPathTemplate $ unUnqualComponentName $ PD.testName suite)]