seihou-core-0.4.0.0: test/Seihou/Dhall/ConfigSpec.hs
module Seihou.Dhall.ConfigSpec (tests) where
import Data.Map.Strict qualified as Map
import Data.Text qualified as T
import Data.Text.IO qualified as TIO
import Seihou.Dhall.Config (escapeDhallText, evalConfigFile, evalConfigFileIfExists, serializeConfig)
import System.Directory (getCurrentDirectory)
import System.FilePath ((</>))
import System.IO.Temp (withSystemTempDirectory)
import Test.Hspec
import Test.Tasty
import Test.Tasty.Hspec (testSpec)
tests :: IO TestTree
tests = testSpec "Seihou.Dhall.Config" spec
spec :: Spec
spec = do
describe "evalConfigFile" $ do
it "evaluates a simple Dhall config to Map Text Text" $ do
withSystemTempDirectory "seihou-config-test" $ \tmpDir -> do
let path = tmpDir </> "config.dhall"
writeFile path "{ license = \"MIT\", `project.name` = \"my-app\" }"
result <- evalConfigFile path
Map.lookup "license" result `shouldBe` Just "MIT"
Map.lookup "project.name" result `shouldBe` Just "my-app"
it "evaluates an empty record" $ do
withSystemTempDirectory "seihou-config-test" $ \tmpDir -> do
let path = tmpDir </> "config.dhall"
writeFile path "{=}"
result <- evalConfigFile path
Map.null result `shouldBe` True
describe "evalConfigFileIfExists" $ do
it "returns empty map for nonexistent file" $ do
result <- evalConfigFileIfExists "/nonexistent/path/config.dhall"
result `shouldBe` Right Map.empty
it "returns Right map for valid config file" $ do
withSystemTempDirectory "seihou-config-test" $ \tmpDir -> do
let path = tmpDir </> "config.dhall"
writeFile path "{ license = \"BSD3\" }"
result <- evalConfigFileIfExists path
case result of
Left err -> expectationFailure ("Expected Right, got Left: " <> show err)
Right m -> Map.lookup "license" m `shouldBe` Just "BSD3"
it "returns Left for invalid Dhall" $ do
withSystemTempDirectory "seihou-config-test" $ \tmpDir -> do
let path = tmpDir </> "config.dhall"
writeFile path "this is not valid dhall @@##"
result <- evalConfigFileIfExists path
case result of
Left _ -> pure ()
Right _ -> expectationFailure "Expected Left for invalid Dhall"
describe "serializeConfig" $ do
it "serializes an empty map to {=}" $ do
serializeConfig Map.empty `shouldBe` "{=}\n"
it "serializes a single entry" $ do
let m = Map.fromList [("license", "MIT")]
result = serializeConfig m
result `shouldSatisfy` T.isInfixOf "`license`"
result `shouldSatisfy` T.isInfixOf "\"MIT\""
it "serializes multiple entries in sorted order" $ do
let m = Map.fromList [("z-key", "last"), ("a-key", "first")]
result = serializeConfig m
aPos = T.findIndex (== 'a') result
zPos = T.findIndex (== 'z') result
-- a-key should appear before z-key (sorted)
case (aPos, zPos) of
(Just a, Just z) -> a `shouldSatisfy` (< z)
_ -> expectationFailure "Expected both keys in output"
it "round-trips through evalConfigFile" $ do
withSystemTempDirectory "seihou-config-test" $ \tmpDir -> do
let original = Map.fromList [("project.name", "my-app"), ("license", "MIT")]
path = tmpDir </> "config.dhall"
TIO.writeFile path (serializeConfig original)
result <- evalConfigFile path
result `shouldBe` original
it "round-trips dotted keys" $ do
withSystemTempDirectory "seihou-config-test" $ \tmpDir -> do
let original = Map.fromList [("haskell.ghc", "9.12.2"), ("project.name", "test")]
path = tmpDir </> "config.dhall"
TIO.writeFile path (serializeConfig original)
result <- evalConfigFile path
result `shouldBe` original
it "round-trips values with special characters" $ do
withSystemTempDirectory "seihou-config-test" $ \tmpDir -> do
let original = Map.fromList [("path", "C:\\Users\\me"), ("quote", "say \"hello\"")]
path = tmpDir </> "config.dhall"
TIO.writeFile path (serializeConfig original)
result <- evalConfigFile path
result `shouldBe` original
describe "escapeDhallText" $ do
it "passes through plain text unchanged" $ do
escapeDhallText "hello world" `shouldBe` "hello world"
it "escapes backslashes" $ do
escapeDhallText "a\\b" `shouldBe` "a\\\\b"
it "escapes double-quotes" $ do
escapeDhallText "say \"hi\"" `shouldBe` "say \\\"hi\\\""