{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

module Test.Syd.Def.Around where

import Control.Exception
import Control.Monad.RWS.Strict
import Data.Kind
import Test.QuickCheck.IO ()
import Test.Syd.Def.TestDefM
import Test.Syd.HList
import Test.Syd.Run
import Test.Syd.SpecDef

-- | Run a custom action before every spec item, to set up an inner resource 'c'.
before ::
  -- | The function to run before every test, to produce the inner resource
  IO inner ->
  TestDefM outers inner result ->
  TestDefM outers () result
before :: IO inner
-> TestDefM outers inner result -> TestDefM outers () result
before IO inner
action = ((inner -> IO ()) -> IO ())
-> TestDefM outers inner result -> TestDefM outers () result
forall inner (outers :: [*]) result.
((inner -> IO ()) -> IO ())
-> TestDefM outers inner result -> TestDefM outers () result
around (IO inner
action IO inner -> (inner -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=)

-- | Run a custom action before every spec item without setting up any inner resources.
before_ ::
  -- | The function to run before every test
  IO () ->
  TestDefM outers inner result ->
  TestDefM outers inner result
before_ :: IO ()
-> TestDefM outers inner result -> TestDefM outers inner result
before_ IO ()
action = (IO () -> IO ())
-> TestDefM outers inner result -> TestDefM outers inner result
forall (outers :: [*]) inner result.
(IO () -> IO ())
-> TestDefM outers inner result -> TestDefM outers inner result
around_ (IO ()
action IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>)

-- | Run a custom action after every spec item, using the inner resource 'c'.
after ::
  -- | The function to run after every test, using the inner resource
  (inner -> IO ()) ->
  TestDefM outers inner result ->
  TestDefM outers inner result
after :: (inner -> IO ())
-> TestDefM outers inner result -> TestDefM outers inner result
after inner -> IO ()
action = ((inner -> IO ()) -> inner -> IO ())
-> TestDefM outers inner result -> TestDefM outers inner result
forall newInner oldInner (outers :: [*]) result.
((newInner -> IO ()) -> oldInner -> IO ())
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
aroundWith (((inner -> IO ()) -> inner -> IO ())
 -> TestDefM outers inner result -> TestDefM outers inner result)
-> ((inner -> IO ()) -> inner -> IO ())
-> TestDefM outers inner result
-> TestDefM outers inner result
forall a b. (a -> b) -> a -> b
$ \inner -> IO ()
e inner
x -> inner -> IO ()
e inner
x IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
`finally` inner -> IO ()
action inner
x

-- | Run a custom action after every spec item without using any inner resources.
after_ ::
  -- | The function to run after every test
  IO () ->
  TestDefM outers inner result ->
  TestDefM outers inner result
after_ :: IO ()
-> TestDefM outers inner result -> TestDefM outers inner result
after_ IO ()
action = (inner -> IO ())
-> TestDefM outers inner result -> TestDefM outers inner result
forall inner (outers :: [*]) result.
(inner -> IO ())
-> TestDefM outers inner result -> TestDefM outers inner result
after ((inner -> IO ())
 -> TestDefM outers inner result -> TestDefM outers inner result)
-> (inner -> IO ())
-> TestDefM outers inner result
-> TestDefM outers inner result
forall a b. (a -> b) -> a -> b
$ \inner
_ -> IO ()
action

-- | Run a custom action before and/or after every spec item, to provide access to an inner resource 'c'.
--
-- See the @FOOTGUN@ note in the docs for 'around_'.
around ::
  -- | The function to provide the inner resource around every test
  ((inner -> IO ()) -> IO ()) ->
  TestDefM outers inner result ->
  TestDefM outers () result
around :: ((inner -> IO ()) -> IO ())
-> TestDefM outers inner result -> TestDefM outers () result
around (inner -> IO ()) -> IO ()
action = ((inner -> IO ()) -> () -> IO ())
-> TestDefM outers inner result -> TestDefM outers () result
forall newInner oldInner (outers :: [*]) result.
((newInner -> IO ()) -> oldInner -> IO ())
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
aroundWith (((inner -> IO ()) -> () -> IO ())
 -> TestDefM outers inner result -> TestDefM outers () result)
-> ((inner -> IO ()) -> () -> IO ())
-> TestDefM outers inner result
-> TestDefM outers () result
forall a b. (a -> b) -> a -> b
$ \inner -> IO ()
e () -> (inner -> IO ()) -> IO ()
action inner -> IO ()
e

-- | Run a custom action before and/or after every spec item without accessing any inner resources.
--
-- It is important that the wrapper function that you provide runs the action that it gets _exactly once_.
--
-- == __FOOTGUN__
--
-- This combinator gives the programmer a lot of power.
-- In fact, it gives the programmer enough power to break the test framework.
-- Indeed, you can provide a wrapper function that just _doesn't_ run the function like this:
--
-- > spec :: Spec
-- > spec = do
-- >    let don'tDo :: IO () -> IO ()
-- >        don'tDo _ = pure ()
-- >    around_ don'tDo $ do
-- >      it "should pass" True
--
-- During execution, you'll then get an error like this:
--
-- > thread blocked indefinitely in an MVar operation
--
-- The same problem exists when using 'Test.Syd.Def.Around.aroundAll_'.
--
-- The same thing will go wrong if you run the given action more than once like this:
--
-- > spec :: Spec
-- > spec = do
-- >    let doTwice :: IO () -> IO ()
-- >        doTwice f = f >> f
-- >    around_ doTwice $ do
-- >      it "should pass" True
--
--
-- Note: If you're interested in fixing this, talk to me, but only after GHC has gotten impredicative types because that will likely be a requirement.
around_ ::
  -- | The function to wrap every test with
  (IO () -> IO ()) ->
  TestDefM outers inner result ->
  TestDefM outers inner result
around_ :: (IO () -> IO ())
-> TestDefM outers inner result -> TestDefM outers inner result
around_ IO () -> IO ()
action = ((inner -> IO ()) -> inner -> IO ())
-> TestDefM outers inner result -> TestDefM outers inner result
forall newInner oldInner (outers :: [*]) result.
((newInner -> IO ()) -> oldInner -> IO ())
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
aroundWith (((inner -> IO ()) -> inner -> IO ())
 -> TestDefM outers inner result -> TestDefM outers inner result)
-> ((inner -> IO ()) -> inner -> IO ())
-> TestDefM outers inner result
-> TestDefM outers inner result
forall a b. (a -> b) -> a -> b
$ \inner -> IO ()
e inner
a -> IO () -> IO ()
action (inner -> IO ()
e inner
a)

-- | Run a custom action before and/or after every spec item, to provide access to an inner resource 'c' while using the inner resource 'd'.
--
-- See the @FOOTGUN@ note in the docs for 'around_'.
aroundWith ::
  forall newInner oldInner outers result.
  ((newInner -> IO ()) -> (oldInner -> IO ())) ->
  TestDefM outers newInner result ->
  TestDefM outers oldInner result
aroundWith :: ((newInner -> IO ()) -> oldInner -> IO ())
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
aroundWith (newInner -> IO ()) -> oldInner -> IO ()
func =
  ((HList outers -> newInner -> IO ())
 -> HList outers -> oldInner -> IO ())
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
forall newInner oldInner outer result (outers :: [*]).
HContains outers outer =>
((outer -> newInner -> IO ()) -> outer -> oldInner -> IO ())
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
aroundWith' (((HList outers -> newInner -> IO ())
  -> HList outers -> oldInner -> IO ())
 -> TestDefM outers newInner result
 -> TestDefM outers oldInner result)
