    module Test.Mockery.Directory (
      inTempDirectory
    , inTempDirectoryNamed
    , withFile
    , touch
    ) where

    import           Control.Exception
    import           Control.Monad
    import           System.Directory
    import           System.FilePath
    import           System.IO.Error
    import           System.IO hiding (withFile)
    import           System.IO.Temp (withSystemTempDirectory, withSystemTempFile)
    import qualified Data.ByteString as B

    -- |
    -- Run given action with the current working directory set to a temporary
    -- directory.
    --
    -- The directory is created before the action is run.  After the action has
    -- completed the directory is removed and the current working directory is
    -- restored to its original value.
    inTempDirectory :: IO a -> IO a
    inTempDirectory :: forall a. IO a -> IO a
    inTempDirectory IO a
    action = String -> (String -> IO a) -> IO a
    forall (m :: * -> *) a.
    (MonadIO m, MonadMask m) =>
    String -> (String -> m a) -> m a
    withSystemTempDirectory String
    "mockery" ((String -> IO a) -> IO a) -> (String -> IO a) -> IO a
    forall a b. (a -> b) -> a -> b
    $ \String
    path -> do
      IO String -> (String -> IO ()) -> (String -> IO a) -> IO a
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
    bracket IO String
    getCurrentDirectory String -> IO ()
    setCurrentDirectory ((String -> IO a) -> IO a) -> (String -> IO a) -> IO a
    forall a b. (a -> b) -> a -> b
    $ \String
    _ -> do
        String -> IO ()
    setCurrentDirectory String
    path
        IO a
    action

    -- |
    -- Similar to `inTempDirectory`, but the temporary directory will have the
    -- specified name.
    inTempDirectoryNamed :: FilePath -> IO a -> IO a
    inTempDirectoryNamed :: forall a. String -> IO a -> IO a
    inTempDirectoryNamed String
    name IO a
    action = IO a -> IO a
    forall a. IO a -> IO a
    inTempDirectory (IO a -> IO a) -> IO a -> IO a
    forall a b. (a -> b) -> a -> b
    $ do
      String -> IO ()
    createDirectory String
    name
      String -> IO ()
    setCurrentDirectory String
    name
      IO a
    action

    -- |
    -- Create a temporary file with the given contents and execute the given
    -- action.
    --
    -- The file is removed after the action has completed.
    withFile :: String -> (FilePath -> IO a) -> IO a
    withFile :: forall a. String -> (String -> IO a) -> IO a
    withFile String
    input String -> IO a
    action = String -> (String -> Handle -> IO a) -> IO a
    forall (m :: * -> *) a.
    (MonadIO m, MonadMask m) =>
    String -> (String -> Handle -> m a) -> m a
    withSystemTempFile String
    "mockery" ((String -> Handle -> IO a) -> IO a)
    -> (String -> Handle -> IO a) -> IO a
    forall a b. (a -> b) -> a -> b
    $ \String
    file Handle
    h -> do
      Handle -> String -> IO ()
    hPutStr Handle
    h String
    input
      Handle -> IO ()
    hClose Handle
    h
      String -> IO a
    action String
    file

    -- |
    -- Update the modification time of the specified file.
    -- Create an empty file (including any missing directories in the file path) if
    -- the file does not exist.
    touch :: FilePath -> IO ()
    touch :: String -> IO ()
    touch String
    file = do
      Bool -> String -> IO ()
    createDirectoryIfMissing Bool
    True (String -> String
    takeDirectory String
    file)
      c <- (IOError -> Maybe ())
    -> IO ByteString -> (() -> IO ByteString) -> IO ByteString
    forall e b a.
    Exception e =>
    (e -> Maybe b) -> IO a -> (b -> IO a) -> IO a
    catchJust (Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Bool -> Maybe ()) -> (IOError -> Bool) -> IOError -> Maybe ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IOError -> Bool
    isDoesNotExistError) (String -> IO ByteString
    B.readFile String
    file) (IO ByteString -> () -> IO ByteString
    forall a b. a -> b -> a
    const (IO ByteString -> () -> IO ByteString)
    -> IO ByteString -> () -> IO ByteString
    forall a b. (a -> b) -> a -> b
    $ ByteString -> IO ByteString
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ByteString
    B.empty)
      B.writeFile file c