utest.markdown.latexrender.pas 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2025 by Michael Van Canneyt
  4. Markdown LaTeX renderer tests
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. *********************************************************************}
  11. unit UTest.Markdown.LaTeXRender;
  12. {$mode ObjFPC}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, fpcunit, testregistry,
  16. MarkDown.Elements,
  17. MarkDown.LatexRender;
  18. type
  19. { TTestLaTeXRender }
  20. TTestLaTeXRender = Class(TTestCase)
  21. private
  22. FLaTeXRenderer : TMarkDownLaTeXRenderer;
  23. FDocument: TMarkDownDocument;
  24. Public
  25. Procedure SetUp; override;
  26. Procedure TearDown; override;
  27. function CreateTextBlock(aParent: TMarkdownBlock; const aText,aTextNode: string; aNodeStyle : TNodeStyles=[]): TMarkDownTextBlock;
  28. function CreateParagraphBlock(const aTextNode: string): TMarkdownBlock;
  29. function CreateQuotedBlock(const aTextNode: string): TMarkdownBlock;
  30. function CreateHeadingBlock(const aTextNode: string; aLevel : integer): TMarkdownBlock;
  31. function CreateListBlock(aOrdered : boolean; const aListItemText : string): TMarkDownListBlock;
  32. function CreateListItemBlock(aParent: TMarkDownContainerBlock; const aText: string): TMarkDownListItemBlock;
  33. function AppendTextNode(aBlock: TMarkDownTextBlock; const aText: string; aNodeStyle : TNodeStyles) : TMarkDownTextNode;
  34. procedure TestRender(const aLaTeX : string);
  35. Property Renderer : TMarkDownLaTeXRenderer Read FLaTeXRenderer;
  36. Property Document : TMarkDownDocument Read FDocument;
  37. Published
  38. procedure TestHookup;
  39. procedure TestEmpty;
  40. procedure TestEmptyNoEnvelope;
  41. procedure TestEmptyTitle;
  42. procedure TestTextBlockEmpty;
  43. procedure TestTextBlockText;
  44. procedure TestTextBlockTextEscaping;
  45. procedure TestTextBlockTextStrong;
  46. procedure TestTextBlockTextEmph;
  47. procedure TestTextBlockTextDelete;
  48. procedure TestTextBlockTextStrongEmph;
  49. procedure TestPragraphBlockEmpty;
  50. procedure TestPragraphBlockText;
  51. procedure TestQuotedBlockEmpty;
  52. procedure TestQuotedBlockText;
  53. procedure TestHeadingBlockEmpty;
  54. procedure TestHeadingBlockText;
  55. procedure TestHeadingBlockTextLevel2;
  56. procedure TestUnorderedListEmpty;
  57. procedure TestUnorderedListOneItem;
  58. end;
  59. implementation
  60. { TTestLaTeXRender }
  61. procedure TTestLaTeXRender.SetUp;
  62. begin
  63. FLaTeXRenderer:=TMarkDownLaTeXRenderer.Create(Nil);
  64. FDocument:=TMarkDownDocument.Create(Nil,1);
  65. end;
  66. procedure TTestLaTeXRender.TearDown;
  67. begin
  68. FreeAndNil(FDocument);
  69. FreeAndNil(FLaTeXRenderer);
  70. end;
  71. function TTestLaTeXRender.CreateTextBlock(aParent: TMarkdownBlock; const aText, aTextNode: string; aNodeStyle: TNodeStyles): TMarkDownTextBlock;
  72. begin
  73. Result:=TMarkDownTextBlock.Create(aParent,1,aText);
  74. if aTextNode<>'' then
  75. AppendTextNode(Result,aTextNode,aNodeStyle);
  76. end;
  77. function TTestLaTeXRender.CreateParagraphBlock(const aTextNode: string): TMarkdownBlock;
  78. begin
  79. Result:=TMarkDownParagraphBlock.Create(FDocument,1);
  80. if aTextNode<>'' then
  81. CreateTextBlock(Result,aTextNode,aTextNode);
  82. end;
  83. function TTestLaTeXRender.CreateQuotedBlock(const aTextNode: string): TMarkdownBlock;
  84. begin
  85. Result:=TMarkDownQuoteBlock.Create(FDocument,1);
  86. if aTextNode<>'' then
  87. CreateTextBlock(Result,aTextNode,aTextNode);
  88. end;
  89. function TTestLaTeXRender.CreateHeadingBlock(const aTextNode: string; aLevel: integer): TMarkdownBlock;
  90. begin
  91. Result:=TMarkDownHeadingBlock.Create(FDocument,1,aLevel);
  92. if aTextNode<>'' then
  93. CreateTextBlock(Result,aTextNode,aTextNode);
  94. end;
  95. function TTestLaTeXRender.CreateListItemBlock(aParent: TMarkDownContainerBlock; const aText: string): TMarkDownListItemBlock;
  96. var
  97. lPar : TMarkDownParagraphBlock;
  98. begin
  99. Result:=TMarkDownListItemBlock.Create(aParent,1);
  100. lPar:=TMarkDownParagraphBlock.Create(Result,1);
  101. CreateTextBlock(lPar,'',aText);
  102. end;
  103. function TTestLaTeXRender.CreateListBlock(aOrdered: boolean; const aListItemText: string): TMarkDownListBlock;
  104. begin
  105. Result:=TMarkDownListBlock.Create(FDocument,1);
  106. Result.ordered:=aOrdered;
  107. if aListItemText<>'' then
  108. CreateListItemBlock(Result,aListItemText);
  109. end;
  110. function TTestLaTeXRender.AppendTextNode(aBlock: TMarkDownTextBlock; const aText: string; aNodeStyle: TNodeStyles): TMarkDownTextNode;
  111. var
  112. p : TPosition;
  113. t : TMarkdownTextNode;
  114. begin
  115. if aBlock.Nodes=Nil then
  116. aBlock.Nodes:=TMarkDownTextNodeList.Create(True);
  117. p.col:=Length(aBlock.Text);
  118. p.line:=1;
  119. t:=TMarkDownTextNode.Create(p,nkText);
  120. t.addText(aText);
  121. t.active:=False;
  122. T.Styles:=aNodeStyle;
  123. aBlock.Nodes.Add(t);
  124. Result:=T;
  125. end;
  126. procedure TTestLaTeXRender.TestRender(const aLaTeX: string);
  127. var
  128. L : TStrings;
  129. begin
  130. L:=TstringList.Create;
  131. try
  132. L.SkipLastLineBreak:=True;
  133. Renderer.RenderDocument(FDocument,L);
  134. assertEquals('Correct latex: ',aLaTeX,L.Text);
  135. finally
  136. L.Free;
  137. end;
  138. end;
  139. procedure TTestLaTeXRender.TestHookup;
  140. begin
  141. AssertNotNull('Have renderer',FLaTeXRenderer);
  142. AssertNotNull('Have document',FDocument);
  143. AssertEquals('Have empty document',0,FDocument.blocks.Count);
  144. end;
  145. procedure TTestLaTeXRender.TestEmpty;
  146. begin
  147. Renderer.Options:=[loEnvelope];
  148. TestRender('\documentclass{article}'+sLineBreak+
  149. '\usepackage[utf8]{inputenc}'+sLineBreak+
  150. '\usepackage{graphicx}'+sLineBreak+
  151. '\usepackage{hyperref}'+sLineBreak+
  152. '\usepackage{ulem}'+sLineBreak+
  153. '\begin{document}'+sLineBreak+
  154. '\end{document}');
  155. end;
  156. procedure TTestLaTeXRender.TestEmptyNoEnvelope;
  157. begin
  158. Renderer.Options:=[];
  159. TestRender('');
  160. end;
  161. procedure TTestLaTeXRender.TestEmptyTitle;
  162. begin
  163. Renderer.Options:=[loEnvelope];
  164. Renderer.Title:='a';
  165. TestRender('\documentclass{article}'+sLineBreak+
  166. '\usepackage[utf8]{inputenc}'+sLineBreak+
  167. '\usepackage{graphicx}'+sLineBreak+
  168. '\usepackage{hyperref}'+sLineBreak+
  169. '\usepackage{ulem}'+sLineBreak+
  170. '\title{a}'+sLineBreak+
  171. '\begin{document}'+sLineBreak+
  172. '\maketitle'+sLineBreak+
  173. '\end{document}');
  174. end;
  175. procedure TTestLaTeXRender.TestTextBlockEmpty;
  176. begin
  177. CreateTextBlock(Document,'a','');
  178. TestRender('');
  179. end;
  180. procedure TTestLaTeXRender.TestTextBlockText;
  181. begin
  182. CreateTextBlock(Document,'a','a');
  183. TestRender('a');
  184. end;
  185. procedure TTestLaTeXRender.TestTextBlockTextEscaping;
  186. begin
  187. CreateTextBlock(Document,'a','# $ % ^ & _ { } ~ \');
  188. // Expected: \# \$ \% \textasciicircum{} \& \_ \{ \} \textasciitilde{} \textbackslash{}
  189. TestRender('\# \$ \% \textasciicircum{} \& \_ \{ \} \textasciitilde{} \textbackslash{}');
  190. end;
  191. procedure TTestLaTeXRender.TestTextBlockTextStrong;
  192. begin
  193. CreateTextBlock(Document,'a','a',[nsStrong]);
  194. TestRender('\textbf{a}');
  195. end;
  196. procedure TTestLaTeXRender.TestTextBlockTextEmph;
  197. begin
  198. CreateTextBlock(Document,'a','a',[nsEmph]);
  199. TestRender('\textit{a}');
  200. end;
  201. procedure TTestLaTeXRender.TestTextBlockTextDelete;
  202. begin
  203. CreateTextBlock(Document,'a','a',[nsDelete]);
  204. TestRender('\sout{a}');
  205. end;
  206. procedure TTestLaTeXRender.TestTextBlockTextStrongEmph;
  207. begin
  208. CreateTextBlock(Document,'a','a',[nsStrong,nsEmph]);
  209. TestRender('\textbf{\textit{a}}');
  210. end;
  211. procedure TTestLaTeXRender.TestPragraphBlockEmpty;
  212. begin
  213. CreateParagraphBlock('');
  214. TestRender(sLineBreak); // Blank line
  215. end;
  216. procedure TTestLaTeXRender.TestQuotedBlockEmpty;
  217. begin
  218. CreateQuotedBlock('');
  219. TestRender('\begin{quote}'+sLineBreak+'\end{quote}');
  220. end;
  221. procedure TTestLaTeXRender.TestUnorderedListEmpty;
  222. begin
  223. CreateListBlock(false,'');
  224. TestRender('\begin{itemize}'+sLineBreak+'\end{itemize}');
  225. end;
  226. procedure TTestLaTeXRender.TestPragraphBlockText;
  227. begin
  228. CreateParagraphBlock('a');
  229. TestRender('a'+sLineBreak);
  230. end;
  231. procedure TTestLaTeXRender.TestQuotedBlockText;
  232. begin
  233. CreateQuotedBlock('a');
  234. TestRender('\begin{quote}'+sLineBreak+'a\end{quote}');
  235. end;
  236. procedure TTestLaTeXRender.TestHeadingBlockEmpty;
  237. begin
  238. CreateHeadingBlock('',1);
  239. TestRender('\section*{}');
  240. end;
  241. procedure TTestLaTeXRender.TestHeadingBlockText;
  242. begin
  243. CreateHeadingBlock('a',1);
  244. TestRender('\section*{a}');
  245. end;
  246. procedure TTestLaTeXRender.TestHeadingBlockTextLevel2;
  247. begin
  248. CreateHeadingBlock('a',2);
  249. TestRender('\subsection*{a}');
  250. end;
  251. procedure TTestLaTeXRender.TestUnorderedListOneItem;
  252. begin
  253. CreateListBlock(false,'a');
  254. // ListItem appends '\item ' then renders children.
  255. // Children = Paragraph 'a'. Plain paragraph renders children (text 'a').
  256. // Item renderer now adds a newline.
  257. // List renderer adds \begin{itemize}\n ... \end{itemize}\n
  258. TestRender('\begin{itemize}'+sLineBreak+'\item a'+sLineBreak+'\end{itemize}');
  259. end;
  260. initialization
  261. Registertest(TTestLaTeXRender);
  262. end.