Skip to content

add --shell option #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,24 @@ ghci:

# TEST

test: testunix testexamples
test: testunix testexamples testbash

# run cross-platform and unix-specific shell tests with default shelltest build
testunix: build
$(SHELLTEST) tests -x /examples -x .windows -w $(DEFAULTEXE)
$(SHELLTEST) tests -x /bash -x /examples -x .windows -w $(DEFAULTEXE)

# run cross-platform and windows-specific shell tests
# (though if you are running make on windows, you may be able to, or have to, use testunix)
testwindows:
$(SHELLTEST) tests -x /examples -x .unix -w $(DEFAULTEXE)
$(SHELLTEST) tests -x /bash -x /examples -x .unix -w $(DEFAULTEXE)

testexamples: build
$(SHELLTEST) tests/examples

testbash: build
! $(SHELLTEST) tests/bash
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@obfusk, what is this syntax ? (!)

Although make testbash passes its test, make then exits with an error, which we don't want.

What's the purpose of tests/bash again ? This is a place to put tests which test bash-specific things, and in theory should be run only with bash I guess.

What is dollar-quote.test for.. is it #15 ? Perhaps worth adding the issue number and a one line description of what's being tested, to the test file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From man bash: "If the reserved word ! precedes a pipeline, the exit status of that pipeline is the logical negation of the exit status".
The dollar-quote.test is indeed for #15. I'm running it both without bash (expecting it to fail) and with bash (expecting it to succeed).
The test that's expected to fail indeed shows an error in the output, but because its exit status is negated, the make test command as a whole succeeds.

$(SHELLTEST) tests/bash --shell /bin/bash

# run shell tests with several ghc versions
# test-with-resolvers: build-with-resolvers $(foreach r,$(RESOLVERS),test-with-resolver-$r)

Expand Down
26 changes: 15 additions & 11 deletions src/shelltest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import System.FilePath (takeDirectory)
import System.FilePath.Find (findWithHandler, (==?), always)
import qualified System.FilePath.Find as Find (extension)
import System.IO (Handle, hGetContents, hPutStr)
import System.Process (StdStream (CreatePipe), shell, createProcess, CreateProcess (..), waitForProcess, ProcessHandle)
import System.Process (StdStream (CreatePipe), shell, proc, createProcess, CreateProcess (..), waitForProcess, ProcessHandle)
import Test.Framework (defaultMainWithArgs)
import Test.Framework.Providers.HUnit (hUnitTestToTests)
import Test.HUnit
Expand Down Expand Up @@ -62,6 +62,7 @@ data Args = Args {
,with :: String
,timeout :: Int
,threads :: Int
,shell_cmd :: Maybe FilePath
,debug :: Bool
,debug_parse :: Bool
,testpaths :: [FilePath]
Expand All @@ -83,6 +84,7 @@ argdefs = Args {
,with = def &= typ "EXE" &= help "Replace the first word of test commands with EXE (unindented commands only)"
,timeout = def &= name "o" &= typ "SECS" &= help "Number of seconds a test may run (default: no limit)"
,threads = def &= name "j" &= typ "N" &= help "Number of threads for running tests (default: 1)"
,shell_cmd = def &= explicit &= name "shell" &= typ "EXE" &= help "The shell program to use (must accept -c CMD; default: /bin/sh on POSIX, cmd.exe on Windows)"
,debug = def &= help "Show debug info while running"
,debug_parse = def &= help "Show test file parsing results and stop"
,testpaths = def &= args &= typ "TESTFILES|TESTDIRS"
Expand Down Expand Up @@ -165,7 +167,7 @@ shellTestToHUnitTest args ShellTest{testname=n,command=c,stdin=i,stdoutExpected=
trim' = if all_ args then id else trim
when (debug args) $ do
printf "actual command was: %s\n" (show cmd)
(o_actual, e_actual, x_actual) <- runCommandWithInput dir cmd i
(o_actual, e_actual, x_actual) <- runCommandWithInput (shell_cmd args) dir cmd i
when (debug args) $ do
printf "actual stdout was : %s\n" (show $ trim' o_actual)
printf "actual stderr was : %s\n" (show $ trim' e_actual)
Expand Down Expand Up @@ -193,10 +195,10 @@ shellTestToHUnitTest args ShellTest{testname=n,command=c,stdin=i,stdoutExpected=
-- | Run a shell command line, passing it standard input if provided,
-- and return the standard output, standard error output and exit code.
-- Note on unix, at least with ghc 6.12, command (and filepath) are assumed to be utf8-encoded.
runCommandWithInput :: Maybe FilePath -> String -> Maybe String -> IO (String, String, Int)
runCommandWithInput wd cmd input = do
runCommandWithInput :: Maybe FilePath -> Maybe FilePath -> String -> Maybe String -> IO (String, String, Int)
runCommandWithInput sh wd cmd input = do
-- this has to be done carefully
(ih,oh,eh,ph) <- runInteractiveCommandInDir wd cmd
(ih,oh,eh,ph) <- runInteractiveCommandInDir sh wd cmd
when (isJust input) $ forkIO (hPutStr ih $ fromJust input) >> return ()
o <- newEmptyMVar
e <- newEmptyMVar
Expand All @@ -207,16 +209,18 @@ runCommandWithInput wd cmd input = do
e_actual <- takeMVar e
return (o_actual, e_actual, x_actual)

runInteractiveCommandInDir :: Maybe FilePath -> String -> IO (Handle, Handle, Handle, ProcessHandle)
runInteractiveCommandInDir wd cmd = do
runInteractiveCommandInDir :: Maybe FilePath -> Maybe FilePath -> String -> IO (Handle, Handle, Handle, ProcessHandle)
runInteractiveCommandInDir sh wd cmd = do
(mb_in, mb_out, mb_err, p) <-
createProcess $
(shell cmd) { cwd = wd
, std_in = CreatePipe
, std_out = CreatePipe
, std_err = CreatePipe }
run { cwd = wd
, std_in = CreatePipe
, std_out = CreatePipe
, std_err = CreatePipe }
-- these should all be Just since we used CreatePipe
return (fromJust mb_in, fromJust mb_out, fromJust mb_err, p)
where
run = maybe (shell cmd) (\shcmd -> proc shcmd ["-c", cmd]) sh

hGetContentsStrictlyAnd :: Handle -> (String -> IO b) -> IO b
hGetContentsStrictlyAnd h f = hGetContents h >>= \s -> length s `seq` f s
Expand Down
4 changes: 4 additions & 0 deletions tests/bash/dollar-quote.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
echo $'\'o\' `elem` p'
>>>
'o' `elem` p
>>>= 0