-> ((HList outers -> newInner -> IO ())
    -> HList outers -> oldInner -> IO ())
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
forall a b. (a -> b) -> a -> b
$
    \(HList outers -> newInner -> IO ()
takeAC :: HList outers -> newInner -> IO ()) -- Just to make sure the 'a' is not ambiguous.
     HList outers
a
     oldInner
d ->
        (newInner -> IO ()) -> oldInner -> IO ()
func (\newInner
c -> HList outers -> newInner -> IO ()
takeAC HList outers
a newInner
c) oldInner
d

-- | Run a custom action around every spec item, to provide access to an inner resource 'newInner' while using the inner resource 'oldInner' and any outer resource available.
aroundWith' ::
  forall newInner oldInner outer result (outers :: [Type]).
  HContains outers outer =>
  -- | The function that provides the new inner resource using the old resource.
  -- It can also use and modify the outer resource
  ((outer -> newInner -> IO ()) -> (outer -> oldInner -> IO ())) ->
  TestDefM outers newInner result ->
  TestDefM outers oldInner result
aroundWith' :: ((outer -> newInner -> IO ()) -> outer -> oldInner -> IO ())
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
aroundWith' (outer -> newInner -> IO ()) -> outer -> oldInner -> IO ()
func (TestDefM RWST TestRunSettings (TestForest outers newInner) () IO result
rwst) = RWST TestRunSettings (TestForest outers oldInner) () IO result
-> TestDefM outers oldInner result
forall (outers :: [*]) inner result.
RWST TestRunSettings (TestForest outers inner) () IO result
-> TestDefM outers inner result
TestDefM (RWST TestRunSettings (TestForest outers oldInner) () IO result
 -> TestDefM outers oldInner result)
