quick-process-0.0.3: src/System/Process/Quick/CallEffect.hs
{-# OPTIONS_GHC -Wno-orphans #-}
module System.Process.Quick.CallEffect where
import System.Directory ( doesDirectoryExist, doesFileExist )
import System.Posix ( FileMode )
import System.Process.Quick.Prelude
import Text.Regex.TDFA
( RegexLike(matchTest),
RegexMaker(makeRegexOpts),
RegexOptions(defaultCompOpt),
CompOption(multiline),
ExecOption(ExecOption),
Regex )
import Language.Haskell.TH.Syntax ( Lift )
data TimeReference
= LaunchTime
| BootTime
| ExitTime
| Now
deriving (Show, Eq, Ord)
data FsPredicate
= FsExists
| DirStructMatches FsEffect
| FsPathHasPerm FileMode -- ^ AND
| FsTime Ordering TimeReference
deriving (Show, Eq)
data FsEffect
= FsPathPredicate FilePath [FsPredicate]
| FsNot FsEffect
| FsAnd [FsEffect]
| FsOr [FsEffect]
deriving (Show, Eq)
data Mismatch a
= Mismatch
{ expected :: a
, got ::a
} deriving (Show, Eq)
data CallEffect
= SleepFor Integer -- call lasts at least N microseconds
| ExitCode (Mismatch ExitCode) -- expected exit code
| FsEffect FsEffect
| OrCe [CallEffect]
| AndCe [CallEffect]
| NotCe [CallEffect]
| StdOutputCe { rx :: String, output :: String }
| StdErrorCe { rx :: String, output :: String }
deriving (Show, Eq)
-- move to module for orphan instances
deriving instance Lift ExitCode
deriving instance Data ExitCode
data CsExecReport
= CsExecReport
{ exitCode :: ExitCode
, stdErr :: String
, stdOut :: String
, execTime :: NominalDiffTime
, processDir :: FilePath
} deriving (Show, Eq)
class CallSpecOutcomeCheck c where
-- | call after callSpec in the same directory
check :: MonadIO m => CsExecReport -> c -> m [CallEffect]
data OutcomeChecker
= ExitCodeEqualTo ExitCode
| StdErrMatches String
| StdOutMatches String
| FileCreated FilePath
| DirCreated FilePath
deriving (Show, Eq, Data, Generic, Lift)
-- | ConcatOutcomeChecker [OutcomeChecker]
-- | BothOutcomeChecker OutcomeChecker OutcomeChecker
parseRx :: String -> Regex
parseRx = makeRegexOpts defaultCompOpt { multiline = False } (ExecOption False)
instance CallSpecOutcomeCheck OutcomeChecker where
check cser | $(tr "/cser") True = \case
ExitCodeEqualTo eec
| eec == exitCode cser -> pure []
| otherwise -> pure [ExitCode . Mismatch eec $ exitCode cser]
StdErrMatches rx
| parseRx rx `matchTest` stdErr cser -> pure []
| otherwise -> pure [StdErrorCe rx $ stdErr cser]
StdOutMatches rx
| parseRx rx `matchTest` stdOut cser -> pure []
| otherwise -> pure [StdOutputCe rx $ stdOut cser]
FileCreated dp ->
liftIO (doesFileExist dp) >>= \case
True -> pure []
False -> pure [FsEffect $ FsPathPredicate dp [FsExists]]
DirCreated dp ->
liftIO (doesDirectoryExist dp) >>= \case
True -> pure []
False -> pure [FsEffect $ FsPathPredicate dp [FsExists]]