module System.Process.Quick.CallEffect where

import System.Posix
import System.Process.Quick.Prelude
import Text.Regex.TDFA
import Prelude (Show (..))

data TimeReference
  = LaunchTime
  | BootTime
  | ExitTime
  | Now
  deriving (Int -> TimeReference -> ShowS
[TimeReference] -> ShowS
TimeReference -> String
(Int -> TimeReference -> ShowS)
-> (TimeReference -> String)
-> ([TimeReference] -> ShowS)
-> Show TimeReference
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TimeReference -> ShowS
showsPrec :: Int -> TimeReference -> ShowS
$cshow :: TimeReference -> String
show :: TimeReference -> String
$cshowList :: [TimeReference] -> ShowS
showList :: [TimeReference] -> ShowS
Show, TimeReference -> TimeReference -> Bool
(TimeReference -> TimeReference -> Bool)
-> (TimeReference -> TimeReference -> Bool) -> Eq TimeReference
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TimeReference -> TimeReference -> Bool
== :: TimeReference -> TimeReference -> Bool
$c/= :: TimeReference -> TimeReference -> Bool
/= :: TimeReference -> TimeReference -> Bool
Eq, Eq TimeReference
Eq TimeReference =>
(TimeReference -> TimeReference -> Ordering)
-> (TimeReference -> TimeReference -> Bool)
-> (TimeReference -> TimeReference -> Bool)
-> (TimeReference -> TimeReference -> Bool)
-> (TimeReference -> TimeReference -> Bool)
-> (TimeReference -> TimeReference -> TimeReference)
-> (TimeReference -> TimeReference -> TimeReference)
-> Ord TimeReference
TimeReference -> TimeReference -> Bool
TimeReference -> TimeReference -> Ordering
TimeReference -> TimeReference -> TimeReference
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: TimeReference -> TimeReference -> Ordering
compare :: TimeReference -> TimeReference -> Ordering
$c< :: TimeReference -> TimeReference -> Bool
< :: TimeReference -> TimeReference -> Bool
$c<= :: TimeReference -> TimeReference -> Bool
<= :: TimeReference -> TimeReference -> Bool
$c> :: TimeReference -> TimeReference -> Bool
> :: TimeReference -> TimeReference -> Bool
$c>= :: TimeReference -> TimeReference -> Bool
>= :: TimeReference -> TimeReference -> Bool
$cmax :: TimeReference -> TimeReference -> TimeReference
max :: TimeReference -> TimeReference -> TimeReference
$cmin :: TimeReference -> TimeReference -> TimeReference
min :: TimeReference -> TimeReference -> TimeReference
Ord)

data FsPredicate
  = FsExists
  | DirStructMatches FsEffect
  | FsPathHasPerm FileMode -- ^ AND
  | FsTime Ordering TimeReference
  deriving (Int -> FsPredicate -> ShowS
[FsPredicate] -> ShowS
FsPredicate -> String
(Int -> FsPredicate -> ShowS)
-> (FsPredicate -> String)
-> ([FsPredicate] -> ShowS)
-> Show FsPredicate
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FsPredicate -> ShowS
showsPrec :: Int -> FsPredicate -> ShowS
$cshow :: FsPredicate -> String
show :: FsPredicate -> String
$cshowList :: [FsPredicate] -> ShowS
showList :: [FsPredicate] -> ShowS
Show, FsPredicate -> FsPredicate -> Bool
(FsPredicate -> FsPredicate -> Bool)
-> (FsPredicate -> FsPredicate -> Bool) -> Eq FsPredicate
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FsPredicate -> FsPredicate -> Bool
== :: FsPredicate -> FsPredicate -> Bool
$c/= :: FsPredicate -> FsPredicate -> Bool
/= :: FsPredicate -> FsPredicate -> Bool
Eq)

