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