stache-2.3.4: tests/Text/Mustache/ParserSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Text.Mustache.ParserSpec
( main,
spec,
)
where
import Test.Hspec
import Test.Hspec.Megaparsec
import Text.Megaparsec
import Text.Mustache.Parser
import Text.Mustache.Type
main :: IO ()
main = hspec spec
spec :: Spec
spec = describe "parseMustache" $ do
let p = parseMustache ""
key = Key . pure
it "parses text" $
p "test12356p0--=-34{}jnv,\n"
`shouldParse` [TextBlock "test12356p0--=-34{}jnv,\n"]
context "when parsing a variable" $ do
context "with white space" $ do
it "parses escaped {{ variable }}" $
p "{{ name }}" `shouldParse` [EscapedVar (key "name")]
it "parses unescaped {{{ variable }}}" $
p "{{{ name }}}" `shouldParse` [UnescapedVar (key "name")]
it "parses unescaped {{& variable }}" $
p "{{& name }}" `shouldParse` [UnescapedVar (key "name")]
it "parses escaped {{ nested.variable }}" $
p "{{ a.b }}" `shouldParse` [EscapedVar (Key ["a", "b"])]
it "parses escaped {{ nested . variable . with . spaces }}" $
p "{{ a . b . c }}" `shouldParse` [EscapedVar (Key ["a ", " b ", " c"])]
context "without white space" $ do
it "parses escaped {{variable}}" $
p "{{name}}" `shouldParse` [EscapedVar (key "name")]
it "parses unescaped {{{variable}}}" $
p "{{{name}}}" `shouldParse` [UnescapedVar (key "name")]
it "parses unescaped {{& variable }}" $
p "{{&name}}" `shouldParse` [UnescapedVar (key "name")]
it "allows '-' in variable names" $
p "{{ var-name }}" `shouldParse` [EscapedVar (key "var-name")]
it "allows '_' in variable names" $
p "{{ var_name }}" `shouldParse` [EscapedVar (key "var_name")]
context "when parsing a section" $ do
it "parses empty section" $
p "{{#section}}{{/section}}" `shouldParse` [Section (key "section") []]
it "parses non-empty section" $
p "{{# section }}Hi, {{name}}!\n{{/section}}"
`shouldParse` [ Section
(key "section")
[ TextBlock "Hi, ",
EscapedVar (key "name"),
TextBlock "!\n"
]
]
context "when parsing an inverted section" $ do
it "parses empty inverted section" $
p "{{^section}}{{/section}}"
`shouldParse` [InvertedSection (key "section") []]
it "parses non-empty inverted section" $
p "{{^ section }}No one here?!\n{{/section}}"
`shouldParse` [InvertedSection (key "section") [TextBlock "No one here?!\n"]]
context "when parsing a partial" $ do
it "parses a partial with white space" $
p "{{> that-s_my-partial }}"
`shouldParse` [Partial "that-s_my-partial" (Just $ mkPos 1)]
it "parses a partial without white space" $
p "{{>that-s_my-partial}}"
`shouldParse` [Partial "that-s_my-partial" (Just $ mkPos 1)]
it "handles indented partial correctly" $
p " {{> next_one }}"
`shouldParse` [Partial "next_one" (Just $ mkPos 4)]
context "when running into delimiter change" $ do
it "has effect" $
p "{{=<< >>=}}<<var>>{{var}}"
`shouldParse` [EscapedVar (key "var"), TextBlock "{{var}}"]
it "handles whitespace just as well" $
p "{{=<< >>=}}<< var >>{{ var }}"
`shouldParse` [EscapedVar (key "var"), TextBlock "{{ var }}"]
it "affects {{{s" $
p "{{=<< >>=}}<<{var}>>"
`shouldParse` [UnescapedVar (key "var")]
it "parses two subsequent delimiter changes" $
p "{{=(( ))=}}(( var ))((=-- $-=))--#section$---/section$-"
`shouldParse` [EscapedVar (key "var"), Section (key "section") []]
it "propagates delimiter change from a nested scope" $
p "{{#section}}{{=<< >>=}}<</section>><<var>>"
`shouldParse` [Section (key "section") [], EscapedVar (key "var")]
context "when given malformed input" $ do
let keyConstErr = "key-constituent characters"
it "rejects unclosed tags" $ do
let s = "{{ name "
p s `shouldFailWith` err 8 (ueof <> etoks "}}" <> etok '.' <> elabel keyConstErr)
it "rejects il-formed expressions" $ do
let s = "{{ foo..bar }}"
p s `shouldFailWith` err 7 (utoks "." <> elabel keyConstErr)
it "rejects unclosed sections" $
p `shouldFailOn` "{{#foo}} bar "