git.iko.soy/typeable/pandoc
on abb0e35 help sign in
214 lines 8.4 kB history raw
1{-# LANGUAGE NoImplicitPrelude #-}
2{-# LANGUAGE OverloadedStrings #-}
3{- |
4 Module : Tests.Lua
5 Copyright : © 2017-2019 Albert Krewinkel
6 License : GNU GPL, version 2 or above
8 Maintainer : Albert Krewinkel <albert@zeitkraut.de>
9 Stability : alpha
10 Portability : portable
12Unit and integration tests for pandoc's Lua subsystem.
13-}
14module Tests.Lua ( runLuaTest, tests ) where
16import Prelude
17import Control.Monad (when)
18import System.FilePath ((</>))
19import Test.Tasty (TestTree, localOption)
20import Test.Tasty.HUnit (Assertion, assertEqual, testCase)
21import Test.Tasty.QuickCheck (QuickCheckTests (..), ioProperty, testProperty)
22import Text.Pandoc.Arbitrary ()
23import Text.Pandoc.Builder (bulletList, definitionList, displayMath, divWith,
24 doc, doubleQuoted, emph, header, lineBlock,
25 linebreak, math, orderedList, para, plain, rawBlock,
26 singleQuoted, space, str, strong)
27import Text.Pandoc.Class (runIOorExplode, setUserDataDir)
28import Text.Pandoc.Definition (Block (BlockQuote, Div, Para), Inline (Emph, Str),
29 Attr, Meta, Pandoc, pandocTypesVersion)
30import Text.Pandoc.Filter (Filter (LuaFilter), applyFilters)
31import Text.Pandoc.Lua (runLua)
32import Text.Pandoc.Options (def)
33import Text.Pandoc.Shared (pandocVersion)
35import qualified Foreign.Lua as Lua
36import qualified Data.Text as T
37import qualified Data.Text.Encoding as TE
39tests :: [TestTree]
40tests = map (localOption (QuickCheckTests 20))
41 [ testProperty "inline elements can be round-tripped through the lua stack" $
42 \x -> ioProperty (roundtripEqual (x::Inline))
44 , testProperty "block elements can be round-tripped through the lua stack" $
45 \x -> ioProperty (roundtripEqual (x::Block))
47 , testProperty "meta blocks can be round-tripped through the lua stack" $
48 \x -> ioProperty (roundtripEqual (x::Meta))
50 , testProperty "documents can be round-tripped through the lua stack" $
51 \x -> ioProperty (roundtripEqual (x::Pandoc))
53 , testCase "macro expansion via filter" $
54 assertFilterConversion "a '{{helloworld}}' string is expanded"
55 "strmacro.lua"
56 (doc . para $ str "{{helloworld}}")
57 (doc . para . emph $ str "Hello, World")
59 , testCase "convert all plains to paras" $
60 assertFilterConversion "plains become para"
61 "plain-to-para.lua"
62 (doc $ bulletList [plain (str "alfa"), plain (str "bravo")])
63 (doc $ bulletList [para (str "alfa"), para (str "bravo")])
65 , testCase "convert display math to inline math" $
66 assertFilterConversion "display math becomes inline math"
67 "math.lua"
68 (doc $ para (displayMath "5+5"))
69 (doc $ para (math "5+5"))
71 , testCase "make hello world document" $
72 assertFilterConversion "Document contains 'Hello, World!'"
73 "hello-world-doc.lua"
74 (doc . para $ str "Hey!" <> linebreak <> str "What's up?")
75 (doc . para $ str "Hello," <> space <> str "World!")
77 , testCase "implicit doc filter" $
78 assertFilterConversion "Document contains 'Hello, World!'"
79 "implicit-doc-filter.lua"
80 (doc . plain $ linebreak)
81 (doc . para $ str "Hello," <> space <> str "World!")
83 , testCase "parse raw markdown blocks" $
84 assertFilterConversion "raw markdown block is converted"
85 "markdown-reader.lua"
86 (doc $ rawBlock "markdown" "*charly* **delta**")
87 (doc . para $ emph "charly" <> space <> strong "delta")
89 , testCase "allow shorthand functions for quote types" $
90 assertFilterConversion "single quoted becomes double quoted string"
91 "single-to-double-quoted.lua"
92 (doc . para . singleQuoted $ str "simple")
93 (doc . para . doubleQuoted $ str "simple")
95 , testCase "Count inlines via metatable catch-all" $
96 assertFilterConversion "filtering with metatable catch-all failed"
97 "metatable-catch-all.lua"
98 (doc . para $ "four words, three spaces")
99 (doc . para $ str "7")
101 , testCase "Count blocks via Block-specific catch-all" $
102 assertFilterConversion "filtering with Block catch-all failed"
103 "block-count.lua"
104 (doc $ para "one" <> para "two")
105 (doc $ para "2")
107 , testCase "Smart constructors" $
108 assertFilterConversion "smart constructors returned a wrong result"
109 "smart-constructors.lua"
110 (doc $ para "")
111 (doc $ mconcat
112 [ bulletList [para "Hello", para "World"]
113 , definitionList [("foo", [para "placeholder"])]
114 , lineBlock ["Moin", "Welt"]
115 , orderedList [plain "one", plain "two"]
116 ])
118 , testCase "Convert header upper case" $
119 assertFilterConversion "converting header to upper case failed"
120 "uppercase-header.lua"
121 (doc $ header 1 "les états-unis" <> para "text")
122 (doc $ header 1 "LES ÉTATS-UNIS" <> para "text")
124 , testCase "Attribute lists are convenient to use" $
125 let kv_before = [("one", "1"), ("two", "2"), ("three", "3")]
126 kv_after = [("one", "eins"), ("three", "3"), ("five", "5")]
127 in assertFilterConversion "Attr doesn't behave as expected"
128 "attr-test.lua"
129 (doc $ divWith ("", [], kv_before) (para "nil"))
130 (doc $ divWith ("", [], kv_after) (para "nil"))
132 , testCase "Script filename is set" $
133 assertFilterConversion "unexpected script name"
134 "script-name.lua"
135 (doc $ para "ignored")
136 (doc $ para (str $ T.pack $ "lua" </> "script-name.lua"))
138 , testCase "Pandoc version is set" . runLuaTest $ do
139 Lua.getglobal "PANDOC_VERSION"
140 Lua.liftIO .
141 assertEqual "pandoc version is wrong" (TE.encodeUtf8 pandocVersion)
142 =<< Lua.tostring' Lua.stackTop
144 , testCase "Pandoc types version is set" . runLuaTest $ do
145 Lua.getglobal "PANDOC_API_VERSION"
146 Lua.liftIO . assertEqual "pandoc-types version is wrong" pandocTypesVersion
147 =<< Lua.peek Lua.stackTop
149 , testCase "Allow singleton inline in constructors" . runLuaTest $ do
150 Lua.liftIO . assertEqual "Not the exptected Emph" (Emph [Str "test"])
151 =<< Lua.callFunc "pandoc.Emph" (Str "test")
152 Lua.liftIO . assertEqual "Unexpected element" (Para [Str "test"])
153 =<< Lua.callFunc "pandoc.Para" ("test" :: String)
154 Lua.liftIO . assertEqual "Unexptected element"
155 (BlockQuote [Para [Str "foo"]]) =<< (
156 do
157 Lua.getglobal' "pandoc.BlockQuote"
158 Lua.push (Para [Str "foo"])
159 _ <- Lua.call 1 1
160 Lua.peek Lua.stackTop
161 )
163 , testCase "Elements with Attr have `attr` accessor" . runLuaTest $ do
164 Lua.push (Div ("hi", ["moin"], [])
165 [Para [Str "ignored"]])
166 Lua.getfield Lua.stackTop "attr"
167 Lua.liftIO . assertEqual "no accessor" (("hi", ["moin"], []) :: Attr)
168 =<< Lua.peek Lua.stackTop
170 , testCase "module `pandoc.system` is present" . runLuaTest $ do
171 Lua.getglobal' "pandoc.system"
172 ty <- Lua.ltype Lua.stackTop
173 Lua.liftIO $ assertEqual "module should be a table" Lua.TypeTable ty
175 , testCase "informative error messages" . runLuaTest $ do
176 Lua.pushboolean True
177 err <- Lua.peekEither Lua.stackTop
178 case (err :: Either String Pandoc) of
179 Left msg -> do
180 let expectedMsg = "Could not get Pandoc value: "
181 <> "table expected, got boolean"
182 Lua.liftIO $ assertEqual "unexpected error message" expectedMsg msg
183 Right _ -> error "Getting a Pandoc element from a bool should fail."
184 ]
186assertFilterConversion :: String -> FilePath -> Pandoc -> Pandoc -> Assertion
187assertFilterConversion msg filterPath docIn expectedDoc = do
188 actualDoc <- runIOorExplode $ do
189 setUserDataDir (Just "../data")
190 applyFilters def [LuaFilter ("lua" </> filterPath)] ["HTML"] docIn
191 assertEqual msg expectedDoc actualDoc
193roundtripEqual :: (Eq a, Lua.Peekable a, Lua.Pushable a) => a -> IO Bool
194roundtripEqual x = (x ==) <$> roundtripped
195 where
196 roundtripped :: Lua.Peekable a => IO a
197 roundtripped = runLuaTest $ do
198 oldSize <- Lua.gettop
199 Lua.push x
200 size <- Lua.gettop
201 when (size - oldSize /= 1) $
202 error ("not exactly one additional element on the stack: " ++ show size)
203 res <- Lua.peekEither (-1)
204 case res of
205 Left e -> error (show e)
206 Right y -> return y
208runLuaTest :: Lua.Lua a -> IO a
209runLuaTest op = runIOorExplode $ do
210 setUserDataDir (Just "../data")
211 res <- runLua op
212 case res of
213 Left e -> error (show e)
214 Right x -> return x