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