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)