import Control.Monad (mapM_)
import Data.ByteString.Char8 (pack)
import System.Environment (getArgs)
import System.Exit (ExitCode(ExitSuccess, ExitFailure) , exitWith)
import System.IO (stderr, hPutStr)
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck
( Arbitrary
, arbitrary
, choose
, oneof
, listOf
)
import Test.Main
import Test.Main.Internal
newtype AExitCode = AExitCode ExitCode deriving Show
instance Arbitrary AExitCode where
arbitrary =
AExitCode <$> oneof [pure ExitSuccess, ExitFailure <$> choose (1, maxBound)]
newtype PrintableAsciiString =
PrintableAsciiString { getPrintableAsciiString :: String } deriving Show
-- https://en.wikipedia.org/wiki/ASCII#Character_set
instance Arbitrary PrintableAsciiString where
arbitrary = PrintableAsciiString <$> listOf (choose (' ', '~'))
main :: IO ()
main = hspec $
describe "Test.Main" $
prop "passes stdin and arguments to the program, and capture stdin data, stderr data, and exitCode" $
\(argsA, inDataA, AExitCode eCode) -> do
let args = map getPrintableAsciiString argsA
inData = pack $ getPrintableAsciiString inDataA
testedMain = do
mapM_ putStrLn =<< getArgs
hPutStr stderr =<< getContents
exitWith eCode
actual <- withStdin inData $ withArgs args $ captureProcessResult testedMain
normalizeNewLines actual `shouldBe`
normalizeNewLines (ProcessResult (pack $ unlines args) inData eCode)