dojang-0.2.1: test/Dojang/Syntax/Manifest/WriterSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Dojang.Syntax.Manifest.WriterSpec (spec) where
import qualified Data.HashMap.Strict as HashMap
import Data.List (sort)
import qualified Data.Map.Strict as Map
import Data.Maybe (listToMaybe)
import Data.Text (isInfixOf, unpack)
import System.OsPath (encodeFS)
import Test.Hspec (Spec, runIO, specify)
import Test.Hspec.Expectations.Pretty (shouldBe, shouldSatisfy)
import Test.Hspec.Hedgehog
( annotate
, annotateShow
, assert
, forAll
, hedgehog
, (===)
)
import Dojang.MonadFileSystem (FileType (File))
import Dojang.Syntax.Manifest.Parser (readManifest)
import Dojang.Syntax.Manifest.Writer (WriteError (..), writeManifest)
import Dojang.Types.EnvironmentPredicate
( EnvironmentPredicate (Moniker, OperatingSystem)
, normalizePredicate
)
import Dojang.Types.FileRoute (FileRoute (FileRoute), fileRoute')
import Dojang.Types.Gen as Gen (arbitraryManifest, manifest)
import Dojang.Types.Manifest (Manifest (Manifest))
import Dojang.Types.MonikerName (parseMonikerName)
spec :: Spec
spec = do
path <- runIO $ encodeFS "foo"
let Right alpha = parseMonikerName "alpha"
Right zeta = parseMonikerName "zeta"
linux = OperatingSystem "linux"
specify "writeManifest" $ hedgehog $ do
manifest' <- forAll Gen.manifest
let Right toml = writeManifest manifest'
annotate $ unpack toml
let Right (parsed, _) = readManifest toml
annotateShow parsed
parsed === manifest'
specify "rejects route predicates that cannot be represented" $ do
let route = fileRoute' (const Nothing) [(linux, Nothing)] File
manifest' = Manifest HashMap.empty (Map.singleton path route) Map.empty Map.empty
writeManifest manifest'
`shouldBe` Left (UnrepresentableRoutePredicate path linux)
specify "rejects route predicates that map to the same moniker" $ do
let monikers = HashMap.singleton alpha linux
route =
fileRoute'
(`HashMap.lookup` monikers)
[(Moniker alpha, Nothing), (linux, Nothing)]
File
manifest' = Manifest monikers (Map.singleton path route) Map.empty Map.empty
writeManifest manifest'
`shouldBe` Left (DuplicateRouteMoniker path alpha)
specify "never drops arbitrary route predicates" $ hedgehog $ do
manifest'@(Manifest monikers routes ignores hooks) <-
forAll Gen.arbitraryManifest
case writeManifest manifest' of
Left (UnrepresentableRoutePredicate routePath predicate) -> do
let Just (FileRoute _ predicates _) = Map.lookup routePath routes
assert $
predicate `elem` (normalizePredicate . fst <$> predicates)
assert $
all
((/= predicate) . normalizePredicate)
(HashMap.elems monikers)
Left (DuplicateRouteMoniker routePath moniker) -> do
let Just (FileRoute _ predicates _) = Map.lookup routePath routes
resolve predicate = case normalizePredicate predicate of
Moniker name -> Just name
normalizedPredicate ->
listToMaybe $
sort
[ name
| (name, definition) <- HashMap.toList monikers
, normalizePredicate definition == normalizedPredicate
]
matches =
[ ()
| (predicate, _) <- predicates
, resolve predicate == Just moniker
]
assert $ length matches > 1
Right toml -> do
annotate $ unpack toml
let Right (Manifest monikers' routes' ignores' hooks', _) =
readManifest toml
routeShape (FileRoute _ predicates fileType) =
(sort $ show . snd <$> predicates, fileType)
monikers' === monikers
Map.map routeShape routes' === Map.map routeShape routes
ignores' === ignores
hooks' === hooks
specify "selects deterministically between equivalent monikers" $ do
let monikers = HashMap.fromList [(zeta, linux), (alpha, linux)]
route = fileRoute' (`HashMap.lookup` monikers) [(linux, Nothing)] File
manifest' = Manifest monikers (Map.singleton path route) Map.empty Map.empty
Right toml = writeManifest manifest'
toml `shouldSatisfy` isInfixOf "alpha = \"\""