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