1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
{-# LANGUAGE OverloadedStrings #-}
module Text.Microstache.RenderSpec
( main
, spec )
where
import Control.Exception (evaluate)
import Data.Aeson (object, KeyValue (..), Value (..))
import Data.Text (Text)
import Test.Hspec
import Text.Parsec
import Text.Microstache.Render
import Text.Microstache.Type
import qualified Data.Map as M
main :: IO ()
main = hspec spec
spec :: Spec
spec = describe "renderMustache" $ do
let w ns value =
let template = Template "test" (M.singleton "test" ns)
in fst (renderMustacheW template value)
r ns value =
let template = Template "test" (M.singleton "test" ns)
in renderMustache template value
key = Key . return
it "leaves text block “as is”" $
r [TextBlock "a text block"] Null `shouldBe` "a text block"
it "renders escaped variables correctly" $
r [EscapedVar (key "foo")]
(object ["foo" .= ("<html>&\"something\"</html>" :: Text)])
`shouldBe` "<html>&"something"</html>"
it "renders unescaped variables “as is”" $
r [UnescapedVar (key "foo")]
(object ["foo" .= ("<html>&\"something\"</html>" :: Text)])
`shouldBe` "<html>&\"something\"</html>"
context "when rendering a variable" $ do
it "warns when variable doesn't exist" $
w [EscapedVar (key "foo")] (object []) `shouldBe`
[MustacheVariableNotFound (key "foo")]
it "warns when variable is non-scalar" $
w [EscapedVar (key "foo")] (object [ "foo" .= object []]) `shouldBe`
[MustacheDirectlyRenderedValue (key "foo")]
context "when rendering a section" $ do
let nodes = [Section (key "foo") [UnescapedVar (key "bar"), TextBlock "*"]]
context "when the key is not present" $
it "warns with the correct warning" $
w nodes (object []) `shouldBe`
[MustacheVariableNotFound (key "foo")]
context "when the key is not present inside a section" $
it "warns with the correct warning" $
w nodes (object ["foo" .= ([1] :: [Int])]) `shouldBe`
[MustacheVariableNotFound (Key ["foo","bar"])]
context "when the key is present" $ do
context "when the key is a “false” value" $ do
it "skips the Null value" $
r nodes (object ["foo" .= Null]) `shouldBe` ""
it "skips false Boolean" $
r nodes (object ["foo" .= False]) `shouldBe` ""
it "skips empty list" $
r nodes (object ["foo" .= ([] :: [Text])]) `shouldBe` ""
it "skips empty object" $
r nodes (object ["foo" .= object []]) `shouldBe` ""
it "skips empty string" $
r nodes (object ["foo" .= ("" :: Text)]) `shouldBe` ""
context "when the key is a Boolean true" $
it "renders the section without interpolation" $
r [Section (key "foo") [TextBlock "brr"]]
(object ["foo" .= object ["bar" .= True]])
`shouldBe` "brr"
context "when the key is an object" $
it "uses it to render section once" $
r nodes (object ["foo" .= object ["bar" .= ("huh?" :: Text)]])
`shouldBe` "huh?*"
context "when the key is a singleton list" $
it "uses it to render section once" $
r nodes (object ["foo" .= object ["bar" .= ("huh!" :: Text)]])
`shouldBe` "huh!*"
context "when the key is a list of Boolean trues" $
it "renders the section as many times as there are elements" $
r [Section (key "foo") [TextBlock "brr"]]
(object ["foo" .= [True, True]])
`shouldBe` "brrbrr"
context "when the key is a list of objects" $
it "renders the section many times changing context" $
r nodes (object ["foo" .= [object ["bar" .= x] | x <- [1..4] :: [Int]]])
`shouldBe` "1*2*3*4*"
context "when the key is a number" $ do
it "renders the section" $
r [Section (key "foo") [TextBlock "brr"]]
(object ["foo" .= (5 :: Int)])
`shouldBe` "brr"
it "uses the key as context" $
r [Section (key "foo") [EscapedVar (Key [])]]
(object ["foo" .= (5 :: Int)])
`shouldBe` "5"
context "when the key is a non-empty string" $ do
it "renders the section" $
r [Section (key "foo") [TextBlock "brr"]]
(object ["foo" .= ("x" :: Text)])
`shouldBe` "brr"
it "uses the key as context" $
r [Section (key "foo") [EscapedVar (Key [])]]
(object ["foo" .= ("x" :: Text)])
`shouldBe` "x"
context "when rendering an inverted section" $ do
let nodes = [InvertedSection (key "foo") [TextBlock "Here!"]]
context "when the key is not present" $
it "warns the correct warning" $
w nodes (object []) `shouldBe`
[MustacheVariableNotFound (key "foo")]
context "when the key is present" $ do
context "when the key is a “false” value" $ do
it "renders with Null value" $
r nodes (object ["foo" .= Null]) `shouldBe` "Here!"
it "renders with false Boolean" $
r nodes (object ["foo" .= False]) `shouldBe` "Here!"
it "renders with empty list" $
r nodes (object ["foo" .= ([] :: [Text])]) `shouldBe` "Here!"
it "renders with empty object" $
r nodes (object ["foo" .= object []]) `shouldBe` "Here!"
context "when the key is a “true” value" $ do
it "skips true Boolean" $
r nodes (object ["foo" .= True]) `shouldBe` ""
it "skips non-empty object" $
r nodes (object ["foo" .= object ["bar" .= True]]) `shouldBe` ""
it "skips non-empty list" $
r nodes (object ["foo" .= [True]]) `shouldBe` ""
context "when rendering a partial" $ do
let nodes = [ Partial "partial" (Just 4)
, TextBlock "*" ]
it "skips missing partial" $
r nodes Null `shouldBe` " *"
it "renders partial correctly" $
let template = Template "test" $
M.fromList [ ("test", nodes)
, ("partial", [TextBlock "one\ntwo\nthree"]) ]
in renderMustache template Null `shouldBe`
" one\n two\n three*"
context "when using dotted keys inside a section" $
it "it should be equivalent to access via one more section" $
r [ Section (key "things")
[ EscapedVar (Key ["atts", "color"])
, TextBlock " == "
, Section (key "atts") [EscapedVar (key "color")] ] ]
(object ["things" .=
[object
["atts" .=
object ["color" .= ("blue" :: Text)]]]])
`shouldBe` "blue == blue"
|