    {-# LANGUAGE CPP #-}
    {-# LANGUAGE LambdaCase #-}
    module Runner (
      runModules
    , FastMode(..)
    , PreserveIt(..)
    , FailFast(..)
    , Verbose(..)
    , Summary(..)
    , isSuccess
    , formatSummary

    #ifdef TEST
    , Report
    , ReportState(..)
    , runReport
    , Interactive(..)
    , report
    , reportTransient
    #endif
    ) where

    import           Prelude ()
    import           Imports hiding (putStr, putStrLn, error)

    import           Text.Printf (printf)
    import           System.IO hiding (putStr, putStrLn)

    import           Control.Monad.Trans.Class
    import           Control.Monad.Trans.Maybe
    import           Control.Monad.Trans.State (StateT, evalStateT)
    import qualified Control.Monad.Trans.State as State
    import           Control.Monad.IO.Class
    import           Data.IORef

    import           Interpreter (Interpreter, PreserveIt(..), safeEvalWith)
    import qualified Interpreter
    import           Parse
    import           Location
    import           Property
    import           Runner.Example

    -- | Summary of a test run.
    data Summary = Summary {
      Summary -> Int
    sExamples :: !Int
    , Summary -> Int
    sTried    :: !Int
    , Summary -> Int
    sErrors   :: !Int
    , Summary -> Int
    sFailures :: !Int
    } deriving Summary -> Summary -> Bool
    (Summary -> Summary -> Bool)
    -> (Summary -> Summary -> Bool) -> Eq Summary
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Summary -> Summary -> Bool
    == :: Summary -> Summary -> Bool
    $c/= :: Summary -> Summary -> Bool
    /= :: Summary -> Summary -> Bool
    Eq

    instance Show Summary where
      show :: Summary -> String
    show = Summary -> String
    formatSummary

    isSuccess :: Summary -> Bool
    isSuccess :: Summary -> Bool
    isSuccess Summary
    s = Summary -> Int
    sErrors Summary
    s Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0 Bool -> Bool -> Bool
    && Summary -> Int
    sFailures Summary
    s Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0

    formatSummary :: Summary -> String
    formatSummary :: Summary -> String
    formatSummary (Summary Int
    examples Int
    tried Int
    errors Int
    failures) =
      String -> Int -> Int -> Int -> Int -> String
    forall r. PrintfType r => String -> r
    printf String
    "Examples: %d  Tried: %d  Errors: %d  Failures: %d" Int
    examples Int
    tried Int
    errors Int
    failures

    -- | Sum up summaries.
    instance Monoid Summary where
      mempty :: Summary
    mempty = Int -> Int -> Int -> Int -> Summary
    Summary Int
    0 Int
    0 Int
    0 Int
    0
    instance Semigroup Summary where
      Summary Int
    x1 Int
    x2 Int
    x3 Int
    x4 <> :: Summary -> Summary -> Summary
    <> Summary Int
    y1 Int
    y2 Int
    y3 Int
    y4 = Int -> Int -> Int -> Int -> Summary
    Summary (Int
    x1 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    y1) (Int
    x2 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    y2) (Int
    x3 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    y3) (Int
    x4 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    y4)

    withLineBuffering :: Handle -> IO c -> IO c
    withLineBuffering :: forall c. Handle -> IO c -> IO c
    withLineBuffering Handle
    h IO c
    action = IO BufferMode
    -> (BufferMode -> IO ()) -> (BufferMode -> IO c) -> IO c
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
    bracket (Handle -> IO BufferMode
    hGetBuffering Handle
    h) (Handle -> BufferMode -> IO ()
    hSetBuffering Handle
    h) ((BufferMode -> IO c) -> IO c) -> (BufferMode -> IO c) -> IO c
    forall a b. (a -> b) -> a -> b
    $ \ BufferMode
    _ -> do
      Handle -> BufferMode -> IO ()
    hSetBuffering Handle
    h BufferMode
    LineBuffering
      IO c
    action

    -- | Run all examples from a list of modules.
    runModules :: FastMode -> PreserveIt -> FailFast -> Verbose -> Interpreter -> [Module [Located DocTest]] -> IO Summary
    runModules :: FastMode
    -> PreserveIt
    -> FailFast
    -> Verbose
    -> Interpreter
    -> [Module [Located DocTest]]
    -> IO Summary
    runModules FastMode
    fastMode PreserveIt
    preserveIt FailFast
    failFast Verbose
    verbose Interpreter
    repl [Module [Located DocTest]]
    modules = Handle -> IO Summary -> IO Summary
    forall c. Handle -> IO c -> IO c
    withLineBuffering Handle
    stderr (IO Summary -> IO Summary) -> IO Summary -> IO Summary
    forall a b. (a -> b) -> a -> b
    $ do

      interactive <- Handle -> IO Bool
    hIsTerminalDevice Handle
    stderr IO Bool -> (Bool -> Interactive) -> IO Interactive
    forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
    <&> \ case
        Bool
    False -> Interactive
    NonInteractive
        Bool
    True -> Interactive
    Interactive

      summary <- newIORef mempty {sExamples = n}

      let
        reportFinalResult :: IO ()
        reportFinalResult = do
          final <- IORef Summary -> IO Summary
    forall a. IORef a -> IO a
    readIORef IORef Summary
    summary
          hPutStrLn stderr (formatSummary final)

        run :: IO ()
        run = ReportState -> Report () -> IO ()
    runReport (Interactive -> FailFast -> Verbose -> IORef Summary -> ReportState
    ReportState Interactive
    interactive FailFast
    failFast Verbose
    verbose IORef Summary
    summary) (Report () -> IO ()) -> Report () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ do
          Report ()
    reportProgress
          [Module [Located DocTest]]
    -> (Module [Located DocTest] -> Report ()) -> Report ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    t a -> (a -> m b) -> m ()
    forM_ [Module [Located DocTest]]
    modules ((Module [Located DocTest] -> Report ()) -> Report ())
    -> (Module [Located DocTest] -> Report ()) -> Report ()
    forall a b. (a -> b) -> a -> b
    $ FastMode
    -> PreserveIt
    -> Interpreter
    -> Module [Located DocTest]
    -> Report ()
    runModule FastMode
    fastMode PreserveIt
    preserveIt Interpreter
    repl
          String -> Report ()
    verboseReport String
    "# Final summary:"

      run `finally` reportFinalResult

      readIORef summary
      where
        n :: Int
        n :: Int
    n = [Int] -> Int
    forall a. Num a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum ((Module [Located DocTest] -> Int)
    -> [Module [Located DocTest]] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map Module [Located DocTest] -> Int
    countExpressions [Module [Located DocTest]]
    modules)

    countExpressions :: Module [Located DocTest] -> Int
    countExpressions :: Module [Located DocTest] -> Int
    countExpressions (Module String
    _ Maybe [Located DocTest]
    setup [[Located DocTest]]
    tests) = [Int] -> Int
    forall a. Num a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum (([Located DocTest] -> Int) -> [[Located DocTest]] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map [Located DocTest] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [[Located DocTest]]
    tests) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int -> ([Located DocTest] -> Int) -> Maybe [Located DocTest] -> Int
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Int
    0 [Located DocTest] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length Maybe [Located DocTest]
    setup

    type Report = MaybeT (StateT ReportState IO)

    data Interactive = NonInteractive | Interactive

    data FastMode = NoFastMode | FastMode

    data FailFast = NoFailFast | FailFast

    data Verbose = NonVerbose | Verbose

    data ReportState = ReportState {
      ReportState -> Interactive
    reportStateInteractive :: Interactive
    , ReportState -> FailFast
    reportStateFailFast :: FailFast
    , ReportState -> Verbose
    reportStateVerbose :: Verbose
    , ReportState -> IORef Summary
    reportStateSummary :: IORef Summary
    }

    runReport :: ReportState -> Report () -> IO ()
    runReport :: ReportState -> Report () -> IO ()
    runReport ReportState
    st = IO (Maybe ()) -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO (Maybe ()) -> IO ())
    -> (Report () -> IO (Maybe ())) -> Report () -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (StateT ReportState IO (Maybe ()) -> ReportState -> IO (Maybe ()))
    -> ReportState -> StateT ReportState IO (Maybe ()) -> IO (Maybe ())
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip StateT ReportState IO (Maybe ()) -> ReportState -> IO (Maybe ())
    forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
    evalStateT ReportState
    st (StateT ReportState IO (Maybe ()) -> IO (Maybe ()))
    -> (Report () -> StateT ReportState IO (Maybe ()))
    -> Report ()
    -> IO (Maybe ())
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Report () -> StateT ReportState IO (Maybe ())
    forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
    runMaybeT

    getSummary :: Report Summary
    getSummary :: Report Summary
    getSummary = (ReportState -> IORef Summary) -> Report (IORef Summary)
    forall a. (ReportState -> a) -> Report a
    gets ReportState -> IORef Summary
    reportStateSummary Report (IORef Summary)
    -> (IORef Summary -> Report Summary) -> Report Summary
    forall a b.
    MaybeT (StateT ReportState IO) a
    -> (a -> MaybeT (StateT ReportState IO) b)
    -> MaybeT (StateT ReportState IO) b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= IO Summary -> Report Summary
    forall a. IO a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Summary -> Report Summary)
    -> (IORef Summary -> IO Summary) -> IORef Summary -> Report Summary
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IORef Summary -> IO Summary
    forall a. IORef a -> IO a
    readIORef

    gets :: (ReportState -> a) -> Report a
    gets :: forall a. (ReportState -> a) -> Report a
    gets = StateT ReportState IO a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. Monad m => m a -> MaybeT m a
    forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (StateT ReportState IO a -> MaybeT (StateT ReportState IO) a)
    -> ((ReportState -> a) -> StateT ReportState IO a)
    -> (ReportState -> a)
    -> MaybeT (StateT ReportState IO) a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (ReportState -> a) -> StateT ReportState IO a
    forall (m :: * -> *) s a. Monad m => (s -> a) -> StateT s m a
    State.gets

    -- | Add output to the report.
    report :: String -> Report ()
    report :: String -> Report ()
    report = IO () -> Report ()
    forall a. IO a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> Report ()) -> (String -> IO ()) -> String -> Report ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Handle -> String -> IO ()
    hPutStrLn Handle
    stderr

    -- | Add intermediate output to the report.
    --
    -- This will be overwritten by subsequent calls to `report`/`report_`.
    -- Intermediate out may not contain any newlines.
    reportTransient :: String -> Report ()
    reportTransient :: String -> Report ()
    reportTransient String
    msg = (ReportState -> Interactive) -> Report Interactive
    forall a. (ReportState -> a) -> Report a
    gets ReportState -> Interactive
    reportStateInteractive Report Interactive -> (Interactive -> Report ()) -> Report ()
    forall a b.
    MaybeT (StateT ReportState IO) a
    -> (a -> MaybeT (StateT ReportState IO) b)
    -> MaybeT (StateT ReportState IO) b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \ case
      Interactive
    NonInteractive -> Report ()
    forall (m :: * -> *). Monad m => m ()
    pass
      Interactive
    Interactive -> IO () -> Report ()
    forall a. IO a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> Report ()) -> IO () -> Report ()
    forall a b. (a -> b) -> a -> b
    $ do
        Handle -> String -> IO ()
    hPutStr Handle
    stderr String
    msg
        Handle -> IO ()
    hFlush Handle
    stderr
        Handle -> String -> IO ()
    hPutStr Handle
    stderr (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Char
    '\r' Char -> String -> String
    forall a. a -> [a] -> [a]
    : (Int -> Char -> String
    forall a. Int -> a -> [a]
    replicate (String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    msg) Char
    ' ') String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "\r"

    -- | Run all examples from given module.
    runModule :: FastMode -> PreserveIt -> Interpreter -> Module [Located DocTest] -> Report ()
    runModule :: FastMode
    -> PreserveIt
    -> Interpreter
    -> Module [Located DocTest]
    -> Report ()
    runModule FastMode
    fastMode PreserveIt
    preserveIt Interpreter
    repl (Module String
    module_ Maybe [Located DocTest]
    setup [[Located DocTest]]
    examples) = do

      Summary _ _ e0 f0 <- Report Summary
    getSummary

      forM_ setup $
        runTestGroup preserveIt repl reload

      Summary _ _ e1 f1 <- getSummary

      -- only run tests, if setup does not produce any errors/failures
      when (e0 == e1 && f0 == f1) $
        forM_ examples $ runTestGroup preserveIt repl setup_
      where
        reload :: IO ()
        reload :: IO ()
    reload = do
          case FastMode
    fastMode of
            FastMode
    NoFastMode -> IO (Either String String) -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO (Either String String) -> IO ())
    -> IO (Either String String) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Interpreter -> String -> IO (Either String String)
    Interpreter.safeEval Interpreter
    repl String
    ":reload"
            FastMode
    FastMode -> IO ()
    forall (m :: * -> *). Monad m => m ()
    pass
          IO (Either String String) -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO (Either String String) -> IO ())
    -> IO (Either String String) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Interpreter -> String -> IO (Either String String)
    Interpreter.safeEval Interpreter
    repl (String -> IO (Either String String))
    -> String -> IO (Either String String)
    forall a b. (a -> b) -> a -> b
    $ String
    ":m *" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    module_

          case PreserveIt
    preserveIt of
            PreserveIt
    NoPreserveIt -> IO ()
    forall (m :: * -> *). Monad m => m ()
    pass
            PreserveIt
    PreserveIt -> do
              -- Evaluate a dumb expression to populate the 'it' variable.
              --
              -- NOTE: This is one reason why we cannot just always use PreserveIt:
              -- 'it' isn't set in a fresh GHCi session.
              IO (Either String String) -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO (Either String String) -> IO ())
    -> IO (Either String String) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Interpreter -> String -> IO (Either String String)
    Interpreter.safeEval Interpreter
    repl (String -> IO (Either String String))
    -> String -> IO (Either String String)
    forall a b. (a -> b) -> a -> b
    $ String
    "()"

        setup_ :: IO ()
        setup_ :: IO ()
    setup_ = do
          IO ()
    reload
          Maybe [Located DocTest] -> ([Located DocTest] -> IO ()) -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    t a -> (a -> m b) -> m ()
    forM_ Maybe [Located DocTest]
    setup (([Located DocTest] -> IO ()) -> IO ())
    -> ([Located DocTest] -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \[Located DocTest]
    l -> [Located DocTest] -> (Located DocTest -> IO ()) -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    t a -> (a -> m b) -> m ()
    forM_ [Located DocTest]
    l ((Located DocTest -> IO ()) -> IO ())
    -> (Located DocTest -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \(Located Location
    _ DocTest
    x) -> case DocTest
    x of
            Property String
    _  -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
            Example String
    e ExpectedResult
    _ -> IO (Either String String) -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO (Either String String) -> IO ())
    -> IO (Either String String) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ PreserveIt -> Interpreter -> String -> IO (Either String String)
    safeEvalWith PreserveIt
    preserveIt Interpreter
    repl String
    e

    reportStart :: Location -> Expression -> String -> Report ()
    reportStart :: Location -> String -> String -> Report ()
    reportStart Location
    loc String
    expression String
    testType = do
      String -> Report ()
    verboseReport (String -> String -> String -> String -> String
    forall r. PrintfType r => String -> r
    printf String
    "### Started execution at %s.\n### %s:\n%s" (Location -> String
    forall a. Show a => a -> String
    show Location
    loc) String
    testType String
    expression)

    reportFailure :: Location -> Expression -> [String] -> Report ()
    reportFailure :: Location -> String -> [String] -> Report ()
    reportFailure Location
    loc String
    expression [String]
    err = do
      String -> Report ()
    report (String -> String -> String -> String
    forall r. PrintfType r => String -> r
    printf String
    "%s: failure in expression `%s'" (Location -> String
    forall a. Show a => a -> String
    show Location
    loc) String
    expression)
      (String -> Report ()) -> [String] -> Report ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ String -> Report ()
    report [String]
    err
      String -> Report ()
    report String
    ""
      Summary -> Report ()
    updateSummary (Int -> Int -> Int -> Int -> Summary
    Summary Int
    0 Int
    1 Int
    0 Int
    1)

    reportError :: Location -> Expression -> String -> Report ()
    reportError :: Location -> String -> String -> Report ()
    reportError Location
    loc String
    expression String
    err = do
      String -> Report ()
    report (String -> String -> String -> String
    forall r. PrintfType r => String -> r
    printf String
    "%s: error in expression `%s'" (Location -> String
    forall a. Show a => a -> String
    show Location
    loc) String
    expression)
      String -> Report ()
    report String
    err
      String -> Report ()
    report String
    ""
      Summary -> Report ()
    updateSummary (Int -> Int -> Int -> Int -> Summary
    Summary Int
    0 Int
    1 Int
    1 Int
    0)

    reportSuccess :: Report ()
    reportSuccess :: Report ()
    reportSuccess = do
      String -> Report ()
    verboseReport String
    "### Successful!\n"
      Summary -> Report ()
    updateSummary (Int -> Int -> Int -> Int -> Summary
    Summary Int
    0 Int
    1 Int
    0 Int
    0)

    verboseReport :: String -> Report ()
    verboseReport :: String -> Report ()
    verboseReport String
    msg = (ReportState -> Verbose) -> Report Verbose
    forall a. (ReportState -> a) -> Report a
    gets ReportState -> Verbose
    reportStateVerbose Report Verbose -> (Verbose -> Report ()) -> Report ()
    forall a b.
    MaybeT (StateT ReportState IO) a
    -> (a -> MaybeT (StateT ReportState IO) b)
    -> MaybeT (StateT ReportState IO) b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \ case
      Verbose
    NonVerbose -> Report ()
    forall (m :: * -> *). Monad m => m ()
    pass
      Verbose
    Verbose -> String -> Report ()
    report String
    msg

    updateSummary :: Summary -> Report ()
    updateSummary :: Summary -> Report ()
    updateSummary Summary
    summary = do
      ref <- (ReportState -> IORef Summary) -> Report (IORef Summary)
    forall a. (ReportState -> a) -> Report a
    gets ReportState -> IORef Summary
    reportStateSummary
      liftIO $ modifyIORef' ref $ mappend summary
      reportProgress
      gets reportStateFailFast >>= \ case
        FailFast
    NoFailFast -> Report ()
    forall (m :: * -> *). Monad m => m ()
    pass
        FailFast
    FailFast -> Bool -> Report () -> Report ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    unless (Summary -> Bool
    isSuccess Summary
    summary) Report ()
    abort

    abort :: Report ()
    abort :: Report ()
    abort = StateT ReportState IO (Maybe ()) -> Report ()
    forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
    MaybeT (StateT ReportState IO (Maybe ()) -> Report ())
    -> StateT ReportState IO (Maybe ()) -> Report ()
    forall a b. (a -> b) -> a -> b
    $ Maybe () -> StateT ReportState IO (Maybe ())
    forall a. a -> StateT ReportState IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe ()
    forall a. Maybe a
    Nothing

    reportProgress :: Report ()
    reportProgress :: Report ()
    reportProgress = (ReportState -> Verbose) -> Report Verbose
    forall a. (ReportState -> a) -> Report a
    gets ReportState -> Verbose
    reportStateVerbose Report Verbose -> (Verbose -> Report ()) -> Report ()
    forall a b.
    MaybeT (StateT ReportState IO) a
    -> (a -> MaybeT (StateT ReportState IO) b)
    -> MaybeT (StateT ReportState IO) b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \ case
      Verbose
    NonVerbose -> do
        summary <- Report Summary
    getSummary
        reportTransient (formatSummary summary)
      Verbose
    Verbose -> Report ()
    forall (m :: * -> *). Monad m => m ()
    pass

    -- | Run given test group.
    --
    -- The interpreter state is zeroed with @:reload@ first.  This means that you
    -- can reuse the same 'Interpreter' for several test groups.
    runTestGroup :: PreserveIt -> Interpreter -> IO () -> [Located DocTest] -> Report ()
    runTestGroup :: PreserveIt
    -> Interpreter -> IO () -> [Located DocTest] -> Report ()
    runTestGroup PreserveIt
    preserveIt Interpreter
    repl IO ()
    setup [Located DocTest]
    tests = do
      IO () -> Report ()
    forall a. IO a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO IO ()
    setup
      PreserveIt -> Interpreter -> [Located Interaction] -> Report ()
    runExampleGroup PreserveIt
    preserveIt Interpreter
    repl [Located Interaction]
    examples

      [(Location, String)]
    -> ((Location, String) -> Report ()) -> Report ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    t a -> (a -> m b) -> m ()
    forM_ [(Location, String)]
    properties (((Location, String) -> Report ()) -> Report ())
    -> ((Location, String) -> Report ()) -> Report ()
    forall a b. (a -> b) -> a -> b
    $ \(Location
    loc, String
    expression) -> do
        r <- do
          IO () -> Report ()
    forall a. IO a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO IO ()
    setup
          Location -> String -> String -> Report ()
    reportStart Location
    loc String
    expression String
    "property"
          IO PropertyResult -> MaybeT (StateT ReportState IO) PropertyResult
    forall a. IO a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO PropertyResult
     -> MaybeT (StateT ReportState IO) PropertyResult)
    -> IO PropertyResult
    -> MaybeT (StateT ReportState IO) PropertyResult
    forall a b. (a -> b) -> a -> b
    $ Interpreter -> String -> IO PropertyResult
    runProperty Interpreter
    repl String
    expression
        case r of
          PropertyResult
    Success ->
            Report ()
    reportSuccess
          Error String
    err -> do
            Location -> String -> String -> Report ()
    reportError Location
    loc String
    expression String
    err
          Failure String
    msg -> do
            Location -> String -> [String] -> Report ()
    reportFailure Location
    loc String
    expression [String
    msg]
      where
        properties :: [(Location, String)]
    properties = [(Location
    loc, String
    p) | Located Location
    loc (Property String
    p) <- [Located DocTest]
    tests]

        examples :: [Located Interaction]
        examples :: [Located Interaction]
    examples = [Location -> Interaction -> Located Interaction
    forall a. Location -> a -> Located a
    Located Location
    loc (String
    e, ExpectedResult
    r) | Located Location
    loc (Example String
    e ExpectedResult
    r) <- [Located DocTest]
    tests]

    type Interaction = (Expression, ExpectedResult)

    -- |
    -- Execute all expressions from given example in given 'Interpreter' and verify
    -- the output.
    runExampleGroup :: PreserveIt -> Interpreter -> [Located Interaction] -> Report ()
    runExampleGroup :: PreserveIt -> Interpreter -> [Located Interaction] -> Report ()
    runExampleGroup PreserveIt
    preserveIt Interpreter
    repl = [Located Interaction] -> Report ()
    go
      where
        go :: [Located Interaction] -> Report ()
    go ((Located Location
    loc (String
    expression, ExpectedResult
    expected)) : [Located Interaction]
    xs) = do
          Location -> String -> String -> Report ()
    reportStart Location
    loc String
    expression String
    "example"
          r <- (String -> [String])
    -> Either String String -> Either String [String]
    forall a b. (a -> b) -> Either String a -> Either String b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap String -> [String]
    lines (Either String String -> Either String [String])
    -> MaybeT (StateT ReportState IO) (Either String String)
    -> MaybeT (StateT ReportState IO) (Either String [String])
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO (Either String String)
    -> MaybeT (StateT ReportState IO) (Either String String)
    forall a. IO a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (PreserveIt -> Interpreter -> String -> IO (Either String String)
    safeEvalWith PreserveIt
    preserveIt Interpreter
    repl String
    expression)
          case r of
            Left String
    err -> do
              Location -> String -> String -> Report ()
    reportError Location
    loc String
    expression String
    err
            Right [String]
    actual -> case ExpectedResult -> [String] -> Result
    mkResult ExpectedResult
    expected [String]
    actual of
              NotEqual [String]
    err -> do
                Location -> String -> [String] -> Report ()
    reportFailure Location
    loc String
    expression [String]
    err
              Result
    Equal -> do
                Report ()
    reportSuccess
                [Located Interaction] -> Report ()
    go [Located Interaction]
    xs
        go [] = () -> Report ()
    forall a. a -> MaybeT (StateT ReportState IO) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()