1{-# LANGUAGE QuasiQuotes #-} 2{-# LANGUAGE TemplateHaskell #-} 3{-# LANGUAGE CPP #-} 4module Text.JuliusSpec (spec) where 5 6import Test.HUnit hiding (Test) 7import Test.Hspec 8 9import Prelude hiding (reverse) 10#ifdef TEST_COFFEE 11import Text.Coffee 12#endif 13import Text.Julius 14import Quoter (quote, quoteFile, quoteFileReload) 15import Data.List (intercalate) 16import qualified Data.Text.Lazy as T 17import qualified Data.List 18import qualified Data.List as L 19import Data.Text (Text, pack, unpack) 20import Data.Monoid (mappend) 21import Data.Aeson (toJSON) 22 23join :: [String] -> String 24#ifdef TEST_COFFEE 25join l = (intercalate ";\n" l) 26#else 27join = intercalate "\n" 28#endif 29 30spec :: Spec 31spec = do 32#if !(defined TEST_COFFEE || defined TEST_ROY) 33 it "julius" $ do 34 let var = "x=2" 35 let urlp = (Home, [(pack "p", pack "q")]) 36 flip jelper [quote|['שלום', @{Home}, #{rawJS var}, '@?{urlp}', ^{jmixin} ]|] 37 $ intercalate " " 38 [ "['שלום'," 39 , "url, " ++ var ++ "," 40 , "'url?p=q'," 41 , "f(2) ]" 42 ] 43 44 45 it "juliusFile" $ do 46 let var = "x=2" 47 let urlp = (Home, [(pack "p", pack "q")]) 48 flip jelper $(quoteFile "test/juliuses/external1.julius") $ join 49 [ "שלום" 50 , var 51 , "url" 52 , "url?p=q" 53 , "f(2)" 54 ] ++ "\n" 55 56 57 it "juliusFileReload" $ do 58 let var = "x=2" 59 let urlp = (Home, [(pack "p", pack "q")]) 60 flip jelper $(quoteFileReload "test/juliuses/external1.julius") $ join 61 [ "שלום" 62 , var 63 , "url" 64 , "url?p=q" 65 , "f(2)" 66 ] ++ "\n" 67#endif 68 69{- TODO 70 it "juliusFileDebugChange" $ do 71 let var = "somevar" 72 test result = jelper result $(juliusFileDebug "test/juliuses/external2.julius") 73 writeFile "test/juliuses/external2.julius" "var #{var} = 1;" 74 test "var somevar = 1;" 75 writeFile "test/juliuses/external2.julius" "var #{var} = 2;" 76 test "var somevar = 2;" 77 writeFile "test/juliuses/external2.julius" "var #{var} = 1;" 78 -} 79 80 81 it "julius module names" $ 82 let foo = "foo" 83 double = 3.14 :: Double 84 int = -5 :: Int 85#ifdef TEST_COFFEE 86 in jelper "var _this = this;\n\n(function(shakespeare_var_rawJSDataListreversefoo, shakespeare_var_rawJSLreversefoo, shakespeare_var_rawJSshowdouble, shakespeare_var_rawJSshowint) {\n return [shakespeare_var_rawJSDataListreversefoo, shakespeare_var_rawJSLreversefoo, shakespeare_var_rawJSshowdouble, shakespeare_var_rawJSshowint];\n})(oof, oof, 3.14, -5);\n" 87#else 88# ifdef TEST_ROY 89 in jelper "(function(shakespeare_var_rawJSDataListreversefoo, shakespeare_var_rawJSLreversefoo, shakespeare_var_rawJSshowdouble, shakespeare_var_rawJSshowint) {\n return [shakespeare_var_rawJSDataListreversefoo, shakespeare_var_rawJSLreversefoo, shakespeare_var_rawJSshowdouble, shakespeare_var_rawJSshowint];\n})(oof, oof, 3.14, -5);\n" 90# else 91 in jelper "[oof, oof, 3.14, -5]" 92# endif 93#endif 94 [quote|[#{rawJS $ Data.List.reverse foo}, #{rawJS $ L.reverse foo}, #{rawJS $ show double}, #{rawJS $ show int}]|] 95 96 97-- not valid coffeescript 98#if !(defined TEST_COFFEE || defined TEST_ROY) 99 it "single dollar at and caret" $ do 100 jelper "$@^" [quote|$@^|] 101 jelper "#{@{^{" [quote|#\{@\{^\{|] 102#endif 103 104 it "dollar operator" $ do 105 let val = (1 :: Int, (2 :: Int, 3 :: Int)) 106#if (defined TEST_COFFEE) 107 jelper "var _this = this;\n\n(function(shakespeare_var_rawJSshowfstsndval) {\n return shakespeare_var_rawJSshowfstsndval;\n})(2);\n" [quote|#{ rawJS $ show $ fst $ snd val }|] 108 jelper "var _this = this;\n\n(function(shakespeare_var_rawJSshowfstsndval) {\n return shakespeare_var_rawJSshowfstsndval;\n})(2);\n" [quote|#{ rawJS $ show $ fst $ snd val }|] 109#else 110 111# if (defined TEST_ROY) 112 jelper "(function(shakespeare_var_rawJSshowfstsndval) {\n return shakespeare_var_rawJSshowfstsndval;\n})(2);\n" [quote|#{ rawJS $ show $ fst $ snd val }|] 113 jelper "(function(shakespeare_var_rawJSshowfstsndval) {\n return shakespeare_var_rawJSshowfstsndval;\n})(2);\n" [quote|#{ rawJS $ show $ fst $ snd val }|] 114 115# else 116 jelper "2" [quote|#{ rawJS $ show $ fst $ snd val }|] 117 jelper "2" [quote|#{ rawJS $ show $ fst $ snd $ val}|] 118# endif 119#endif 120 121#if (defined TEST_ROY) 122 it "roy function wrapper" $ do 123 let royInsert = rawJS "\"royInsert\"" 124 jelper "(function(shakespeare_var_royInsert) {\n var roy = {\n \"royInsert\": shakespeare_var_royInsert\n };\n return console.log(roy);\n})(\"royInsert\");\n" [quote| 125let roy = { royInsert: #{royInsert} } 126console.log roy 127|] 128#endif 129 it "empty file" $ jelper "" [quote||] 130 131 it "JSON data" $ jelper "\"Hello \\\"World!\\\"\"" [julius|#{toJSON "Hello \"World!\""}|] 132 133 it "< escaping" $ jelper "\"\\u003c\"" [julius|#{toJSON "<"}|] 134 135 it "> escaping" $ jelper "\"\\u003e\"" [julius|#{toJSON ">"}|] 136 137 it "& escaping" $ jelper "\"\\u0026\"" [julius|#{toJSON "&"}|] 138 139 it "boolean interpolation" $ jelper 140 "true false true false true false" 141 [julius|#{True} #{False} #{toJSON True} #{toJSON False} #{rawJS True} #{rawJS False}|] 142 143 it "^\\ should not be escaped" $ jelper 144 "var re = /[^\\r]/;" 145 [julius|var re = /[^\r]/;|] 146 147 it "^\\{ should be escaped" $ jelper 148 "var re = /[^{]/;" 149 [julius|var re = /[^\{]/;|] 150 151 it "produces escaped JavaScript" $ jelper 152 "\"yay\"" 153 [julius|#{"yay"}|] 154 155data Url = Home | Sub SubUrl 156data SubUrl = SubUrl 157render :: Url -> [(Text, Text)] -> Text 158render Home qs = pack "url" `mappend` showParams qs 159render (Sub SubUrl) qs = pack "suburl" `mappend` showParams qs 160 161showParams :: [(Text, Text)] -> Text 162showParams [] = pack "" 163showParams z = 164 pack $ '?' : intercalate "&" (map go z) 165 where 166 go (x, y) = go' x ++ '=' : go' y 167 go' = concatMap encodeUrlChar . unpack 168 169-- | Taken straight from web-encodings; reimplemented here to avoid extra 170-- dependencies. 171encodeUrlChar :: Char -> String 172encodeUrlChar c 173 -- List of unreserved characters per RFC 3986 174 -- Gleaned from http://en.wikipedia.org/wiki/Percent-encoding 175 | 'A' <= c && c <= 'Z' = [c] 176 | 'a' <= c && c <= 'z' = [c] 177 | '0' <= c && c <= '9' = [c] 178encodeUrlChar c@'-' = [c] 179encodeUrlChar c@'_' = [c] 180encodeUrlChar c@'.' = [c] 181encodeUrlChar c@'~' = [c] 182encodeUrlChar ' ' = "+" 183encodeUrlChar y = 184 let (a, c) = fromEnum y `divMod` 16 185 b = a `mod` 16 186 showHex' x 187 | x < 10 = toEnum $ x + (fromEnum '0') 188 | x < 16 = toEnum $ x - 10 + (fromEnum 'A') 189 | otherwise = error $ "Invalid argument to showHex: " ++ show x 190 in ['%', showHex' b, showHex' c] 191 192 193 194 195#ifndef TEST_ROY 196jmixin :: JavascriptUrl u 197jmixin = [quote|f(2)|] 198#endif 199 200jelper :: String -> JavascriptUrl Url -> Assertion 201jelper res h = do 202 T.pack res @=? renderJavascriptUrl render h 203 204instance Show Url where 205 show _ = "FIXME remove this instance show Url" 206