6
6
module Hedgehog.Extras.Test.Process
7
7
( createProcess
8
8
, exec
9
+ , execAny
9
10
, exec_
10
11
, execFlex
11
12
, execFlex'
13
+ , execFlexAny'
12
14
, procFlex
13
15
, binFlex
14
16
@@ -43,7 +45,7 @@ import Hedgehog (MonadTest)
43
45
import Hedgehog.Extras.Internal.Cli (argQuote )
44
46
import Hedgehog.Extras.Internal.Plan (Component (.. ), Plan (.. ))
45
47
import Hedgehog.Extras.Stock.IO.Process (TimedOut (.. ))
46
- import Prelude (error )
48
+ import Prelude (error , (++) )
47
49
import System.Exit (ExitCode )
48
50
import System.FilePath (takeDirectory )
49
51
import System.FilePath.Posix ((</>) )
@@ -164,27 +166,36 @@ execFlex'
164
166
-> [String ]
165
167
-> m String
166
168
execFlex' execConfig pkgBin envBin arguments = GHC. withFrozenCallStack $ do
167
- cp <- procFlex' execConfig pkgBin envBin arguments
168
- H. annotate . (" Command: " <> ) $ case IO. cmdspec cp of
169
- IO. ShellCommand cmd -> cmd
170
- IO. RawCommand cmd args -> cmd <> " " <> L. unwords args
171
- (exitResult, stdout, stderr) <- H. evalIO $ IO. readCreateProcessWithExitCode cp " "
169
+ (exitResult, stdout, stderr) <- execFlexAny' execConfig pkgBin envBin arguments
172
170
case exitResult of
173
171
IO. ExitFailure exitCode -> do
174
172
H. annotate $ L. unlines $
175
- [ " Process exited with non-zero exit-code"
173
+ [ " Process exited with non-zero exit-code: " ++ show @ Int exitCode
176
174
, " ━━━━ command ━━━━"
177
175
, pkgBin <> " " <> L. unwords (fmap argQuote arguments)
178
- , " ━━━━ stdout ━━━━"
179
- , stdout
180
- , " ━━━━ stderr ━━━━"
181
- , stderr
182
- , " ━━━━ exit code ━━━━"
183
- , show @ Int exitCode
184
176
]
177
+ ++ if L. null stdout then [] else [" ━━━━ stdout ━━━━" , stdout]
178
+ ++ if L. null stderr then [] else [" ━━━━ stderr ━━━━" , stderr]
185
179
H. failMessage GHC. callStack " Execute process failed"
186
180
IO. ExitSuccess -> return stdout
187
181
182
+ -- | Run a process, returning its exit code, its stdout, and its stderr.
183
+ -- Contrary to @execFlex'@, this function doesn't fail if the call fails.
184
+ -- So, if you want to test something negative, this is the function to use.
185
+ execFlexAny'
186
+ :: (MonadTest m , MonadCatch m , MonadIO m , HasCallStack )
187
+ => ExecConfig
188
+ -> String -- ^ @pkgBin@: name of the binary to launch via 'cabal exec'
189
+ -> String -- ^ @envBin@: environment variable defining the binary to launch the process, when in Nix
190
+ -> [String ]
191
+ -> m (ExitCode , String , String ) -- ^ exit code, stdout, stderr
192
+ execFlexAny' execConfig pkgBin envBin arguments = GHC. withFrozenCallStack $ do
193
+ cp <- procFlex' execConfig pkgBin envBin arguments
194
+ H. annotate . (" Command: " <> ) $ case IO. cmdspec cp of
195
+ IO. ShellCommand cmd -> cmd
196
+ IO. RawCommand cmd args -> cmd <> " " <> L. unwords args
197
+ H. evalIO $ IO. readCreateProcessWithExitCode cp " "
198
+
188
199
-- | Execute a process, returning '()'.
189
200
exec_
190
201
:: (MonadTest m , MonadIO m , HasCallStack )
@@ -194,34 +205,42 @@ exec_
194
205
-> m ()
195
206
exec_ execConfig bin arguments = void $ exec execConfig bin arguments
196
207
197
- -- | Execute a process
208
+ -- | Execute a process, returning the stdout. Fail if the call returns
209
+ -- with a non-zero exit code. For a version that doesn't fail upon receiving
210
+ -- a non-zero exit code, see 'execAny'.
198
211
exec
199
212
:: (MonadTest m , MonadIO m , HasCallStack )
200
213
=> ExecConfig
201
214
-> String
202
215
-> [String ]
203
216
-> m String
204
217
exec execConfig bin arguments = GHC. withFrozenCallStack $ do
205
- let cp = (IO. proc bin arguments)
206
- { IO. env = getLast $ execConfigEnv execConfig
207
- , IO. cwd = getLast $ execConfigCwd execConfig
208
- }
209
- H. annotate . (" Command: " <> ) $ bin <> " " <> L. unwords arguments
210
- (exitResult, stdout, stderr) <- H. evalIO $ IO. readCreateProcessWithExitCode cp " "
218
+ (exitResult, stdout, stderr) <- execAny execConfig bin arguments
211
219
case exitResult of
212
220
IO. ExitFailure exitCode -> H. failMessage GHC. callStack . L. unlines $
213
- [ " Process exited with non-zero exit-code"
221
+ [ " Process exited with non-zero exit-code: " ++ show @ Int exitCode
214
222
, " ━━━━ command ━━━━"
215
223
, bin <> " " <> L. unwords (fmap argQuote arguments)
216
- , " ━━━━ stdout ━━━━"
217
- , stdout
218
- , " ━━━━ stderr ━━━━"
219
- , stderr
220
- , " ━━━━ exit code ━━━━"
221
- , show @ Int exitCode
222
224
]
225
+ ++ if L. null stdout then [] else [" ━━━━ stdout ━━━━" , stdout]
226
+ ++ if L. null stderr then [] else [" ━━━━ stderr ━━━━" , stderr]
223
227
IO. ExitSuccess -> return stdout
224
228
229
+ -- | Execute a process, returning the error code, the stdout, and the stderr.
230
+ execAny
231
+ :: (MonadTest m , MonadIO m , HasCallStack )
232
+ => ExecConfig
233
+ -> String -- ^ The binary to launch
234
+ -> [String ] -- ^ The binary's arguments
235
+ -> m (ExitCode , String , String ) -- ^ exit code, stdout, stderr
236
+ execAny execConfig bin arguments = GHC. withFrozenCallStack $ do
237
+ let cp = (IO. proc bin arguments)
238
+ { IO. env = getLast $ execConfigEnv execConfig
239
+ , IO. cwd = getLast $ execConfigCwd execConfig
240
+ }
241
+ H. annotate . (" Command: " <> ) $ bin <> " " <> L. unwords arguments
242
+ H. evalIO $ IO. readCreateProcessWithExitCode cp " "
243
+
225
244
-- | Wait for process to exit.
226
245
waitForProcess
227
246
:: (MonadTest m , MonadIO m , HasCallStack )
0 commit comments