{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Test.Morpheus.Utils
( FileUrl,
deepScan,
scan,
getResolver,
getSchema,
requireEq,
readSchemaFile,
)
where
import Data.Aeson
( FromJSON (..),
eitherDecode,
)
import Data.ByteString.Lazy.Char8 (ByteString)
import qualified Data.ByteString.Lazy.Char8 as L
import Relude hiding (ByteString)
import Test.Morpheus.File
( FileUrl (FileUrl, fileName, isDir),
ReadSource,
isDirectory,
ls,
readGQL,
readJSON,
scanDirectories,
)
import Test.Tasty
( TestTree,
testGroup,
)
import Test.Tasty.HUnit
( assertFailure,
)
readSchemaFile :: (ReadSource t) => FileUrl -> IO t
readSchemaFile = readGQL "schema"
runCaseTree :: (FileUrl -> [FileUrl] -> [TestTree]) -> CaseTree [FileUrl] -> TestTree
runCaseTree f CaseTree {caseUrl, children = [], assets} =
testGroup (fileName caseUrl) (f caseUrl assets)
runCaseTree f CaseTree {caseUrl = FileUrl {fileName}, children} =
testGroup fileName (fmap (runCaseTree f) children)
foldCaseTree :: (FileUrl -> TestTree) -> CaseTree () -> TestTree
foldCaseTree f CaseTree {caseUrl, children = []} = f caseUrl
foldCaseTree f CaseTree {caseUrl = FileUrl {fileName}, children} =
testGroup fileName (fmap (foldCaseTree f) children)
recursiveScan :: (Monoid assets) => (FileUrl -> IO assets) -> FileUrl -> IO (CaseTree assets)
recursiveScan scanAssets caseUrl = do
dir <- isDirectory caseUrl
children <-
if dir
then do
list <- ls caseUrl
if all isDir list
then traverse (recursiveScan scanAssets) list
else pure []
else pure []
assets <- if dir && null children then scanAssets caseUrl else pure mempty
pure CaseTree {..}
scan :: (FileUrl -> TestTree) -> FileUrl -> IO TestTree
scan f url = foldCaseTree f <$> recursiveScan (const (pure ())) url
deepScan :: (FileUrl -> [FileUrl] -> [TestTree]) -> FileUrl -> IO TestTree
deepScan f url = runCaseTree f <$> recursiveScan scanDirectories url
data CaseTree assets = CaseTree
{ caseUrl :: FileUrl,
children :: [CaseTree assets],
assets :: assets
}
deriving (Show)
requireEq :: (Eq t) => (t -> ByteString) -> t -> t -> IO ()
requireEq f expected actual
| expected == actual = pure ()
| otherwise = eqFailureMessage (f expected) (f actual)
eqFailureMessage :: ByteString -> ByteString -> IO a3
eqFailureMessage expected actual =
assertFailure
$ L.unpack
$ "expected: \n\n "
<> expected
<> " \n\n but got: \n\n "
<> actual
getSchema :: (ReadSource a, Show err) => (a -> Either err b) -> FileUrl -> IO b
getSchema f url =
readSchemaFile url
>>= assertValidSchema
. f
assertValidSchema :: (Show err) => Either err a -> IO a
assertValidSchema =
either
( assertFailure
. ( "unexpected schema validation error: \n "
<>
)
. show
)
pure
getResolver :: (FromJSON resolver) => FileUrl -> IO resolver
getResolver url = readJSON "resolvers" url >>= either fail pure . eitherDecode