data FsEffect
  = FsPathPredicate FilePath [FsPredicate]
  | FsNot FsEffect
  | FsAnd [FsEffect]
  | FsOr [FsEffect]
  deriving (Int -> FsEffect -> ShowS
[FsEffect] -> ShowS
FsEffect -> String
(Int -> FsEffect -> ShowS)
-> (FsEffect -> String) -> ([FsEffect] -> ShowS) -> Show FsEffect
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FsEffect -> ShowS
showsPrec :: Int -> FsEffect -> ShowS
$cshow :: FsEffect -> String
show :: FsEffect -> String
$cshowList :: [FsEffect] -> ShowS
showList :: [FsEffect] -> ShowS
Show, FsEffect -> FsEffect -> Bool
(FsEffect -> FsEffect -> Bool)
-> (FsEffect -> FsEffect -> Bool) -> Eq FsEffect
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FsEffect -> FsEffect -> Bool
== :: FsEffect -> FsEffect -> Bool
$c/= :: FsEffect -> FsEffect -> Bool
/= :: FsEffect -> FsEffect -> Bool
Eq)

data ViRex = ViRex ByteString Regex

instance Show ViRex where
  show :: ViRex -> String
show (ViRex ByteString
bs Regex
_) = ByteString -> String
forall a. Show a => a -> String
Prelude.show ByteString
bs

instance Eq ViRex where
  (ViRex ByteString
a Regex
_) == :: ViRex -> ViRex -> Bool
== (ViRex ByteString
b Regex
_) = ByteString
a ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
b

data OutMatcher
  = ExactMatching ByteString
  | WholeMatching ViRex -- read all input
  | LineMatching ViRex -- consume file line by line - at least one line match
  deriving (Int -> OutMatcher -> ShowS
[OutMatcher] -> ShowS
OutMatcher -> String
(Int -> OutMatcher -> ShowS)
-> (OutMatcher -> String)
-> ([OutMatcher] -> ShowS)
-> Show OutMatcher
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OutMatcher -> ShowS
showsPrec :: Int -> OutMatcher -> ShowS
$cshow :: OutMatcher -> String
show :: OutMatcher -> String
$cshowList :: [OutMatcher] -> ShowS
showList :: [OutMatcher] -> ShowS
Show, OutMatcher -> OutMatcher -> Bool
(OutMatcher -> OutMatcher -> Bool)
-> (OutMatcher -> OutMatcher -> Bool) -> Eq OutMatcher
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OutMatcher -> OutMatcher -> Bool
== :: OutMatcher -> OutMatcher -> Bool
$c/= :: OutMatcher -> OutMatcher -> Bool
/= :: OutMatcher -> OutMatcher -> Bool
Eq)

data CallEffect
  = SleepFor Integer -- call lasts at least N microseconds
  | ExitCode Int -- expected exit code
  | FsEffect FsEffect
  | OrCe [CallEffect]
  | AndCe [CallEffect]
  | NotCe [CallEffect]
  | StdOutputCe OutMatcher
  | StdErrorCe OutMatcher
  deriving (Int -> CallEffect -> ShowS
[CallEffect] -> ShowS
CallEffect -> String
(Int -> CallEffect -> ShowS)
-> (CallEffect -> String)
-> ([CallEffect] -> ShowS)
-> Show CallEffect
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CallEffect -> ShowS
showsPrec :: Int -> CallEffect -> ShowS
$cshow :: CallEffect -> String
show :: CallEffect -> String
$cshowList :: [CallEffect] -> ShowS
showList :: [CallEffect] -> ShowS
Show, CallEffect -> CallEffect -> Bool
(CallEffect -> CallEffect -> Bool)
-> (CallEffect -> CallEffect -> Bool) -> Eq CallEffect
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CallEffect -> CallEffect -> Bool
== :: CallEffect -> CallEffect -> Bool
$c/= :: CallEffect -> CallEffect -> Bool
/= :: CallEffect -> CallEffect -> Bool
Eq)

-- | instances are generated for types with CallSpec and Subcases
-- The class is introduced because,
-- expected effects don't have fields in a CallSpec record
class CallSpecEffect cse where
  -- call after callSpec in the same directory
  unsatisfiedEffects :: MonadIO m => cse -> m [CallEffect]