module Test.Mockery.Environment (
  withEnvironment
, withModifiedEnvironment
) where

import           Control.Exception.Base
import           Control.Monad
import           System.Environment.Compat

-- |
-- Run the given action within the specified environment.
--
-- Before executing the action, `withEnvironment` backs up the current
-- environment, clears out the environment, and then applies the supplied
-- environment.
-- After the action has completed the original environment is restored.
--
-- __Note__: The environment is global to a process, so tests that modify the
-- environment can no longer be run in parallel.
withEnvironment :: [(String, String)] -> IO a -> IO a
withEnvironment :: forall a. [(String, String)] -> IO a -> IO a
withEnvironment [(String, String)]
environment IO a
action = forall a. IO a -> IO a
bracketEnvironment forall a b. (a -> b) -> a -> b
$ do
  [(String, String)] -> IO ()
setEnvironment [(String, String)]
environment
  IO a
action

-- |
-- Run the given action within an augmented environment.
--
-- Before executing the action, `withModifiedEnvironment` backs up the current
-- environment and then augments it with the supplied values.
-- After the action has completed the original environment is restored.
--
-- __Note__: The environment is global to a process, so tests that modify the
-- environment can no longer be run in parallel.
withModifiedEnvironment :: [(String, String)] -> IO a -> IO a
withModifiedEnvironment :: forall a. [(String, String)] -> IO a -> IO a
withModifiedEnvironment [(String, String)]
environment IO a
action = forall a. IO a -> IO a
bracketEnvironment forall a b. (a -> b) -> a -> b
$ do
  [(String, String)] -> IO ()
extendEnvironment [(String, String)]
environment
  IO a
action

bracketEnvironment :: IO a -> IO a
bracketEnvironment :: forall a. IO a -> IO a
bracketEnvironment = forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket IO [(String, String)]
getEnvironment [(String, String)] -> IO ()
setEnvironment forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> b -> a
const

setEnvironment :: [(String, String)] -> IO ()
setEnvironment :: [(String, String)] -> IO ()
setEnvironment [(String, String)]
environment = do
  IO ()
clearEnvironment
  [(String, String)] -> IO ()
extendEnvironment [(String, String)]
environment

extendEnvironment :: [(String, String)] -> IO ()
extendEnvironment :: [(String, String)] -> IO ()
extendEnvironment [(String, String)]
environment = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(String, String)]
environment forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry String -> String -> IO ()
setEnv

clearEnvironment :: IO ()
clearEnvironment :: IO ()
clearEnvironment = do
  [(String, String)]
environment <- IO [(String, String)]
getEnvironment
  forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(String, String)]
environment (String -> IO ()
unsetEnv forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)