kdl-hs-0.2.0: test/KDL/ParserSpec.hs
{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
module KDL.ParserSpec (spec) where
import Data.Text (Text)
import Data.Text qualified as Text
import KDL.Parser
import KDL.Types (
Entry (..),
Identifier (..),
Node (..),
NodeList (..),
Value (..),
ValueData (..),
)
import Skeletest
import Skeletest.Predicate qualified as P
import System.IO.Temp (withSystemTempDirectory)
spec :: Spec
spec = do
describe "parse" $ do
it "parses a KDL document" $ do
let expected =
newNodeList
[ newNode
"foo"
[ newArg $ Number 1.0
, newProp "hello" $ Text "world"
]
( Just
[ newNode "bar" [] (Just [])
]
)
]
parse "foo hello=world 1.0 { bar; }" `shouldBe` Right expected
it "returns a textual error on parse failure" $ do
let msg =
Text.intercalate "\n" $
[ "1:10:"
, " |"
, "1 | foo hello= 123"
, " | ^^"
, "unexpected \"= \""
, "expecting Node Child, Node Space, or Node Terminator"
]
parse "foo hello= 123" `shouldBe` Left msg
describe "parseFile" $ do
it "parses a KDL document from a filepath" $ do
withSystemTempDirectory "" $ \tmpdir -> do
let file = tmpdir ++ "/test.kdl"
writeFile file "foo hello=world 1.0 { bar; }"
let expected =
newNodeList
[ newNode
"foo"
[ newArg $ Number 1.0
, newProp "hello" $ Text "world"
]
( Just
[ newNode "bar" [] (Just [])
]
)
]
parseFile file `shouldSatisfy` P.returns (P.right (P.eq expected))
{----- Helpers -----}
newNodeList :: [Node] -> NodeList
newNodeList nodes =
NodeList
{ nodes = nodes
, format = Nothing
}
newNode :: Text -> [Entry] -> Maybe [Node] -> Node
newNode name entries children =
Node
{ ann = Nothing
, name = newIdentifier name
, entries = entries
, children = newNodeList <$> children
, format = Nothing
}
newArg :: ValueData -> Entry
newArg = newEntry Nothing
newProp :: Text -> ValueData -> Entry
newProp = newEntry . Just
newEntry :: Maybe Text -> ValueData -> Entry
newEntry mName data_ =
Entry
{ name = newIdentifier <$> mName
, value =
Value
{ ann = Nothing
, data_ = data_
, format = Nothing
}
, format = Nothing
}
newIdentifier :: Text -> Identifier
newIdentifier value =
Identifier
{ value = value
, format = Nothing
}