{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} import Test.Framework (defaultMain, testGroup, Test) import Test.Framework.Providers.HUnit import Test.HUnit hiding (Test) import Prelude hiding (reverse) import Text.Hamlet import Text.Cassius import Text.Julius import Data.List (intercalate) import qualified Data.Text.Lazy as T import qualified Data.List import qualified Data.List as L main :: IO () main = defaultMain [testSuite] testSuite :: Test testSuite = testGroup "Text.Hamlet" [ testCase "empty" caseEmpty , testCase "static" caseStatic , testCase "tag" caseTag , testCase "var" caseVar , testCase "var chain " caseVarChain , testCase "url" caseUrl , testCase "url chain " caseUrlChain , testCase "embed" caseEmbed , testCase "embed chain " caseEmbedChain , testCase "if" caseIf , testCase "if chain " caseIfChain , testCase "else" caseElse , testCase "else chain " caseElseChain , testCase "elseif" caseElseIf , testCase "elseif chain " caseElseIfChain , testCase "list" caseList , testCase "list chain" caseListChain , testCase "script not empty" caseScriptNotEmpty , testCase "meta empty" caseMetaEmpty , testCase "input empty" caseInputEmpty , testCase "multiple classes" caseMultiClass , testCase "attrib order" caseAttribOrder , testCase "nothing" caseNothing , testCase "nothing chain " caseNothingChain , testCase "just" caseJust , testCase "just chain " caseJustChain , testCase "constructor" caseConstructor , testCase "url + params" caseUrlParams , testCase "escape" caseEscape , testCase "empty statement list" caseEmptyStatementList , testCase "attribute conditionals" caseAttribCond , testCase "non-ascii" caseNonAscii , testCase "maybe function" caseMaybeFunction , testCase "trailing dollar sign" caseTrailingDollarSign , testCase "non leading percent sign" caseNonLeadingPercent , testCase "quoted attributes" caseQuotedAttribs , testCase "spaced derefs" caseSpacedDerefs , testCase "attrib vars" caseAttribVars , testCase "strings and html" caseStringsAndHtml , testCase "nesting" caseNesting , testCase "trailing space" caseTrailingSpace , testCase "currency symbols" caseCurrency , testCase "external" caseExternal , testCase "parens" caseParens , testCase "hamlet literals" caseHamletLiterals , testCase "hamlet' and xhamlet'" caseHamlet' , testCase "hamletDebug" caseHamletDebug , testCase "hamlet runtime" caseHamletRT , testCase "hamletFileDebug- changing file" caseHamletFileDebugChange , testCase "hamletFileDebug- features" caseHamletFileDebugFeatures , testCase "cassius" caseCassius , testCase "cassiusFile" caseCassiusFile , testCase "cassiusFileDebug" caseCassiusFileDebug , testCase "cassiusFileDebugChange" caseCassiusFileDebugChange , testCase "julius" caseJulius , testCase "juliusFile" caseJuliusFile , testCase "juliusFileDebug" caseJuliusFileDebug , testCase "juliusFileDebugChange" caseJuliusFileDebugChange , testCase "comments" caseComments , testCase "hamletFileDebug double foralls" caseDoubleForalls , testCase "cassius pseudo-class" casePseudo -- FIXME test is disabled , testCase "different binding names" caseDiffBindNames , testCase "blank line" caseBlankLine , testCase "leading spaces" caseLeadingSpaces , testCase "cassius all spaces" caseCassiusAllSpaces , testCase "cassius whitespace and colons" caseCassiusWhitespaceColons , testCase "cassius trailing comments" caseCassiusTrailingComments , testCase "hamlet angle bracket syntax" caseHamletAngleBrackets , testCase "hamlet module names" caseHamletModuleNames , testCase "cassius module names" caseCassiusModuleNames , testCase "julius module names" caseJuliusModuleNames , testCase "single dollar at and caret" caseSingleDollarAtCaret , testCase "dollar operator" caseDollarOperator , testCase "in a row" caseInARow , testCase "embedded slash" caseEmbeddedSlash , testCase "string literals" caseStringLiterals ] data Url = Home | Sub SubUrl data SubUrl = SubUrl render :: Url -> [(String, String)] -> String render Home qs = "url" ++ showParams qs render (Sub SubUrl) qs = "suburl" ++ showParams qs showParams :: [(String, String)] -> String showParams [] = "" showParams z = '?' : intercalate "&" (map go z) where go (x, y) = go' x ++ '=' : go' y go' = concatMap encodeUrlChar -- | Taken straight from web-encodings; reimplemented here to avoid extra -- dependencies. encodeUrlChar :: Char -> String encodeUrlChar c -- List of unreserved characters per RFC 3986 -- Gleaned from http://en.wikipedia.org/wiki/Percent-encoding | 'A' <= c && c <= 'Z' = [c] | 'a' <= c && c <= 'z' = [c] | '0' <= c && c <= '9' = [c] encodeUrlChar c@'-' = [c] encodeUrlChar c@'_' = [c] encodeUrlChar c@'.' = [c] encodeUrlChar c@'~' = [c] encodeUrlChar ' ' = "+" encodeUrlChar y = let (a, c) = fromEnum y `divMod` 16 b = a `mod` 16 showHex' x | x < 10 = toEnum $ x + (fromEnum '0') | x < 16 = toEnum $ x - 10 + (fromEnum 'A') | otherwise = error $ "Invalid argument to showHex: " ++ show x in ['%', showHex' b, showHex' c] data Arg url = Arg { getArg :: Arg url , var :: Html , url :: Url , embed :: Hamlet url , true :: Bool , false :: Bool , list :: [Arg url] , nothing :: Maybe String , just :: Maybe String , urlParams :: (Url, [(String, String)]) } theArg :: Arg url theArg = Arg { getArg = theArg , var = string "" , url = Home , embed = [$hamlet|embed|] , true = True , false = False , list = [theArg, theArg, theArg] , nothing = Nothing , just = Just "just" , urlParams = (Home, [("foo", "bar"), ("foo1", "bar1")]) } helper :: String -> Hamlet Url -> Assertion helper res h = do let x = renderHamletText render h T.pack res @=? x caseEmpty :: Assertion caseEmpty = helper "" [$hamlet||] caseStatic :: Assertion caseStatic = helper "some static content" [$hamlet|some static content|] caseTag :: Assertion caseTag = helper "

baz

" [$hamlet|

baz |] caseVar :: Assertion caseVar = do helper "<var>" [$hamlet|#{var theArg}|] caseVarChain :: Assertion caseVarChain = do helper "<var>" [$hamlet|#{var (getArg (getArg (getArg theArg)))}|] caseUrl :: Assertion caseUrl = do helper (render Home []) [$hamlet|@{url theArg}|] caseUrlChain :: Assertion caseUrlChain = do helper (render Home []) [$hamlet|@{url (getArg (getArg (getArg theArg)))}|] caseEmbed :: Assertion caseEmbed = do helper "embed" [$hamlet|^{embed theArg}|] caseEmbedChain :: Assertion caseEmbedChain = do helper "embed" [$hamlet|^{embed (getArg (getArg (getArg theArg)))}|] caseIf :: Assertion caseIf = do helper "if" [$hamlet| $if true theArg if |] caseIfChain :: Assertion caseIfChain = do helper "if" [$hamlet| $if true (getArg (getArg (getArg theArg))) if |] caseElse :: Assertion caseElse = helper "else" [$hamlet| $if false theArg if $else else |] caseElseChain :: Assertion caseElseChain = helper "else" [$hamlet| $if false (getArg (getArg (getArg theArg))) if $else else |] caseElseIf :: Assertion caseElseIf = helper "elseif" [$hamlet| $if false theArg if $elseif true theArg elseif $else else |] caseElseIfChain :: Assertion caseElseIfChain = helper "elseif" [$hamlet| $if false(getArg(getArg(getArg theArg))) if $elseif true(getArg(getArg(getArg theArg))) elseif $else else |] caseList :: Assertion caseList = do helper "xxx" [$hamlet| $forall _x <- (list theArg) x |] caseListChain :: Assertion caseListChain = do helper "urlurlurl" [$hamlet| $forall x <- list(getArg(getArg(getArg(getArg(getArg (theArg)))))) @{url x} |] caseScriptNotEmpty :: Assertion caseScriptNotEmpty = helper "" [$hamlet|" [$hamlet|" [$xhamlet|" [$hamlet||] helper "" [$xhamlet||] caseInputEmpty :: Assertion caseInputEmpty = do helper "" [$hamlet|" [$xhamlet|" [$hamlet||] helper "" [$xhamlet||] caseMultiClass :: Assertion caseMultiClass = do helper "

" [$hamlet|<.foo.bar|] helper "
" [$hamlet|<.foo.bar>|] caseAttribOrder :: Assertion caseAttribOrder = do helper "" [$hamlet|" [$hamlet||] caseNothing :: Assertion caseNothing = do helper "" [$hamlet| $maybe _n <- nothing theArg nothing |] helper "nothing" [$hamlet| $maybe _n <- nothing theArg something $nothing nothing |] caseNothingChain :: Assertion caseNothingChain = helper "" [$hamlet| $maybe n <- nothing(getArg(getArg(getArg theArg))) nothing #{n} |] caseJust :: Assertion caseJust = helper "it's just" [$hamlet| $maybe n <- just theArg it's #{n} |] caseJustChain :: Assertion caseJustChain = helper "it's just" [$hamlet| $maybe n <- just(getArg(getArg(getArg theArg))) it's #{n} |] caseConstructor :: Assertion caseConstructor = do helper "url" [$hamlet|@{Home}|] helper "suburl" [$hamlet|@{Sub SubUrl}|] let text = "" helper "" [$hamlet|#{preEscapedString text}|] caseUrlParams :: Assertion caseUrlParams = do helper "url?foo=bar&foo1=bar1" [$hamlet|@?{urlParams theArg}|] caseEscape :: Assertion caseEscape = do helper "#this is raw\n " [$hamlet| \#this is raw \ \ |] helper "$@^" [$hamlet|$@^|] caseEmptyStatementList :: Assertion caseEmptyStatementList = do helper "" [$hamlet|$if True|] helper "" [$hamlet|$maybe _x <- Nothing|] let emptyList = [] helper "" [$hamlet|$forall _x <- emptyList|] caseAttribCond :: Assertion caseAttribCond = do helper "" [$hamlet|" [$hamlet|" [$hamlet|" [$hamlet|" [$hamlet|" [$hamlet|" [$hamlet| " [$hamlet|<.#{var theArg}|] caseAttribVars :: Assertion caseAttribVars = do helper "
" [$hamlet|<##{var theArg}|] helper "
" [$hamlet|<.#{var theArg}|] helper "
" [$hamlet|< f=#{var theArg}|] helper "
" [$hamlet|<##{var theArg}>|] helper "
" [$hamlet|<.#{var theArg}>|] helper "
" [$hamlet|< f=#{var theArg}>|] caseStringsAndHtml :: Assertion caseStringsAndHtml = do let str = "" let html = preEscapedString "" helper "<string> " [$hamlet|#{str} #{html}|] caseNesting :: Assertion caseNesting = do helper "
1
2
" [$hamlet| #{user} |] helper (concat [ "" ]) [$hamlet|