pandoc-3.8: test/Tests/Writers/LaTeX.hs
{-# LANGUAGE OverloadedStrings #-}
module Tests.Writers.LaTeX (tests) where
import Data.Text (pack, unpack)
import Test.Tasty
import Test.Tasty.HUnit (HasCallStack)
import Tests.Helpers
import Text.Pandoc
import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
latex :: (ToPandoc a) => a -> String
latex = latexWithOpts def
latexListing :: (ToPandoc a) => a -> String
latexListing = latexWithOpts def{ writerHighlightMethod = IdiomaticHighlighting }
latexWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
latexWithOpts opts = unpack . purely (writeLaTeX opts) . toPandoc
beamerWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
beamerWithOpts opts = unpack . purely (writeBeamer opts) . toPandoc
{-
"my test" =: X =?> Y
is shorthand for
test latex "my test" $ X =?> Y
which is in turn shorthand for
test latex "my test" (X,Y)
-}
infix 4 =:
(=:) :: (ToString a, ToPandoc a, HasCallStack)
=> String -> (a, String) -> TestTree
(=:) = test latex
tests :: [TestTree]
tests = [ testGroup "code blocks"
[ "in footnotes" =: note (para "hi" <> codeBlock "hi") =?>
"\\footnote{hi\n\n\\begin{Verbatim}\nhi\n\\end{Verbatim}\n}"
, test latexListing "identifier" $ codeBlockWith ("id",[],[]) "hi" =?>
("\\begin{lstlisting}[label=id]\nhi\n\\end{lstlisting}" :: String)
, test latexListing "no identifier" $ codeBlock "hi" =?>
("\\begin{lstlisting}\nhi\n\\end{lstlisting}" :: String)
]
, testGroup "definition lists"
[ "with internal link" =: definitionList [(link "#go" "" (str "testing"),
[plain (text "hi there")])] =?>
"\\begin{description}\n\\tightlist\n\\item[{\\hyperref[go]{testing}}]\nhi there\n\\end{description}"
]
, testGroup "math"
[ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
"\\(\\sigma|_{\\{x\\}}\\)"
]
, testGroup "headers"
[ "unnumbered header" =:
headerWith ("foo",["unnumbered"],[]) 1
(text "Header 1" <> note (plain $ text "note")) =?>
"\\section*{\\texorpdfstring{Header 1\\footnote{note}}{Header 1}}\\label{foo}\n\\addcontentsline{toc}{section}{Header 1}\n"
, "in list item" =:
bulletList [header 2 (text "foo")] =?>
"\\begin{itemize}\n\\item ~\n \\subsection{foo}\n\\end{itemize}"
, "in definition list item" =:
definitionList [(text "foo", [header 2 (text "bar"),
para $ text "baz"])] =?>
"\\begin{description}\n\\item[foo] ~ \n\\subsection{bar}\n\nbaz\n\\end{description}"
, "containing image" =:
header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?>
"\\section{\\texorpdfstring{\\protect\\pandocbounded{\\includegraphics[keepaspectratio,alt={Alt text}]{imgs/foo.jpg}}}{Alt text}}"
]
, testGroup "inline code"
[ "struck out and highlighted" =:
strikeout (codeWith ("",["haskell"],[]) "foo" <> space
<> str "bar") =?>
"\\st{\\mbox{\\VERB|\\NormalTok{foo}|} bar}"
, "struck out and not highlighted" =:
strikeout (code "foo" <> space
<> str "bar") =?>
"\\st{\\mbox{\\texttt{foo}} bar}"
, "single quotes" =:
code "dog's" =?> "\\texttt{dog\\textquotesingle{}s}"
, "backtick" =:
code "`nu?`" =?> "\\texttt{\\textasciigrave{}nu?\\textasciigrave{}}"
]
, testGroup "inline note"
[ "Big note in emph" =:
emph (str "This sentence"
<> note (para (str "paragraph1")
<> para (str "paragraph2"))
<> str " has footnote.")
=?>
"\\emph{This sentence}\\footnote{paragraph1\n\n paragraph2}"
<> "\\emph{ has footnote.}"
, "Big note in strong" =:
strong (str "This sentence"
<> note (para (str "paragraph1")
<> para (str "paragraph2"))
<> str " has footnote.")
=?>
"\\textbf{This sentence}\\footnote{paragraph1\n\n paragraph2}"
<> "\\textbf{ has footnote.}"
, "Big note in underline" =:
underline (str "This sentence"
<> note (para (str "paragraph1")
<> para (str "paragraph2"))
<> str " has footnote.")
=?>
"\\ul{This sentence}\\footnote{paragraph1\n\n paragraph2}"
<> "\\ul{ has footnote.}"
, "Big note in strikeout" =:
strikeout (str "This sentence"
<> note (para (str "paragraph1")
<> para (str "paragraph2"))
<> str " has footnote.")
=?>
"\\st{This sentence}\\footnote{paragraph1\n\n paragraph2}"
<> "\\st{ has footnote.}"
, "Small note in emph" =:
emph (str "This sentence"
<> note (para (str "paragraph"))
<> str " has footnote.")
=?>
"\\emph{This sentence\\footnote{paragraph} has footnote.}"
, "Big note nested in emph and strong" =:
emph (str "This "
<> strong (str "nested sentence "
<> note (para (str "paragraph1")
<> para (str "paragraph2"))
<> str "has ")
<> str "footnote."
)
=?>
"\\emph{This \\textbf{nested sentence }}\\footnote{paragraph1\n\n"
<> " paragraph2}\\emph{\\textbf{has }footnote.}"
, "Two Big notes in emph" =:
emph (str "This sentence"
<> note (para (str "1-paragraph1")
<> para (str "1-paragraph2"))
<> str " has"
<> note (para (str "2-paragraph1")
<> para (str "2-paragraph2"))
<> str " footnote.")
=?>
"\\emph{This sentence}\\footnote{1-paragraph1\n\n 1-paragraph2}"
<> "\\emph{ has}\\footnote{2-paragraph1\n\n 2-paragraph2}"
<> "\\emph{ footnote.}"
]
, testGroup "writer options"
[ testGroup "top-level division" $
let
headers = header 1 (text "header1")
<> header 2 (text "header2")
<> header 3 (text "header3")
latexTopLevelDiv :: (ToPandoc a) => TopLevelDivision -> a -> String
latexTopLevelDiv division =
latexWithOpts def{ writerTopLevelDivision = division }
beamerTopLevelDiv :: (ToPandoc a)
=> TopLevelDivision -> a -> String
beamerTopLevelDiv division =
beamerWithOpts def { writerTopLevelDivision = division }
in
[ test (latexTopLevelDiv TopLevelSection)
"sections as top-level" $ headers =?>
unlines [ "\\section{header1}\n"
, "\\subsection{header2}\n"
, "\\subsubsection{header3}"
]
, test (latexTopLevelDiv TopLevelChapter)
"chapters as top-level" $ headers =?>
unlines [ "\\chapter{header1}\n"
, "\\section{header2}\n"
, "\\subsection{header3}"
]
, test (latexTopLevelDiv TopLevelPart)
"parts as top-level" $ headers =?>
unlines [ "\\part{header1}\n"
, "\\chapter{header2}\n"
, "\\section{header3}"
]
, test (latexTopLevelDiv TopLevelDefault)
"default top-level" $ headers =?>
unlines [ "\\section{header1}\n"
, "\\subsection{header2}\n"
, "\\subsubsection{header3}"
]
, test (beamerTopLevelDiv TopLevelSection)
"sections as top-level in beamer" $ headers =?>
unlines [ "\\section{header1}\n"
, "\\subsection{header2}\n"
, "\\subsubsection{header3}"
]
, test (beamerTopLevelDiv TopLevelChapter)
"chapters are as part in beamer" $ headers =?>
unlines [ "\\part{header1}\n"
, "\\section{header2}\n"
, "\\subsection{header3}"
]
, test (beamerTopLevelDiv TopLevelPart)
"parts as top-level in beamer" $ headers =?>
unlines [ "\\part{header1}\n"
, "\\section{header2}\n"
, "\\subsection{header3}"
]
, test (beamerTopLevelDiv TopLevelDefault)
"default top-level in beamer" $ headers =?>
unlines [ "\\section{header1}\n"
, "\\subsection{header2}\n"
, "\\subsubsection{header3}"
]
, test (latexTopLevelDiv TopLevelPart)
"part top-level, section not in toc" $
( headerWith ("", ["unnumbered"], []) 1 (text "header1")
<> headerWith ("", ["unnumbered"], []) 2 (text "header2")
<> headerWith ("", ["unnumbered"], []) 3 (text "header3")
<> headerWith ("", ["unnumbered"], []) 4 (text "header4")
<> headerWith ("", ["unnumbered"], []) 5 (text "header5")
<> headerWith ("", ["unnumbered"], []) 6 (text "header6"))
=?>
unlines [ "\\part*{header1}"
, "\\addcontentsline{toc}{part}{header1}\n"
, "\\chapter*{header2}"
, "\\addcontentsline{toc}{chapter}{header2}\n"
, "\\section*{header3}"
, "\\addcontentsline{toc}{section}{header3}\n"
, "\\subsection*{header4}"
, "\\addcontentsline{toc}{subsection}{header4}\n"
, "\\subsubsection*{header5}"
, "\\addcontentsline{toc}{subsubsection}{header5}\n"
, "\\paragraph*{header6}"
, "\\addcontentsline{toc}{paragraph}{header6}"
]
]
]
, testGroup "figures"
[ "placement" =:
figureWith ("", [], [("latex-placement", "htbp")])
(simpleCaption $ plain "caption")
(plain $ image (pack "img.jpg") (pack "") (text "alt text"))
=?>
"\\begin{figure}[htbp]\n\\centering\n"
<> "\\pandocbounded{\\includegraphics[keepaspectratio,alt={alt text}]{img.jpg}}\n"
<> "\\caption{caption}\n\\end{figure}"
]
]