Cutelee  6.2.0
testdefaulttags.cpp
1 /*
2  This file is part of the Cutelee template system.
3 
4  Copyright (c) 2009,2010 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 #ifndef DEFAULTTAGSTEST_H
22 #define DEFAULTTAGSTEST_H
23 
24 #include <QtCore/QDebug>
25 #include <QtTest/QTest>
26 
27 #include "context.h"
28 #include "coverageobject.h"
29 #include "engine.h"
30 #include "cutelee_paths.h"
31 #include "metatype.h"
32 #include "template.h"
33 #include "util.h"
34 
37 typedef QPair<QString, QString> StringPair;
38 
39 Q_DECLARE_METATYPE(Cutelee::Error)
40 
42 {
43 public:
45  {
46  m_existingMedia << QStringLiteral("existing_image.png")
47  << QStringLiteral("another_existing_image.png")
48  << QStringLiteral("this&that.png");
49  }
50 
51  std::pair<QString, QString> getMediaUri(const QString &fileName) const override
52  {
53  if (m_existingMedia.contains(fileName))
54  return {QStringLiteral("/path/to/"), fileName};
55  return {};
56  }
57 
58 private:
59  QStringList m_existingMedia;
60 };
61 
62 class Zoo : public QObject
63 {
64  Q_OBJECT
65 public:
66  Zoo(QObject *parent = {}) : QObject(parent) {}
67 
68  enum Animals { Lions, Tigers, Bears };
69  Q_ENUM(Animals)
70 };
71 
72 using namespace Cutelee;
73 
75 {
76  Q_OBJECT
77 
78 private Q_SLOTS:
79  void initTestCase();
80  void cleanupTestCase();
81 
82  void testCommentTag_data();
83  void testCommentTag() { doTest(); }
84 
85  void testFirstOfTag_data();
86  void testFirstOfTag() { doTest(); }
87 
88  void testIfTag_data();
89  void testIfTag() { doTest(); }
90 
91  void testForTag_data();
92  void testForTag() { doTest(); }
93 
94  void testIfEqualTag_data();
95  void testIfEqualTag() { doTest(); }
96 
97  void testIfNotEqualTag_data();
98  void testIfNotEqualTag() { doTest(); }
99 
100  void testTemplateTagTag_data();
101  void testTemplateTagTag() { doTest(); }
102 
103  void testWithTag_data();
104  void testWithTag() { doTest(); }
105 
106  void testCycleTag_data();
107  void testCycleTag() { doTest(); }
108 
109  void testWidthRatioTag_data();
110  void testWidthRatioTag() { doTest(); }
111 
112  void testFilterTag_data();
113  void testFilterTag() { doTest(); }
114 
115  void testNowTag_data();
116  void testNowTag() { doTest(); }
117 
118  void testSpacelessTag_data();
119  void testSpacelessTag() { doTest(); }
120 
121  void testRegroupTag_data();
122  void testRegroupTag() { doTest(); }
123 
124  void testIfChangedTag_data();
125  void testIfChangedTag() { doTest(); }
126 
127  void testAutoescapeTag_data();
128  void testAutoescapeTag() { doTest(); }
129 
130  void testMediaFinderTag_data();
131  void testMediaFinderTag() { doTest(); }
132 
133  void testRangeTag_data();
134  void testRangeTag() { doTest(); }
135 
136  void testDebugTag_data();
137  void testDebugTag() { doTest(); }
138 
139  void testLoadTag_data();
140  void testLoadTag() { doTest(); }
141 
142  void testUrlTypes_data();
143  void testUrlTypes();
144 
145  void testRelativePaths_data();
146  void testRelativePaths();
147 
148 private:
149  void doTest();
150 
151  Engine *m_engine;
152 };
153 
154 void TestDefaultTags::initTestCase()
155 {
156  m_engine = new Engine(this);
157  m_engine->setPluginPaths({QStringLiteral(CUTELEE_PLUGIN_PATH)});
158 
159  auto loader1 = std::shared_ptr<FakeTemplateLoader>(new FakeTemplateLoader());
160 
161  m_engine->addTemplateLoader(loader1);
162 }
163 
164 void TestDefaultTags::cleanupTestCase() { delete m_engine; }
165 
166 void TestDefaultTags::doTest()
167 {
168  QFETCH(QString, input);
169  QFETCH(Dict, dict);
170  QFETCH(QString, output);
171  QFETCH(Cutelee::Error, error);
172 
173  auto t = m_engine->newTemplate(input, QLatin1String(QTest::currentDataTag()));
174 
175  if (t->error() != NoError) {
176  if (t->error() != error)
177  qDebug() << t->errorString();
178  QCOMPARE(t->error(), error);
179  return;
180  }
181 
182  Context context(dict);
183 
184  auto result = t->render(&context);
185 
186  if (t->error() != NoError) {
187  if (t->error() != error)
188  qDebug() << t->errorString();
189  QCOMPARE(t->error(), error);
190  return;
191  }
192 
193  // Didn't catch any errors, so make sure I didn't expect any.
194  QCOMPARE(NoError, error);
195 
196  QCOMPARE(t->error(), NoError);
197 
198  QCOMPARE(result, output);
199 
200  if (!result.isEmpty()
201  && QString::fromLatin1(QTest::currentTestFunction())
202  == QStringLiteral("testMediaFinderTag")) {
203  QVERIFY(!context.externalMedia().isEmpty());
204  }
205 }
206 
207 void TestDefaultTags::testCommentTag_data()
208 {
209  QTest::addColumn<QString>("input");
210  QTest::addColumn<Dict>("dict");
211  QTest::addColumn<QString>("output");
212  QTest::addColumn<Cutelee::Error>("error");
213 
214  Dict dict;
215 
216  QTest::newRow("comment-tag01")
217  << QStringLiteral("{% comment %}this is hidden{% endcomment %}hello")
218  << dict << QStringLiteral("hello") << NoError;
219 
220  QTest::newRow("comment-tag02")
221  << QStringLiteral("{% comment %}this is hidden{% endcomment %}hello{% "
222  "comment %}foo{% endcomment %}")
223  << dict << QStringLiteral("hello") << NoError;
224  // Comment tag can contain invalid stuff.
225  QTest::newRow("comment-tag03")
226  << QStringLiteral("foo{% comment %} {% if %} {% endcomment %}") << dict
227  << QStringLiteral("foo") << NoError;
228  QTest::newRow("comment-tag04")
229  << QStringLiteral("foo{% comment %} {% endblock %} {% endcomment %}")
230  << dict << QStringLiteral("foo") << NoError;
231  QTest::newRow("comment-tag05")
232  << QStringLiteral("foo{% comment %} {% somerandomtag %} {% endcomment %}")
233  << dict << QStringLiteral("foo") << NoError;
234  QTest::newRow("comment-tag06") << QStringLiteral("{% comment %}yes") << dict
235  << QString() << UnclosedBlockTagError;
236 }
237 
238 void TestDefaultTags::testFirstOfTag_data()
239 {
240  QTest::addColumn<QString>("input");
241  QTest::addColumn<Dict>("dict");
242  QTest::addColumn<QString>("output");
243  QTest::addColumn<Cutelee::Error>("error");
244 
245  Dict dict;
246  dict.insert(QStringLiteral("a"), 0);
247  dict.insert(QStringLiteral("b"), 0);
248  dict.insert(QStringLiteral("c"), 0);
249  QTest::newRow("firstof01")
250  << QStringLiteral("{% firstof a b c %}") << dict << QString() << NoError;
251 
252  dict.clear();
253  dict.insert(QStringLiteral("a"), 1);
254  dict.insert(QStringLiteral("b"), 0);
255  dict.insert(QStringLiteral("c"), 0);
256  QTest::newRow("firstof02") << QStringLiteral("{% firstof a b c %}") << dict
257  << QStringLiteral("1") << NoError;
258 
259  dict.clear();
260  dict.insert(QStringLiteral("a"), 0);
261  dict.insert(QStringLiteral("b"), 2);
262  dict.insert(QStringLiteral("c"), 0);
263  QTest::newRow("firstof03") << QStringLiteral("{% firstof a b c %}") << dict
264  << QStringLiteral("2") << NoError;
265 
266  dict.clear();
267  dict.insert(QStringLiteral("a"), 0);
268  dict.insert(QStringLiteral("b"), 0);
269  dict.insert(QStringLiteral("c"), 3);
270  QTest::newRow("firstof04") << QStringLiteral("{% firstof a b c %}") << dict
271  << QStringLiteral("3") << NoError;
272 
273  dict.clear();
274  dict.insert(QStringLiteral("a"), 1);
275  dict.insert(QStringLiteral("b"), 2);
276  dict.insert(QStringLiteral("c"), 3);
277  QTest::newRow("firstof05") << QStringLiteral("{% firstof a b c %}") << dict
278  << QStringLiteral("1") << NoError;
279 
280  dict.clear();
281  dict.insert(QStringLiteral("b"), 0);
282  dict.insert(QStringLiteral("c"), 3);
283  QTest::newRow("firstof06") << QStringLiteral("{% firstof a b c %}") << dict
284  << QStringLiteral("3") << NoError;
285 
286  dict.clear();
287  dict.insert(QStringLiteral("a"), 0);
288  QTest::newRow("firstof07")
289  << "{% firstof a b \"c\" %}" << dict << QStringLiteral("c") << NoError;
290 
291  dict.clear();
292  dict.insert(QStringLiteral("a"), 0);
293  dict.insert(QStringLiteral("b"), 0);
294  QTest::newRow("firstof08") << "{% firstof a b \"c and d\" %}" << dict
295  << QStringLiteral("c and d") << NoError;
296  QTest::newRow("firstof09") << QStringLiteral("{% firstof %}") << dict
297  << QStringLiteral("a") << TagSyntaxError;
298 }
299 
300 class BadIfObject : public QObject
301 {
302  Q_OBJECT
303  Q_PROPERTY(bool isTrue READ isTrue CONSTANT)
304  Q_PROPERTY(bool isFalse READ isFalse CONSTANT)
305  Q_PROPERTY(bool isBad READ isBad CONSTANT)
306 public:
307  BadIfObject(QObject *parent = {}) : QObject(parent), mIsBadCalled(false) {}
308 
309  bool isTrue() const { return true; }
310 
311  bool isFalse() const { return false; }
312 
313  bool isBad() const
314  {
315  mIsBadCalled = true;
316  return true;
317  }
318 
319  bool isBadCalled() { return mIsBadCalled; }
320 
321 private:
322  mutable bool mIsBadCalled;
323 };
324 
325 void TestDefaultTags::testIfTag_data()
326 {
327  QTest::addColumn<QString>("input");
328  QTest::addColumn<Dict>("dict");
329  QTest::addColumn<QString>("output");
330  QTest::addColumn<Cutelee::Error>("error");
331 
332  Dict dict;
333 
334  dict.insert(QStringLiteral("foo"), true);
335 
336  QTest::newRow("if-tag01")
337  << QStringLiteral("{% if foo %}yes{% else %}no{% endif %}") << dict
338  << QStringLiteral("yes") << NoError;
339 
340  dict.clear();
341  dict.insert(QStringLiteral("foo"), false);
342  QTest::newRow("if-tag02")
343  << QStringLiteral("{% if foo %}yes{% else %}no{% endif %}") << dict
344  << QStringLiteral("no") << NoError;
345 
346  dict.clear();
347  QTest::newRow("if-tag03")
348  << QStringLiteral("{% if foo %}yes{% else %}no{% endif %}") << dict
349  << QStringLiteral("no") << NoError;
350 
351  dict.clear();
352  dict.insert(QStringLiteral("foo"), true);
353  QTest::newRow("if-tag04")
354  << QStringLiteral("{% if foo %}foo{% elif bar %}bar{% endif %}") << dict
355  << QStringLiteral("foo") << NoError;
356 
357  dict.clear();
358  dict.insert(QStringLiteral("bar"), true);
359  QTest::newRow("if-tag05")
360  << QStringLiteral("{% if foo %}foo{% elif bar %}bar{% endif %}") << dict
361  << QStringLiteral("bar") << NoError;
362 
363  dict.clear();
364  QTest::newRow("if-tag06")
365  << QStringLiteral("{% if foo %}foo{% elif bar %}bar{% endif %}") << dict
366  << QString() << NoError;
367 
368  dict.clear();
369  dict.insert(QStringLiteral("foo"), true);
370  QTest::newRow("if-tag07") << QStringLiteral(
371  "{% if foo %}foo{% elif bar %}bar{% else %}nothing{% endif %}")
372  << dict << QStringLiteral("foo") << NoError;
373 
374  dict.clear();
375  dict.insert(QStringLiteral("bar"), true);
376  QTest::newRow("if-tag08") << QStringLiteral(
377  "{% if foo %}foo{% elif bar %}bar{% else %}nothing{% endif %}")
378  << dict << QStringLiteral("bar") << NoError;
379 
380  dict.clear();
381  QTest::newRow("if-tag09") << QStringLiteral(
382  "{% if foo %}foo{% elif bar %}bar{% else %}nothing{% endif %}")
383  << dict << QStringLiteral("nothing") << NoError;
384 
385  dict.clear();
386  dict.insert(QStringLiteral("foo"), true);
387  QTest::newRow("if-tag10")
388  << QStringLiteral("{% if foo %}foo{% elif bar %}bar{% elif baz %}baz{% "
389  "else %}nothing{% endif %}")
390  << dict << QStringLiteral("foo") << NoError;
391 
392  dict.clear();
393  dict.insert(QStringLiteral("bar"), true);
394  QTest::newRow("if-tag11")
395  << QStringLiteral("{% if foo %}foo{% elif bar %}bar{% elif baz %}baz{% "
396  "else %}nothing{% endif %}")
397  << dict << QStringLiteral("bar") << NoError;
398 
399  dict.clear();
400  dict.insert(QStringLiteral("baz"), true);
401  QTest::newRow("if-tag12")
402  << QStringLiteral("{% if foo %}foo{% elif bar %}bar{% elif baz %}baz{% "
403  "else %}nothing{% endif %}")
404  << dict << QStringLiteral("baz") << NoError;
405 
406  dict.clear();
407  QTest::newRow("if-tag13")
408  << QStringLiteral("{% if foo %}foo{% elif bar %}bar{% elif baz %}baz{% "
409  "else %}nothing{% endif %}")
410  << dict << QStringLiteral("nothing") << NoError;
411 
412  // Filters
413 
414  dict.clear();
415  dict.insert(QStringLiteral("foo"), QStringLiteral("abcde"));
416  QTest::newRow("if-tag-filter01")
417  << QStringLiteral("{% if foo|length == 5 %}yes{% else %}{{ foo|length }}{% endif %}")
418  << dict << QStringLiteral("yes") << NoError;
419 
420  dict.clear();
421  QTest::newRow("if-tag-filter02") << QStringLiteral(
422  "{% if foo|upper == \'ABC\' %}yes{% else %}no{% endif %}")
423  << dict << QStringLiteral("no") << NoError;
424 
425  // Equality
426 
427  dict.clear();
428  QTest::newRow("if-tag-eq01")
429  << QStringLiteral("{% if foo == bar %}yes{% else %}no{% endif %}") << dict
430  << QStringLiteral("yes") << NoError;
431 
432  dict.clear();
433  dict.insert(QStringLiteral("foo"), 1);
434  QTest::newRow("if-tag-eq02")
435  << QStringLiteral("{% if foo == bar %}yes{% else %}no{% endif %}") << dict
436  << QStringLiteral("no") << NoError;
437 
438  dict.clear();
439  dict.insert(QStringLiteral("foo"), 1);
440  dict.insert(QStringLiteral("bar"), 1);
441  QTest::newRow("if-tag-eq03")
442  << QStringLiteral("{% if foo == bar %}yes{% else %}no{% endif %}") << dict
443  << QStringLiteral("yes") << NoError;
444 
445  dict.clear();
446  dict.insert(QStringLiteral("foo"), 1);
447  dict.insert(QStringLiteral("bar"), 2);
448  QTest::newRow("if-tag-eq04")
449  << QStringLiteral("{% if foo == bar %}yes{% else %}no{% endif %}") << dict
450  << QStringLiteral("no") << NoError;
451 
452  dict.clear();
453  QTest::newRow("if-tag-eq05")
454  << QStringLiteral("{% if foo == \'\' %}yes{% else %}no{% endif %}")
455  << dict << QStringLiteral("no") << NoError;
456 
457  dict.clear();
458  dict.insert(QStringLiteral("foostring"), QStringLiteral("foo"));
459  QTest::newRow("if-tag-eq06") << QStringLiteral(
460  "{% if foostring == \'foo\' %}yes{% else %}no{% endif %}")
461  << dict << QStringLiteral("yes") << NoError;
462 
463  dict.clear();
464  QTest::newRow("if-tag-eq07")
465  << QStringLiteral("{% if \"foo\" == \"foo\" %}yes{% else %}no{% endif %}")
466  << dict << QStringLiteral("yes") << NoError;
467  dict.clear();
468  dict.insert(QStringLiteral("foo"), QStringLiteral("bar"));
469  QTest::newRow("if-tag-eq08")
470  << QStringLiteral("{% if foo == \"bar\" %}yes{% else %}no{% endif %}")
471  << dict << QStringLiteral("yes") << NoError;
472 
473  // Comparison
474 
475  dict.clear();
476  QTest::newRow("if-tag-gt-01")
477  << QStringLiteral("{% if 2 > 1 %}yes{% else %}no{% endif %}") << dict
478  << QStringLiteral("yes") << NoError;
479 
480  dict.clear();
481  QTest::newRow("if-tag-gt-02")
482  << QStringLiteral("{% if 1 > 1 %}yes{% else %}no{% endif %}") << dict
483  << QStringLiteral("no") << NoError;
484 
485  dict.clear();
486  QTest::newRow("if-tag-gte-01")
487  << QStringLiteral("{% if 1 >= 1 %}yes{% else %}no{% endif %}") << dict
488  << QStringLiteral("yes") << NoError;
489 
490  dict.clear();
491  QTest::newRow("if-tag-gte-02")
492  << QStringLiteral("{% if 1 >= 2 %}yes{% else %}no{% endif %}") << dict
493  << QStringLiteral("no") << NoError;
494 
495  dict.clear();
496  QTest::newRow("if-tag-lt-01")
497  << QStringLiteral("{% if 1 < 2 %}yes{% else %}no{% endif %}") << dict
498  << QStringLiteral("yes") << NoError;
499 
500  dict.clear();
501  QTest::newRow("if-tag-lt-02")
502  << QStringLiteral("{% if 1 < 1 %}yes{% else %}no{% endif %}") << dict
503  << QStringLiteral("no") << NoError;
504 
505  dict.clear();
506  QTest::newRow("if-tag-lte-01")
507  << QStringLiteral("{% if 1 <= 1 %}yes{% else %}no{% endif %}") << dict
508  << QStringLiteral("yes") << NoError;
509 
510  dict.clear();
511  QTest::newRow("if-tag-lte-02")
512  << QStringLiteral("{% if 2 <= 1 %}yes{% else %}no{% endif %}") << dict
513  << QStringLiteral("no") << NoError;
514 
515  // Contains
516 
517  dict.clear();
518  dict.insert(QStringLiteral("x"), QVariantList{1});
519  QTest::newRow("if-tag-in-01")
520  << QStringLiteral("{% if 1 in x %}yes{% else %}no{% endif %}") << dict
521  << QStringLiteral("yes") << NoError;
522 
523  dict.clear();
524  dict.insert(QStringLiteral("x"), QVariantList{1});
525  QTest::newRow("if-tag-in-02")
526  << QStringLiteral("{% if 2 in x %}yes{% else %}no{% endif %}") << dict
527  << QStringLiteral("no") << NoError;
528 
529  dict.clear();
530  dict.insert(QStringLiteral("x"), QVariantList{1});
531  QTest::newRow("if-tag-not-in-01")
532  << QStringLiteral("{% if 1 not in x %}yes{% else %}no{% endif %}") << dict
533  << QStringLiteral("no") << NoError;
534 
535  dict.clear();
536  dict.insert(QStringLiteral("x"), QVariantList{1});
537  QTest::newRow("if-tag-not-in-02")
538  << QStringLiteral("{% if 2 not in x %}yes{% else %}no{% endif %}") << dict
539  << QStringLiteral("yes") << NoError;
540 
541  // operator in with string
542  dict.clear();
543  dict.insert(QStringLiteral("colors"), QStringLiteral("green"));
544  QTest::newRow("if-tag-operator-in-string01")
545  << QStringLiteral(
546  "{% if \"green\" in colors %}yes{% else %}no{% endif %}")
547  << dict << QStringLiteral("yes") << NoError;
548 
549  dict.clear();
550  dict.insert(QStringLiteral("colors"), QStringLiteral("red"));
551  QTest::newRow("if-tag-operator-in-string02")
552  << QStringLiteral(
553  "{% if \"green\" in colors %}yes{% else %}no{% endif %}")
554  << dict << QStringLiteral("no") << NoError;
555 
556  dict.clear();
557  dict.insert(QStringLiteral("colors"), QStringLiteral("green"));
558  QTest::newRow("if-tag-operator-in-string03")
559  << QStringLiteral(
560  "{% if \"green\" in colors %}yes{% else %}no{% endif %}")
561  << dict << QStringLiteral("yes") << NoError;
562 
563  dict.clear();
564  dict.insert(QStringLiteral("colors"), QStringLiteral("red"));
565  QTest::newRow("if-tag-operator-in-string04")
566  << QStringLiteral(
567  "{% if \"green\" in colors %}yes{% else %}no{% endif %}")
568  << dict << QStringLiteral("no") << NoError;
569 
570  dict.clear();
571  dict.insert(QStringLiteral("color"), QStringLiteral("green"));
572  dict.insert(QStringLiteral("colors"), QStringLiteral("green"));
573  QTest::newRow("if-tag-operator-in-string05")
574  << QStringLiteral("{% if color in colors %}yes{% else %}no{% endif %}")
575  << dict << QStringLiteral("yes") << NoError;
576 
577  dict.clear();
578  dict.insert(QStringLiteral("color"), QStringLiteral("green"));
579  dict.insert(QStringLiteral("colors"), QStringLiteral("red"));
580  QTest::newRow("if-tag-operator-in-string06")
581  << QStringLiteral("{% if color in colors %}yes{% else %}no{% endif %}")
582  << dict << QStringLiteral("no") << NoError;
583 
584  // AND
585 
586  dict.clear();
587  dict.insert(QStringLiteral("foo"), true);
588  dict.insert(QStringLiteral("bar"), true);
589  QTest::newRow("if-tag-and01")
590  << QStringLiteral("{% if foo and bar %}yes{% else %}no{% endif %}")
591  << dict << QStringLiteral("yes") << NoError;
592 
593  dict.clear();
594  dict.insert(QStringLiteral("foo"), true);
595  dict.insert(QStringLiteral("bar"), false);
596  QTest::newRow("if-tag-and02")
597  << QStringLiteral("{% if foo and bar %}yes{% else %}no{% endif %}")
598  << dict << QStringLiteral("no") << NoError;
599 
600  dict.clear();
601  dict.insert(QStringLiteral("foo"), false);
602  dict.insert(QStringLiteral("bar"), true);
603  QTest::newRow("if-tag-and03")
604  << QStringLiteral("{% if foo and bar %}yes{% else %}no{% endif %}")
605  << dict << QStringLiteral("no") << NoError;
606 
607  dict.clear();
608  dict.insert(QStringLiteral("foo"), false);
609  dict.insert(QStringLiteral("bar"), false);
610  QTest::newRow("if-tag-and04")
611  << QStringLiteral("{% if foo and bar %}yes{% else %}no{% endif %}")
612  << dict << QStringLiteral("no") << NoError;
613 
614  dict.clear();
615  dict.insert(QStringLiteral("foo"), false);
616  QTest::newRow("if-tag-and05")
617  << QStringLiteral("{% if foo and bar %}yes{% else %}no{% endif %}")
618  << dict << QStringLiteral("no") << NoError;
619 
620  dict.clear();
621  dict.insert(QStringLiteral("bar"), false);
622  QTest::newRow("if-tag-and06")
623  << QStringLiteral("{% if foo and bar %}yes{% else %}no{% endif %}")
624  << dict << QStringLiteral("no") << NoError;
625 
626  dict.clear();
627  dict.insert(QStringLiteral("foo"), true);
628  QTest::newRow("if-tag-and07")
629  << QStringLiteral("{% if foo and bar %}yes{% else %}no{% endif %}")
630  << dict << QStringLiteral("no") << NoError;
631 
632  dict.clear();
633  dict.insert(QStringLiteral("bar"), true);
634  QTest::newRow("if-tag-and08")
635  << QStringLiteral("{% if foo and bar %}yes{% else %}no{% endif %}")
636  << dict << QStringLiteral("no") << NoError;
637 
638  // OR
639 
640  dict.clear();
641  dict.insert(QStringLiteral("foo"), true);
642  dict.insert(QStringLiteral("bar"), true);
643  QTest::newRow("if-tag-or01")
644  << QStringLiteral("{% if foo or bar %}yes{% else %}no{% endif %}") << dict
645  << QStringLiteral("yes") << NoError;
646 
647  dict.clear();
648  dict.insert(QStringLiteral("foo"), true);
649  dict.insert(QStringLiteral("bar"), false);
650  QTest::newRow("if-tag-or02")
651  << QStringLiteral("{% if foo or bar %}yes{% else %}no{% endif %}") << dict
652  << QStringLiteral("yes") << NoError;
653 
654  dict.clear();
655  dict.insert(QStringLiteral("foo"), false);
656  dict.insert(QStringLiteral("bar"), true);
657  QTest::newRow("if-tag-or03")
658  << QStringLiteral("{% if foo or bar %}yes{% else %}no{% endif %}") << dict
659  << QStringLiteral("yes") << NoError;
660 
661  dict.clear();
662  dict.insert(QStringLiteral("foo"), false);
663  dict.insert(QStringLiteral("bar"), false);
664  QTest::newRow("if-tag-or04")
665  << QStringLiteral("{% if foo or bar %}yes{% else %}no{% endif %}") << dict
666  << QStringLiteral("no") << NoError;
667 
668  dict.clear();
669  dict.insert(QStringLiteral("foo"), false);
670  QTest::newRow("if-tag-or05")
671  << QStringLiteral("{% if foo or bar %}yes{% else %}no{% endif %}") << dict
672  << QStringLiteral("no") << NoError;
673 
674  dict.clear();
675  dict.insert(QStringLiteral("bar"), false);
676  QTest::newRow("if-tag-or06")
677  << QStringLiteral("{% if foo or bar %}yes{% else %}no{% endif %}") << dict
678  << QStringLiteral("no") << NoError;
679 
680  dict.clear();
681  dict.insert(QStringLiteral("foo"), true);
682  QTest::newRow("if-tag-or07")
683  << QStringLiteral("{% if foo or bar %}yes{% else %}no{% endif %}") << dict
684  << QStringLiteral("yes") << NoError;
685 
686  dict.clear();
687  dict.insert(QStringLiteral("bar"), true);
688  QTest::newRow("if-tag-or08")
689  << QStringLiteral("{% if foo or bar %}yes{% else %}no{% endif %}") << dict
690  << QStringLiteral("yes") << NoError;
691 
692  dict.clear();
693  dict.insert(QStringLiteral("baz"), true);
694  QTest::newRow("if-tag-or09")
695  << QStringLiteral("{% if foo or bar or baz %}yes{% else %}no{% endif %}")
696  << dict << QStringLiteral("yes") << NoError;
697 
698  // NOT
699 
700  dict.clear();
701  dict.insert(QStringLiteral("foo"), true);
702  QTest::newRow("if-tag-not01")
703  << QStringLiteral("{% if not foo %}no{% else %}yes{% endif %}") << dict
704  << QStringLiteral("yes") << NoError;
705 
706  dict.insert(QStringLiteral("foo"), true);
707  QTest::newRow("if-tag-not02")
708  << QStringLiteral("{% if not not foo %}no{% else %}yes{% endif %}")
709  << dict << QStringLiteral("no") << NoError;
710 
711  dict.clear();
712  QTest::newRow("if-tag-not06")
713  << QStringLiteral("{% if foo and not bar %}yes{% else %}no{% endif %}")
714  << dict << QStringLiteral("no") << NoError;
715 
716  dict.clear();
717  dict.insert(QStringLiteral("foo"), true);
718  dict.insert(QStringLiteral("bar"), true);
719  QTest::newRow("if-tag-not07")
720  << QStringLiteral("{% if foo and not bar %}yes{% else %}no{% endif %}")
721  << dict << QStringLiteral("no") << NoError;
722 
723  dict.clear();
724  dict.insert(QStringLiteral("foo"), true);
725  dict.insert(QStringLiteral("bar"), false);
726  QTest::newRow("if-tag-not08")
727  << QStringLiteral("{% if foo and not bar %}yes{% else %}no{% endif %}")
728  << dict << QStringLiteral("yes") << NoError;
729 
730  dict.clear();
731  dict.insert(QStringLiteral("foo"), false);
732  dict.insert(QStringLiteral("bar"), true);
733  QTest::newRow("if-tag-not09")
734  << QStringLiteral("{% if foo and not bar %}yes{% else %}no{% endif %}")
735  << dict << QStringLiteral("no") << NoError;
736 
737  dict.clear();
738  dict.insert(QStringLiteral("foo"), false);
739  dict.insert(QStringLiteral("bar"), false);
740  QTest::newRow("if-tag-not10")
741  << QStringLiteral("{% if foo and not bar %}yes{% else %}no{% endif %}")
742  << dict << QStringLiteral("no") << NoError;
743 
744  dict.clear();
745  QTest::newRow("if-tag-not11")
746  << QStringLiteral("{% if not foo and bar %}yes{% else %}no{% endif %}")
747  << dict << QStringLiteral("no") << NoError;
748 
749  dict.clear();
750  dict.insert(QStringLiteral("foo"), true);
751  dict.insert(QStringLiteral("bar"), true);
752  QTest::newRow("if-tag-not12")
753  << QStringLiteral("{% if not foo and bar %}yes{% else %}no{% endif %}")
754  << dict << QStringLiteral("no") << NoError;
755 
756  dict.clear();
757  dict.insert(QStringLiteral("foo"), true);
758  dict.insert(QStringLiteral("bar"), false);
759  QTest::newRow("if-tag-not13")
760  << QStringLiteral("{% if not foo and bar %}yes{% else %}no{% endif %}")
761  << dict << QStringLiteral("no") << NoError;
762 
763  dict.clear();
764  dict.insert(QStringLiteral("foo"), false);
765  dict.insert(QStringLiteral("bar"), true);
766  QTest::newRow("if-tag-not14")
767  << QStringLiteral("{% if not foo and bar %}yes{% else %}no{% endif %}")
768  << dict << QStringLiteral("yes") << NoError;
769 
770  dict.clear();
771  dict.insert(QStringLiteral("foo"), false);
772  dict.insert(QStringLiteral("bar"), false);
773  QTest::newRow("if-tag-not15")
774  << QStringLiteral("{% if not foo and bar %}yes{% else %}no{% endif %}")
775  << dict << QStringLiteral("no") << NoError;
776 
777  dict.clear();
778  QTest::newRow("if-tag-not16")
779  << QStringLiteral("{% if foo or not bar %}yes{% else %}no{% endif %}")
780  << dict << QStringLiteral("yes") << NoError;
781 
782  dict.clear();
783  dict.insert(QStringLiteral("foo"), true);
784  dict.insert(QStringLiteral("bar"), true);
785  QTest::newRow("if-tag-not17")
786  << QStringLiteral("{% if foo or not bar %}yes{% else %}no{% endif %}")
787  << dict << QStringLiteral("yes") << NoError;
788 
789  dict.clear();
790  dict.insert(QStringLiteral("foo"), true);
791  dict.insert(QStringLiteral("bar"), false);
792  QTest::newRow("if-tag-not18")
793  << QStringLiteral("{% if foo or not bar %}yes{% else %}no{% endif %}")
794  << dict << QStringLiteral("yes") << NoError;
795 
796  dict.clear();
797  dict.insert(QStringLiteral("foo"), false);
798  dict.insert(QStringLiteral("bar"), true);
799  QTest::newRow("if-tag-not19")
800  << QStringLiteral("{% if foo or not bar %}yes{% else %}no{% endif %}")
801  << dict << QStringLiteral("no") << NoError;
802 
803  dict.clear();
804  dict.insert(QStringLiteral("foo"), false);
805  dict.insert(QStringLiteral("bar"), false);
806  QTest::newRow("if-tag-not20")
807  << QStringLiteral("{% if foo or not bar %}yes{% else %}no{% endif %}")
808  << dict << QStringLiteral("yes") << NoError;
809 
810  dict.clear();
811  QTest::newRow("if-tag-not21")
812  << QStringLiteral("{% if not foo or bar %}yes{% else %}no{% endif %}")
813  << dict << QStringLiteral("yes") << NoError;
814 
815  dict.clear();
816  dict.insert(QStringLiteral("foo"), true);
817  dict.insert(QStringLiteral("bar"), true);
818  QTest::newRow("if-tag-not22")
819  << QStringLiteral("{% if not foo or bar %}yes{% else %}no{% endif %}")
820  << dict << QStringLiteral("yes") << NoError;
821 
822  dict.clear();
823  dict.insert(QStringLiteral("foo"), true);
824  dict.insert(QStringLiteral("bar"), false);
825  QTest::newRow("if-tag-not23")
826  << QStringLiteral("{% if not foo or bar %}yes{% else %}no{% endif %}")
827  << dict << QStringLiteral("no") << NoError;
828 
829  dict.clear();
830  dict.insert(QStringLiteral("foo"), false);
831  dict.insert(QStringLiteral("bar"), true);
832  QTest::newRow("if-tag-not24")
833  << QStringLiteral("{% if not foo or bar %}yes{% else %}no{% endif %}")
834  << dict << QStringLiteral("yes") << NoError;
835 
836  dict.clear();
837  dict.insert(QStringLiteral("foo"), false);
838  dict.insert(QStringLiteral("bar"), false);
839  QTest::newRow("if-tag-not25")
840  << QStringLiteral("{% if not foo or bar %}yes{% else %}no{% endif %}")
841  << dict << QStringLiteral("yes") << NoError;
842 
843  dict.clear();
844  QTest::newRow("if-tag-not26") << QStringLiteral(
845  "{% if not foo and not bar %}yes{% else %}no{% endif %}")
846  << dict << QStringLiteral("yes") << NoError;
847 
848  dict.clear();
849  dict.insert(QStringLiteral("foo"), true);
850  dict.insert(QStringLiteral("bar"), true);
851  QTest::newRow("if-tag-not27") << QStringLiteral(
852  "{% if not foo and not bar %}yes{% else %}no{% endif %}")
853  << dict << QStringLiteral("no") << NoError;
854 
855  dict.clear();
856  dict.insert(QStringLiteral("foo"), true);
857  dict.insert(QStringLiteral("bar"), false);
858  QTest::newRow("if-tag-not28") << QStringLiteral(
859  "{% if not foo and not bar %}yes{% else %}no{% endif %}")
860  << dict << QStringLiteral("no") << NoError;
861 
862  dict.clear();
863  dict.insert(QStringLiteral("foo"), false);
864  dict.insert(QStringLiteral("bar"), true);
865  QTest::newRow("if-tag-not29") << QStringLiteral(
866  "{% if not foo and not bar %}yes{% else %}no{% endif %}")
867  << dict << QStringLiteral("no") << NoError;
868 
869  dict.clear();
870  dict.insert(QStringLiteral("foo"), false);
871  dict.insert(QStringLiteral("bar"), false);
872  QTest::newRow("if-tag-not30") << QStringLiteral(
873  "{% if not foo and not bar %}yes{% else %}no{% endif %}")
874  << dict << QStringLiteral("yes") << NoError;
875 
876  dict.clear();
877  QTest::newRow("if-tag-not31")
878  << QStringLiteral("{% if not foo or not bar %}yes{% else %}no{% endif %}")
879  << dict << QStringLiteral("yes") << NoError;
880 
881  dict.clear();
882  dict.insert(QStringLiteral("foo"), true);
883  dict.insert(QStringLiteral("bar"), true);
884  QTest::newRow("if-tag-not32")
885  << QStringLiteral("{% if not foo or not bar %}yes{% else %}no{% endif %}")
886  << dict << QStringLiteral("no") << NoError;
887 
888  dict.clear();
889  dict.insert(QStringLiteral("foo"), true);
890  dict.insert(QStringLiteral("bar"), false);
891  QTest::newRow("if-tag-not33")
892  << QStringLiteral("{% if not foo or not bar %}yes{% else %}no{% endif %}")
893  << dict << QStringLiteral("yes") << NoError;
894 
895  dict.clear();
896  dict.insert(QStringLiteral("foo"), false);
897  dict.insert(QStringLiteral("bar"), true);
898  QTest::newRow("if-tag-not34")
899  << QStringLiteral("{% if not foo or not bar %}yes{% else %}no{% endif %}")
900  << dict << QStringLiteral("yes") << NoError;
901 
902  dict.clear();
903  dict.insert(QStringLiteral("foo"), false);
904  dict.insert(QStringLiteral("bar"), false);
905  QTest::newRow("if-tag-not35")
906  << QStringLiteral("{% if not foo or not bar %}yes{% else %}no{% endif %}")
907  << dict << QStringLiteral("yes") << NoError;
908 
909  QTest::newRow("if-tag-error01") << QStringLiteral("{% if %}yes{% endif %}")
910  << dict << QString() << TagSyntaxError;
911 
912  dict.clear();
913  dict.insert(QStringLiteral("foo"), true);
914  QTest::newRow("if-tag-error02")
915  << QStringLiteral("{% if foo and %}yes{% else %}no{% endif %}") << dict
916  << QString() << TagSyntaxError;
917  QTest::newRow("if-tag-error03")
918  << QStringLiteral("{% if foo or %}yes{% else %}no{% endif %}") << dict
919  << QString() << TagSyntaxError;
920  QTest::newRow("if-tag-error04")
921  << QStringLiteral("{% if not foo and %}yes{% else %}no{% endif %}")
922  << dict << QString() << TagSyntaxError;
923  QTest::newRow("if-tag-error05")
924  << QStringLiteral("{% if not foo or %}yes{% else %}no{% endif %}") << dict
925  << QString() << TagSyntaxError;
926  QTest::newRow("if-tag-error06")
927  << QStringLiteral("{% if abc def %}yes{% endif %}") << dict << QString()
928  << TagSyntaxError;
929  QTest::newRow("if-tag-error07")
930  << QStringLiteral("{% if not %}yes{% endif %}") << dict << QString()
931  << TagSyntaxError;
932  QTest::newRow("if-tag-error08")
933  << QStringLiteral("{% if and %}yes{% endif %}") << dict << QString()
934  << TagSyntaxError;
935  QTest::newRow("if-tag-error09") << QStringLiteral("{% if or %}yes{% endif %}")
936  << dict << QString() << TagSyntaxError;
937  QTest::newRow("if-tag-error10") << QStringLiteral("{% if == %}yes{% endif %}")
938  << dict << QString() << TagSyntaxError;
939  QTest::newRow("if-tag-error11")
940  << QStringLiteral("{% if 1 == %}yes{% endif %}") << dict << QString()
941  << TagSyntaxError;
942  QTest::newRow("if-tag-error12")
943  << QStringLiteral("{% if a not b %}yes{% endif %}") << dict << QString()
944  << TagSyntaxError;
945 
946  // Short circuit
947  dict.clear();
948  {
950  dict.insert(QStringLiteral("x"), QVariant::fromValue(bio));
951  QTest::newRow("if-tag-shortcircuit01")
952  << QStringLiteral(
953  "{% if x.isTrue or x.isBad %}yes{% else %}no{% endif %}")
954  << dict << QStringLiteral("yes") << NoError;
955 
956  QTest::newRow("if-tag-shortcircuit02")
957  << QStringLiteral(
958  "{% if x.isFalse and x.isBad %}yes{% else %}no{% endif %}")
959  << dict << QStringLiteral("no") << NoError;
960  dict.clear();
961  }
962 
963  QTest::newRow("if-tag-badarg01")
964  << QStringLiteral("{% if x|default_if_none:y %}yes{% endif %}") << dict
965  << QString() << NoError;
966 
967  dict.clear();
968  dict.insert(QStringLiteral("y"), 0);
969  QTest::newRow("if-tag-badarg02")
970  << QStringLiteral("{% if x|default_if_none:y %}yes{% endif %}") << dict
971  << QString() << NoError;
972 
973  dict.clear();
974  dict.insert(QStringLiteral("y"), 1);
975  QTest::newRow("if-tag-badarg03")
976  << QStringLiteral("{% if x|default_if_none:y %}yes{% endif %}") << dict
977  << QStringLiteral("yes") << NoError;
978 
979  dict.clear();
980  QTest::newRow("if-tag-badarg04") << QStringLiteral(
981  "{% if x|default_if_none:y %}yes{% else %}no{% endif %}")
982  << dict << QStringLiteral("no") << NoError;
983 
984  dict.clear();
985  dict.insert(QStringLiteral("foo"), 1);
986  QTest::newRow("if-tag-single-eq")
987  << QStringLiteral("{% if foo = bar %}yes{% else %}no{% endif %}") << dict
988  << QString() << TagSyntaxError;
989 
990  // Truthiness
991  dict.clear();
992  QVariantHash hash;
993  dict.insert(QStringLiteral("var"), hash);
994  QTest::newRow("if-truthiness01")
995  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
996  << QStringLiteral("No") << NoError;
997  hash.insert(QStringLiteral("foo"), QStringLiteral("bar"));
998  dict.insert(QStringLiteral("var"), hash);
999  QTest::newRow("if-truthiness02")
1000  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1001  << QStringLiteral("Yes") << NoError;
1002  QVariantList list;
1003  dict.insert(QStringLiteral("var"), list);
1004  QTest::newRow("if-truthiness03")
1005  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1006  << QStringLiteral("No") << NoError;
1007  list.append(QStringLiteral("foo"));
1008  dict.insert(QStringLiteral("var"), list);
1009  QTest::newRow("if-truthiness04")
1010  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1011  << QStringLiteral("Yes") << NoError;
1012  QVariantMap map;
1013  dict.insert(QStringLiteral("var"), map);
1014  QTest::newRow("if-truthiness05")
1015  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1016  << QStringLiteral("No") << NoError;
1017  map.insert(QStringLiteral("foo"), QStringLiteral("bar"));
1018  dict.insert(QStringLiteral("var"), map);
1019  QTest::newRow("if-truthiness06")
1020  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1021  << QStringLiteral("Yes") << NoError;
1022 
1023 
1024  QVariant var;
1025  dict.insert(QStringLiteral("var"), var);
1026  QTest::newRow("if-truthiness07")
1027  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1028  << QStringLiteral("No") << NoError;
1029  var = QStringLiteral("foo");
1030  dict.insert(QStringLiteral("var"), var);
1031  QTest::newRow("if-truthiness08")
1032  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1033  << QStringLiteral("Yes") << NoError;
1034 
1035  QString str;
1036  dict.insert(QStringLiteral("var"), str);
1037  QTest::newRow("if-truthiness09")
1038  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1039  << QStringLiteral("No") << NoError;
1040  str = QStringLiteral("foo");
1041  dict.insert(QStringLiteral("var"), str);
1042  QTest::newRow("if-truthiness10")
1043  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1044  << QStringLiteral("Yes") << NoError;
1045 
1046  auto i = 0;
1047  dict.insert(QStringLiteral("var"), i);
1048  QTest::newRow("if-truthiness11")
1049  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1050  << QStringLiteral("No") << NoError;
1051  i = 7;
1052  dict.insert(QStringLiteral("var"), i);
1053  QTest::newRow("if-truthiness12")
1054  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1055  << QStringLiteral("Yes") << NoError;
1056 
1057  auto r = 0.0;
1058  dict.insert(QStringLiteral("var"), r);
1059  QTest::newRow("if-truthiness13")
1060  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1061  << QStringLiteral("No") << NoError;
1062  r = 7.1;
1063  dict.insert(QStringLiteral("var"), r);
1064  QTest::newRow("if-truthiness14")
1065  << QStringLiteral("{% if var %}Yes{% else %}No{% endif %}") << dict
1066  << QStringLiteral("Yes") << NoError;
1067 
1068  dict.clear();
1069  QTest::newRow("if-tag-badarg01")
1070  << QStringLiteral("{% if x|default_if_none:y %}yes{% endif %}") << dict
1071  << QString() << NoError;
1072 
1073  dict.insert(QStringLiteral("y"), 0);
1074 
1075  QTest::newRow("if-tag-badarg02")
1076  << QStringLiteral("{% if x|default_if_none:y %}yes{% endif %}") << dict
1077  << QString() << NoError;
1078 
1079  dict.clear();
1080  dict.insert(QStringLiteral("y"), 1);
1081 
1082  QTest::newRow("if-tag-badarg03")
1083  << QStringLiteral("{% if x|default_if_none:y %}yes{% endif %}") << dict
1084  << QStringLiteral("yes") << NoError;
1085 
1086  dict.clear();
1087  QTest::newRow("if-tag-badarg04") << QStringLiteral(
1088  "{% if x|default_if_none:y %}yes{% else %}no{% endif %}")
1089  << dict << QStringLiteral("no") << NoError;
1090 }
1091 
1092 void TestDefaultTags::testForTag_data()
1093 {
1094  QTest::addColumn<QString>("input");
1095  QTest::addColumn<Dict>("dict");
1096  QTest::addColumn<QString>("output");
1097  QTest::addColumn<Cutelee::Error>("error");
1098 
1099  Dict dict;
1100 
1101  QVariantList list{1, 2, 3};
1102  dict.insert(QStringLiteral("values"), list);
1103  QTest::newRow("for-tag01")
1104  << QStringLiteral("{% for val in values %}{{ val }}{% endfor %}") << dict
1105  << QStringLiteral("123") << NoError;
1106  QTest::newRow("for-tag02")
1107  << QStringLiteral("{% for val in values reversed %}{{ val }}{% endfor %}")
1108  << dict << QStringLiteral("321") << NoError;
1109  list.clear();
1110  dict.insert(QStringLiteral("values"), list);
1111  QTest::newRow("for-tag03") << QStringLiteral(
1112  "{% for val in values %}({{ val }} sdfsdf,){% endfor %}")
1113  << dict << QString() << NoError;
1114  QStringList emails{QStringLiteral("one"), QStringLiteral("two")};
1115  QVariantHash obj;
1116  obj.insert(QStringLiteral("emails"), emails);
1117  dict.insert(QStringLiteral("contact"), obj);
1118  QTest::newRow("for-tag04")
1119  << QStringLiteral(
1120  "{% for val in contact.emails %}({{ val }},){% endfor %}")
1121  << dict << QStringLiteral("(one,)(two,)") << NoError;
1122  emails.clear();
1123  obj.insert(QStringLiteral("emails"), emails);
1124  dict.insert(QStringLiteral("contact"), obj);
1125  QTest::newRow("for-tag05") << QStringLiteral(
1126  "{% for val in contact.emails %}({{ val }},){% endfor %}")
1127  << dict << QString() << NoError;
1128  list.clear();
1129  dict.clear();
1130  emails << QStringLiteral("one");
1131  dict.insert(QStringLiteral("emails"), emails);
1132  QTest::newRow("for-tag06")
1133  << QStringLiteral("{% for val in emails %}({{ val }},){% endfor %}")
1134  << dict << QStringLiteral("(one,)") << NoError;
1135  list.clear();
1136  dict.clear();
1137 
1138  QTest::newRow("for-tag07") << QStringLiteral("{% for %}{% endfor %}") << dict
1139  << QString() << TagSyntaxError;
1140  QTest::newRow("for-tag08")
1141  << QStringLiteral("{% for foo bar bat %}{% endfor %}") << dict
1142  << QString() << TagSyntaxError;
1143  QTest::newRow("for-tag09")
1144  << QStringLiteral("{% for foo bar '' %}{% endfor %}") << dict << QString()
1145  << TagSyntaxError;
1146 
1147  list << 1 << 2 << 3;
1148  dict.insert(QStringLiteral("values"), list);
1149  QTest::newRow("for-tag-vars01") << QStringLiteral(
1150  "{% for val in values %}{{ forloop.counter }}{% endfor %}")
1151  << dict << QStringLiteral("123") << NoError;
1152  QTest::newRow("for-tag-vars02") << QStringLiteral(
1153  "{% for val in values %}{{ forloop.counter0 }}{% endfor %}")
1154  << dict << QStringLiteral("012") << NoError;
1155  QTest::newRow("for-tag-vars03") << QStringLiteral(
1156  "{% for val in values %}{{ forloop.revcounter }}{% endfor %}")
1157  << dict << QStringLiteral("321") << NoError;
1158  QTest::newRow("for-tag-vars04") << QStringLiteral(
1159  "{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}")
1160  << dict << QStringLiteral("210") << NoError;
1161  QTest::newRow("for-tag-vars05")
1162  << QStringLiteral("{% for val in values %}{% if forloop.first %}f{% else "
1163  "%}x{% endif %}{% endfor %}")
1164  << dict << QStringLiteral("fxx") << NoError;
1165  QTest::newRow("for-tag-vars06")
1166  << QStringLiteral("{% for val in values %}{% if forloop.last %}l{% else "
1167  "%}x{% endif %}{% endfor %}")
1168  << dict << QStringLiteral("xxl") << NoError;
1169 
1170  dict.clear();
1171  list.clear();
1172  QVariantList innerList{QStringLiteral("one"), 1};
1173  list.append(QVariant(innerList));
1174  innerList.clear();
1175  innerList << QStringLiteral("two") << 2;
1176  list.append(QVariant(innerList));
1177  dict.insert(QStringLiteral("items"), list);
1178  QTest::newRow("for-tag-unpack01")
1179  << QStringLiteral(
1180  "{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}")
1181  << dict << QStringLiteral("one:1/two:2/") << NoError;
1182 
1183  QTest::newRow("for-tag-unpack03")
1184  << QStringLiteral(
1185  "{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}")
1186  << dict << QStringLiteral("one:1/two:2/") << NoError;
1187  QTest::newRow("for-tag-unpack04")
1188  << QStringLiteral(
1189  "{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}")
1190  << dict << QStringLiteral("one:1/two:2/") << NoError;
1191  QTest::newRow("for-tag-unpack05")
1192  << QStringLiteral(
1193  "{% for key ,value in items %}{{ key }}:{{ value }}/{% endfor %}")
1194  << dict << QStringLiteral("one:1/two:2/") << NoError;
1195  QTest::newRow("for-tag-unpack06")
1196  << QStringLiteral(
1197  "{% for key value in items %}{{ key }}:{{ value }}/{% endfor %}")
1198  << dict << QStringLiteral("one:1/two:2/") << NoError;
1199  QTest::newRow("for-tag-unpack07")
1200  << QStringLiteral(
1201  "{% for key,,value in items %}{{ key }}:{{ value }}/{% endfor %}")
1202  << dict << QStringLiteral("one:1/two:2/") << NoError;
1203  QTest::newRow("for-tag-unpack08")
1204  << QStringLiteral(
1205  "{% for key,value, in items %}{{ key }}:{{ value }}/{% endfor %}")
1206  << dict << QStringLiteral("one:1/two:2/") << NoError;
1207 
1208  // Ensure that a single loopvar doesn't truncate the list in val.
1209  QTest::newRow("for-tag-unpack09")
1210  << QStringLiteral(
1211  "{% for val in items %}{{ val.0 }}:{{ val.1 }}/{% endfor %}")
1212  << dict << QStringLiteral("one:1/two:2/") << NoError;
1213 
1214  // Otherwise, silently truncate if the length of loopvars differs to the
1215  // length of each set of items.
1216 
1217  dict.clear();
1218  list.clear();
1219  innerList.clear();
1220  innerList << QStringLiteral("one") << 1 << QStringLiteral("carrot");
1221  list.append(QVariant(innerList));
1222  innerList.clear();
1223  innerList << QStringLiteral("two") << 2 << QStringLiteral("orange");
1224  list.append(QVariant(innerList));
1225  dict.insert(QStringLiteral("items"), list);
1226 
1227  QTest::newRow("for-tag-unpack10")
1228  << QStringLiteral("{% for x,y in items %}{{ x }}:{{ y }}/{% endfor %}")
1229  << dict << QStringLiteral("one:1/two:2/") << NoError;
1230 
1231  dict.clear();
1232  list.clear();
1233  innerList.clear();
1234  innerList << QStringLiteral("one") << 1;
1235  list.append(QVariant(innerList));
1236  innerList.clear();
1237  innerList << QStringLiteral("two") << 2;
1238  list.append(QVariant(innerList));
1239  dict.insert(QStringLiteral("items"), list);
1240 
1241  QTest::newRow("for-tag-unpack11")
1242  << QStringLiteral(
1243  "{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}")
1244  << dict << QStringLiteral("one:1,/two:2,/") << NoError;
1245 
1246  dict.clear();
1247  list.clear();
1248  innerList.clear();
1249  innerList << QStringLiteral("one") << 1 << QStringLiteral("carrot");
1250  list.append(QVariant(innerList));
1251  innerList.clear();
1252  innerList << QStringLiteral("two") << 2;
1253  list.append(QVariant(innerList));
1254  dict.insert(QStringLiteral("items"), list);
1255 
1256  QTest::newRow("for-tag-unpack12")
1257  << QStringLiteral(
1258  "{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}")
1259  << dict << QStringLiteral("one:1,carrot/two:2,/") << NoError;
1260 
1261  dict.clear();
1262  list.clear();
1263  innerList.clear();
1264  innerList << QStringLiteral("one") << 1 << QStringLiteral("carrot");
1265  list.append(QVariant(innerList));
1266  innerList.clear();
1267  innerList << QStringLiteral("two") << 2 << QStringLiteral("cheese");
1268  list.append(QVariant(innerList));
1269 
1270  dict.insert(QStringLiteral("items"), list);
1271 
1272  QTest::newRow("for-tag-unpack13")
1273  << QStringLiteral(
1274  "{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}")
1275  << dict << QStringLiteral("one:1,carrot/two:2,cheese/") << NoError;
1276 
1277  // Empty tag:
1278 
1279  dict.clear();
1280  dict.insert(QStringLiteral("values"), QVariantList{1, 2, 3});
1281  QTest::newRow("for-tag-empty01") << QStringLiteral(
1282  "{% for val in values %}{{ val }}{% empty %}empty text{% endfor %}")
1283  << dict << QStringLiteral("123") << NoError;
1284 
1285  dict.clear();
1286  dict.insert(QStringLiteral("values"), QVariantList());
1287  QTest::newRow("for-tag-empty02")
1288  << QStringLiteral("{% for val in values %}{{ val }}{% empty %}values "
1289  "array empty{% endfor %}")
1290  << dict << QStringLiteral("values array empty") << NoError;
1291 
1292  dict.clear();
1293  QTest::newRow("for-tag-empty03")
1294  << QStringLiteral("{% for val in values %}{{ val }}{% empty %}values "
1295  "array not found{% endfor %}")
1296  << dict << QStringLiteral("values array not found") << NoError;
1297 }
1298 
1299 void TestDefaultTags::testIfEqualTag_data()
1300 {
1301  QTest::addColumn<QString>("input");
1302  QTest::addColumn<Dict>("dict");
1303  QTest::addColumn<QString>("output");
1304  QTest::addColumn<Cutelee::Error>("error");
1305 
1306  Dict dict;
1307 
1308  dict.insert(QStringLiteral("a"), 1);
1309  dict.insert(QStringLiteral("b"), 2);
1310 
1311  QTest::newRow("ifequal01")
1312  << QStringLiteral("{% ifequal a b %}yes{% endifequal %}") << dict
1313  << QString() << NoError;
1314  QTest::newRow("ifequal03")
1315  << QStringLiteral("{% ifequal a b %}yes{% else %}no{% endifequal %}")
1316  << dict << QStringLiteral("no") << NoError;
1317 
1318  dict.clear();
1319  dict.insert(QStringLiteral("a"), 1);
1320  dict.insert(QStringLiteral("b"), 1);
1321 
1322  QTest::newRow("ifequal02")
1323  << QStringLiteral("{% ifequal a b %}yes{% endifequal %}") << dict
1324  << QStringLiteral("yes") << NoError;
1325  QTest::newRow("ifequal04")
1326  << QStringLiteral("{% ifequal a b %}yes{% else %}no{% endifequal %}")
1327  << dict << QStringLiteral("yes") << NoError;
1328 
1329  dict.clear();
1330  dict.insert(QStringLiteral("a"), QStringLiteral("test"));
1331 
1332  QTest::newRow("ifequal05")
1333  << QStringLiteral("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}")
1334  << dict << QStringLiteral("yes") << NoError;
1335 
1336  dict.clear();
1337  dict.insert(QStringLiteral("a"), QStringLiteral("no"));
1338 
1339  QTest::newRow("ifequal06")
1340  << QStringLiteral("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}")
1341  << dict << QStringLiteral("no") << NoError;
1342 
1343  dict.clear();
1344  dict.insert(QStringLiteral("a"), QStringLiteral("test"));
1345 
1346  QTest::newRow("ifequal07")
1347  << "{% ifequal a \"test\" %}yes{% else %}no{% endifequal %}" << dict
1348  << QStringLiteral("yes") << NoError;
1349 
1350  dict.clear();
1351  dict.insert(QStringLiteral("a"), QStringLiteral("no"));
1352 
1353  QTest::newRow("ifequal08")
1354  << "{% ifequal a \"test\" %}yes{% else %}no{% endifequal %}" << dict
1355  << QStringLiteral("no") << NoError;
1356 
1357  dict.clear();
1358 
1359  QTest::newRow("ifequal09")
1360  << "{% ifequal a \"test\" %}yes{% else %}no{% endifequal %}" << dict
1361  << QStringLiteral("no") << NoError;
1362 
1363  QTest::newRow("ifequal10")
1364  << QStringLiteral("{% ifequal a b %}yes{% else %}no{% endifequal %}")
1365  << dict << QStringLiteral("yes") << NoError;
1366 
1367  QTest::newRow("ifequal-split01")
1368  << "{% ifequal a \"test man\" %}yes{% else %}no{% endifequal %}" << dict
1369  << QStringLiteral("no") << NoError;
1370 
1371  dict.insert(QStringLiteral("a"), QStringLiteral("foo"));
1372  QTest::newRow("ifequal-split02")
1373  << "{% ifequal a \"test man\" %}yes{% else %}no{% endifequal %}" << dict
1374  << QStringLiteral("no") << NoError;
1375 
1376  dict.clear();
1377  dict.insert(QStringLiteral("a"), QStringLiteral("test man"));
1378  QTest::newRow("ifequal-split03")
1379  << "{% ifequal a \"test man\" %}yes{% else %}no{% endifequal %}" << dict
1380  << QStringLiteral("yes") << NoError;
1381  QTest::newRow("ifequal-split04") << QStringLiteral(
1382  "{% ifequal a 'test man' %}yes{% else %}no{% endifequal %}")
1383  << dict << QStringLiteral("yes") << NoError;
1384 
1385  dict.clear();
1386  dict.insert(QStringLiteral("a"), QStringLiteral(""));
1387  QTest::newRow("ifequal-split05")
1388  << "{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}"
1389  << dict << QStringLiteral("no") << NoError;
1390 
1391  dict.clear();
1392  dict.insert(QStringLiteral("a"), QStringLiteral("i \"love\" you"));
1393  QTest::newRow("ifequal-split06")
1394  << "{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}"
1395  << dict << QStringLiteral("yes") << NoError;
1396 
1397  dict.clear();
1398  dict.insert(QStringLiteral("a"), QStringLiteral("i love you"));
1399  QTest::newRow("ifequal-split07")
1400  << "{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}"
1401  << dict << QStringLiteral("no") << NoError;
1402 
1403  dict.clear();
1404  dict.insert(QStringLiteral("a"), QStringLiteral("I'm happy"));
1405  QTest::newRow("ifequal-split08")
1406  << "{% ifequal a 'I\\'m happy' %}yes{% else %}no{% endifequal %}" << dict
1407  << QStringLiteral("yes") << NoError;
1408 
1409  dict.clear();
1410  dict.insert(QStringLiteral("a"), QStringLiteral("slash\\man"));
1411  QTest::newRow("ifequal-split09")
1412  << "{% ifequal a 'slash\\man' %}yes{% else %}no{% endifequal %}" << dict
1413  << QStringLiteral("yes") << NoError;
1414 
1415  dict.clear();
1416  dict.insert(QStringLiteral("a"), QStringLiteral("slashman"));
1417  QTest::newRow("ifequal-split10")
1418  << "{% ifequal a 'slash\\man' %}yes{% else %}no{% endifequal %}" << dict
1419  << QStringLiteral("no") << NoError;
1420  // NUMERIC RESOLUTION
1421 
1422  dict.clear();
1423  dict.insert(QStringLiteral("x"), QStringLiteral("5"));
1424 
1425  QTest::newRow("ifequal-numeric01")
1426  << QStringLiteral("{% ifequal x 5 %}yes{% endifequal %}") << dict
1427  << QString() << NoError;
1428 
1429  dict.clear();
1430  dict.insert(QStringLiteral("x"), 5);
1431  QTest::newRow("ifequal-numeric02")
1432  << QStringLiteral("{% ifequal x 5 %}yes{% endifequal %}") << dict
1433  << QStringLiteral("yes") << NoError;
1434 
1435  dict.clear();
1436  dict.insert(QStringLiteral("x"), 5.2);
1437  QTest::newRow("ifequal-numeric03")
1438  << QStringLiteral("{% ifequal x 5 %}yes{% endifequal %}") << dict
1439  << QString() << NoError;
1440  QTest::newRow("ifequal-numeric04")
1441  << QStringLiteral("{% ifequal x 5.2 %}yes{% endifequal %}") << dict
1442  << QStringLiteral("yes") << NoError;
1443 
1444  dict.clear();
1445  dict.insert(QStringLiteral("x"), .2);
1446 
1447  QTest::newRow("ifequal-numeric05")
1448  << QStringLiteral("{% ifequal x 0.2 %}yes{% endifequal %}") << dict
1449  << QStringLiteral("yes") << NoError;
1450  QTest::newRow("ifequal-numeric06")
1451  << QStringLiteral("{% ifequal x .2 %}yes{% endifequal %}") << dict
1452  << QStringLiteral("yes") << NoError;
1453 
1454  dict.clear();
1455  dict.insert(QStringLiteral("x"), 2);
1456 
1457  QTest::newRow("ifequal-numeric07")
1458  << QStringLiteral("{% ifequal x 2. %}yes{% endifequal %}") << dict
1459  << QString() << TagSyntaxError;
1460 
1461  dict.clear();
1462  dict.insert(QStringLiteral("x"), 5);
1463  QTest::newRow("ifequal-numeric08")
1464  << "{% ifequal x \"5\" %}yes{% endifequal %}" << dict << QString()
1465  << NoError;
1466 
1467  dict.clear();
1468  dict.insert(QStringLiteral("x"), QStringLiteral("5"));
1469  QTest::newRow("ifequal-numeric09")
1470  << "{% ifequal x \"5\" %}yes{% endifequal %}" << dict
1471  << QStringLiteral("yes") << NoError;
1472 
1473  dict.clear();
1474  dict.insert(QStringLiteral("x"), -5);
1475  QTest::newRow("ifequal-numeric10")
1476  << QStringLiteral("{% ifequal x -5 %}yes{% endifequal %}") << dict
1477  << QStringLiteral("yes") << NoError;
1478 
1479  dict.clear();
1480  dict.insert(QStringLiteral("x"), -5.2);
1481  QTest::newRow("ifequal-numeric11")
1482  << QStringLiteral("{% ifequal x -5.2 %}yes{% endifequal %}") << dict
1483  << QStringLiteral("yes") << NoError;
1484 
1485  dict.clear();
1486  dict.insert(QStringLiteral("x"), 5);
1487  QTest::newRow("ifequal-numeric12")
1488  << QStringLiteral("{% ifequal x +5 %}yes{% endifequal %}") << dict
1489  << QStringLiteral("yes") << NoError;
1490 
1491  // FILTER EXPRESSIONS AS ARGUMENTS
1492 
1493  dict.clear();
1494  dict.insert(QStringLiteral("a"), QStringLiteral("a"));
1495  QTest::newRow("ifequal-filter01")
1496  << "{% ifequal a|upper \"A\" %}x{% endifequal %}" << dict
1497  << QStringLiteral("x") << NoError;
1498 
1499  QTest::newRow("ifequal-filter02")
1500  << "{% ifequal \"A\" a|upper %}x{% endifequal %}" << dict
1501  << QStringLiteral("x") << NoError;
1502 
1503  dict.clear();
1504  dict.insert(QStringLiteral("a"), QStringLiteral("x"));
1505  dict.insert(QStringLiteral("b"), QStringLiteral("X"));
1506 
1507  QTest::newRow("ifequal-filter03")
1508  << QStringLiteral("{% ifequal a|upper b|upper %}x{% endifequal %}")
1509  << dict << QStringLiteral("x") << NoError;
1510 
1511  dict.clear();
1512  dict.insert(QStringLiteral("x"), QStringLiteral("aaa"));
1513 
1514  QTest::newRow("ifequal-filter04")
1515  << "{% ifequal x|slice:\"1\" \"a\" %}x{% endifequal %}" << dict
1516  << QStringLiteral("x") << NoError;
1517 
1518  dict.clear();
1519  dict.insert(QStringLiteral("x"), QStringLiteral("aaa"));
1520 
1521  QTest::newRow("ifequal-filter05")
1522  << "{% ifequal x|slice:\"1\"|upper \"A\" %}x{% endifequal %}" << dict
1523  << QStringLiteral("x") << NoError;
1524 
1525  QTest::newRow("ifequal-error01")
1526  << "{% ifequal x|slice:\"1\"|upper %}x{% endifequal %}" << dict
1527  << QString() << TagSyntaxError;
1528 }
1529 
1530 void TestDefaultTags::testIfNotEqualTag_data()
1531 {
1532  QTest::addColumn<QString>("input");
1533  QTest::addColumn<Dict>("dict");
1534  QTest::addColumn<QString>("output");
1535  QTest::addColumn<Cutelee::Error>("error");
1536 
1537  Dict dict;
1538 
1539  dict.insert(QStringLiteral("a"), 1);
1540  dict.insert(QStringLiteral("b"), 2);
1541 
1542  QTest::newRow("ifnotequal01")
1543  << QStringLiteral("{% ifnotequal a b %}yes{% endifnotequal %}") << dict
1544  << QStringLiteral("yes") << NoError;
1545  QTest::newRow("ifnotequal03") << QStringLiteral(
1546  "{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}")
1547  << dict << QStringLiteral("yes") << NoError;
1548 
1549  dict.clear();
1550  dict.insert(QStringLiteral("a"), 1);
1551  dict.insert(QStringLiteral("b"), 1);
1552 
1553  QTest::newRow("ifnotequal02")
1554  << QStringLiteral("{% ifnotequal a b %}yes{% endifnotequal %}") << dict
1555  << QString() << NoError;
1556  QTest::newRow("ifnotequal04") << QStringLiteral(
1557  "{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}")
1558  << dict << QStringLiteral("no") << NoError;
1559 }
1560 
1561 void TestDefaultTags::testTemplateTagTag_data()
1562 {
1563  QTest::addColumn<QString>("input");
1564  QTest::addColumn<Dict>("dict");
1565  QTest::addColumn<QString>("output");
1566  QTest::addColumn<Cutelee::Error>("error");
1567 
1568  Dict dict;
1569 
1570  QTest::newRow("templatetag01")
1571  << QStringLiteral("{% templatetag openblock %}") << dict
1572  << QStringLiteral("{%") << NoError;
1573  QTest::newRow("templatetag02")
1574  << QStringLiteral("{% templatetag closeblock %}") << dict
1575  << QStringLiteral("%}") << NoError;
1576  QTest::newRow("templatetag03")
1577  << QStringLiteral("{% templatetag openvariable %}") << dict
1578  << QStringLiteral("{{") << NoError;
1579  QTest::newRow("templatetag04")
1580  << QStringLiteral("{% templatetag closevariable %}") << dict
1581  << QStringLiteral("}}") << NoError;
1582  QTest::newRow("templatetag05") << QStringLiteral("{% templatetag %}") << dict
1583  << QString() << TagSyntaxError;
1584  QTest::newRow("templatetag06") << QStringLiteral("{% templatetag foo %}")
1585  << dict << QString() << TagSyntaxError;
1586  QTest::newRow("templatetag07")
1587  << QStringLiteral("{% templatetag openbrace %}") << dict
1588  << QStringLiteral("{") << NoError;
1589  QTest::newRow("templatetag08")
1590  << QStringLiteral("{% templatetag closebrace %}") << dict
1591  << QStringLiteral("}") << NoError;
1592  QTest::newRow("templatetag09") << QStringLiteral(
1593  "{% templatetag openbrace %}{% templatetag openbrace %}")
1594  << dict << QStringLiteral("{{") << NoError;
1595  QTest::newRow("templatetag10") << QStringLiteral(
1596  "{% templatetag closebrace %}{% templatetag closebrace %}")
1597  << dict << QStringLiteral("}}") << NoError;
1598  QTest::newRow("templatetag11")
1599  << QStringLiteral("{% templatetag opencomment %}") << dict
1600  << QStringLiteral("{#") << NoError;
1601  QTest::newRow("templatetag12")
1602  << QStringLiteral("{% templatetag closecomment %}") << dict
1603  << QStringLiteral("#}") << NoError;
1604 }
1605 
1606 void TestDefaultTags::testWithTag_data()
1607 {
1608  QTest::addColumn<QString>("input");
1609  QTest::addColumn<Dict>("dict");
1610  QTest::addColumn<QString>("output");
1611  QTest::addColumn<Cutelee::Error>("error");
1612 
1613  Dict dict;
1614 
1615  QVariantHash hash;
1616  hash.insert(QStringLiteral("key"), 50);
1617  dict.insert(QStringLiteral("dict"), hash);
1618  QTest::newRow("with01") << QStringLiteral(
1619  "{% with dict.key as key %}{{ key }}{% endwith %}")
1620  << dict << QStringLiteral("50") << NoError;
1621  QTest::newRow("with02") << QStringLiteral(
1622  "{{ key }}{% with dict.key as key %}{{ key }}-{{ dict.key }}-{{ key }}{% "
1623  "endwith %}{{ key }}")
1624  << dict << QStringLiteral("50-50-50") << NoError;
1625  QTest::newRow("with03") << QStringLiteral(
1626  "{{ key }}{% with key=dict.key %}{{ key }}-{{ dict.key }}-{{ key }}{% "
1627  "endwith %}{{ key }}")
1628  << dict << QStringLiteral("50-50-50") << NoError;
1629  QTest::newRow("with04") << QStringLiteral(
1630  "{{ key1 }}{% with key1=dict.key key2=dict.key key3=dict.key %}{{ key1 }}-{{ dict.key }}-{{ key3 }}{% "
1631  "endwith %}{{ key }}")
1632  << dict << QStringLiteral("50-50-50") << NoError;
1633  QTest::newRow("with-error01")
1634  << QStringLiteral("{% with dict.key xx key %}{{ key }}{% endwith %}")
1635  << dict << QString() << TagSyntaxError;
1636  QTest::newRow("with-error02")
1637  << QStringLiteral("{% with dict.key as %}{{ key }}{% endwith %}") << dict
1638  << QString() << TagSyntaxError;
1639 }
1640 
1641 void TestDefaultTags::testCycleTag_data()
1642 {
1643  QTest::addColumn<QString>("input");
1644  QTest::addColumn<Dict>("dict");
1645  QTest::addColumn<QString>("output");
1646  QTest::addColumn<Cutelee::Error>("error");
1647 
1648  Dict dict;
1649 
1650  QTest::newRow("cycle01") << QStringLiteral("{% cycle a %}") << dict
1651  << QString() << TagSyntaxError;
1652  QTest::newRow("cycle02") << QStringLiteral(
1653  "{% cycle a,b,c as abc %}{% cycle abc %}")
1654  << dict << QStringLiteral("ab") << NoError;
1655  QTest::newRow("cycle03") << QStringLiteral(
1656  "{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}")
1657  << dict << QStringLiteral("abc") << NoError;
1658  QTest::newRow("cycle04") << QStringLiteral(
1659  "{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}")
1660  << dict << QStringLiteral("abca") << NoError;
1661  QTest::newRow("cycle05") << QStringLiteral("{% cycle a %}") << dict
1662  << QString() << TagSyntaxError;
1663  // TODO: This is the same as cycle01. Remove.
1664  QTest::newRow("cycle06") << QStringLiteral("{% cycle a %}") << dict
1665  << QString() << TagSyntaxError;
1666  QTest::newRow("cycle07") << QStringLiteral(
1667  "{% cycle a,b,c as foo %}{% cycle bar %}")
1668  << dict << QString() << TagSyntaxError;
1669  QTest::newRow("cycle08") << QStringLiteral(
1670  "{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo "
1671  "%}{{ foo }}") << dict
1672  << QStringLiteral("abbbcc") << NoError;
1673 
1674  dict.insert(QStringLiteral("test"), QVariantList{0, 1, 2, 3, 4});
1675  QTest::newRow("cycle09") << QStringLiteral(
1676  "{% for i in test %}{% cycle a,b %}{{ i }},{% endfor %}")
1677  << dict << QStringLiteral("a0,b1,a2,b3,a4,")
1678  << NoError;
1679 
1680  dict.clear();
1681  QTest::newRow("cycle10") << QStringLiteral(
1682  "{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}")
1683  << dict << QStringLiteral("ab") << NoError;
1684  QTest::newRow("cycle11") << QStringLiteral(
1685  "{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}{% cycle abc %}")
1686  << dict << QStringLiteral("abc") << NoError;
1687  QTest::newRow("cycle12") << QStringLiteral(
1688  "{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}{% cycle abc %}{% cycle "
1689  "abc %}") << dict << QStringLiteral("abca")
1690  << NoError;
1691 
1692  dict.insert(QStringLiteral("test"), QVariantList{0, 1, 2, 3, 4});
1693  QTest::newRow("cycle13") << QStringLiteral(
1694  "{% for i in test %}{% cycle 'a' 'b' %}{{ i }},{% endfor %}")
1695  << dict << QStringLiteral("a0,b1,a2,b3,a4,")
1696  << NoError;
1697 
1698  dict.clear();
1699  dict.insert(QStringLiteral("one"), QStringLiteral("1"));
1700  dict.insert(QStringLiteral("two"), QStringLiteral("2"));
1701  QTest::newRow("cycle14") << QStringLiteral(
1702  "{% cycle one two as foo %}{% cycle foo %}")
1703  << dict << QStringLiteral("12") << NoError;
1704 
1705  dict.clear();
1706  dict.insert(QStringLiteral("test"), QVariantList{0, 1, 2, 3, 4});
1707  dict.insert(QStringLiteral("aye"), QStringLiteral("a"));
1708  dict.insert(QStringLiteral("bee"), QStringLiteral("b"));
1709  QTest::newRow("cycle15") << QStringLiteral(
1710  "{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}")
1711  << dict << QStringLiteral("a0,b1,a2,b3,a4,")
1712  << NoError;
1713 
1714  dict.clear();
1715  dict.insert(QStringLiteral("one"), QStringLiteral("A"));
1716  dict.insert(QStringLiteral("two"), QStringLiteral("2"));
1717  QTest::newRow("cycle16") << QStringLiteral(
1718  "{% cycle one|lower two as foo %}{% cycle foo %}")
1719  << dict << QStringLiteral("a2") << NoError;
1720 
1721  QTest::newRow("cycle17") << QStringLiteral("{% cycle %}") << dict << QString()
1722  << TagSyntaxError;
1723  QTest::newRow("cycle18") << QStringLiteral("{% cycle var %}") << dict
1724  << QString() << TagSyntaxError;
1725 
1726  dict.insert(QStringLiteral("three"), QStringLiteral("B"));
1727  dict.insert(QStringLiteral("four"), QStringLiteral("4"));
1728 
1729  QTest::newRow("cycle19") << QStringLiteral("{% cycle one two three foo %}")
1730  << dict << QStringLiteral("A") << NoError;
1731  QTest::newRow("cycle20") << QStringLiteral(
1732  "{% cycle one two as foo %}{% cycle three four as bar %}")
1733  << dict << QStringLiteral("AB") << NoError;
1734 }
1735 
1736 void TestDefaultTags::testWidthRatioTag_data()
1737 {
1738  QTest::addColumn<QString>("input");
1739  QTest::addColumn<Dict>("dict");
1740  QTest::addColumn<QString>("output");
1741  QTest::addColumn<Cutelee::Error>("error");
1742 
1743  Dict dict;
1744 
1745  dict.insert(QStringLiteral("a"), 50);
1746  dict.insert(QStringLiteral("b"), 100);
1747  QTest::newRow("widthratio01") << QStringLiteral("{% widthratio a b 0 %}")
1748  << dict << QStringLiteral("0") << NoError;
1749 
1750  dict.clear();
1751  dict.insert(QStringLiteral("a"), 0);
1752  dict.insert(QStringLiteral("b"), 0);
1753  QTest::newRow("widthratio02") << QStringLiteral("{% widthratio a b 0 %}")
1754  << dict << QString() << NoError;
1755 
1756  dict.clear();
1757  dict.insert(QStringLiteral("a"), 0);
1758  dict.insert(QStringLiteral("b"), 100);
1759  QTest::newRow("widthratio03") << QStringLiteral("{% widthratio a b 100 %}")
1760  << dict << QStringLiteral("0") << NoError;
1761 
1762  dict.clear();
1763  dict.insert(QStringLiteral("a"), 50);
1764  dict.insert(QStringLiteral("b"), 100);
1765  QTest::newRow("widthratio04") << QStringLiteral("{% widthratio a b 100 %}")
1766  << dict << QStringLiteral("50") << NoError;
1767 
1768  dict.clear();
1769  dict.insert(QStringLiteral("a"), 100);
1770  dict.insert(QStringLiteral("b"), 100);
1771  QTest::newRow("widthratio05") << QStringLiteral("{% widthratio a b 100 %}")
1772  << dict << QStringLiteral("100") << NoError;
1773 
1774  dict.clear();
1775  dict.insert(QStringLiteral("a"), 50);
1776  dict.insert(QStringLiteral("b"), 80);
1777  QTest::newRow("widthratio06") << QStringLiteral("{% widthratio a b 100 %}")
1778  << dict << QStringLiteral("63") << NoError;
1779 
1780  dict.clear();
1781  dict.insert(QStringLiteral("a"), 50);
1782  dict.insert(QStringLiteral("b"), 70);
1783  QTest::newRow("widthratio07") << QStringLiteral("{% widthratio a b 100 %}")
1784  << dict << QStringLiteral("71") << NoError;
1785 
1786  dict.clear();
1787  // Raise exception if we don't have 3 args, last one an integer
1788  QTest::newRow("widthratio08") << QStringLiteral("{% widthratio %}") << dict
1789  << QString() << TagSyntaxError;
1790 
1791  dict.clear();
1792  QTest::newRow("widthratio09") << QStringLiteral("{% widthratio a b %}")
1793  << dict << QString() << TagSyntaxError;
1794 
1795  dict.clear();
1796  dict.insert(QStringLiteral("a"), 50);
1797  dict.insert(QStringLiteral("b"), 100);
1798  QTest::newRow("widthratio10") << QStringLiteral("{% widthratio a b 100.0 %}")
1799  << dict << QStringLiteral("50") << NoError;
1800 
1801  dict.clear();
1802  dict.insert(QStringLiteral("a"), 50);
1803  dict.insert(QStringLiteral("b"), 100);
1804  dict.insert(QStringLiteral("c"), 100);
1805  QTest::newRow("widthratio11") << QStringLiteral("{% widthratio a b c %}")
1806  << dict << QStringLiteral("50") << NoError;
1807 }
1808 
1809 void TestDefaultTags::testFilterTag_data()
1810 {
1811  QTest::addColumn<QString>("input");
1812  QTest::addColumn<Dict>("dict");
1813  QTest::addColumn<QString>("output");
1814  QTest::addColumn<Cutelee::Error>("error");
1815 
1816  Dict dict;
1817 
1818  QTest::newRow("filter01")
1819  << QStringLiteral("{% filter upper %}{% endfilter %}") << dict
1820  << QString() << NoError;
1821  QTest::newRow("filter02")
1822  << QStringLiteral("{% filter upper %}django{% endfilter %}") << dict
1823  << QStringLiteral("DJANGO") << NoError;
1824  QTest::newRow("filter03")
1825  << QStringLiteral("{% filter upper|lower %}django{% endfilter %}") << dict
1826  << QStringLiteral("django") << NoError;
1827 
1828  dict.insert(QStringLiteral("remove"), QStringLiteral("spam"));
1829  QTest::newRow("filter04")
1830  << QStringLiteral("{% filter cut:remove %}djangospam{% endfilter %}")
1831  << dict << QStringLiteral("django") << NoError;
1832 }
1833 
1834 void TestDefaultTags::testNowTag_data()
1835 {
1836  QTest::addColumn<QString>("input");
1837  QTest::addColumn<Dict>("dict");
1838  QTest::addColumn<QString>("output");
1839  QTest::addColumn<Cutelee::Error>("error");
1840 
1841  Dict dict;
1842 
1843  auto today = QDateTime::currentDateTime().date();
1844 
1845  QTest::newRow("now01") << QStringLiteral("{% now \"d M yyyy\"%}") << dict
1846  << (QString::number(today.day()) + QLatin1Char(' ')
1847  + QString::number(today.month()) + QLatin1Char(' ')
1848  + QString::number(today.year()))
1849  << NoError;
1850 
1851  QTest::newRow("now02") << QStringLiteral("{% now \"d \"M\" yyyy\"%}") << dict
1852  << QString() << TagSyntaxError;
1853 }
1854 
1855 void TestDefaultTags::testSpacelessTag_data()
1856 {
1857  QTest::addColumn<QString>("input");
1858  QTest::addColumn<Dict>("dict");
1859  QTest::addColumn<QString>("output");
1860  QTest::addColumn<Cutelee::Error>("error");
1861 
1862  Dict dict;
1863 
1864  QTest::newRow("spaceless01")
1865  << QStringLiteral(
1866  "{% spaceless %} <b> <i> text </i> </b> {% endspaceless %}")
1867  << dict << QStringLiteral("<b><i> text </i></b>") << NoError;
1868  QTest::newRow("spaceless02")
1869  << "{% spaceless %} <b> \n <i> text </i> \n </b> {% endspaceless %}"
1870  << dict << QStringLiteral("<b><i> text </i></b>") << NoError;
1871  QTest::newRow("spaceless03")
1872  << QStringLiteral("{% spaceless %}<b><i>text</i></b>{% endspaceless %}")
1873  << dict << QStringLiteral("<b><i>text</i></b>") << NoError;
1874 
1875  dict.insert(QStringLiteral("text"), QStringLiteral("This & that"));
1876  QTest::newRow("spaceless04")
1877  << QStringLiteral(
1878  "{% spaceless %}<b> <i>{{ text }}</i> </b>{% endspaceless %}")
1879  << dict << QStringLiteral("<b><i>This &amp; that</i></b>") << NoError;
1880  QTest::newRow("spaceless05")
1881  << QStringLiteral("{% autoescape off %}{% spaceless %}<b> <i>{{ text "
1882  "}}</i> </b>{% endspaceless %}{% endautoescape %}")
1883  << dict << QStringLiteral("<b><i>This & that</i></b>") << NoError;
1884  QTest::newRow("spaceless06") << QStringLiteral(
1885  "{% spaceless %}<b> <i>{{ text|safe }}</i> </b>{% endspaceless %}")
1886  << dict
1887  << QStringLiteral("<b><i>This & that</i></b>")
1888  << NoError;
1889 }
1890 
1891 void TestDefaultTags::testRegroupTag_data()
1892 {
1893  QTest::addColumn<QString>("input");
1894  QTest::addColumn<Dict>("dict");
1895  QTest::addColumn<QString>("output");
1896  QTest::addColumn<Cutelee::Error>("error");
1897 
1898  Dict dict;
1899 
1900  QVariantList list;
1901  QVariantHash hash;
1902 
1903  hash.insert(QStringLiteral("foo"), QStringLiteral("c"));
1904  hash.insert(QStringLiteral("bar"), 1);
1905  list.append(hash);
1906 
1907  hash.clear();
1908  hash.insert(QStringLiteral("foo"), QStringLiteral("d"));
1909  hash.insert(QStringLiteral("bar"), 1);
1910  list.append(hash);
1911 
1912  hash.clear();
1913  hash.insert(QStringLiteral("foo"), QStringLiteral("a"));
1914  hash.insert(QStringLiteral("bar"), 2);
1915  list.append(hash);
1916 
1917  hash.clear();
1918  hash.insert(QStringLiteral("foo"), QStringLiteral("b"));
1919  hash.insert(QStringLiteral("bar"), 2);
1920  list.append(hash);
1921 
1922  hash.clear();
1923  hash.insert(QStringLiteral("foo"), QStringLiteral("x"));
1924  hash.insert(QStringLiteral("bar"), 3);
1925  list.append(hash);
1926 
1927  dict.insert(QStringLiteral("data"), list);
1928 
1929  QTest::newRow("regroup01")
1930  << QString::fromLatin1("{% regroup data by bar as grouped %}"
1931  "{% for group in grouped %}"
1932  "{{ group.grouper }}:"
1933  "{% for item in group.list %}"
1934  "{{ item.foo }}"
1935  "{% endfor %},"
1936  "{% endfor %}")
1937  << dict << QStringLiteral("1:cd,2:ab,3:x,") << NoError;
1938 
1939  dict.clear();
1940  hash.clear();
1941  list.clear();
1942 
1943  hash.insert(QStringLiteral("foo"), QStringLiteral("a"));
1944  hash.insert(QStringLiteral("bar"), 2);
1945  list.append(hash);
1946 
1947  hash.clear();
1948  hash.insert(QStringLiteral("foo"), QStringLiteral("b"));
1949  hash.insert(QStringLiteral("bar"), 2);
1950  list.append(hash);
1951 
1952  hash.clear();
1953  hash.insert(QStringLiteral("foo"), QStringLiteral("x"));
1954  hash.insert(QStringLiteral("bar"), 3);
1955  list.append(hash);
1956 
1957  hash.clear();
1958  hash.insert(QStringLiteral("foo"), QStringLiteral("c"));
1959  hash.insert(QStringLiteral("bar"), 1);
1960  list.append(hash);
1961 
1962  hash.clear();
1963  hash.insert(QStringLiteral("foo"), QStringLiteral("d"));
1964  hash.insert(QStringLiteral("bar"), 1);
1965  list.append(hash);
1966 
1967  dict.insert(QStringLiteral("data"), list);
1968 
1969  // Data is output in the order it is sent in.
1970 
1971  QTest::newRow("regroup02")
1972  << QString::fromLatin1("{% regroup data by bar as grouped %}"
1973  "{% for group in grouped %}"
1974  "{{ group.grouper }}:"
1975  "{% for item in group.list %}"
1976  "{{ item.foo }}"
1977  "{% endfor %},"
1978  "{% endfor %}")
1979  << dict << QStringLiteral("2:ab,3:x,1:cd,") << NoError;
1980 
1981  dict.clear();
1982  hash.clear();
1983  list.clear();
1984 
1985  Table table;
1986 
1987  QVariantList row;
1988  row.append(1);
1989  row.append(QStringLiteral("a"));
1990  table.append(row);
1991 
1992  row.clear();
1993  row.append(1);
1994  row.append(QStringLiteral("b"));
1995  table.append(row);
1996 
1997  row.clear();
1998  row.append(2);
1999  row.append(QStringLiteral("a"));
2000  table.append(row);
2001 
2002  row.clear();
2003  row.append(3);
2004  row.append(QStringLiteral("c"));
2005  table.append(row);
2006 
2007  row.clear();
2008  row.append(3);
2009  row.append(QStringLiteral("d"));
2010  table.append(row);
2011 
2012  dict.insert(QStringLiteral("data"), QVariant::fromValue(table));
2013 
2014  QTest::newRow("regroup03")
2015  << QString::fromLatin1("{% regroup data by 0 as grouped %}"
2016  "{% for group in grouped %}"
2017  "{{ group.grouper }}:"
2018  "{% for item in group.list %}"
2019  "{{ item.1 }}"
2020  "{% endfor %},"
2021  "{% endfor %}")
2022  << dict << QStringLiteral("1:ab,2:a,3:cd,") << NoError;
2023 }
2024 
2025 void TestDefaultTags::testIfChangedTag_data()
2026 {
2027  QTest::addColumn<QString>("input");
2028  QTest::addColumn<Dict>("dict");
2029  QTest::addColumn<QString>("output");
2030  QTest::addColumn<Cutelee::Error>("error");
2031 
2032  Dict dict;
2033 
2034  dict.insert(QStringLiteral("num"), QVariantList{1, 2, 3});
2035  QTest::newRow("ifchanged01") << QStringLiteral(
2036  "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}")
2037  << dict << QStringLiteral("123") << NoError;
2038 
2039  dict.clear();
2040  dict.insert(QStringLiteral("num"), QVariantList{1, 1, 3});
2041  QTest::newRow("ifchanged02") << QStringLiteral(
2042  "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}")
2043  << dict << QStringLiteral("13") << NoError;
2044 
2045  dict.clear();
2046  dict.insert(QStringLiteral("num"), QVariantList{1, 1, 1});
2047  QTest::newRow("ifchanged03") << QStringLiteral(
2048  "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}")
2049  << dict << QStringLiteral("1") << NoError;
2050 
2051  dict.clear();
2052  dict.insert(QStringLiteral("num"), QVariantList{1, 2, 3});
2053  dict.insert(QStringLiteral("numx"), QVariantList{2, 2, 2});
2054  QTest::newRow("ifchanged04") << QStringLiteral(
2055  "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in "
2056  "numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}")
2057  << dict << QStringLiteral("122232") << NoError;
2058 
2059  dict.clear();
2060  dict.insert(QStringLiteral("num"), QVariantList{1, 1, 1});
2061  dict.insert(QStringLiteral("numx"), QVariantList{1, 2, 3});
2062  QTest::newRow("ifchanged05") << QStringLiteral(
2063  "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in "
2064  "numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}")
2065  << dict << QStringLiteral("1123123123")
2066  << NoError;
2067 
2068  dict.clear();
2069  dict.insert(QStringLiteral("num"), QVariantList{1, 1, 1});
2070  dict.insert(QStringLiteral("numx"), QVariantList{2, 2, 2});
2071  QTest::newRow("ifchanged06") << QStringLiteral(
2072  "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in "
2073  "numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}")
2074  << dict << QStringLiteral("1222") << NoError;
2075 
2076  dict.clear();
2077  dict.insert(QStringLiteral("num"), QVariantList{1, 1, 1});
2078  dict.insert(QStringLiteral("numx"), QVariantList{2, 2, 2});
2079  dict.insert(QStringLiteral("numy"), QVariantList{3, 3, 3});
2080  QTest::newRow("ifchanged07") << QStringLiteral(
2081  "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in "
2082  "numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% "
2083  "ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor "
2084  "%}") << dict << QStringLiteral("1233323332333")
2085  << NoError;
2086  QTest::newRow("ifchanged08")
2087  << QStringLiteral("{% ifchanged %}{{ num.0 }}{% endifchanged %}") << dict
2088  << QStringLiteral("1") << NoError;
2089 
2090  // datalist': [[(1, 'a'), (1, 'a'), (0, 'b'), (1, 'c')], [(0, 'a'), (1,
2091  // 'c'),
2092  // (1, 'd'), (1, 'd'), (0, 'e')]]}
2093  dict.clear();
2094  QVariantList list;
2095  QVariantList innerList;
2096  QVariantList tuple{1, QStringLiteral("a")};
2097  innerList.append(QVariant(tuple));
2098  tuple = {1, QStringLiteral("a")};
2099  innerList.append(QVariant(tuple));
2100  tuple = {0, QStringLiteral("b")};
2101  innerList.append(QVariant(tuple));
2102  tuple = {1, QStringLiteral("c")};
2103  innerList.append(QVariant(tuple));
2104  list.append(QVariant(innerList));
2105  innerList.clear();
2106 
2107  tuple = {0, QStringLiteral("a")};
2108  innerList.append(QVariant(tuple));
2109  tuple = {1, QStringLiteral("c")};
2110  innerList.append(QVariant(tuple));
2111  tuple = {1, QStringLiteral("d")};
2112  innerList.append(QVariant(tuple));
2113  tuple = {1, QStringLiteral("d")};
2114  innerList.append(QVariant(tuple));
2115  tuple = {0, QStringLiteral("e")};
2116  innerList.append(QVariant(tuple));
2117  list.append(QVariant(innerList));
2118  innerList.clear();
2119 
2120  dict.insert(QStringLiteral("datalist"), list);
2121  QTest::newRow("ifchanged08") << QStringLiteral(
2122  "{% for data in datalist %}{% for c,d in data %}{% if c %}{% ifchanged "
2123  "%}{{ d }}{% endifchanged %}{% endif %}{% endfor %}{% endfor %}")
2124  << dict << QStringLiteral("accd") << NoError;
2125 
2126  // Test one parameter given to ifchanged.
2127  dict.clear();
2128  dict.insert(QStringLiteral("num"), QVariantList{1, 2, 3});
2129  QTest::newRow("ifchanged-param01")
2130  << QStringLiteral("{% for n in num %}{% ifchanged n %}..{% endifchanged "
2131  "%}{{ n }}{% endfor %}")
2132  << dict << QStringLiteral("..1..2..3") << NoError;
2133 
2134  dict.clear();
2135  dict.insert(QStringLiteral("num"), QVariantList{1, 2, 3});
2136  dict.insert(QStringLiteral("numx"), QVariantList{5, 6, 7});
2137  QTest::newRow("ifchanged-param02")
2138  << QStringLiteral("{% for n in num %}{% for x in numx %}{% ifchanged n "
2139  "%}..{% endifchanged %}{{ x }}{% endfor %}{% endfor %}")
2140  << dict << QStringLiteral("..567..567..567") << NoError;
2141 
2142  // Test multiple parameters to ifchanged.
2143 
2144  dict.clear();
2145  dict.insert(QStringLiteral("num"), QVariantList{1, 1, 2});
2146  dict.insert(QStringLiteral("numx"), QVariantList{5, 6, 6});
2147  QTest::newRow("ifchanged-param03")
2148  << QStringLiteral(
2149  "{% for n in num %}{{ n }}{% for x in numx %}{% ifchanged x n "
2150  "%}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}")
2151  << dict << QStringLiteral("156156256") << NoError;
2152 
2153  // Test a date+hour like construct, where the hour of the last day
2154  // is the same but the date had changed, so print the hour anyway.
2155 
2156  dict.clear();
2157  QVariantList days;
2158  QVariantHash hash;
2159  hash.insert(QStringLiteral("day"), 1);
2160  hash.insert(QStringLiteral("hours"), QVariantList{1, 2, 3});
2161  days << hash;
2162  hash.clear();
2163  hash.insert(QStringLiteral("day"), 2);
2164  hash.insert(QStringLiteral("hours"), QVariantList{3});
2165  days << hash;
2166  dict.insert(QStringLiteral("days"), days);
2167  QTest::newRow("ifchanged-param04")
2168  << QStringLiteral("{% for d in days %}{% ifchanged %}{{ d.day }}{% "
2169  "endifchanged %}{% for h in d.hours %}{% ifchanged d h "
2170  "%}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}")
2171  << dict << QStringLiteral("112323") << NoError;
2172 
2173  // Logically the same as above, just written with explicit
2174  // ifchanged for the day.
2175 
2176  QTest::newRow("ifchanged-param05") << QStringLiteral(
2177  "{% for d in days %}{% ifchanged d.day %}{{ d.day }}{% endifchanged %}{% "
2178  "for h in d.hours %}{% ifchanged d.day h %}{{ h }}{% endifchanged %}{% "
2179  "endfor %}{% endfor %}") << dict
2180  << QStringLiteral("112323") << NoError;
2181 
2182  // Test the else clause of ifchanged.
2183  dict.clear();
2184  dict.insert(QStringLiteral("ids"), QVariantList{1, 1, 2, 2, 2, 3});
2185  QTest::newRow("ifchanged-else01")
2186  << QStringLiteral("{% for id in ids %}{{ id }}{% ifchanged id %}-first{% "
2187  "else %}-other{% endifchanged %},{% endfor %}")
2188  << dict
2189  << QStringLiteral("1-first,1-other,2-first,2-other,2-other,3-first,")
2190  << NoError;
2191  QTest::newRow("ifchanged-else02")
2192  << QStringLiteral(
2193  "{% for id in ids %}{{ id }}-{% ifchanged id %}{% cycle red,blue "
2194  "%}{% else %}grey{% endifchanged %},{% endfor %}")
2195  << dict << QStringLiteral("1-red,1-grey,2-blue,2-grey,2-grey,3-red,")
2196  << NoError;
2197  QTest::newRow("ifchanged-else03")
2198  << QStringLiteral(
2199  "{% for id in ids %}{{ id }}{% ifchanged id %}-{% cycle red,blue "
2200  "%}{% else %}{% endifchanged %},{% endfor %}")
2201  << dict << QStringLiteral("1-red,1,2-blue,2,2,3-red,") << NoError;
2202 
2203  dict.clear();
2204  dict.insert(QStringLiteral("ids"), QVariantList{1, 1, 2, 2, 2, 3, 4});
2205  QTest::newRow("ifchanged-else04")
2206  << QStringLiteral(
2207  "{% for id in ids %}{% ifchanged %}***{{ id }}*{% else %}...{% "
2208  "endifchanged %}{{ forloop.counter }}{% endfor %}")
2209  << dict << QStringLiteral("***1*1...2***2*3...4...5***3*6***4*7")
2210  << NoError;
2211 }
2212 
2213 void TestDefaultTags::testAutoescapeTag_data()
2214 {
2215  QTest::addColumn<QString>("input");
2216  QTest::addColumn<Dict>("dict");
2217  QTest::addColumn<QString>("output");
2218  QTest::addColumn<Cutelee::Error>("error");
2219 
2220  Dict dict;
2221 
2222  QTest::newRow("autoescape-tag01")
2223  << QStringLiteral("{% autoescape off %}hello{% endautoescape %}") << dict
2224  << QStringLiteral("hello") << NoError;
2225 
2226  dict.insert(QStringLiteral("first"), QStringLiteral("<b>hello</b>"));
2227  QTest::newRow("autoescape-tag02")
2228  << QStringLiteral("{% autoescape off %}{{ first }}{% endautoescape %}")
2229  << dict << QStringLiteral("<b>hello</b>") << NoError;
2230  QTest::newRow("autoescape-tag03")
2231  << QStringLiteral("{% autoescape on %}{{ first }}{% endautoescape %}")
2232  << dict << QStringLiteral("&lt;b&gt;hello&lt;/b&gt;") << NoError;
2233  // Autoescape disabling and enabling nest in a predictable way.
2234  dict.insert(QStringLiteral("first"), QStringLiteral("<a>"));
2235  QTest::newRow("autoescape-tag04")
2236  << QStringLiteral("{% autoescape off %}{{ first }} {% autoescape on%}{{ "
2237  "first }}{% endautoescape %}{% endautoescape %}")
2238  << dict << QStringLiteral("<a> &lt;a&gt;") << NoError;
2239 
2240  dict.insert(QStringLiteral("first"), QStringLiteral("<b>first</b>"));
2241  QTest::newRow("autoescape-tag05")
2242  << QStringLiteral("{% autoescape on %}{{ first }}{% endautoescape %}")
2243  << dict << QStringLiteral("&lt;b&gt;first&lt;/b&gt;") << NoError;
2244  // Strings (ASCII or unicode) already marked as "safe" are not
2245  // auto-escaped
2246  SafeString safeString(QStringLiteral("<b>first</b>"));
2247  auto safeStringVar = QVariant::fromValue<SafeString>(markSafe(safeString));
2248  dict.insert(QStringLiteral("first"), safeStringVar);
2249 
2250  QTest::newRow("autoescape-tag06")
2251  << QStringLiteral("{{ first }}") << dict << QStringLiteral("<b>first</b>")
2252  << NoError;
2253  QTest::newRow("autoescape-tag07")
2254  << QStringLiteral("{% autoescape on %}{{ first }}{% endautoescape %}")
2255  << dict << QStringLiteral("<b>first</b>") << NoError;
2256 
2257  // Literal string arguments to filters, if used in the result, are
2258  // safe.
2259  dict.clear();
2260  dict.insert(QStringLiteral("var"), QVariant());
2261  QTest::newRow("autoescape-tag08")
2262  << "{% autoescape on %}{{ var|default_if_none:\"endquote\\\" hah\" "
2263  "}}{% "
2264  "endautoescape %}"
2265  << dict << "endquote\" hah" << NoError;
2266 
2267  QTest::newRow("autoescape-tag09")
2268  << "{% autoescape on extra %}{{ var|default_if_none:\"endquote\\\" "
2269  "hah\" "
2270  "}}{% endautoescape %}"
2271  << dict << "" << TagSyntaxError;
2272  QTest::newRow("autoescape-tag10")
2273  << "{% autoescape bad %}{{ var|default_if_none:\"endquote\\\" hah\" "
2274  "}}{% "
2275  "endautoescape %}"
2276  << dict << "" << TagSyntaxError;
2277 
2278  // Objects which return safe strings as their __unicode__ method
2279  // won't get double-escaped.
2280  // 'autoescape-tag09': (r'{{ unsafe }}', {'unsafe':
2281  // filters.UnsafeClass()},
2282  // 'you &amp; me'),
2283  // 'autoescape-tag10': (r'{{ safe }}', {'safe': filters.SafeClass()}, 'you
2284  // &gt; me'),
2285  // The "safe" and "escape" filters cannot work due to internal
2286  // implementation details (fortunately, the (no)autoescape block
2287  // tags can be used in those cases)
2288  dict.clear();
2289  dict.insert(QStringLiteral("first"), QStringLiteral("<a>"));
2290  QTest::newRow("autoescape-filtertag01")
2291  << QStringLiteral(
2292  "{{ first }}{% filter safe %}{{ first }} x<y{% endfilter %}")
2293  << dict << QString() << TagSyntaxError;
2294  QTest::newRow("autoescape-filtertag02")
2295  << QStringLiteral(
2296  "{{ first }}{% filter escape %}{{ first }} x<y{% endfilter %}")
2297  << dict << QString() << TagSyntaxError;
2298 }
2299 
2300 void TestDefaultTags::testMediaFinderTag_data()
2301 {
2302  QTest::addColumn<QString>("input");
2303  QTest::addColumn<Dict>("dict");
2304  QTest::addColumn<QString>("output");
2305  QTest::addColumn<Cutelee::Error>("error");
2306 
2307  Dict dict;
2308  QTest::newRow("media_finder-tag01")
2309  << "{% media_finder \"existing_image.png\" %}" << dict
2310  << QStringLiteral("file:///path/to/existing_image.png") << NoError;
2311  QTest::newRow("media_finder-tag02")
2312  << "{% media_finder \"does_not_exist.png\" %}" << dict << QString()
2313  << NoError;
2314  QTest::newRow("media_finder-tag03")
2315  << "{% media_finder \"existing_image.png\" \"does_not_exist.png\" %}"
2316  << dict << QStringLiteral("file:///path/to/existing_image.png")
2317  << NoError;
2318 
2319  dict.insert(QStringLiteral("existing_img"),
2320  QStringLiteral("existing_image.png"));
2321  dict.insert(QStringLiteral("nonexisting_img"),
2322  QStringLiteral("does_not_exist.png"));
2323 
2324  QTest::newRow("media_finder-tag04") << QStringLiteral("{% media_finder %}")
2325  << dict << QString() << TagSyntaxError;
2326  QTest::newRow("media_finder-tag05")
2327  << QStringLiteral("{% media_finder existing_img %}") << dict
2328  << QStringLiteral("file:///path/to/existing_image.png") << NoError;
2329  QTest::newRow("media_finder-tag06")
2330  << QStringLiteral("{% media_finder nonexisting_img %}") << dict
2331  << QString() << NoError;
2332  QTest::newRow("media_finder-tag07")
2333  << "{% media_finder \"does_not_exist.png\" existing_img %}" << dict
2334  << QStringLiteral("file:///path/to/existing_image.png") << NoError;
2335  QTest::newRow("media_finder-tag08")
2336  << QStringLiteral("{% media_finder nonexisting_img existing_img %}")
2337  << dict << QStringLiteral("file:///path/to/existing_image.png")
2338  << NoError;
2339  QTest::newRow("media_finder-tag09")
2340  << "{% media_finder \"existing_image.png\" "
2341  "\"another_existing_image.png\" %}"
2342  << dict << QStringLiteral("file:///path/to/existing_image.png")
2343  << NoError;
2344  QTest::newRow("media_finder-tag10")
2345  << "{% media_finder \"another_existing_image.png\" "
2346  "\"existing_image.png\" %}"
2347  << dict << QStringLiteral("file:///path/to/another_existing_image.png")
2348  << NoError;
2349 
2350  dict.insert(QStringLiteral("this_and_that_img"),
2351  QStringLiteral("this&that.png"));
2352 
2353  QTest::newRow("media_finder-tag11")
2354  << "{% media_finder \"this&that.png\" %}" << dict
2355  << QStringLiteral("file:///path/to/this&amp;that.png") << NoError;
2356  QTest::newRow("media_finder-tag12")
2357  << "{% media_finder this_and_that_img %}" << dict
2358  << QStringLiteral("file:///path/to/this&amp;that.png") << NoError;
2359  QTest::newRow("media_finder-tag13")
2360  << "{% autoescape off %}{% media_finder \"this&that.png\" %}{% "
2361  "endautoescape %}"
2362  << dict << QStringLiteral("file:///path/to/this&that.png") << NoError;
2363  QTest::newRow("media_finder-tag14")
2364  << "{% autoescape off %}{% media_finder this_and_that_img %}{% "
2365  "endautoescape %}"
2366  << dict << QStringLiteral("file:///path/to/this&that.png") << NoError;
2367 }
2368 
2369 void TestDefaultTags::testRangeTag_data()
2370 {
2371  QTest::addColumn<QString>("input");
2372  QTest::addColumn<Dict>("dict");
2373  QTest::addColumn<QString>("output");
2374  QTest::addColumn<Cutelee::Error>("error");
2375 
2376  Dict dict;
2377 
2378  QTest::newRow("range-tag01")
2379  << QStringLiteral("{% range 5 as i %}{{ i }};{% endrange %}") << dict
2380  << QStringLiteral("0;1;2;3;4;") << NoError;
2381  QTest::newRow("range-tag02")
2382  << QStringLiteral("{% range 1 6 as i %}{{ i }};{% endrange %}") << dict
2383  << QStringLiteral("1;2;3;4;5;") << NoError;
2384  QTest::newRow("range-tag03")
2385  << QStringLiteral("{% range 5 26 5 as i %}{{ i }};{% endrange %}") << dict
2386  << QStringLiteral("5;10;15;20;25;") << NoError;
2387 
2388  QVariantList list{10, 15, 2};
2389  dict.insert(QStringLiteral("values"), list);
2390 
2391  QTest::newRow("range-tag04") << QStringLiteral(
2392  "{% range values.0 values.1 values.2 as i %}{{ i }};{% endrange %}")
2393  << dict << QStringLiteral("10;12;14;")
2394  << NoError;
2395 
2396  QTest::newRow("range-tag05")
2397  << QStringLiteral("{% range 5 %}Foo;{% endrange %}") << dict
2398  << QStringLiteral("Foo;Foo;Foo;Foo;Foo;") << NoError;
2399  QTest::newRow("range-tag06")
2400  << QStringLiteral("{% range 5 6 %}Foo;{% endrange %}") << dict
2401  << QString() << TagSyntaxError;
2402  QTest::newRow("range-tag07")
2403  << QStringLiteral("{% range 5 6 7 %}Foo;{% endrange %}") << dict
2404  << QString() << TagSyntaxError;
2405 }
2406 
2407 void TestDefaultTags::testDebugTag_data()
2408 {
2409 
2410  QTest::addColumn<QString>("input");
2411  QTest::addColumn<Dict>("dict");
2412  QTest::addColumn<QString>("output");
2413  QTest::addColumn<Cutelee::Error>("error");
2414 
2415  Dict dict;
2416 
2417  QTest::newRow("debug-tag01")
2418  << QStringLiteral("{% debug %}") << dict
2419  << QStringLiteral("\n\nContext:\nEnd context:\n\n") << NoError;
2420  dict.insert(QStringLiteral("answer"), 42);
2421  QTest::newRow("debug-tag02")
2422  << QStringLiteral("{% debug %}") << dict
2423  << QStringLiteral("\n\nContext:\nkey answer, type int\nEnd context:\n\n")
2424  << NoError;
2425 }
2426 
2427 void TestDefaultTags::testLoadTag_data()
2428 {
2429 
2430  QTest::addColumn<QString>("input");
2431  QTest::addColumn<Dict>("dict");
2432  QTest::addColumn<QString>("output");
2433  QTest::addColumn<Cutelee::Error>("error");
2434 
2435  Dict dict;
2436 
2437  QTest::newRow("load-tag01") << QStringLiteral("{% load does_not_exist %}foo")
2438  << dict << QString() << TagSyntaxError;
2439 }
2440 
2441 void TestDefaultTags::testUrlTypes_data()
2442 {
2443  QTest::addColumn<QString>("input");
2444  QTest::addColumn<Dict>("dict");
2445  QTest::addColumn<QPair<QString, QString>>("output");
2446 
2447  Dict dict;
2448  QTest::newRow("url-types01")
2449  << "{% media_finder \"existing_image.png\" %}" << dict
2450  << qMakePair(QStringLiteral("file:///path/to/"),
2451  QStringLiteral("existing_image.png"));
2452 
2453  QTest::newRow("url-types02") << "{% media_finder \"does_not_exist.png\" %}"
2454  << dict << qMakePair(QString(), QString());
2455 
2456  dict.insert(QStringLiteral("existing_img"),
2457  QStringLiteral("existing_image.png"));
2458  dict.insert(QStringLiteral("nonexisting_img"),
2459  QStringLiteral("does_not_exist.png"));
2460 
2461  QTest::newRow("url-types03")
2462  << QStringLiteral("{% media_finder existing_img %}") << dict
2463  << qMakePair(QStringLiteral("file:///path/to/"),
2464  QStringLiteral("existing_image.png"));
2465 
2466  QTest::newRow("url-types04")
2467  << QStringLiteral("{% media_finder nonexisting_img %}") << dict
2468  << qMakePair(QString(), QString());
2469 }
2470 
2471 void TestDefaultTags::testUrlTypes()
2472 {
2473  QFETCH(QString, input);
2474  QFETCH(Dict, dict);
2475  QFETCH(StringPair, output);
2476 
2477  auto t = m_engine->newTemplate(input, QLatin1String(QTest::currentDataTag()));
2478  QVERIFY(t->error() == NoError);
2479  Context c(dict);
2480  auto result = t->render(&c);
2481  QVERIFY(t->error() == NoError);
2482  QVERIFY(result == output.first + output.second);
2483 
2484  c.setUrlType(Context::RelativeUrls);
2485  result = t->render(&c);
2486  QVERIFY(t->error() == NoError);
2487  QVERIFY(result == output.second);
2488 }
2489 
2490 void TestDefaultTags::testRelativePaths_data()
2491 {
2492  QTest::addColumn<QString>("input");
2493  QTest::addColumn<Dict>("dict");
2494  QTest::addColumn<QString>("output");
2495 
2496  Dict dict;
2497  QTest::newRow("relativepaths01")
2498  << "{% media_finder \"existing_image.png\" %}" << dict
2499  << QStringLiteral("existing_image.png");
2500 
2501  QTest::newRow("relativepaths02")
2502  << "{% media_finder \"does_not_exist.png\" %}" << dict << QString();
2503 
2504  dict.insert(QStringLiteral("existing_img"),
2505  QStringLiteral("existing_image.png"));
2506  dict.insert(QStringLiteral("nonexisting_img"),
2507  QStringLiteral("does_not_exist.png"));
2508 
2509  QTest::newRow("relativepaths03")
2510  << QStringLiteral("{% media_finder existing_img %}") << dict
2511  << QStringLiteral("existing_image.png");
2512 
2513  QTest::newRow("relativepaths04")
2514  << QStringLiteral("{% media_finder nonexisting_img %}") << dict
2515  << QString();
2516 }
2517 
2518 void TestDefaultTags::testRelativePaths()
2519 {
2520  QFETCH(QString, input);
2521  QFETCH(Dict, dict);
2522  QFETCH(QString, output);
2523 
2524  auto t = m_engine->newTemplate(input, QLatin1String(QTest::currentDataTag()));
2525  QVERIFY(t->error() == NoError);
2526  Context c(dict);
2527  auto result = t->render(&c);
2528  QVERIFY(t->error() == NoError);
2529  if (!output.isEmpty())
2530  QVERIFY(result == QStringLiteral("file:///path/to/") + output);
2531  else
2532  QVERIFY(result.isEmpty());
2533 
2534  c.setUrlType(Context::RelativeUrls);
2535  auto relativePath = QStringLiteral("relative/path");
2536  c.setRelativeMediaPath(relativePath);
2537  result = t->render(&c);
2538  QVERIFY(t->error() == NoError);
2539  if (!output.isEmpty())
2540  QVERIFY(result == relativePath + QLatin1Char('/') + output);
2541  else
2542  QVERIFY(result.isEmpty());
2543 }
2544 
2545 QTEST_MAIN(TestDefaultTags)
2546 #include "testdefaulttags.moc"
2547 
2548 #endif
Q_ENUM(...)
Relative URLs should be put in the template.
Definition: context.h:244
iterator insert(const Key &key, const T &value)
The Context class holds the context to render a Template with.
Definition: context.h:118
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Definition: util.cpp:93
The Cutelee namespace holds all public Cutelee API.
Definition: Mainpage.dox:7
iterator insert(const_iterator before, parameter_type value)
QVariant fromValue(T &&value)
QString number(double n, char format, int precision)
QString & insert(qsizetype position, QChar ch)
Q_OBJECTQ_OBJECT
QDateTime currentDateTime()
Cutelee::Engine is the main entry point for creating Cutelee Templates.
Definition: engine.h:120
Utility functions used throughout Cutelee.
A QString wrapper class for containing whether a string is safe or needs to be escaped.
Definition: safestring.h:91
QString fromLatin1(QByteArrayView str)
QObject(QObject *parent)
QDate date() const const
The InMemoryTemplateLoader loads Templates set dynamically in memory.
void append(QList< T > &&value)
QObject * parent() const const
std::pair< QString, QString > getMediaUri(const QString &fileName) const override