teardown-0.5.0.0: src/Control/Teardown/Internal/Types.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Control.Teardown.Internal.Types where
import RIO
import RIO.Time (NominalDiffTime)
#if MIN_VERSION_base(4,9,0)
import GHC.Generics (Generic)
#endif
import Data.Text.Prettyprint.Doc (Pretty, pretty, (<+>))
import qualified Data.Text.Prettyprint.Doc as Pretty
--------------------------------------------------------------------------------
type Description = Text
-- | Result from a 'Teardown' sub-routine
data TeardownResult
-- | Result is composed by multiple teardown sub-routines
= BranchResult
{
-- | Text description of parent teardown spec
resultDescription :: !Description
-- | Sum of elapsed time on sub-routines execution
, resultElapsedTime :: !NominalDiffTime
-- | Tells if any sub-routines failed
, resultDidFail :: !Bool
-- | Results of inner sub-routines
, resultListing :: ![TeardownResult]
}
-- | Result represents a single teardown sub-routine
| LeafResult
{
-- | Text description of sub-routine
resultDescription :: !Description
-- | Elapsed time on sub-routine execution
, resultElapsedTime :: !NominalDiffTime
-- | Exception from sub-routine
, resultError :: !(Maybe SomeException)
}
-- | Represents a stub cleanup operation (for lifting pure values)
| EmptyResult
{
-- | Text description of faked sub-routine
resultDescription :: !Description
}
deriving (Generic, Show)
instance Pretty TeardownResult where
pretty result =
case result of
EmptyResult {resultDescription} ->
"✓" <+> pretty resultDescription <+> Pretty.parens "empty"
LeafResult {resultDescription, resultElapsedTime, resultError} ->
case resultError of
Nothing ->
"✓" <+> pretty resultDescription <+> Pretty.parens (pretty $ show resultElapsedTime)
Just err ->
Pretty.hang 2
(Pretty.vsep ["✘"
<+> pretty resultDescription
<+> Pretty.parens (pretty $ show resultElapsedTime)
, "|" <+> pretty (show err) ])
BranchResult {resultDidFail, resultDescription, resultElapsedTime, resultListing} ->
let
symbolDoc = if resultDidFail then "✘" else "✓"
in
symbolDoc
<+> pretty resultDescription
<+> Pretty.parens (pretty $ show resultElapsedTime)
<> Pretty.hardline
<> Pretty.indent 2 (Pretty.align (Pretty.vsep (map pretty resultListing)))
instance Display TeardownResult where
display = displayShow . pretty
getElapsedTime :: TeardownResult -> NominalDiffTime
getElapsedTime result =
case result of
BranchResult {resultElapsedTime} -> resultElapsedTime
LeafResult {resultElapsedTime} -> resultElapsedTime
EmptyResult {} -> 0
instance NFData TeardownResult where
rnf result =
case result of
EmptyResult !_desc ->
()
LeafResult !_desc !_time !_err ->
()
BranchResult !_desc !_time !_didFail listing ->
rnf listing
-- | Sub-routine that performs a resource cleanup operation
newtype Teardown
= Teardown (IO TeardownResult)
deriving (Generic)
instance NFData Teardown where
rnf !_ = ()
-- | A record that __is__ or __contains__ a 'Teardown' sub-routine should
-- instantiate this typeclass
class HasTeardown teardown where
-- | Executes teardown sub-routine returning a "TeardownResult"
getTeardown :: teardown -> Teardown
-- | A resource or sub-routine that can be transformed into a 'Teardown'
-- operation
class IResource resource where
newTeardown :: Text -> resource -> IO Teardown