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