packages feed

shelltestrunner 0.4 → 0.5

raw patch · 2 files changed

+35/−37 lines, 2 files

Files

shelltestrunner.cabal view
@@ -1,10 +1,10 @@ name:           shelltestrunner-version:        0.4+version:        0.5 category:       Testing synopsis:       A tool for testing command-line programs. description:  .- Run a given program through "shell" tests specifed by one or more test+ Run a given program through \"shell\" tests specifed by one or more test  files, each of which can specify: command-line arguments, input, expected  output, expected stderr output, and expected exit code.  This was  extracted from the hledger project, inspired by the tests in John@@ -31,27 +31,24 @@  > >>>= [/regexp/]  > [..or expected numeric exit code]  .- The expected fields can also have a regular expression match expression- following the delimiter on the same line, with no other data lines, in- which case the test passes if the output is matched by the regexp. The- regexp is enclosed in forward slashess. A ! preceding the expression- negates the match. For example, to check that stdout does not contain- "axe":- .- > >>> !/axe/+ Each expected field can have either a regular expression match+ expression, in which case the test passes if the output is matched, or 0+ or more data lines, in which case the output must match these exactly.  A+ ! preceding a /regexp/ negates the match. The regular expression syntax+ is that supported by the regexpr library.  .  Apart from the command line, all fields are optional. Only fields  specified in the test will be tested, unless you use the  -i/--implicit-tests flag, which will test for empty stdout, empty stderr,- or 0 exit code whenever fields are omitted.+ or 0 exit code where fields are omitted.  .  Issues:  .- - output order is mixed up- .- - option processing is weak+ - can't put / in a regexp  .  - can't test input/output which does not end with newline+ .+ - option processing is weak  .  Wishlist:  .
shelltestrunner.hs view
@@ -14,13 +14,13 @@ import Control.Concurrent (forkIO) import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar) import Control.Monad (liftM,when)-import Data.List (partition)+import Data.List (partition, intercalate) import Data.Maybe (fromJust,isJust,maybe) import qualified Test.HUnit (Test) import System.Console.ParseArgs hiding (args) import System.Environment (withArgs) import System.Exit (ExitCode(..),exitWith)-import System.IO (Handle, hGetContents, hPutStr, stderr)+import System.IO (Handle, hGetContents, hPutStr) import System.Process (runInteractiveCommand, waitForProcess) import Test.Framework (defaultMain) import Test.Framework.Providers.HUnit (hUnitTestToTests)@@ -34,7 +34,7 @@   version :: String-version = "0.4" -- keep synced with .cabal+version = "0.5" -- keep synced with .cabal  data ArgId = HelpFlag            | VersionFlag@@ -201,11 +201,9 @@ -- running  shellTestToHUnitTest :: Args ArgId -> ShellTest -> Test.HUnit.Test-shellTestToHUnitTest args t = testname t ~: do {r <- runShellTest args t; assertBool "" r}--runShellTest :: Args ArgId -> ShellTest -> IO Bool-runShellTest args ShellTest{testname=n,commandargs=c,stdin=i,stdoutExpected=o_expected,-                            stderrExpected=e_expected,exitCodeExpected=x_expected} = do+shellTestToHUnitTest args ShellTest{testname=n,commandargs=c,stdin=i,stdoutExpected=o_expected,+                                    stderrExpected=e_expected,exitCodeExpected=x_expected} = + n ~: do   let exe = fromJust $ getArgString args ExecutableArg       cmd = unwords [exe,c]       (o_expected',e_expected',x_expected') =@@ -234,17 +232,19 @@   o_actual <- takeMVar o   e_actual <- takeMVar e -  let o_ok = maybe True (o_actual `matches`) o_expected'-  let e_ok = maybe True (e_actual `matches`) e_expected'-  let x_ok = maybe True ((show $ fromExitCode x_actual) `matches`) x_expected'-  if o_ok && e_ok && x_ok-   then do-     return True -   else do-     when (not o_ok) $ printExpectedActual "stdout" (fromJust o_expected') o_actual-     when (not e_ok) $ printExpectedActual "stderr" (fromJust e_expected') e_actual-     when (not x_ok) $ printExpectedActual "exit code" (fromJust x_expected') (show $ fromExitCode x_actual)-     return False+  assertString $ addnewline $ intercalate "\n" $ filter (not . null)+      [if (maybe True (o_actual `matches`) o_expected')+        then "" +        else showExpectedActual "stdout"    (fromJust o_expected') o_actual+      ,if (maybe True (e_actual `matches`) e_expected')+        then "" +        else showExpectedActual "stderr"    (fromJust e_expected') e_actual+      ,if (maybe True ((show $ fromExitCode x_actual) `matches`) x_expected')+        then ""+        else showExpectedActual "exit code" (fromJust x_expected') (show $ fromExitCode x_actual)+      ]+      where addnewline "" = ""+            addnewline s  = "\n"++s  hGetContentsStrictlyAnd :: Handle -> (String -> IO b) -> IO b hGetContentsStrictlyAnd h f = hGetContents h >>= \c -> length c `seq` f c@@ -255,14 +255,15 @@ matches s (Numeric p)       = s == p matches s (Exact p)         = s == p +showExpectedActual :: String -> Matcher -> String -> String+showExpectedActual field e a =+    printf "**Expected %s:%s**Got %s:\n%s" field (showMatcher e) field a+ showMatcher :: Matcher -> String showMatcher (PositiveRegex r) = " /"++r++"/\n" showMatcher (NegativeRegex r) = " !/"++r++"/\n"-showMatcher (Numeric s)       = "\n"++s+showMatcher (Numeric s)       = "\n"++s++"\n" showMatcher (Exact s)         = "\n"++s--printExpectedActual :: String -> Matcher -> String -> IO ()-printExpectedActual f e a = hPutStr stderr $ printf "**Expected %s:%s**Got %s:\n%s" f (showMatcher e) f a   -- utils