1 /*
2   This file is part of the Grantlee template system.
3 
4   Copyright (c) 2008 Stephen Kelly <steveire@gmail.com>
5 
6   This library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either version
9   2.1 of the Licence, or (at your option) any later version.
10 
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public
17   License along with this library.  If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 #include <QtCore/QRegularExpression>
22 #include <QtCore>
23 #include <QtGui/QTextCursor>
24 #include <QtGui/QTextDocument>
25 #include <QtTest/QtTest>
26 #include <QtTest/qtestevent.h>
27 
28 #include "coverageobject.h"
29 #include "markupdirector.h"
30 #include "texthtmlbuilder.h"
31 
32 using namespace Grantlee;
33 
34 class TestHtmlOutput : public CoverageObject
35 {
36   Q_OBJECT
37 private Q_SLOTS:
38 
39   // Test paragraph contents:
40   void testSingleFormat();
41   void testDoubleFormat();
42   void testDoubleStartDifferentFinish();
43   void testDoubleStartDifferentFinishReverseOrder();
44   void testDifferentStartDoubleFinish();
45   void testDifferentStartDoubleFinishReverseOrder();
46   void testOverlap();
47   void testAnchor();
48   void testAnchorWithFormattedContent();
49   void testAdjacentAnchors();
50   void testNestedFormatting();
51   void testSpan();
52   void testDoubleSpan();
53   void testSpanNesting();
54   void testEdgeCaseLeft();
55   void testEdgeCaseRight();
56   void testImage();
57   void testImageResized();
58   void testEachFormatTagSingly();
59   void testHorizontalRule();
60   void testNewlines();
61   void testNewlinesThroughQTextCursor();
62 };
63 
testSingleFormat()64 void TestHtmlOutput::testSingleFormat()
65 {
66   auto doc = new QTextDocument();
67 
68   // One format
69   doc->setHtml(QStringLiteral("This <b>text</b> is bold."));
70 
71   auto hb = new TextHTMLBuilder();
72   auto md = new MarkupDirector(hb);
73   md->processDocument(doc);
74   auto result = hb->getResult();
75   QRegularExpression regex(
76       QStringLiteral("^<p>This <strong>text</strong> is bold.</p>\\n$"));
77 
78   QVERIFY(regex.match(result).hasMatch());
79 }
80 
testDoubleFormat()81 void TestHtmlOutput::testDoubleFormat()
82 {
83   auto doc = new QTextDocument();
84 
85   // One format
86   doc->setHtml(QStringLiteral("Some <b><i>formatted</i></b> text."));
87 
88   auto hb = new TextHTMLBuilder();
89   auto md = new MarkupDirector(hb);
90   md->processDocument(doc);
91   auto result = hb->getResult();
92   QRegularExpression regex(
93       QStringLiteral("^<p>Some "
94                      "(<strong><em>|<em><strong>)formatted(</em></strong>|</"
95                      "strong></em>) text.</p>\\n$"));
96 
97   QVERIFY(regex.match(result).hasMatch());
98 }
99 
testAnchor()100 void TestHtmlOutput::testAnchor()
101 {
102   auto doc = new QTextDocument();
103   doc->setHtml(
104       QStringLiteral("A <a href=\"http://www.kde.org\">link</a> to KDE."));
105 
106   auto hb = new TextHTMLBuilder();
107   auto md = new MarkupDirector(hb);
108   md->processDocument(doc);
109   auto result = hb->getResult();
110 
111   QRegularExpression regex(QStringLiteral(
112       "^<p>A <a href=\"http://www.kde.org\">link</a> to KDE.</p>\\n$"));
113 
114   QVERIFY(regex.match(result).hasMatch());
115 }
116 
testAnchorWithFormattedContent()117 void TestHtmlOutput::testAnchorWithFormattedContent()
118 {
119   auto doc = new QTextDocument();
120   doc->setHtml(QStringLiteral(
121       "A <a href=\"http://www.kde.org\"><b>formatted</b> link</a> to KDE."));
122 
123   auto hb = new TextHTMLBuilder();
124   auto md = new MarkupDirector(hb);
125   md->processDocument(doc);
126   auto result = hb->getResult();
127 
128   QRegularExpression regex(QStringLiteral(
129       "^<p>A <a href=\"http://www.kde.org\"><strong>formatted</strong> "
130       "link</a> to KDE.</p>\\n$"));
131 
132   QVERIFY(regex.match(result).hasMatch());
133 }
134 
testAdjacentAnchors()135 void TestHtmlOutput::testAdjacentAnchors()
136 {
137   auto doc = new QTextDocument();
138   doc->setHtml(
139       QStringLiteral("Two <a href=\"http://www.kde.org\">links</a><a "
140                      "href=\"http://www.google.com\">next</a> to eachother."));
141 
142   auto hb = new TextHTMLBuilder();
143   auto md = new MarkupDirector(hb);
144   md->processDocument(doc);
145   auto result = hb->getResult();
146 
147   QRegularExpression regex(QStringLiteral(
148       "^<p>Two <a href=\"http://www.kde.org\">links</a><a "
149       "href=\"http://www.google.com\">next</a> to eachother.</p>\\n$"));
150 
151   QVERIFY(regex.match(result).hasMatch());
152 }
153 
testNestedFormatting()154 void TestHtmlOutput::testNestedFormatting()
155 {
156   auto doc = new QTextDocument();
157   doc->setHtml(QStringLiteral("This <b>text is <i>italic</i> and</b> bold."));
158 
159   auto hb = new TextHTMLBuilder();
160   auto md = new MarkupDirector(hb);
161   md->processDocument(doc);
162   auto result = hb->getResult();
163 
164   QRegularExpression regex(QStringLiteral(
165       "^<p>This <strong>text is <em>italic</em> and</strong> bold.</p>\\n$"));
166 
167   QVERIFY(regex.match(result).hasMatch());
168 }
169 
testSpan()170 void TestHtmlOutput::testSpan()
171 {
172   auto doc = new QTextDocument();
173   doc->setHtml(QStringLiteral(
174       "Some <span style=\"color:#ff0000;\">formatted</span> text."));
175 
176   auto hb = new TextHTMLBuilder();
177   auto md = new MarkupDirector(hb);
178   md->processDocument(doc);
179   auto result = hb->getResult();
180 
181   auto regex = QRegularExpression(
182       QStringLiteral("^<p>Some <span style=\"color:#ff0000;\">formatted</span> "
183                      "text.</p>\\n$"));
184 
185   QVERIFY(regex.match(result).hasMatch());
186 }
187 
testDoubleSpan()188 void TestHtmlOutput::testDoubleSpan()
189 {
190   auto doc = new QTextDocument();
191   doc->setHtml(QStringLiteral("Some <span "
192                               "style=\"color:#ff0000;background-color:#00ff00;"
193                               "\">formatted</span> text."));
194 
195   auto hb = new TextHTMLBuilder();
196   auto md = new MarkupDirector(hb);
197   md->processDocument(doc);
198   auto result = hb->getResult();
199 
200   auto regex = QRegularExpression(QStringLiteral(
201       "^<p>Some <span "
202       "style=\"(color:#ff0000|background-color:#00ff00);\"><span "
203       "style=\"(color:#ff0000|background-color:#00ff00);\">formatted</span></"
204       "span> text.</p>\\n$"));
205 
206   QVERIFY(regex.match(result).hasMatch());
207 }
208 
testSpanNesting()209 void TestHtmlOutput::testSpanNesting()
210 {
211   auto doc = new QTextDocument();
212   doc->setHtml(QStringLiteral(
213       "Paragraph <span style=\"background-color:#00ff00;\">with some <span "
214       "style=\"color:#ff0000;\">formatted</span> nested</span> text."));
215 
216   auto hb = new TextHTMLBuilder();
217   auto md = new MarkupDirector(hb);
218   md->processDocument(doc);
219   auto result = hb->getResult();
220 
221   auto regex = QRegularExpression(QStringLiteral(
222       "^<p>Paragraph <span style=\"background-color:#00ff00;\">with some <span "
223       "style=\"color:#ff0000;\">formatted</span> nested</span> text.</p>\\n$"));
224 
225   QVERIFY(regex.match(result).hasMatch());
226 }
227 
testDoubleStartDifferentFinish()228 void TestHtmlOutput::testDoubleStartDifferentFinish()
229 {
230   auto doc = new QTextDocument();
231   doc->setHtml(
232       QStringLiteral("Paragraph <i><b>with</b> some formatted</i> text."));
233 
234   auto hb = new TextHTMLBuilder();
235   auto md = new MarkupDirector(hb);
236   md->processDocument(doc);
237   auto result = hb->getResult();
238 
239   auto regex = QRegularExpression(
240       QStringLiteral("^<p>Paragraph <em><strong>with</strong> some "
241                      "formatted</em> text.</p>\\n$"));
242 
243   QVERIFY(regex.match(result).hasMatch());
244 }
245 
testDoubleStartDifferentFinishReverseOrder()246 void TestHtmlOutput::testDoubleStartDifferentFinishReverseOrder()
247 {
248   auto doc = new QTextDocument();
249   doc->setHtml(
250       QStringLiteral("Paragraph <b><i>with</i> some formatted</b> text."));
251 
252   auto hb = new TextHTMLBuilder();
253   auto md = new MarkupDirector(hb);
254   md->processDocument(doc);
255   auto result = hb->getResult();
256 
257   auto regex = QRegularExpression(
258       QStringLiteral("^<p>Paragraph <strong><em>with</em> some "
259                      "formatted</strong> text.</p>\\n$"));
260 
261   QVERIFY(regex.match(result).hasMatch());
262 }
263 
testDifferentStartDoubleFinish()264 void TestHtmlOutput::testDifferentStartDoubleFinish()
265 {
266   auto doc = new QTextDocument();
267   doc->setHtml(
268       QStringLiteral("Paragraph <i>with some <b>formatted<b></i> text."));
269 
270   auto hb = new TextHTMLBuilder();
271   auto md = new MarkupDirector(hb);
272   md->processDocument(doc);
273   auto result = hb->getResult();
274 
275   auto regex = QRegularExpression(
276       QStringLiteral("^<p>Paragraph <em>with some "
277                      "<strong>formatted</strong></em> text.</p>\\n$"));
278 
279   QVERIFY(regex.match(result).hasMatch());
280 }
281 
testDifferentStartDoubleFinishReverseOrder()282 void TestHtmlOutput::testDifferentStartDoubleFinishReverseOrder()
283 {
284   auto doc = new QTextDocument();
285   doc->setHtml(
286       QStringLiteral("Paragraph <b>with some <i>formatted</i></b> text."));
287 
288   auto hb = new TextHTMLBuilder();
289   auto md = new MarkupDirector(hb);
290   md->processDocument(doc);
291   auto result = hb->getResult();
292 
293   auto regex = QRegularExpression(
294       QStringLiteral("^<p>Paragraph <strong>with some "
295                      "<em>formatted</em></strong> text.</p>\\n$"));
296 
297   QVERIFY(regex.match(result).hasMatch());
298 }
299 
testOverlap()300 void TestHtmlOutput::testOverlap()
301 {
302   auto doc = new QTextDocument();
303   doc->setHtml(QStringLiteral(
304       "Paragraph <b>with <i>some</i></b><i> formatted</i> text."));
305 
306   auto hb = new TextHTMLBuilder();
307   auto md = new MarkupDirector(hb);
308   md->processDocument(doc);
309   auto result = hb->getResult();
310 
311   auto regex = QRegularExpression(
312       QStringLiteral("^<p>Paragraph <strong>with <em>some</em></strong><em> "
313                      "formatted</em> text.</p>\\n$"));
314 
315   QVERIFY(regex.match(result).hasMatch());
316 }
317 
testEdgeCaseLeft()318 void TestHtmlOutput::testEdgeCaseLeft()
319 {
320   auto doc = new QTextDocument();
321   doc->setHtml(QStringLiteral("Paragraph <b>with some formatted text.</b>"));
322 
323   auto hb = new TextHTMLBuilder();
324   auto md = new MarkupDirector(hb);
325   md->processDocument(doc);
326   auto result = hb->getResult();
327 
328   auto regex = QRegularExpression(QStringLiteral(
329       "^<p>Paragraph <strong>with some formatted text.</strong></p>\\n$"));
330 
331   QVERIFY(regex.match(result).hasMatch());
332 }
333 
testEdgeCaseRight()334 void TestHtmlOutput::testEdgeCaseRight()
335 {
336   auto doc = new QTextDocument();
337   doc->setHtml(QStringLiteral("<b>Paragraph with some formatted</b> text."));
338 
339   auto hb = new TextHTMLBuilder();
340   auto md = new MarkupDirector(hb);
341   md->processDocument(doc);
342   auto result = hb->getResult();
343 
344   auto regex = QRegularExpression(QStringLiteral(
345       "^<p><strong>Paragraph with some formatted</strong> text.</p>\\n$"));
346 
347   QVERIFY(regex.match(result).hasMatch());
348 }
349 
testImage()350 void TestHtmlOutput::testImage()
351 {
352   auto doc = new QTextDocument();
353   doc->setHtml(
354       QStringLiteral("Paragraph with an inline <img "
355                      "src=\"http://kde.org/img/kde41.png\" /> image."));
356 
357   auto hb = new TextHTMLBuilder();
358   auto md = new MarkupDirector(hb);
359   md->processDocument(doc);
360   auto result = hb->getResult();
361 
362   auto regex = QRegularExpression(
363       QStringLiteral("^<p>Paragraph with an inline <img "
364                      "src=\"http://kde.org/img/kde41.png\" /> image.</p>\\n$"));
365 
366   QVERIFY(regex.match(result).hasMatch());
367 }
368 
testImageResized()369 void TestHtmlOutput::testImageResized()
370 {
371   QString result;
372   QRegularExpression regex;
373   TextHTMLBuilder *hb;
374   MarkupDirector *md;
375   auto doc = new QTextDocument();
376 
377   // width
378   doc->setHtml(QStringLiteral(
379       "Paragraph with an inline <img src=\"http://kde.org/img/kde41.png\" "
380       "width=\"10\" /> image."));
381 
382   hb = new TextHTMLBuilder();
383   md = new MarkupDirector(hb);
384   md->processDocument(doc);
385   result = hb->getResult();
386 
387   regex = QRegularExpression(QStringLiteral(
388       "^<p>Paragraph with an inline <img src=\"http://kde.org/img/kde41.png\" "
389       "width=\"10\" /> image.</p>\\n$"));
390   QVERIFY(regex.match(result).hasMatch());
391 
392   // height
393   doc->setHtml(QStringLiteral(
394       "Paragraph with an inline <img src=\"http://kde.org/img/kde41.png\" "
395       "height=\"10\" /> image."));
396 
397   hb = new TextHTMLBuilder();
398   md = new MarkupDirector(hb);
399   md->processDocument(doc);
400   result = hb->getResult();
401 
402   regex = QRegularExpression(QStringLiteral(
403       "^<p>Paragraph with an inline <img src=\"http://kde.org/img/kde41.png\" "
404       "height=\"10\" /> image.</p>\\n$"));
405   QVERIFY(regex.match(result).hasMatch());
406 
407   // height and width
408   doc->setHtml(QStringLiteral(
409       "Paragraph with an inline <img src=\"http://kde.org/img/kde41.png\" "
410       "height=\"10\" width=\"10\" /> image."));
411 
412   hb = new TextHTMLBuilder();
413   md = new MarkupDirector(hb);
414   md->processDocument(doc);
415   result = hb->getResult();
416 
417   regex = QRegularExpression(QStringLiteral(
418       "^<p>Paragraph with an inline <img src=\"http://kde.org/img/kde41.png\" "
419       "width=\"10\" height=\"10\" /> image.</p>\\n$"));
420 
421   QVERIFY(regex.match(result).hasMatch());
422 }
423 
testEachFormatTagSingly()424 void TestHtmlOutput::testEachFormatTagSingly()
425 {
426   QString result;
427   QRegularExpression regex;
428   TextHTMLBuilder *hb;
429   MarkupDirector *md;
430   auto doc = new QTextDocument();
431 
432   // Test bold
433   doc->setHtml(QStringLiteral("Some <b>formatted</b> text."));
434   hb = new TextHTMLBuilder();
435   md = new MarkupDirector(hb);
436   md->processDocument(doc);
437   result = hb->getResult();
438 
439   regex = QRegularExpression(
440       QStringLiteral("^<p>Some <strong>formatted</strong> text.</p>\\n$"));
441   QVERIFY(regex.match(result).hasMatch());
442 
443   // Test Italic
444   doc->setHtml(QStringLiteral("Some <i>formatted</i> text."));
445   hb = new TextHTMLBuilder();
446   md = new MarkupDirector(hb);
447   md->processDocument(doc);
448   result = hb->getResult();
449 
450   regex = QRegularExpression(
451       QStringLiteral("^<p>Some <em>formatted</em> text.</p>\\n$"));
452   QVERIFY(regex.match(result).hasMatch());
453 
454   // Test Underline
455   doc->setHtml(QStringLiteral("Some <u>formatted</u> text."));
456   hb = new TextHTMLBuilder();
457   md = new MarkupDirector(hb);
458   md->processDocument(doc);
459   result = hb->getResult();
460 
461   regex = QRegularExpression(
462       QStringLiteral("^<p>Some <u>formatted</u> text.</p>\\n$"));
463   QVERIFY(regex.match(result).hasMatch());
464 
465   // Test Strikeout
466   doc->setHtml(QStringLiteral("Some <s>formatted</s> text."));
467   hb = new TextHTMLBuilder();
468   md = new MarkupDirector(hb);
469   md->processDocument(doc);
470   result = hb->getResult();
471 
472   regex = QRegularExpression(
473       QStringLiteral("^<p>Some <s>formatted</s> text.</p>\\n$"));
474   QVERIFY(regex.match(result).hasMatch());
475 
476   // Test Superscript
477   doc->setHtml(QStringLiteral("Some <sup>formatted</sup> text."));
478   hb = new TextHTMLBuilder();
479   md = new MarkupDirector(hb);
480   md->processDocument(doc);
481   result = hb->getResult();
482 
483   regex = QRegularExpression(
484       QStringLiteral("^<p>Some <sup>formatted</sup> text.</p>\\n$"));
485   QVERIFY(regex.match(result).hasMatch());
486 
487   // Test Subscript
488   doc->setHtml(QStringLiteral("Some <sub>formatted</sub> text."));
489   hb = new TextHTMLBuilder();
490   md = new MarkupDirector(hb);
491   md->processDocument(doc);
492   result = hb->getResult();
493 
494   regex = QRegularExpression(
495       QStringLiteral("^<p>Some <sub>formatted</sub> text.</p>\\n$"));
496   QVERIFY(regex.match(result).hasMatch());
497 
498   // Test Foreground
499   doc->setHtml(QStringLiteral(
500       "Some <span style=\"color:#ff0000;\">formatted</span> text."));
501   hb = new TextHTMLBuilder();
502   md = new MarkupDirector(hb);
503   md->processDocument(doc);
504   result = hb->getResult();
505 
506   regex = QRegularExpression(
507       QStringLiteral("^<p>Some <span style=\"color:#ff0000;\">formatted</span> "
508                      "text.</p>\\n$"));
509   QVERIFY(regex.match(result).hasMatch());
510 
511   // Test Background
512   doc->setHtml(QStringLiteral(
513       "Some <span style=\"background-color:#ff0000;\">formatted</span> text."));
514   hb = new TextHTMLBuilder();
515   md = new MarkupDirector(hb);
516   md->processDocument(doc);
517   result = hb->getResult();
518 
519   regex = QRegularExpression(QStringLiteral(
520       "^<p>Some <span style=\"background-color:#ff0000;\">formatted</span> "
521       "text.</p>\\n$"));
522   QVERIFY(regex.match(result).hasMatch());
523 
524   // Test Font Family
525   doc->setHtml(QStringLiteral(
526       "Some <span style=\"font-family:courier;\">formatted</span> text."));
527   hb = new TextHTMLBuilder();
528   md = new MarkupDirector(hb);
529   md->processDocument(doc);
530   result = hb->getResult();
531 
532   regex = QRegularExpression(QStringLiteral(
533       "^<p>Some <span style=\"font-family:courier;\">formatted</span> "
534       "text.</p>\\n$"));
535   QVERIFY(regex.match(result).hasMatch());
536 
537   // Test Font Size
538   doc->setHtml(QStringLiteral(
539       "Some <span style=\"font-size:20pt;\">formatted</span> text."));
540   hb = new TextHTMLBuilder();
541   md = new MarkupDirector(hb);
542   md->processDocument(doc);
543   result = hb->getResult();
544 
545   regex = QRegularExpression(QStringLiteral(
546       "^<p>Some <span style=\"font-size:20pt;\">formatted</span> "
547       "text.</p>\\n$"));
548   QVERIFY(regex.match(result).hasMatch());
549 }
550 
testHorizontalRule()551 void TestHtmlOutput::testHorizontalRule()
552 {
553   auto doc = new QTextDocument();
554   doc->setHtml(
555       QStringLiteral("<p style=\"margin-top:0;margin-bottom:0;\">Foo</p><hr "
556                      "/><p style=\"margin-top:0;margin-bottom:0;\">Bar</p>"));
557 
558   auto hb = new TextHTMLBuilder();
559   auto md = new MarkupDirector(hb);
560   md->processDocument(doc);
561   auto result = hb->getResult();
562 
563   auto regex = QRegularExpression(
564       QStringLiteral("^<p>Foo</p>\\n<hr />\\n<p>Bar</p>\\n$"));
565 
566   QVERIFY(regex.match(result).hasMatch());
567 }
568 
testNewlines()569 void TestHtmlOutput::testNewlines()
570 {
571   auto doc = new QTextDocument();
572   doc->setHtml(QStringLiteral("<p>Foo<br /><br />\n<p>Bar</p>"));
573 
574   auto hb = new TextHTMLBuilder();
575   auto md = new MarkupDirector(hb);
576   md->processDocument(doc);
577   auto result = hb->getResult();
578 
579   auto regex = QRegularExpression(
580       QStringLiteral("^<p>Foo</p>\\n<p>&nbsp;<p>&nbsp;</p>\\n<p>Bar</p>\\n$"));
581 
582   QVERIFY(regex.match(result).hasMatch());
583 }
584 
testNewlinesThroughQTextCursor()585 void TestHtmlOutput::testNewlinesThroughQTextCursor()
586 {
587   auto doc = new QTextDocument(this);
588   QTextCursor cursor(doc);
589   cursor.movePosition(QTextCursor::Start);
590   cursor.insertText(QStringLiteral("Foo"));
591   cursor.insertText(QStringLiteral("\n"));
592   cursor.insertText(QStringLiteral("\n"));
593   cursor.insertText(QStringLiteral("\n"));
594   cursor.insertText(QStringLiteral("Bar"));
595 
596   auto hb = new TextHTMLBuilder();
597   auto md = new MarkupDirector(hb);
598   md->processDocument(doc);
599   auto result = hb->getResult();
600 
601   auto regex = QRegularExpression(
602       QStringLiteral("^<p>Foo</p>\\n<p>&nbsp;<p>&nbsp;<p>Bar</p>\\n$"));
603 
604   QVERIFY(regex.match(result).hasMatch());
605 }
606 
607 QTEST_MAIN(TestHtmlOutput)
608 #include "htmlbuildertest.moc"
609