{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
module Test.Hspec.Dirstream
(
testFiles
, testFilesErr
, testFilesIO
, testFilesPure
, dirFiles
, allFiles
, F.extension
, hasExtension
, FileProcessor (..)
, PathFilter
, Recursor
, PathProducer
, SafeSpecM
) where
import Control.Monad.Fail (MonadFail (..))
import Data.DirStream
import Data.Text (Text)
import qualified Filesystem.Path.CurrentOS as F
import Pipes
import qualified Pipes.Prelude as P
import Pipes.Safe
import System.FilePath hiding (hasExtension)
import Test.Hspec
import Test.Hspec.Core.Spec
deriving instance MonadCatch (SpecM a)
deriving instance MonadThrow (SpecM a)
deriving instance MonadMask (SpecM a)
deriving instance MonadIO (SpecM a)
instance MonadFail (SpecM a) where
fail = error
hasExtension :: Text -> F.FilePath -> Bool
hasExtension = flip F.hasExtension
mapS :: (a -> SpecM () ()) -> Proxy () a y' y (SafeT (SpecM ())) r
mapS = P.mapM_ . (lift .)
type SafeSpecM = SafeT (SpecM ())
type Recursor = F.FilePath -> ListT SafeSpecM F.FilePath
type PathProducer = String -> PathFilter -> Producer String SafeSpecM ()
dirFiles :: PathProducer
dirFiles = getDirFiles childOf
allFiles :: PathProducer
allFiles = getDirFiles descendentOf
getDirFiles :: Recursor -> PathProducer
getDirFiles g dir p = every (g path) >-> P.filter p >-> P.map F.encodeString
where path = F.decodeString dir
testFiles :: (Eq a, Show a)
=> FilePath
-> (F.FilePath -> Bool)
-> (String -> Either a String)
-> SpecWith ()
testFiles = testHelper testFile dirFiles
testHelper :: (a -> String -> SpecWith ()) -> PathProducer -> String -> PathFilter -> a -> SpecWith ()
testHelper testFunction paths dir p = runSafeT . runEffect . (paths dir p >->) . mapS . testFunction
testFilesIO :: FilePath
-> PathFilter
-> (String -> IO String)
-> SpecWith ()
testFilesIO = testHelper testFileIO dirFiles
testFilesPure :: (Show b, Eq b)
=> FilePath
-> PathFilter
-> PathProducer
-> FileProcessor a b
-> SpecWith ()
testFilesPure dir p paths = runSafeT . runEffect . (paths dir p >->) . mapS . testFilePure
testFileIO :: (String -> IO String) -> String -> SpecWith ()
testFileIO fun f = it f $ do
sample <- readFile f
expected <- readFile (replaceExtension f ".out")
fun sample >>= (`shouldBe` expected)
type PathFilter = F.FilePath -> Bool
testFilesErr :: (Show b, Eq b) => FilePath -> PathFilter -> (String -> Either String b) -> SpecWith ()
testFilesErr dir p f = runSafeT $ runEffect $ dirFiles dir p >-> mapS (testFileErr f)
data FileProcessor a b = FileProc { reader :: FilePath -> IO a
, processor :: a -> b
, check :: b -> Bool
}
testFilePure :: (Eq b, Show b) => FileProcessor a b
-> String
-> SpecWith ()
testFilePure (FileProc rdr g p) f = it f $ do
sample <- rdr f
g sample `shouldSatisfy` p
testFileErr :: (Eq b, Show b) => (String -> Either String b) -> String -> SpecWith ()
testFileErr fun f = it f $ do
sample <- readFile f
expected <- readFile (replaceExtension f ".out")
fun sample `shouldBe` Left expected
testFile :: (Eq a, Show a) => (String -> Either a String) -> String -> SpecWith ()
testFile fun f = it f $ do
sample <- readFile f
expected <- readFile (replaceExtension f ".out")
fun sample `shouldBe` Right expected