module Test.Syd.Def.Scenario (scenarioDir, scenarioDirRecur) where

import Control.Monad
import Control.Monad.IO.Class
import Data.Maybe
import Path
import Path.IO
import qualified System.FilePath as FP
import Test.Syd.Def.Specify
import Test.Syd.Def.TestDefM

-- | Define a test for each file in the given directory.
--
-- Example:
--
-- >   scenarioDir "test_resources/even" $ \fp ->
-- >     it "contains an even number" $ do
-- >       s <- readFile fp
-- >       n <- readIO s
-- >       (n :: Int) `shouldSatisfy` even
scenarioDir :: FilePath -> (FilePath -> TestDefM outers inner ()) -> TestDefM outers inner ()
scenarioDir :: FilePath
-> (FilePath -> TestDefM outers inner ())
-> TestDefM outers inner ()
scenarioDir = (Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File]))
-> FilePath
-> (FilePath -> TestDefM outers inner ())
-> TestDefM outers inner ()
forall (outers :: [*]) inner.
(Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File]))
-> FilePath
-> (FilePath -> TestDefM outers inner ())
-> TestDefM outers inner ()
scenarioDirHelper Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File])
forall (m :: * -> *) b.
MonadIO m =>
Path b Dir -> m ([Path Rel Dir], [Path Rel File])
listDirRel

-- | Define a test for each file in the given directory, recursively.
--
-- Example:
--
-- >   scenarioDirRecur "test_resources/odd" $ \fp ->
-- >     it "contains an odd number" $ do
-- >       s <- readFile fp
-- >       n <- readIO s
-- >       (n :: Int) `shouldSatisfy` odd
scenarioDirRecur :: FilePath -> (FilePath -> TestDefM outers inner ()) -> TestDefM outers inner ()
scenarioDirRecur :: FilePath
-> (FilePath -> TestDefM outers inner ())
-> TestDefM outers inner ()
scenarioDirRecur = (Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File]))
-> FilePath
-> (FilePath -> TestDefM outers inner ())
-> TestDefM outers inner ()
forall (outers :: [*]) inner.
(Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File]))
-> FilePath
-> (FilePath -> TestDefM outers inner ())
-> TestDefM outers inner ()
scenarioDirHelper Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File])
forall (m :: * -> *) b.
MonadIO m =>
Path b Dir -> m ([Path Rel Dir], [Path Rel File])
listDirRecurRel

scenarioDirHelper ::
  (Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File])) ->
  FilePath ->
  (FilePath -> TestDefM outers inner ()) ->
  TestDefM outers inner ()
scenarioDirHelper :: (Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File]))
-> FilePath
-> (FilePath -> TestDefM outers inner ())
-> TestDefM outers inner ()
scenarioDirHelper Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File])
lister FilePath
dp FilePath -> TestDefM outers inner ()
func =
  FilePath -> TestDefM outers inner () -> TestDefM outers inner ()
forall (outers :: [*]) inner.
FilePath -> TestDefM outers inner () -> TestDefM outers inner ()
describe FilePath
dp (TestDefM outers inner () -> TestDefM outers inner ())
-> TestDefM outers inner () -> TestDefM outers inner ()
forall a b. (a -> b) -> a -> b
$ do
    Path Abs Dir
ad <- IO (Path Abs Dir) -> TestDefM outers inner (Path Abs Dir)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Path Abs Dir) -> TestDefM outers inner (Path Abs Dir))
-> IO (Path Abs Dir) -> TestDefM outers inner (Path Abs Dir)
forall a b. (a -> b) -> a -> b
$ FilePath -> IO (Path Abs Dir)
forall (m :: * -> *). MonadIO m => FilePath -> m (Path Abs Dir)
resolveDir' FilePath
dp
    [Path Rel File]
fs <- IO [Path Rel File] -> TestDefM outers inner [Path Rel File]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [Path Rel File] -> TestDefM outers inner [Path Rel File])
-> IO [Path Rel File] -> TestDefM outers inner [Path Rel File]
forall a b. (a -> b) -> a -> b
$ (Maybe [Path Rel File] -> [Path Rel File])
-> IO (Maybe [Path Rel File]) -> IO [Path Rel File]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Path Rel File] -> Maybe [Path Rel File] -> [Path Rel File]
forall a. a -> Maybe a -> a
fromMaybe []) (IO (Maybe [Path Rel File]) -> IO [Path Rel File])
-> IO (Maybe [Path Rel File]) -> IO [Path Rel File]
forall a b. (a -> b) -> a -> b
$ IO [Path Rel File] -> IO (Maybe [Path Rel File])
forall (m :: * -> *) a.
(MonadIO m, MonadCatch m) =>
m a -> m (Maybe a)
forgivingAbsence (IO [Path Rel File] -> IO (Maybe [Path Rel File]))
-> IO [Path Rel File] -> IO (Maybe [Path Rel File])
forall a b. (a -> b) -> a -> b
$ ([Path Rel Dir], [Path Rel File]) -> [Path Rel File]
forall a b. (a, b) -> b
snd (([Path Rel Dir], [Path Rel File]) -> [Path Rel File])
-> IO ([Path Rel Dir], [Path Rel File]) -> IO [Path Rel File]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Path Abs Dir -> IO ([Path Rel Dir], [Path Rel File])
lister Path Abs Dir
ad
    [Path Rel File]
-> (Path Rel File -> TestDefM outers inner ())
-> TestDefM outers inner ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Path Rel File]
fs ((Path Rel File -> TestDefM outers inner ())
 -> TestDefM outers inner ())
-> (Path Rel File -> TestDefM outers inner ())
-> TestDefM outers inner ()
forall a b. (a -> b) -> a -> b
$ \Path Rel File
rf -> do
      let fp :: FilePath
fp = FilePath
dp FilePath -> FilePath -> FilePath
FP.</> Path Rel File -> FilePath
fromRelFile Path Rel File
rf
      FilePath -> TestDefM outers inner () -> TestDefM outers inner ()
forall (outers :: [*]) inner.
FilePath -> TestDefM outers inner () -> TestDefM outers inner ()
describe (Path Rel File -> FilePath
fromRelFile Path Rel File
rf) (TestDefM outers inner () -> TestDefM outers inner ())
-> TestDefM outers inner () -> TestDefM outers inner ()
forall a b. (a -> b) -> a -> b
$ FilePath -> TestDefM outers inner ()
func FilePath
fp