Add new unit tests from DJango trunk.
[grantlee:grantlee.git] / tests / testdefaulttags.cpp
1 /*
2     Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>
3 */
4
5 #ifndef DEFAULTTAGSTEST_H
6 #define DEFAULTTAGSTEST_H
7
8 #include <QtTest>
9 #include <QtCore>
10 #include <QObject>
11
12 #include "template.h"
13 #include "context.h"
14
15 #include "grantlee.h"
16
17 typedef QHash<QString, QVariant> Dict;
18
19 Q_DECLARE_METATYPE(Dict)
20 Q_DECLARE_METATYPE(Grantlee::Error)
21
22 using namespace Grantlee;
23
24 class TestDefaultTags : public QObject
25 {
26   Q_OBJECT
27
28 private slots:
29   void initTestCase();
30   void cleanupTestCase();
31
32   void testCommentTag_data();
33   void testCommentTag() { doTest(); }
34
35   void testFirstOfTag_data();
36   void testFirstOfTag() {  doTest(); }
37
38   void testIfTag_data();
39   void testIfTag() {  doTest();  }
40
41   void testForTag_data();
42   void testForTag() {  doTest();  }
43
44   void testIfEqualTag_data();
45   void testIfEqualTag() {  doTest();  }
46
47   void testIfNotEqualTag_data();
48   void testIfNotEqualTag() {  doTest();  }
49
50   void testTemplateTagTag_data();
51   void testTemplateTagTag() {  doTest();  }
52
53   void testWithTag_data();
54   void testWithTag() {  doTest();  }
55
56   void testCycleTag_data();
57   void testCycleTag() {  doTest();  }
58
59   void testWidthRatioTag_data();
60   void testWidthRatioTag() {  doTest();  }
61
62   void testFilterTag_data();
63   void testFilterTag() {  doTest();  }
64
65   void testNowTag_data();
66   void testNowTag() {  doTest();  }
67
68   void testSpacelessTag_data();
69   void testSpacelessTag() {  doTest();  }
70
71   void testRegroupTag_data();
72   void testRegroupTag() {  doTest();  }
73
74   void testIfChangedTag_data();
75   void testIfChangedTag() {  doTest();  }
76
77 private:
78
79   void doTest();
80
81   TemplateLoader *m_tl;
82
83 };
84
85 void TestDefaultTags::initTestCase()
86 {
87   m_tl = TemplateLoader::instance();
88
89   QString appDirPath = QFileInfo(QCoreApplication::applicationDirPath() ).absoluteDir().path();
90   m_tl->setPluginDirs(QStringList() << appDirPath + "/grantlee_loadertags/"
91                                     << appDirPath + "/grantlee_defaulttags/"
92                                     << appDirPath + "/grantlee_defaultfilters/" );
93 }
94
95 void TestDefaultTags::cleanupTestCase()
96 {
97   delete m_tl;
98 }
99
100 void TestDefaultTags::doTest()
101 {
102   QFETCH(QString, input);
103   QFETCH(Dict, dict);
104   QFETCH(QString, output);
105   QFETCH(Grantlee::Error, error);
106
107   Template *t = m_tl->getTemplate(this);
108
109   QSignalSpy spy(t, SIGNAL(error(int, const QString &)));
110   t->setContent(input);
111
112   if (spy.count() > 0)
113   {
114     QVariantList l = spy.takeFirst();
115     QCOMPARE(l.at(0).toInt(), (int)error );
116     return;
117   }
118
119   Context context(dict);
120
121   QString result = t->render(&context);
122
123   if (spy.count() > 0)
124   {
125     QVariantList l = spy.takeFirst();
126     QCOMPARE(l.at(0).toInt(), (int)error );
127     QCOMPARE(result, QString());
128     return;
129   }
130
131   // Didn't catch any errors, so make sure I didn't expect any.
132   QCOMPARE(NoError, error);
133
134   QCOMPARE(result, output);
135 }
136
137 void TestDefaultTags::testCommentTag_data()
138 {
139   QTest::addColumn<QString>("input");
140   QTest::addColumn<Dict>("dict");
141   QTest::addColumn<QString>("output");
142   QTest::addColumn<Grantlee::Error>("error");
143
144   Dict dict;
145
146   QTest::newRow("comment-tag01") << "{% comment %}this is hidden{% endcomment %}hello" << dict << "hello" << NoError;
147
148   QTest::newRow("comment-tag02") << "{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}" << dict << "hello" << NoError;
149   // Comment tag can contain invalid stuff.
150   QTest::newRow("comment-tag03") << "foo{% comment %} {% if %} {% endcomment %}" << dict << "foo" << NoError;
151   QTest::newRow("comment-tag04") << "foo{% comment %} {% endblock %} {% endcomment %}" << dict << "foo" << NoError;
152   QTest::newRow("comment-tag05") << "foo{% comment %} {% somerandomtag %} {% endcomment %}" << dict << "foo" << NoError;
153 }
154
155 void TestDefaultTags::testFirstOfTag_data()
156 {
157   QTest::addColumn<QString>("input");
158   QTest::addColumn<Dict>("dict");
159   QTest::addColumn<QString>("output");
160   QTest::addColumn<Grantlee::Error>("error");
161
162   Dict dict;
163   dict.insert("a", 0);
164   dict.insert("b", 0);
165   dict.insert("c", 0);
166   QTest::newRow("firstof01") << "{% firstof a b c %}" << dict << "" << NoError;
167
168   dict.clear();
169   dict.insert("a", 1);
170   dict.insert("b", 0);
171   dict.insert("c", 0);
172   QTest::newRow("firstof02") << "{% firstof a b c %}" << dict << "1" << NoError;
173
174   dict.clear();
175   dict.insert("a", 0);
176   dict.insert("b", 2);
177   dict.insert("c", 0);
178   QTest::newRow("firstof03") << "{% firstof a b c %}" << dict << "2" << NoError;
179
180   dict.clear();
181   dict.insert("a", 0);
182   dict.insert("b", 0);
183   dict.insert("c", 3);
184   QTest::newRow("firstof04") << "{% firstof a b c %}" << dict << "3" << NoError;
185
186   dict.clear();
187   dict.insert("a", 1);
188   dict.insert("b", 2);
189   dict.insert("c", 3);
190   QTest::newRow("firstof05") << "{% firstof a b c %}" << dict << "1" << NoError;
191
192   dict.clear();
193   dict.insert("b", 0);
194   dict.insert("c", 3);
195   QTest::newRow("firstof06") << "{% firstof a b c %}" << dict << "3" << NoError;
196
197   dict.clear();
198   dict.insert("a", 0);
199   QTest::newRow("firstof07") << "{% firstof a b \"c\" %}" << dict << "c" << NoError;
200
201   dict.clear();
202   dict.insert("a", 0);
203   dict.insert("b", 0);
204   QTest::newRow("firstof08") << "{% firstof a b \"c and d\" %}" << dict << "c and d" << NoError;
205   QTest::newRow("firstof09") << "{% firstof %}" << dict << "a" << TagSyntaxError;
206
207 }
208
209
210 void TestDefaultTags::testIfTag_data()
211 {
212   QTest::addColumn<QString>("input");
213   QTest::addColumn<Dict>("dict");
214   QTest::addColumn<QString>("output");
215   QTest::addColumn<Grantlee::Error>("error");
216
217   Dict dict;
218
219   dict.insert("foo", true);
220
221   QTest::newRow("if-tag01") << "{% if foo %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
222
223   dict.clear();
224   dict.insert("foo", false);
225   QTest::newRow("if-tag02") << "{% if foo %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
226
227   dict.clear();
228   QTest::newRow("if-tag03") << "{% if foo %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
229
230   // AND
231
232   dict.clear();
233   dict.insert("foo", true);
234   dict.insert("bar", true);
235   QTest::newRow("if-tag-and01") << "{% if foo and bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
236
237   dict.clear();
238   dict.insert("foo", true);
239   dict.insert("bar", false);
240   QTest::newRow("if-tag-and02") << "{% if foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
241
242   dict.clear();
243   dict.insert("foo", false);
244   dict.insert("bar", true);
245   QTest::newRow("if-tag-and03") << "{% if foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
246
247   dict.clear();
248   dict.insert("foo", false);
249   dict.insert("bar", false);
250   QTest::newRow("if-tag-and04") << "{% if foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
251
252   dict.clear();
253   dict.insert("foo", false);
254   QTest::newRow("if-tag-and05") << "{% if foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
255
256   dict.clear();
257   dict.insert("bar", false);
258   QTest::newRow("if-tag-and06") << "{% if foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
259
260   dict.clear();
261   dict.insert("foo", true);
262   QTest::newRow("if-tag-and07") << "{% if foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
263
264   dict.clear();
265   dict.insert("bar", true);
266   QTest::newRow("if-tag-and08") << "{% if foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
267
268   // OR
269
270   dict.clear();
271   dict.insert("foo", true);
272   dict.insert("bar", true);
273   QTest::newRow("if-tag-or01") << "{% if foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
274
275   dict.clear();
276   dict.insert("foo", true);
277   dict.insert("bar", false);
278   QTest::newRow("if-tag-or02") << "{% if foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
279
280   dict.clear();
281   dict.insert("foo", false);
282   dict.insert("bar", true);
283   QTest::newRow("if-tag-or03") << "{% if foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
284
285   dict.clear();
286   dict.insert("foo", false);
287   dict.insert("bar", false);
288   QTest::newRow("if-tag-or04") << "{% if foo or bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
289
290   dict.clear();
291   dict.insert("foo", false);
292   QTest::newRow("if-tag-or05") << "{% if foo or bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
293
294   dict.clear();
295   dict.insert("bar", false);
296   QTest::newRow("if-tag-or06") << "{% if foo or bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
297
298   dict.clear();
299   dict.insert("foo", true);
300   QTest::newRow("if-tag-or07") << "{% if foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
301
302   dict.clear();
303   dict.insert("bar", true);
304   QTest::newRow("if-tag-or08") << "{% if foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
305
306   // TODO: multiple ORs
307
308
309   // NOT
310
311   dict.clear();
312   dict.insert("foo", true);
313   QTest::newRow("if-tag-not01") << "{% if not foo %}no{% else %}yes{% endif %}" << dict << "yes" << NoError;
314   QTest::newRow("if-tag-not02") << "{% if not %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
315
316   dict.clear();
317   dict.insert("not", true);
318   QTest::newRow("if-tag-not03") << "{% if not %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
319   QTest::newRow("if-tag-not04") << "{% if not not %}no{% else %}yes{% endif %}" << dict << "yes" << NoError;
320
321   dict.clear();
322   QTest::newRow("if-tag-not05") << "{% if not not %}no{% else %}yes{% endif %}" << dict << "no" << NoError;
323   QTest::newRow("if-tag-not06") << "{% if foo and not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
324
325   dict.clear();
326   dict.insert("foo", true);
327   dict.insert("bar", true);
328   QTest::newRow("if-tag-not07") << "{% if foo and not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
329
330   dict.clear();
331   dict.insert("foo", true);
332   dict.insert("bar", false);
333   QTest::newRow("if-tag-not08") << "{% if foo and not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
334
335   dict.clear();
336   dict.insert("foo", false);
337   dict.insert("bar", true);
338   QTest::newRow("if-tag-not09") << "{% if foo and not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
339
340   dict.clear();
341   dict.insert("foo", false);
342   dict.insert("bar", false);
343   QTest::newRow("if-tag-not10") << "{% if foo and not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
344
345   dict.clear();
346   QTest::newRow("if-tag-not11") << "{% if not foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
347
348   dict.clear();
349   dict.insert("foo", true);
350   dict.insert("bar", true);
351   QTest::newRow("if-tag-not12") << "{% if not foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
352
353   dict.clear();
354   dict.insert("foo", true);
355   dict.insert("bar", false);
356   QTest::newRow("if-tag-not13") << "{% if not foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
357
358   dict.clear();
359   dict.insert("foo", false);
360   dict.insert("bar", true);
361   QTest::newRow("if-tag-not14") << "{% if not foo and bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
362
363   dict.clear();
364   dict.insert("foo", false);
365   dict.insert("bar", false);
366   QTest::newRow("if-tag-not15") << "{% if not foo and bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
367
368   dict.clear();
369   QTest::newRow("if-tag-not16") << "{% if foo or not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
370
371   dict.clear();
372   dict.insert("foo", true);
373   dict.insert("bar", true);
374   QTest::newRow("if-tag-not17") << "{% if foo or not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
375
376   dict.clear();
377   dict.insert("foo", true);
378   dict.insert("bar", false);
379   QTest::newRow("if-tag-not18") << "{% if foo or not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
380
381   dict.clear();
382   dict.insert("foo", false);
383   dict.insert("bar", true);
384   QTest::newRow("if-tag-not19") << "{% if foo or not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
385
386   dict.clear();
387   dict.insert("foo", false);
388   dict.insert("bar", false);
389   QTest::newRow("if-tag-not20") << "{% if foo or not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
390
391   dict.clear();
392   QTest::newRow("if-tag-not21") << "{% if not foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
393
394   dict.clear();
395   dict.insert("foo", true);
396   dict.insert("bar", true);
397   QTest::newRow("if-tag-not22") << "{% if not foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
398
399   dict.clear();
400   dict.insert("foo", true);
401   dict.insert("bar", false);
402   QTest::newRow("if-tag-not23") << "{% if not foo or bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
403
404   dict.clear();
405   dict.insert("foo", false);
406   dict.insert("bar", true);
407   QTest::newRow("if-tag-not24") << "{% if not foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
408
409   dict.clear();
410   dict.insert("foo", false);
411   dict.insert("bar", false);
412   QTest::newRow("if-tag-not25") << "{% if not foo or bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
413
414   dict.clear();
415   QTest::newRow("if-tag-not26") << "{% if not foo and not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
416
417   dict.clear();
418   dict.insert("foo", true);
419   dict.insert("bar", true);
420   QTest::newRow("if-tag-not27") << "{% if not foo and not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
421
422   dict.clear();
423   dict.insert("foo", true);
424   dict.insert("bar", false);
425   QTest::newRow("if-tag-not28") << "{% if not foo and not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
426
427   dict.clear();
428   dict.insert("foo", false);
429   dict.insert("bar", true);
430   QTest::newRow("if-tag-not29") << "{% if not foo and not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
431
432   dict.clear();
433   dict.insert("foo", false);
434   dict.insert("bar", false);
435   QTest::newRow("if-tag-not30") << "{% if not foo and not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
436
437   dict.clear();
438   QTest::newRow("if-tag-not31") << "{% if not foo or not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
439
440   dict.clear();
441   dict.insert("foo", true);
442   dict.insert("bar", true);
443   QTest::newRow("if-tag-not32") << "{% if not foo or not bar %}yes{% else %}no{% endif %}" << dict << "no" << NoError;
444
445   dict.clear();
446   dict.insert("foo", true);
447   dict.insert("bar", false);
448   QTest::newRow("if-tag-not33") << "{% if not foo or not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
449
450   dict.clear();
451   dict.insert("foo", false);
452   dict.insert("bar", true);
453   QTest::newRow("if-tag-not34") << "{% if not foo or not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
454
455   dict.clear();
456   dict.insert("foo", false);
457   dict.insert("bar", false);
458   QTest::newRow("if-tag-not35") << "{% if not foo or not bar %}yes{% else %}no{% endif %}" << dict << "yes" << NoError;
459
460   // AND and OR raises a TemplateSyntaxError
461   QTest::newRow("if-tag-error01") << "{% if foo or bar and baz %}yes{% else %}no{% endif %}" << dict << "" << TagSyntaxError;
462
463   dict.clear();
464   dict.insert("foo", true);
465   QTest::newRow("if-tag-error02") << "{% if foo and %}yes{% else %}no{% endif %}" << dict << "" << TagSyntaxError;
466   QTest::newRow("if-tag-error03") << "{% if foo or %}yes{% else %}no{% endif %}" << dict << "" << TagSyntaxError;
467   QTest::newRow("if-tag-error04") << "{% if not foo and %}yes{% else %}no{% endif %}" << dict << "" << TagSyntaxError;
468   QTest::newRow("if-tag-error05") << "{% if not foo or %}yes{% else %}no{% endif %}" << dict << "" << TagSyntaxError;
469
470 }
471
472 void TestDefaultTags::testForTag_data()
473 {
474   QTest::addColumn<QString>("input");
475   QTest::addColumn<Dict>("dict");
476   QTest::addColumn<QString>("output");
477   QTest::addColumn<Grantlee::Error>("error");
478
479   Dict dict;
480
481   QVariantList list;
482   list << 1 << 2 << 3;
483   dict.insert("values", list);
484   QTest::newRow("for-tag01") << "{% for val in values %}{{ val }}{% endfor %}" << dict << "123" << NoError;
485   QTest::newRow("for-tag02") << "{% for val in values reversed %}{{ val }}{% endfor %}" << dict << "321" << NoError;
486   list.clear();
487   list << 6 << 6 << 6;
488   QTest::newRow("for-tag-vars01") << "{% for val in values %}{{ forloop.counter }}{% endfor %}" << dict << "123" << NoError;
489   QTest::newRow("for-tag-vars02") << "{% for val in values %}{{ forloop.counter0 }}{% endfor %}" << dict << "012" << NoError;
490   QTest::newRow("for-tag-vars03") << "{% for val in values %}{{ forloop.revcounter }}{% endfor %}" << dict << "321" << NoError;
491   QTest::newRow("for-tag-vars04") << "{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}" << dict << "210" << NoError;
492   QTest::newRow("for-tag-vars05") << "{% for val in values %}{% if forloop.first %}f{% else %}x{% endif %}{% endfor %}" << dict << "fxx" << NoError;
493   QTest::newRow("for-tag-vars06") << "{% for val in values %}{% if forloop.last %}l{% else %}x{% endif %}{% endfor %}" << dict << "xxl" << NoError;
494
495   dict.clear();
496   QVariantMap map;
497   map.insert("one", 1);
498   map.insert("two", 2);
499   dict.insert("items", map);
500   QTest::newRow("for-tag-unpack01") << "{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
501
502   QTest::newRow("for-tag-unpack03") << "{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
503   QTest::newRow("for-tag-unpack04") << "{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
504   QTest::newRow("for-tag-unpack05") << "{% for key ,value in items %}{{ key }}:{{ value }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
505   QTest::newRow("for-tag-unpack06") << "{% for key value in items %}{{ key }}:{{ value }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
506   QTest::newRow("for-tag-unpack07") << "{% for key,,value in items %}{{ key }}:{{ value }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
507   QTest::newRow("for-tag-unpack08") << "{% for key,value, in items %}{{ key }}:{{ value }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
508
509 // Ensure that a single loopvar doesn't truncate the list in val.
510   QTest::newRow("for-tag-unpack09") << "{% for val in items %}{{ val.0 }}:{{ val.1 }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
511
512 // Otherwise, silently truncate if the length of loopvars differs to the length of each set of items.
513
514   dict.clear();
515   list.clear();
516   QVariantList innerList;
517   innerList << "one" << 1 << "carrot";
518   list.append(QVariant(innerList));
519   innerList.clear();
520   innerList << "two" << 2 << "orange";
521   list.append(QVariant(innerList));
522   dict.insert("items", list);
523
524   QTest::newRow("for-tag-unpack10") << "{% for x,y in items %}{{ x }}:{{ y }}/{% endfor %}" << dict << "one:1/two:2/" << NoError;
525
526   dict.clear();
527   list.clear();
528   innerList.clear();
529   innerList << "one" << 1;
530   list.append(QVariant(innerList));
531   innerList.clear();
532   innerList << "two" << 2;
533   list.append(QVariant(innerList));
534   dict.insert("items", list);
535
536   QTest::newRow("for-tag-unpack11") << "{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}" << dict << "one:1,/two:2,/" << NoError;
537
538   dict.clear();
539   list.clear();
540   innerList.clear();
541   innerList << "one" << 1 << "carrot";
542   list.append(QVariant(innerList));
543   innerList.clear();
544   innerList << "two" << 2;
545   list.append(QVariant(innerList));
546   dict.insert("items", list);
547
548   QTest::newRow("for-tag-unpack12") << "{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}" << dict << "one:1,carrot/two:2,/" << NoError;
549
550   dict.clear();
551   list.clear();
552   innerList.clear();
553   innerList << "one" << 1 << "carrot";
554   list.append(QVariant(innerList));
555   innerList.clear();
556   innerList << "two" << 2 << "cheese";
557   list.append(QVariant(innerList));
558
559   dict.insert("items", list);
560
561   QTest::newRow("for-tag-unpack13") << "{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}" << dict << "one:1,carrot/two:2,cheese/" << NoError;
562
563 // Empty tag:
564
565   dict.clear();
566   dict.insert("values", QVariantList() << 1 << 2 << 3 );
567   QTest::newRow("for-tag-empty01") << "{% for val in values %}{{ val }}{% empty %}empty text{% endfor %}" << dict << "123" << NoError;
568
569   dict.clear();
570   dict.insert("values", QVariantList());
571   QTest::newRow("for-tag-empty02") << "{% for val in values %}{{ val }}{% empty %}values array empty{% endfor %}" << dict << "values array empty" << NoError;
572
573   dict.clear();
574   QTest::newRow("for-tag-empty03") << "{% for val in values %}{{ val }}{% empty %}values array not found{% endfor %}" << dict << "values array not found" << NoError;
575
576 }
577
578 void TestDefaultTags::testIfEqualTag_data()
579 {
580   QTest::addColumn<QString>("input");
581   QTest::addColumn<Dict>("dict");
582   QTest::addColumn<QString>("output");
583   QTest::addColumn<Grantlee::Error>("error");
584
585   Dict dict;
586
587   dict.insert("a", 1);
588   dict.insert("b", 2);
589
590   QTest::newRow("ifequal01") << "{% ifequal a b %}yes{% endifequal %}" << dict << "" << NoError;
591   QTest::newRow("ifequal03") << "{% ifequal a b %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
592
593   dict.clear();
594   dict.insert("a", 1);
595   dict.insert("b", 1);
596
597   QTest::newRow("ifequal02") << "{% ifequal a b %}yes{% endifequal %}" << dict << "yes" << NoError;
598   QTest::newRow("ifequal04") << "{% ifequal a b %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
599
600   dict.clear();
601   dict.insert("a", "test");
602
603   QTest::newRow("ifequal05") << "{% ifequal a 'test' %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
604
605   dict.clear();
606   dict.insert("a", "no");
607
608   QTest::newRow("ifequal06") << "{% ifequal a 'test' %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
609
610   dict.clear();
611   dict.insert("a", "test");
612
613   QTest::newRow("ifequal07") << "{% ifequal a \"test\" %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
614
615   dict.clear();
616   dict.insert("a", "no");
617
618   QTest::newRow("ifequal08") << "{% ifequal a \"test\" %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
619
620   dict.clear();
621
622   QTest::newRow("ifequal09") << "{% ifequal a \"test\" %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
623
624   QTest::newRow("ifequal10") << "{% ifequal a b %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
625
626
627   QTest::newRow("ifequal-split01") << "{% ifequal a \"test man\" %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
628
629   dict.insert("a", "foo");
630   QTest::newRow("ifequal-split01") << "{% ifequal a \"test man\" %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
631   QTest::newRow("ifequal-split02") << "{% ifequal a \"test man\" %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
632
633   dict.clear();
634   dict.insert("a", "test man");
635   QTest::newRow("ifequal-split03") << "{% ifequal a \"test man\" %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
636   QTest::newRow("ifequal-split04") << "{% ifequal a 'test man' %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
637
638   dict.clear();
639   dict.insert("a", "");
640   QTest::newRow("ifequal-split05") << "{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
641
642   dict.clear();
643   dict.insert("a", "i \"love\" you");
644   QTest::newRow("ifequal-split06") << "{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
645
646   dict.clear();
647   dict.insert("a", "i love you");
648   QTest::newRow("ifequal-split07") << "{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
649
650   dict.clear();
651   dict.insert("a", "I'm happy");
652   QTest::newRow("ifequal-split08") << "{% ifequal a 'I\\'m happy' %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
653
654   dict.clear();
655   dict.insert("a", "slash\\man");
656   QTest::newRow("ifequal-split09") << "{% ifequal a 'slash\\man' %}yes{% else %}no{% endifequal %}" << dict << "yes" << NoError;
657
658   dict.clear();
659   dict.insert("a", "slashman");
660   QTest::newRow("ifequal-split10") << "{% ifequal a 'slash\\man' %}yes{% else %}no{% endifequal %}" << dict << "no" << NoError;
661 // NUMERIC RESOLUTION
662
663   dict.clear();
664   dict.insert("x", "5");
665
666   QTest::newRow("ifequal-numeric01") << "{% ifequal x 5 %}yes{% endifequal %}" << dict << "" << NoError;
667
668   dict.clear();
669   dict.insert("x", 5);
670   QTest::newRow("ifequal-numeric02") << "{% ifequal x 5 %}yes{% endifequal %}" << dict << "yes" << NoError;
671
672   dict.clear();
673   dict.insert("x", 5.2);
674   QTest::newRow("ifequal-numeric03") << "{% ifequal x 5 %}yes{% endifequal %}" << dict << "" << NoError;
675   QTest::newRow("ifequal-numeric04") << "{% ifequal x 5.2 %}yes{% endifequal %}" << dict << "yes" << NoError;
676
677   dict.clear();
678   dict.insert("x", .2);
679
680   QTest::newRow("ifequal-numeric05") << "{% ifequal x 0.2 %}yes{% endifequal %}" << dict << "yes" << NoError;
681   QTest::newRow("ifequal-numeric06") << "{% ifequal x .2 %}yes{% endifequal %}" << dict << "yes" << NoError;
682
683   dict.clear();
684   dict.insert("x", 2);
685
686   QTest::newRow("ifequal-numeric07") << "{% ifequal x 2. %}yes{% endifequal %}" << dict << "" << NoError;
687
688   dict.clear();
689   dict.insert("x", 5);
690   QTest::newRow("ifequal-numeric08") << "{% ifequal x \"5\" %}yes{% endifequal %}" << dict << "" << NoError;
691
692   dict.clear();
693   dict.insert("x", "5");
694   QTest::newRow("ifequal-numeric09") << "{% ifequal x \"5\" %}yes{% endifequal %}" << dict << "yes" << NoError;
695
696   dict.clear();
697   dict.insert("x", -5);
698   QTest::newRow("ifequal-numeric10") << "{% ifequal x -5 %}yes{% endifequal %}" << dict << "yes" << NoError;
699
700   dict.clear();
701   dict.insert("x", -5.2);
702   QTest::newRow("ifequal-numeric11") << "{% ifequal x -5.2 %}yes{% endifequal %}" << dict << "yes" << NoError;
703
704   dict.clear();
705   dict.insert("x", 5);
706   QTest::newRow("ifequal-numeric12") << "{% ifequal x +5 %}yes{% endifequal %}" << dict << "yes" << NoError;
707
708
709   // FILTER EXPRESSIONS AS ARGUMENTS
710
711   dict.clear();
712   dict.insert("a", "a");
713   QTest::newRow("ifequal-filter01") << "{% ifequal a|upper \"A\" %}x{% endifequal %}" << dict << "x" << NoError;
714
715   QTest::newRow("ifequal-filter02") << "{% ifequal \"A\" a|upper %}x{% endifequal %}" << dict << "x" << NoError;
716
717   dict.clear();
718   dict.insert("a", "x");
719   dict.insert("b", "X");
720
721   QTest::newRow("ifequal-filter03") << "{% ifequal a|upper b|upper %}x{% endifequal %}" << dict << "x" << NoError;
722
723   dict.clear();
724   dict.insert("x", "aaa");
725
726   QTest::newRow("ifequal-filter04") << "{% ifequal x|slice:\"1\" \"a\" %}x{% endifequal %}" << dict << "x" << NoError;
727
728   dict.clear();
729   dict.insert("x", "aaa");
730
731   QTest::newRow("ifequal-filter05") << "{% ifequal x|slice:\"1\"|upper \"A\" %}x{% endifequal %}" << dict << "x" << NoError;
732
733 }
734
735 void TestDefaultTags::testIfNotEqualTag_data()
736 {
737   QTest::addColumn<QString>("input");
738   QTest::addColumn<Dict>("dict");
739   QTest::addColumn<QString>("output");
740   QTest::addColumn<Grantlee::Error>("error");
741
742   Dict dict;
743
744   dict.insert("a", 1);
745   dict.insert("b", 2);
746
747   QTest::newRow("ifnotequal01") << "{% ifnotequal a b %}yes{% endifnotequal %}" << dict << "yes" << NoError;
748   QTest::newRow("ifnotequal03") << "{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}" << dict << "yes" << NoError;
749
750   dict.clear();
751   dict.insert("a", 1);
752   dict.insert("b", 1);
753
754   QTest::newRow("ifnotequal02") << "{% ifnotequal a b %}yes{% endifnotequal %}" << dict << "" << NoError;
755   QTest::newRow("ifnotequal04") << "{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}" << dict << "no" << NoError;
756
757 }
758
759 void TestDefaultTags::testTemplateTagTag_data()
760 {
761   QTest::addColumn<QString>("input");
762   QTest::addColumn<Dict>("dict");
763   QTest::addColumn<QString>("output");
764   QTest::addColumn<Grantlee::Error>("error");
765
766   Dict dict;
767
768   QTest::newRow("templatetag01") << "{% templatetag openblock %}" << dict << "{%" << NoError;
769   QTest::newRow("templatetag02") << "{% templatetag closeblock %}" << dict << "%}" << NoError;
770   QTest::newRow("templatetag03") << "{% templatetag openvariable %}" << dict << "{{" << NoError;
771   QTest::newRow("templatetag04") << "{% templatetag closevariable %}" << dict << "}}" << NoError;
772   QTest::newRow("templatetag05") << "{% templatetag %}" << dict << "" << TagSyntaxError;
773   QTest::newRow("templatetag06") << "{% templatetag foo %}" << dict << "" << TagSyntaxError;
774   QTest::newRow("templatetag07") << "{% templatetag openbrace %}" << dict << "{" << NoError;
775   QTest::newRow("templatetag08") << "{% templatetag closebrace %}" << dict << "}" << NoError;
776   QTest::newRow("templatetag09") << "{% templatetag openbrace %}{% templatetag openbrace %}" << dict << "{{" << NoError;
777   QTest::newRow("templatetag10") << "{% templatetag closebrace %}{% templatetag closebrace %}" << dict << "}}" << NoError;
778   QTest::newRow("templatetag11") << "{% templatetag opencomment %}" << dict << "{#" << NoError;
779   QTest::newRow("templatetag12") << "{% templatetag closecomment %}" << dict << "#}" << NoError;
780
781 }
782
783 void TestDefaultTags::testWithTag_data()
784 {
785   QTest::addColumn<QString>("input");
786   QTest::addColumn<Dict>("dict");
787   QTest::addColumn<QString>("output");
788   QTest::addColumn<Grantlee::Error>("error");
789
790   Dict dict;
791
792   QVariantMap map;
793   map.insert("key", 50);
794   dict.insert("dict", map);
795   QTest::newRow("with01") << "{% with dict.key as key %}{{ key }}{% endwith %}" << dict << "50" << NoError;
796   QTest::newRow("with02")
797         << "{{ key }}{% with dict.key as key %}{{ key }}-{{ dict.key }}-{{ key }}{% endwith %}{{ key }}"
798         << dict << "50-50-50" << NoError;
799   QTest::newRow("with03") << "{% with dict.key xx key %}{{ key }}{% endwith %}" << dict << "" << TagSyntaxError;
800   QTest::newRow("with04") << "{% with dict.key as %}{{ key }}{% endwith %}" << dict << "" << TagSyntaxError;
801 }
802
803 void TestDefaultTags::testCycleTag_data()
804 {
805   QTest::addColumn<QString>("input");
806   QTest::addColumn<Dict>("dict");
807   QTest::addColumn<QString>("output");
808   QTest::addColumn<Grantlee::Error>("error");
809
810   Dict dict;
811
812   QTest::newRow("cycle01") << "{% cycle a %}" << dict << "" << TagSyntaxError;
813   QTest::newRow("cycle02") << "{% cycle a,b,c as abc %}{% cycle abc %}" << dict << "ab" << NoError;
814   QTest::newRow("cycle03") << "{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}" << dict << "abc" << NoError;
815   QTest::newRow("cycle04") << "{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}" << dict << "abca" << NoError;
816   QTest::newRow("cycle05") << "{% cycle a %}" << dict << "" << TagSyntaxError;
817   // TODO: This is the same as cycle01. Remove.
818   QTest::newRow("cycle06") << "{% cycle a %}" << dict << "" << TagSyntaxError;
819   QTest::newRow("cycle07") << "{% cycle a,b,c as foo %}{% cycle bar %}" << dict << "" << TagSyntaxError;
820   QTest::newRow("cycle08") << "{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo %}{{ foo }}" << dict << "abbbcc" << NoError;
821
822   dict.insert("test", QVariantList() << 0 << 1 << 2 << 3 << 4);
823   QTest::newRow("cycle09") << "{% for i in test %}{% cycle a,b %}{{ i }},{% endfor %}" << dict << "a0,b1,a2,b3,a4," << NoError;
824
825   dict.clear();
826   QTest::newRow("cycle10") << "{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}" << dict << "ab" << NoError;
827   QTest::newRow("cycle11") << "{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}{% cycle abc %}" << dict << "abc" << NoError;
828   QTest::newRow("cycle12") << "{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}" << dict << "abca" << NoError;
829
830   dict.insert("test", QVariantList() << 0 << 1 << 2 << 3 << 4);
831   QTest::newRow("cycle13") << "{% for i in test %}{% cycle 'a' 'b' %}{{ i }},{% endfor %}" << dict << "a0,b1,a2,b3,a4," << NoError;
832
833   dict.clear();
834   dict.insert("one", "1");
835   dict.insert("two", "2");
836   QTest::newRow("cycle14") << "{% cycle one two as foo %}{% cycle foo %}" << dict << "12" << NoError;
837
838   dict.clear();
839   dict.insert("test", QVariantList() << 0 << 1 << 2 << 3 << 4);
840   dict.insert("aye", "a");
841   dict.insert("bee", "b");
842   QTest::newRow("cycle15") << "{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}" << dict << "a0,b1,a2,b3,a4," << NoError;
843
844   dict.clear();
845   dict.insert("one", "A");
846   dict.insert("two", "2");
847   QTest::newRow("cycle16") << "{% cycle one|lower two as foo %}{% cycle foo %}" << dict << "a2" << NoError;
848 }
849
850 void TestDefaultTags::testWidthRatioTag_data()
851 {
852   QTest::addColumn<QString>("input");
853   QTest::addColumn<Dict>("dict");
854   QTest::addColumn<QString>("output");
855   QTest::addColumn<Grantlee::Error>("error");
856
857   Dict dict;
858
859   dict.insert("a", 50);
860   dict.insert("b", 100);
861   QTest::newRow("widthratio01") << "{% widthratio a b 0 %}" << dict << "0" << NoError;
862
863   dict.clear();
864   dict.insert("a", 0);
865   dict.insert("b", 0);
866   QTest::newRow("widthratio02") << "{% widthratio a b 0 %}" << dict << "" << NoError;
867
868   dict.clear();
869   dict.insert("a", 0);
870   dict.insert("b", 100);
871   QTest::newRow("widthratio03") << "{% widthratio a b 100 %}" << dict << "0" << NoError;
872
873   dict.clear();
874   dict.insert("a", 50);
875   dict.insert("b", 100);
876   QTest::newRow("widthratio04") << "{% widthratio a b 100 %}" << dict << "50" << NoError;
877
878   dict.clear();
879   dict.insert("a", 100);
880   dict.insert("b", 100);
881   QTest::newRow("widthratio05") << "{% widthratio a b 100 %}" << dict << "100" << NoError;
882
883   dict.clear();
884   dict.insert("a", 50);
885   dict.insert("b", 80);
886   QTest::newRow("widthratio06") << "{% widthratio a b 100 %}" << dict << "63" << NoError;
887
888   dict.clear();
889   dict.insert("a", 50);
890   dict.insert("b", 70);
891   QTest::newRow("widthratio07") << "{% widthratio a b 100 %}" << dict << "71" << NoError;
892
893   dict.clear();
894 // Raise exception if we don't have 3 args, last one an integer
895   QTest::newRow("widthratio08") << "{% widthratio %}" << dict << "" << TagSyntaxError;
896
897   dict.clear();
898   QTest::newRow("widthratio09") << "{% widthratio a b %}" << dict << "" << TagSyntaxError;
899
900   dict.clear();
901   dict.insert("a", 50);
902   dict.insert("b", 100);
903   QTest::newRow("widthratio10") << "{% widthratio a b 100.0 %}" << dict << "50" << NoError;
904
905   dict.clear();
906   dict.insert("a", 50);
907   dict.insert("b", 100);
908   dict.insert("c", 100);
909   QTest::newRow("widthratio11") << "{% widthratio a b c %}" << dict << "50" << NoError;
910
911 }
912
913
914 void TestDefaultTags::testFilterTag_data()
915 {
916   QTest::addColumn<QString>("input");
917   QTest::addColumn<Dict>("dict");
918   QTest::addColumn<QString>("output");
919   QTest::addColumn<Grantlee::Error>("error");
920
921   Dict dict;
922
923   QTest::newRow("filter01") << "{% filter upper %}{% endfilter %}" << dict << "" << NoError;
924   QTest::newRow("filter02") << "{% filter upper %}django{% endfilter %}" << dict << "DJANGO" << NoError;
925   QTest::newRow("filter03") << "{% filter upper|lower %}django{% endfilter %}" << dict << "django" << NoError;
926
927   dict.insert("remove", "spam");
928   QTest::newRow("filter04") << "{% filter cut:remove %}djangospam{% endfilter %}" << dict << "django" << NoError;
929
930 }
931
932 void TestDefaultTags::testNowTag_data()
933 {
934   QTest::addColumn<QString>("input");
935   QTest::addColumn<Dict>("dict");
936   QTest::addColumn<QString>("output");
937   QTest::addColumn<Grantlee::Error>("error");
938
939   Dict dict;
940
941   QDate today = QDateTime::currentDateTime().date();
942
943   QTest::newRow("now01") << "{% now \"d M yyyy\"%}" << dict << (QString::number(today.day()) + " " +  QString::number(today.month()) + " " + QString::number(today.year())) << NoError;
944
945
946 }
947
948 void TestDefaultTags::testSpacelessTag_data()
949 {
950   QTest::addColumn<QString>("input");
951   QTest::addColumn<Dict>("dict");
952   QTest::addColumn<QString>("output");
953   QTest::addColumn<Grantlee::Error>("error");
954
955   Dict dict;
956
957   QTest::newRow("spaceless01") << "{% spaceless %} <b>    <i> text </i>    </b> {% endspaceless %}" << dict << "<b><i> text </i></b>" << NoError;
958   QTest::newRow("spaceless02") << "{% spaceless %} <b> \n <i> text </i> \n </b> {% endspaceless %}" << dict << "<b><i> text </i></b>" << NoError;
959   QTest::newRow("spaceless03") << "{% spaceless %}<b><i>text</i></b>{% endspaceless %}" << dict << "<b><i>text</i></b>" << NoError;
960
961 }
962
963 void TestDefaultTags::testRegroupTag_data()
964 {
965   QTest::addColumn<QString>("input");
966   QTest::addColumn<Dict>("dict");
967   QTest::addColumn<QString>("output");
968   QTest::addColumn<Grantlee::Error>("error");
969
970   Dict dict;
971
972   QVariantList list;
973   QVariantMap map;
974
975   map.insert("foo", "c");
976   map.insert("bar", 1);
977   list.append(map);
978
979   map.clear();
980   map.insert("foo", "d");
981   map.insert("bar", 1);
982   list.append(map);
983
984   map.clear();
985   map.insert("foo", "a");
986   map.insert("bar", 2);
987   list.append(map);
988
989   map.clear();
990   map.insert("foo", "b");
991   map.insert("bar", 2);
992   list.append(map);
993
994   map.clear();
995   map.insert("foo", "x");
996   map.insert("bar", 3);
997   list.append(map);
998
999   dict.insert("data", list);
1000
1001   QTest::newRow("regroup01") << "{% regroup data by bar as grouped %}"
1002                                   "{% for group in grouped %}"
1003                                     "{{ group.grouper }}:"
1004                                     "{% for item in group.list %}"
1005                                       "{{ item.foo }}"
1006                                     "{% endfor %},"
1007                                   "{% endfor %}" << dict << "1:cd,2:ab,3:x," << NoError;
1008
1009 }
1010
1011 void TestDefaultTags::testIfChangedTag_data()
1012 {
1013   QTest::addColumn<QString>("input");
1014   QTest::addColumn<Dict>("dict");
1015   QTest::addColumn<QString>("output");
1016   QTest::addColumn<Grantlee::Error>("error");
1017
1018   Dict dict;
1019
1020   dict.insert("num", QVariantList() << 1 << 2 << 3 );
1021   QTest::newRow("ifchanged01") << "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}" << dict << "123" << NoError;
1022
1023   dict.clear();
1024   dict.insert("num", QVariantList() << 1 << 1 << 3 );
1025   QTest::newRow("ifchanged02") << "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}" << dict << "13" << NoError;
1026
1027   dict.clear();
1028   dict.insert("num", QVariantList() << 1 << 1 << 1 );
1029   QTest::newRow("ifchanged03") << "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}" << dict << "1" << NoError;
1030
1031   dict.clear();
1032   dict.insert("num", QVariantList() << 1 << 2 << 3 );
1033   dict.insert("numx", QVariantList() << 2 << 2 << 2 );
1034   QTest::newRow("ifchanged04") << "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}" << dict << "122232" << NoError;
1035
1036   dict.clear();
1037   dict.insert("num", QVariantList() << 1 << 1 << 1 );
1038   dict.insert("numx", QVariantList() << 1 << 2 << 3 );
1039   QTest::newRow("ifchanged05") << "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}" << dict << "1123123123" << NoError;
1040
1041   dict.clear();
1042   dict.insert("num", QVariantList() << 1 << 1 << 1 );
1043   dict.insert("numx", QVariantList() << 2 << 2 << 2 );
1044   QTest::newRow("ifchanged06") << "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}" << dict << "1222" << NoError;
1045
1046   dict.clear();
1047   dict.insert("num", QVariantList() << 1 << 1 << 1 );
1048   dict.insert("numx", QVariantList() << 2 << 2 << 2 );
1049   dict.insert("numy", QVariantList() << 3 << 3 << 3 );
1050   QTest::newRow("ifchanged07") << "{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}" << dict << "1233323332333" << NoError;
1051
1052   // datalist': [[(1, 'a'), (1, 'a'), (0, 'b'), (1, 'c')], [(0, 'a'), (1, 'c'), (1, 'd'), (1, 'd'), (0, 'e')]]}
1053   dict.clear();
1054   QVariantList list;
1055   QVariantList innerList;
1056   QVariantList tuple;
1057   tuple << 1 << "a";
1058   innerList.append(QVariant(tuple));
1059   tuple.clear();
1060   tuple << 1 << "a";
1061   innerList.append(QVariant(tuple));
1062   tuple.clear();
1063   tuple << 0 << "b";
1064   innerList.append(QVariant(tuple));
1065   tuple.clear();
1066   tuple << 1 << "c";
1067   innerList.append(QVariant(tuple));
1068   tuple.clear();
1069   list.append(QVariant(innerList));
1070   innerList.clear();
1071
1072   tuple << 0 << "a";
1073   innerList.append(QVariant(tuple));
1074   tuple.clear();
1075   tuple << 1 << "c";
1076   innerList.append(QVariant(tuple));
1077   tuple.clear();
1078   tuple << 1 << "d";
1079   innerList.append(QVariant(tuple));
1080   tuple.clear();
1081   tuple << 1 << "d";
1082   innerList.append(QVariant(tuple));
1083   tuple.clear();
1084   tuple << 0 << "e";
1085   innerList.append(QVariant(tuple));
1086   tuple.clear();
1087   list.append(QVariant(innerList));
1088   innerList.clear();
1089
1090   dict.insert("datalist", list);
1091   QTest::newRow("ifchanged08") << "{% for data in datalist %}{% for c,d in data %}{% if c %}{% ifchanged %}{{ d }}{% endifchanged %}{% endif %}{% endfor %}{% endfor %}" << dict << "accd" << NoError;
1092
1093 // Test one parameter given to ifchanged.
1094   dict.clear();
1095   dict.insert("num", QVariantList() << 1 << 2 << 3 );
1096   QTest::newRow("ifchanged-param01") << "{% for n in num %}{% ifchanged n %}..{% endifchanged %}{{ n }}{% endfor %}" << dict << "..1..2..3" << NoError;
1097
1098   dict.clear();
1099   dict.insert("num", QVariantList() << 1 << 2 << 3 );
1100   dict.insert("numx", QVariantList() << 5 << 6 << 7 );
1101   QTest::newRow("ifchanged-param02") << "{% for n in num %}{% for x in numx %}{% ifchanged n %}..{% endifchanged %}{{ x }}{% endfor %}{% endfor %}" << dict << "..567..567..567" << NoError;
1102
1103 // Test multiple parameters to ifchanged.
1104
1105   dict.clear();
1106   dict.insert("num", QVariantList() << 1 << 1 << 2 );
1107   dict.insert("numx", QVariantList() << 5 << 6 << 6 );
1108   QTest::newRow("ifchanged-param03") << "{% for n in num %}{{ n }}{% for x in numx %}{% ifchanged x n %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}" << dict << "156156256" << NoError;
1109
1110 // Test a date+hour like construct, where the hour of the last day
1111 // is the same but the date had changed, so print the hour anyway.
1112
1113   dict.clear();
1114   QVariantList days;
1115   QVariantMap day;
1116   day.insert("day", 1);
1117   day.insert("hours", QVariantList() << 1 << 2 << 3 );
1118   days << day;
1119   day.clear();
1120   day.insert("day", 2);
1121   day.insert("hours", QVariantList() << 3 );
1122   days << day;
1123   dict.insert("days", days );
1124   QTest::newRow("ifchanged-param04") << "{% for d in days %}{% ifchanged %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}" << dict << "112323" << NoError;
1125
1126
1127 // Logically the same as above, just written with explicit
1128 // ifchanged for the day.
1129
1130   // TODO: fix name conflict upstream
1131   QTest::newRow("ifchanged-param05") << "{% for d in days %}{% ifchanged d.day %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d.day h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}" << dict << "112323" << NoError;
1132
1133 // Test the else clause of ifchanged.
1134   dict.clear();
1135   dict.insert("ids", QVariantList() << 1 << 1 << 2 << 2 << 2 << 3 );
1136   QTest::newRow("ifchanged-else01") << "{% for id in ids %}{{ id }}{% ifchanged id %}-first{% else %}-other{% endifchanged %},{% endfor %}" << dict << "1-first,1-other,2-first,2-other,2-other,3-first," << NoError;
1137   QTest::newRow("ifchanged-else02") << "{% for id in ids %}{{ id }}-{% ifchanged id %}{% cycle red,blue %}{% else %}grey{% endifchanged %},{% endfor %}" << dict << "1-red,1-grey,2-blue,2-grey,2-grey,3-red," << NoError;
1138   QTest::newRow("ifchanged-else03") << "{% for id in ids %}{{ id }}{% ifchanged id %}-{% cycle red,blue %}{% else %}{% endifchanged %},{% endfor %}" << dict << "1-red,1,2-blue,2,2,3-red," << NoError;
1139
1140   dict.clear();
1141   dict.insert("ids", QVariantList() << 1 << 1 << 2 << 2 << 2 << 3 << 4 );
1142   QTest::newRow("ifchanged-else04") << "{% for id in ids %}{% ifchanged %}***{{ id }}*{% else %}...{% endifchanged %}{{ forloop.counter }}{% endfor %}" << dict << "***1*1...2***2*3...4...5***3*6***4*7" << NoError;
1143
1144 }
1145
1146
1147 QTEST_MAIN(TestDefaultTags)
1148 #include "testdefaulttags.moc"
1149
1150 #endif