-> RWST TestRunSettings (TestForest outers oldInner) () IO result
-> TestDefM outers oldInner result
forall a b. (a -> b) -> a -> b
$
  ((IO (result, (), TestForest outers newInner)
  -> IO (result, (), TestForest outers oldInner))
 -> RWST TestRunSettings (TestForest outers newInner) () IO result
 -> RWST TestRunSettings (TestForest outers oldInner) () IO result)
-> RWST TestRunSettings (TestForest outers newInner) () IO result
-> (IO (result, (), TestForest outers newInner)
    -> IO (result, (), TestForest outers oldInner))
-> RWST TestRunSettings (TestForest outers oldInner) () IO result
forall a b c. (a -> b -> c) -> b -> a -> c
flip (IO (result, (), TestForest outers newInner)
 -> IO (result, (), TestForest outers oldInner))
-> RWST TestRunSettings (TestForest outers newInner) () IO result
-> RWST TestRunSettings (TestForest outers oldInner) () IO result
forall (m :: * -> *) a s w (n :: * -> *) b w' r.
(m (a, s, w) -> n (b, s, w')) -> RWST r w s m a -> RWST r w' s n b
mapRWST RWST TestRunSettings (TestForest outers newInner) () IO result
rwst ((IO (result, (), TestForest outers newInner)
  -> IO (result, (), TestForest outers oldInner))
 -> RWST TestRunSettings (TestForest outers oldInner) () IO result)
-> (IO (result, (), TestForest outers newInner)
    -> IO (result, (), TestForest outers oldInner))
-> RWST TestRunSettings (TestForest outers oldInner) () IO result
forall a b. (a -> b) -> a -> b
$ \IO (result, (), TestForest outers newInner)
inner -> do
    (result
res, ()
s, TestForest outers newInner
forest) <- IO (result, (), TestForest outers newInner)
inner
    -- a: outers
    -- c: newInner
    -- d: oldInner
    let modifyVal ::
          forall x.
          HContains x outer =>
          (((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult) ->
          ((HList x -> oldInner -> IO ()) -> IO ()) ->
          IO TestRunResult
        modifyVal :: (((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult)
-> ((HList x -> oldInner -> IO ()) -> IO ()) -> IO TestRunResult
modifyVal ((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult
takeSupplyXC (HList x -> oldInner -> IO ()) -> IO ()
supplyXD =
          let supplyXC :: (HList x -> newInner -> IO ()) -> IO ()
              supplyXC :: (HList x -> newInner -> IO ()) -> IO ()
supplyXC HList x -> newInner -> IO ()
takeXC =
                let takeXD :: HList x -> oldInner -> IO ()
                    takeXD :: HList x -> oldInner -> IO ()
takeXD HList x
x oldInner
d =
                      let takeAC :: outer -> newInner -> IO ()
takeAC outer
_ newInner
c = HList x -> newInner -> IO ()
takeXC HList x
x newInner
c
                       in (outer -> newInner -> IO ()) -> outer -> oldInner -> IO ()
func outer -> newInner -> IO ()
takeAC (HList x -> outer
forall (l :: [*]) a. HContains l a => HList l -> a
getElem HList x
x) oldInner
d
                 in (HList x -> oldInner -> IO ()) -> IO ()
supplyXD HList x -> oldInner -> IO ()
takeXD
           in ((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult
takeSupplyXC (HList x -> newInner -> IO ()) -> IO ()
supplyXC

        -- For this function to work recursively, the first parameter of the input and the output types must be the same
        modifyTree ::
          forall x extra. HContains x outer => SpecDefTree x newInner extra -> SpecDefTree x oldInner extra
        modifyTree :: SpecDefTree x newInner extra -> SpecDefTree x oldInner extra
modifyTree = \case
          DefDescribeNode Text
t SpecDefForest x newInner extra
sdf -> Text
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall (outers :: [*]) inner extra.
Text
-> SpecDefForest outers inner extra
-> SpecDefTree outers inner extra
DefDescribeNode Text
t (SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra)
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall a b. (a -> b) -> a -> b
$ SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest SpecDefForest x newInner extra
sdf
          DefPendingNode Text
t Maybe Text
mr -> Text -> Maybe Text -> SpecDefTree x oldInner extra
forall (outers :: [*]) inner extra.
Text -> Maybe Text -> SpecDefTree outers inner extra
DefPendingNode Text
t Maybe Text
mr
          DefSpecifyNode Text
t TDef
  (((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult)
td extra
e -> Text
-> TDef
     (((HList x -> oldInner -> IO ()) -> IO ()) -> IO TestRunResult)
-> extra
-> SpecDefTree x oldInner extra
forall (outers :: [*]) inner extra.
Text
-> TDef
     (((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
-> extra
-> SpecDefTree outers inner extra
DefSpecifyNode Text
t ((((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult)
-> ((HList x -> oldInner -> IO ()) -> IO ()) -> IO TestRunResult
forall (x :: [*]).
HContains x outer =>
(((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult)
-> ((HList x -> oldInner -> IO ()) -> IO ()) -> IO TestRunResult
modifyVal ((((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult)
 -> ((HList x -> oldInner -> IO ()) -> IO ()) -> IO TestRunResult)
-> TDef
     (((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult)
-> TDef
     (((HList x -> oldInner -> IO ()) -> IO ()) -> IO TestRunResult)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TDef
  (((HList x -> newInner -> IO ()) -> IO ()) -> IO TestRunResult)
td) extra
e
          DefWrapNode IO () -> IO ()
f SpecDefForest x newInner extra
sdf -> (IO () -> IO ())
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall (outers :: [*]) inner extra.
(IO () -> IO ())
-> SpecDefForest outers inner extra
-> SpecDefTree outers inner extra
DefWrapNode IO () -> IO ()
f (SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra)
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall a b. (a -> b) -> a -> b
$ SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest SpecDefForest x newInner extra
sdf
          DefBeforeAllNode IO outer
f SpecDefForest (outer : x) newInner extra
sdf -> IO outer
-> SpecDefForest (outer : x) oldInner extra
-> SpecDefTree x oldInner extra
forall outer (otherOuters :: [*]) inner extra.
IO outer
-> SpecDefForest (outer : otherOuters) inner extra
-> SpecDefTree otherOuters inner extra
DefBeforeAllNode IO outer
f (SpecDefForest (outer : x) oldInner extra
 -> SpecDefTree x oldInner extra)
-> SpecDefForest (outer : x) oldInner extra
-> SpecDefTree x oldInner extra
forall a b. (a -> b) -> a -> b
$ SpecDefForest (outer : x) newInner extra
-> SpecDefForest (outer : x) oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest SpecDefForest (outer : x) newInner extra
sdf
          DefAroundAllNode (outer -> IO ()) -> IO ()
f SpecDefForest (outer : x) newInner extra
sdf -> ((outer -> IO ()) -> IO ())
-> SpecDefForest (outer : x) oldInner extra
-> SpecDefTree x oldInner extra
forall outer (otherOuters :: [*]) inner extra.
((outer -> IO ()) -> IO ())
-> SpecDefForest (outer : otherOuters) inner extra
-> SpecDefTree otherOuters inner extra
DefAroundAllNode (outer -> IO ()) -> IO ()
f (SpecDefForest (outer : x) oldInner extra
 -> SpecDefTree x oldInner extra)
-> SpecDefForest (outer : x) oldInner extra
-> SpecDefTree x oldInner extra
forall a b. (a -> b) -> a -> b
$ SpecDefForest (outer : x) newInner extra
-> SpecDefForest (outer : x) oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest SpecDefForest (outer : x) newInner extra
sdf
          DefAroundAllWithNode (newOuter -> IO ()) -> oldOuter -> IO ()
f SpecDefForest (newOuter : oldOuter : otherOuters) newInner extra
sdf -> ((newOuter -> IO ()) -> oldOuter -> IO ())
-> SpecDefForest (newOuter : oldOuter : otherOuters) oldInner extra
-> SpecDefTree (oldOuter : otherOuters) oldInner extra
forall newOuter oldOuter (otherOuters :: [*]) inner extra.
((newOuter -> IO ()) -> oldOuter -> IO ())
-> SpecDefForest (newOuter : oldOuter : otherOuters) inner extra
-> SpecDefTree (oldOuter : otherOuters) inner extra
DefAroundAllWithNode (newOuter -> IO ()) -> oldOuter -> IO ()
f (SpecDefForest (newOuter : oldOuter : otherOuters) oldInner extra
 -> SpecDefTree (oldOuter : otherOuters) oldInner extra)
-> SpecDefForest (newOuter : oldOuter : otherOuters) oldInner extra
-> SpecDefTree (oldOuter : otherOuters) oldInner extra
forall a b. (a -> b) -> a -> b
$ SpecDefForest (newOuter : oldOuter : otherOuters) newInner extra
-> SpecDefForest (newOuter : oldOuter : otherOuters) oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest SpecDefForest (newOuter : oldOuter : otherOuters) newInner extra
sdf
          DefAfterAllNode HList x -> IO ()
f SpecDefForest x newInner extra
sdf -> (HList x -> IO ())
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall (outers :: [*]) inner extra.
(HList outers -> IO ())
-> SpecDefForest outers inner extra
-> SpecDefTree outers inner extra
DefAfterAllNode HList x -> IO ()
f (SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra)
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall a b. (a -> b) -> a -> b
$ SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest SpecDefForest x newInner extra
sdf
          DefParallelismNode Parallelism
f SpecDefForest x newInner extra
sdf -> Parallelism
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall (outers :: [*]) inner extra.
Parallelism
-> SpecDefForest outers inner extra
-> SpecDefTree outers inner extra
DefParallelismNode Parallelism
f (SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra)
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall a b. (a -> b) -> a -> b
$ SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest SpecDefForest x newInner extra
sdf
          DefRandomisationNode ExecutionOrderRandomisation
f SpecDefForest x newInner extra
sdf -> ExecutionOrderRandomisation
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall (outers :: [*]) inner extra.
ExecutionOrderRandomisation
-> SpecDefForest outers inner extra
-> SpecDefTree outers inner extra
DefRandomisationNode ExecutionOrderRandomisation
f (SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra)
-> SpecDefForest x oldInner extra -> SpecDefTree x oldInner extra
forall a b. (a -> b) -> a -> b
$ SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest SpecDefForest x newInner extra
sdf
        modifyForest ::
          forall x extra.
          HContains x outer =>
          SpecDefForest x newInner extra ->
          SpecDefForest x oldInner extra
        modifyForest :: SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest = (SpecDefTree x newInner extra -> SpecDefTree x oldInner extra)
-> SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
forall a b. (a -> b) -> [a] -> [b]
map SpecDefTree x newInner extra -> SpecDefTree x oldInner extra
forall (x :: [*]) extra.
HContains x outer =>
SpecDefTree x newInner extra -> SpecDefTree x oldInner extra
modifyTree
    let forest' :: SpecDefForest outers oldInner ()
        forest' :: TestForest outers oldInner
forest' = TestForest outers newInner -> TestForest outers oldInner
forall (x :: [*]) extra.
HContains x outer =>
SpecDefForest x newInner extra -> SpecDefForest x oldInner extra
modifyForest TestForest outers newInner
forest
    (result, (), TestForest outers oldInner)
-> IO (result, (), TestForest outers oldInner)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (result
res, ()
s, TestForest outers oldInner
forest')