Cutelee 6.1.0
testfilters.cpp
1/*
2 This file is part of the Cutelee 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.1 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 Lesser 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 FILTERSTEST_H
22#define FILTERSTEST_H
23
24#include <QtCore/QDebug>
25#include <QtCore/QDir>
26#include <QtCore/QFileInfo>
27#include <QtTest/QTest>
28
29#include "context.h"
30#include "coverageobject.h"
31#include "engine.h"
32#include "cutelee_paths.h"
33
34#include "template.h"
35#include <util.h>
36
37typedef QHash<QString, QVariant> Dict;
38
39Q_DECLARE_METATYPE(Cutelee::Error)
40
41using namespace Cutelee;
42
43class TestFilters : public CoverageObject
44{
46
47private Q_SLOTS:
48 void initTestCase();
49 void cleanupTestCase();
50
51 void testDateBasedFilters_data();
52 void testDateBasedFilters() { doTest(); }
53
54 void testStringFilters_data();
55 void testStringFilters() { doTest(); }
56
57 void testListFilters_data();
58 void testListFilters() { doTest(); }
59
60 void testLogicFilters_data();
61 void testLogicFilters() { doTest(); }
62
63 void testMiscFilters_data();
64 void testMiscFilters() { doTest(); }
65
66 void testIntegerFilters_data();
67 void testIntegerFilters() { doTest(); }
68
69private:
70 void doTest();
71
72 std::shared_ptr<InMemoryTemplateLoader> loader;
73 Engine *m_engine;
74};
75
76void TestFilters::initTestCase()
77{
78 m_engine = new Engine(this);
79
80 loader = std::shared_ptr<InMemoryTemplateLoader>(new InMemoryTemplateLoader());
81 m_engine->addTemplateLoader(loader);
82
83 auto appDirPath
85 m_engine->setPluginPaths({
86 QStringLiteral(CUTELEE_PLUGIN_PATH),
87 appDirPath + QStringLiteral("/tests/") // For testtags.qs
88 });
89}
90
91void TestFilters::cleanupTestCase() { delete m_engine; }
92
93void TestFilters::doTest()
94{
95 QFETCH(QString, input);
96 QFETCH(Dict, dict);
97 QFETCH(QString, output);
98 QFETCH(Cutelee::Error, error);
99
100 auto t = m_engine->newTemplate(input, QLatin1String(QTest::currentDataTag()));
101
102 Context context(dict);
103
104 auto result = t->render(&context);
105
106 if (t->error() != NoError) {
107 if (t->error() != error)
108 qDebug() << t->errorString();
109 QCOMPARE(t->error(), error);
110 return;
111 }
112
113 // Didn't catch any errors, so make sure I didn't expect any.
114 QCOMPARE(NoError, error);
115
116 QCOMPARE(t->error(), NoError);
117
118 QCOMPARE(result, output);
119}
120
121void TestFilters::testDateBasedFilters_data()
122{
123 QTest::addColumn<QString>("input");
124 QTest::addColumn<Dict>("dict");
125 QTest::addColumn<QString>("output");
126 QTest::addColumn<Cutelee::Error>("error");
127
128 Dict dict;
130
131 dict.insert(QStringLiteral("a"), now.addSecs(-70));
132
133 QTest::newRow("filter-timesince01")
134 << QStringLiteral("{{ a|timesince }}") << dict
135 << QStringLiteral("1 minute") << NoError;
136
137 dict.clear();
138
139 dict.insert(QStringLiteral("a"), now.addDays(-1).addSecs(-60));
140
141 QTest::newRow("filter-timesince02")
142 << QStringLiteral("{{ a|timesince }}") << dict << QStringLiteral("1 day")
143 << NoError;
144
145 dict.clear();
146
147 dict.insert(QStringLiteral("a"),
148 now.addSecs(-1 * 60 * 60).addSecs(-1 * 25 * 60).addSecs(-1 * 10));
149 QTest::newRow("filter-timesince03")
150 << QStringLiteral("{{ a|timesince }}") << dict
151 << QStringLiteral("1 hour, 25 minutes") << NoError;
152
153 dict.clear();
154
155 // Compare to a given parameter
156
157 dict.insert(QStringLiteral("a"), now.addDays(-2));
158 dict.insert(QStringLiteral("b"), now.addDays(-1));
159
160 QTest::newRow("filter-timesince04")
161 << QStringLiteral("{{ a|timesince:b }}") << dict
162 << QStringLiteral("1 day") << NoError;
163
164 dict.clear();
165
166 dict.insert(QStringLiteral("a"), now.addDays(-2).addSecs(-60));
167 dict.insert(QStringLiteral("b"), now.addDays(-2));
168
169 QTest::newRow("filter-timesince05")
170 << QStringLiteral("{{ a|timesince:b }}") << dict
171 << QStringLiteral("1 minute") << NoError;
172
173 dict.clear();
174
175 // Check that timezone is respected
176
177 // {"a":now_tz - timedelta(hours=8), "b":now_tz
178 // QTest::newRow( "filter-timesince06" ) << QString::fromLatin1( "{{
179 // a|timesince:b }}" ) << dict << QString::fromLatin1( "8 hours" ) <<
180 // NoError;
181
182 dict.insert(QStringLiteral("earlier"), now.addDays(-7));
183 QTest::newRow("filter-timesince07")
184 << QStringLiteral("{{ earlier|timesince }}") << dict
185 << QStringLiteral("1 week") << NoError;
186
187 dict.clear();
188
189 dict.insert(QStringLiteral("now"), now);
190 dict.insert(QStringLiteral("earlier"), now.addDays(-7));
191
192 QTest::newRow("filter-timesince08")
193 << QStringLiteral("{{ earlier|timesince:now }}") << dict
194 << QStringLiteral("1 week") << NoError;
195
196 dict.clear();
197
198 dict.insert(QStringLiteral("later"), now.addDays(7));
199
200 QTest::newRow("filter-timesince09")
201 << QStringLiteral("{{ later|timesince }}") << dict
202 << QStringLiteral("0 minutes") << NoError;
203
204 dict.clear();
205
206 dict.insert(QStringLiteral("now"), now);
207 dict.insert(QStringLiteral("later"), now.addDays(7));
208
209 QTest::newRow("filter-timesince10")
210 << QStringLiteral("{{ later|timesince:now }}") << dict
211 << QStringLiteral("0 minutes") << NoError;
212
213 // Ensures that differing timezones are calculated correctly
214
215 // {"a": now
216 // QTest::newRow( "filter-timesince11" ) << QString::fromLatin1( "{{
217 // a|timesince }}" ) << dict << QString::fromLatin1( "0 minutes" ) <<
218 // NoError;
219
220 // {"a": now_tz
221 // QTest::newRow( "filter-timesince12" ) << QString::fromLatin1( "{{
222 // a|timesince }}" ) << dict << QString::fromLatin1( "0 minutes" ) <<
223 // NoError;
224
225 // {"a": now_tz_i
226 // QTest::newRow( "filter-timesince13" ) << QString::fromLatin1( "{{
227 // a|timesince }}" ) << dict << QString::fromLatin1( "0 minutes" ) <<
228 // NoError;
229
230 // {"a": now_tz, "b": now_tz_i
231 // QTest::newRow( "filter-timesince14" ) << QString::fromLatin1( "{{
232 // a|timesince:b }}" ) << dict << QString::fromLatin1( "0 minutes" ) <<
233 // NoError;
234
235 // {"a": now, "b": now_tz_i
236 // QTest::newRow( "filter-timesince15" ) << QString::fromLatin1( "{{
237 // a|timesince:b }}" ) << dict << QString() << NoError;
238
239 // {"a": now_tz_i, "b": now
240 // QTest::newRow( "filter-timesince16" ) << QString::fromLatin1( "{{
241 // a|timesince:b }}" ) << dict << QString() << NoError;
242
243 dict.clear();
244
245 dict.insert(QStringLiteral("a"), now);
246 dict.insert(QStringLiteral("b"), now);
247
248 QTest::newRow("filter-timesince17")
249 << QStringLiteral("{{ a|timesince:b }}") << dict
250 << QStringLiteral("0 minutes") << NoError;
251
252 dict.clear();
253
254 dict.insert(QStringLiteral("a"), now);
255 dict.insert(QStringLiteral("b"), now.addDays(1));
256
257 QTest::newRow("filter-timesince18")
258 << QStringLiteral("{{ a|timesince:b }}") << dict
259 << QStringLiteral("1 day") << NoError;
260
261 dict.clear();
262 QTest::newRow("filter-timesince19") << QStringLiteral("{{xx|timesince}}")
263 << dict << QStringLiteral("") << NoError;
264 QTest::newRow("filter-timesince20") << QStringLiteral("{{|timesince}}")
265 << dict << QStringLiteral("") << NoError;
266
267 // Default compare with datetime.now()
268
269 dict.clear();
270 dict.insert(QStringLiteral("a"), now.addSecs(130));
271
272 QTest::newRow("filter-timeuntil01")
273 << QStringLiteral("{{ a|timeuntil }}") << dict
274 << QStringLiteral("2 minutes") << NoError;
275
276 dict.clear();
277 dict.insert(QStringLiteral("a"), now.addDays(1).addSecs(10));
278
279 QTest::newRow("filter-timeuntil02")
280 << QStringLiteral("{{ a|timeuntil }}") << dict << QStringLiteral("1 day")
281 << NoError;
282
283 dict.clear();
284 dict.insert(QStringLiteral("a"), now.addSecs(60 * 60 * 8).addSecs(610));
285
286 QTest::newRow("filter-timeuntil03")
287 << QStringLiteral("{{ a|timeuntil }}") << dict
288 << QStringLiteral("8 hours, 10 minutes") << NoError;
289
290 // Compare to a given parameter
291
292 dict.clear();
293 dict.insert(QStringLiteral("a"), now.addDays(-1));
294 dict.insert(QStringLiteral("b"), now.addDays(-2));
295
296 QTest::newRow("filter-timeuntil04")
297 << QStringLiteral("{{ a|timeuntil:b }}") << dict
298 << QStringLiteral("1 day") << NoError;
299
300 dict.clear();
301 dict.insert(QStringLiteral("a"), now.addDays(-1));
302 dict.insert(QStringLiteral("b"), now.addDays(-1).addSecs(-60));
303
304 QTest::newRow("filter-timeuntil05")
305 << QStringLiteral("{{ a|timeuntil:b }}") << dict
306 << QStringLiteral("1 minute") << NoError;
307
308 dict.clear();
309 dict.insert(QStringLiteral("earlier"), now.addDays(-7));
310
311 QTest::newRow("filter-timeuntil06")
312 << QStringLiteral("{{ earlier|timeuntil }}") << dict
313 << QStringLiteral("0 minutes") << NoError;
314
315 dict.clear();
316 dict.insert(QStringLiteral("now"), now);
317 dict.insert(QStringLiteral("earlier"), now.addDays(-7));
318
319 QTest::newRow("filter-timeuntil07")
320 << QStringLiteral("{{ earlier|timeuntil:now }}") << dict
321 << QStringLiteral("0 minutes") << NoError;
322
323 dict.clear();
324 dict.insert(QStringLiteral("later"), now.addDays(7).addSecs(5));
325
326 QTest::newRow("filter-timeuntil08")
327 << QStringLiteral("{{ later|timeuntil }}") << dict
328 << QStringLiteral("1 week") << NoError;
329
330 dict.clear();
331 dict.insert(QStringLiteral("now"), now);
332 dict.insert(QStringLiteral("later"), now.addDays(7));
333
334 QTest::newRow("filter-timeuntil09")
335 << QStringLiteral("{{ later|timeuntil:now }}") << dict
336 << QStringLiteral("1 week") << NoError;
337
338 // Ensures that differing timezones are calculated correctly
339 //
340 // // {"a": now_tz_i
341 // QTest::newRow( "filter-timeuntil10" ) << QString::fromLatin1( "{{
342 // a|timeuntil }}" ) << dict << QString::fromLatin1( "0 minutes" ) <<
343 // NoError;
344 //
345 // // {"a": now_tz_i, "b": now_tz
346 // QTest::newRow( "filter-timeuntil11" ) << QString::fromLatin1( "{{
347 // a|timeuntil:b }}" ) << dict << QString::fromLatin1( "0 minutes" ) <<
348 // NoError;
349
350 dict.clear();
351 dict.insert(QStringLiteral("a"), now);
352 dict.insert(QStringLiteral("b"), now);
353 QTest::newRow("filter-timeuntil12")
354 << QStringLiteral("{{ a|timeuntil:b }}") << dict
355 << QStringLiteral("0 minutes") << NoError;
356
357 dict.clear();
358 dict.insert(QStringLiteral("a"), now);
359 dict.insert(QStringLiteral("b"), now.addDays(-1));
360
361 QTest::newRow("filter-timeuntil13")
362 << QStringLiteral("{{ a|timeuntil:b }}") << dict
363 << QStringLiteral("1 day") << NoError;
364
365 dict.clear();
366 QTest::newRow("filter-timeuntil14") << QStringLiteral("{{xx|timeuntil}}")
367 << dict << QStringLiteral("") << NoError;
368 QTest::newRow("filter-timeuntil15") << QStringLiteral("{{|timeuntil}}")
369 << dict << QStringLiteral("") << NoError;
370
371 QDate d(2008, 1, 1);
372
373 dict.clear();
374 dict.insert(QStringLiteral("d"), d);
375
376 QTest::newRow("date01") << "{{ d|date:\"MM\" }}" << dict
377 << QStringLiteral("01") << NoError;
378 QTest::newRow("date02") << QStringLiteral("{{ d|date }}") << dict
379 << d.toString(QStringLiteral("MMM. d, yyyy"))
380 << NoError;
381
382 dict.clear();
383 dict.insert(QStringLiteral("d"), QStringLiteral("fail_string"));
384 QTest::newRow("date03") << "{{ d|date:\"MM\" }}" << dict << QString()
385 << NoError;
386}
387
388void TestFilters::testStringFilters_data()
389{
390 QTest::addColumn<QString>("input");
391 QTest::addColumn<Dict>("dict");
392 QTest::addColumn<QString>("output");
393 QTest::addColumn<Cutelee::Error>("error");
394
395 Dict dict;
396
397 dict.clear();
398 dict.insert(QStringLiteral("a"), QStringLiteral("<a>\'"));
399 dict.insert(QStringLiteral("b"),
400 QVariant::fromValue(markSafe(QStringLiteral("<a>\'"))));
401
402 QTest::newRow("filter-addslash01")
403 << QStringLiteral("{% autoescape off %}{{ a|addslashes }} {{ "
404 "b|addslashes }}{% endautoescape %}")
405 << dict << "<a>\\\' <a>\\\'" << NoError;
406
407 dict.clear();
408 dict.insert(QStringLiteral("a"), QStringLiteral("<a>\'"));
409 dict.insert(QStringLiteral("b"),
410 QVariant::fromValue(markSafe(QStringLiteral("<a>\'"))));
411
412 QTest::newRow("filter-addslash02")
413 << QStringLiteral("{{ a|addslashes }} {{ b|addslashes }}") << dict
414 << "&lt;a&gt;\\&#39; <a>\\\'" << NoError;
415
416 dict.clear();
417 dict.insert(QStringLiteral("a"), QStringLiteral("fred>"));
418 dict.insert(QStringLiteral("b"),
419 QVariant::fromValue(markSafe(QStringLiteral("fred&gt;"))));
420
421 QTest::newRow("filter-capfirst01")
422 << QStringLiteral("{% autoescape off %}{{ a|capfirst }} {{ b|capfirst "
423 "}}{% endautoescape %}")
424 << dict << QStringLiteral("Fred> Fred&gt;") << NoError;
425
426 dict.clear();
427 dict.insert(QStringLiteral("a"), QStringLiteral("fred>"));
428 dict.insert(QStringLiteral("b"),
429 QVariant::fromValue(markSafe(QStringLiteral("fred&gt;"))));
430
431 QTest::newRow("filter-capfirst02")
432 << QStringLiteral("{{ a|capfirst }} {{ b|capfirst }}") << dict
433 << QStringLiteral("Fred&gt; Fred&gt;") << NoError;
434
435 // Note that applying fix_ampsersands in autoescape mode leads to
436 // double escaping.
437
438 dict.clear();
439 dict.insert(QStringLiteral("a"), QStringLiteral("a&b"));
440 dict.insert(QStringLiteral("b"),
441 QVariant::fromValue(markSafe(QStringLiteral("a&b"))));
442
443 QTest::newRow("filter-fix_ampersands01")
444 << QStringLiteral("{% autoescape off %}{{ a|fix_ampersands }} {{ "
445 "b|fix_ampersands }}{% endautoescape %}")
446 << dict << QStringLiteral("a&amp;b a&amp;b") << NoError;
447
448 dict.clear();
449 dict.insert(QStringLiteral("a"), QStringLiteral("a&b"));
450 dict.insert(QStringLiteral("b"),
451 QVariant::fromValue(markSafe(QStringLiteral("a&b"))));
452
453 QTest::newRow("filter-fix_ampersands02")
454 << QStringLiteral("{{ a|fix_ampersands }} {{ b|fix_ampersands }}") << dict
455 << QStringLiteral("a&amp;amp;b a&amp;b") << NoError;
456
457 dict.clear();
458 dict.insert(QStringLiteral("a"), QStringLiteral("1.42"));
459 dict.insert(QStringLiteral("b"),
460 QVariant::fromValue(markSafe(QStringLiteral("1.42"))));
461
462 QTest::newRow("filter-floatformat01")
463 << QStringLiteral("{% autoescape off %}{{ a|floatformat }} {{ "
464 "b|floatformat }}{% endautoescape %}")
465 << dict << QStringLiteral("1.4 1.4") << NoError;
466
467 dict.clear();
468 dict.insert(QStringLiteral("a"), QStringLiteral("1.42"));
469 dict.insert(QStringLiteral("b"),
470 QVariant::fromValue(markSafe(QStringLiteral("1.42"))));
471
472 QTest::newRow("filter-floatformat02")
473 << QStringLiteral("{{ a|floatformat }} {{ b|floatformat }}") << dict
474 << QStringLiteral("1.4 1.4") << NoError;
475
476 dict.clear();
477 dict.insert(QStringLiteral("a"), double(1234.54321));
478 dict.insert(QStringLiteral("b"), int(1234));
479
480 QTest::newRow("filter-floatformat03")
481 << QStringLiteral("{{ a|floatformat }} {{ b|floatformat }}") << dict
482 << QStringLiteral("1234.5 1234.0") << NoError;
483 QTest::newRow("filter-floatformat04")
484 << QStringLiteral("{{ a|floatformat:2 }} {{ b|floatformat:2 }}") << dict
485 << QStringLiteral("1234.54 1234.00") << NoError;
486 QTest::newRow("filter-floatformat04")
487 << QStringLiteral("{{ a|floatformat:0 }} {{ b|floatformat:0 }}") << dict
488 << QStringLiteral("1235 1234") << NoError;
489
490 // The contents of "linenumbers" is escaped according to the current
491 // autoescape setting.
492
493 dict.clear();
494 dict.insert(QStringLiteral("a"), QStringLiteral("one\n<two>\nthree"));
495 dict.insert(
496 QStringLiteral("b"),
497 QVariant::fromValue(markSafe(QStringLiteral("one\n&lt;two&gt;\nthree"))));
498
499 QTest::newRow("filter-linenumbers01")
500 << QStringLiteral("{{ a|linenumbers }} {{ b|linenumbers }}") << dict
501 << "1. one\n2. &lt;two&gt;\n3. three 1. one\n2. &lt;two&gt;\n3. three"
502 << NoError;
503
504 dict.clear();
505 dict.insert(QStringLiteral("a"), QStringLiteral("one\n<two>\nthree"));
506 dict.insert(
507 QStringLiteral("b"),
508 QVariant::fromValue(markSafe(QStringLiteral("one\n&lt;two&gt;\nthree"))));
509 QTest::newRow("filter-linenumbers02")
510 << QStringLiteral("{% autoescape off %}{{ a|linenumbers }} {{ "
511 "b|linenumbers }}{% endautoescape %}")
512 << dict << "1. one\n2. <two>\n3. three 1. one\n2. &lt;two&gt;\n3. three"
513 << NoError;
514
515 dict.clear();
516 dict.insert(QStringLiteral("a"), QStringLiteral("Apple & banana"));
517 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(
518 QStringLiteral("Apple &amp; banana"))));
519
520 QTest::newRow("filter-lower01") << QStringLiteral(
521 "{% autoescape off %}{{ a|lower }} {{ b|lower }}{% endautoescape %}")
522 << dict
523 << QStringLiteral(
524 "apple & banana apple &amp; banana")
525 << NoError;
526
527 dict.clear();
528 dict.insert(QStringLiteral("a"), QStringLiteral("Apple & banana"));
529 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(
530 QStringLiteral("Apple &amp; banana"))));
531
532 QTest::newRow("filter-lower02")
533 << QStringLiteral("{{ a|lower }} {{ b|lower }}") << dict
534 << QStringLiteral("apple &amp; banana apple &amp; banana") << NoError;
535
536 // The make_list filter can destroy existing escaping, so the results are
537 // escaped.
538
539 dict.clear();
540 dict.insert(QStringLiteral("a"), markSafe(QStringLiteral("&")));
541
542 QTest::newRow("filter-make_list01") << QStringLiteral(
543 "{% autoescape off %}{{ a|make_list }}{% endautoescape %}")
544 << dict << "[u\'&\']" << NoError;
545 QTest::newRow("filter-make_list02")
546 << QStringLiteral("{{ a|make_list }}") << dict
547 << QStringLiteral("[u&#39;&amp;&#39;]") << NoError;
548
549 QTest::newRow("filter-make_list03") << QStringLiteral(
550 "{% autoescape off %}{{ a|make_list|stringformat:\"%1\"|safe }}{% "
551 "endautoescape %}") << dict << QStringLiteral("[u\'&\']")
552 << NoError;
553 QTest::newRow("filter-make_list04")
554 << QStringLiteral("{{ a|make_list|stringformat:\"%1\"|safe }}") << dict
555 << QStringLiteral("[u\'&\']") << NoError;
556
557 // Running slugify on a pre-escaped string leads to odd behaviour,
558 // but the result is still safe.
559
560 dict.clear();
561 dict.insert(QStringLiteral("a"), QStringLiteral("a & b"));
562 dict.insert(QStringLiteral("b"), markSafe(QStringLiteral("a &amp; b")));
563
564 QTest::newRow("filter-slugify01") << QStringLiteral(
565 "{% autoescape off %}{{ a|slugify }} {{ b|slugify }}{% endautoescape %}")
566 << dict << QStringLiteral("a-b a-amp-b")
567 << NoError;
568 QTest::newRow("filter-slugify02")
569 << QStringLiteral("{{ a|slugify }} {{ b|slugify }}") << dict
570 << QStringLiteral("a-b a-amp-b") << NoError;
571
572 dict.clear();
573 dict.insert(QStringLiteral("a"), QStringLiteral("Schöne Grüße"));
574
575 QTest::newRow("filter-slugify03") << QStringLiteral("{{ a|slugify }}") << dict
576 << QStringLiteral("schone-grue") << NoError;
577
578 dict.clear();
579 dict.insert(
580 QStringLiteral("a"),
581 QStringLiteral("testing\r\njavascript \'string\" <b>escaping</b>"));
582 QTest::newRow("escapejs01")
583 << QStringLiteral("{{ a|escapejs }}") << dict
584 << "testing\\u000D\\u000Ajavascript \\u0027string\\u0022 "
585 "\\u003Cb\\u003Eescaping\\u003C/b\\u003E"
586 << NoError;
587 QTest::newRow("escapejs02")
588 << QStringLiteral(
589 "{% autoescape off %}{{ a|escapejs }}{% endautoescape %}")
590 << dict
591 << "testing\\u000D\\u000Ajavascript \\u0027string\\u0022 "
592 "\\u003Cb\\u003Eescaping\\u003C/b\\u003E"
593 << NoError;
594
595 // Notice that escaping is applied *after* any filters, so the string
596 // formatting here only needs to deal with pre-escaped characters.
597
598 dict.clear();
599 dict.insert(QStringLiteral("a"), QStringLiteral("a<b"));
600 dict.insert(QStringLiteral("b"),
601 QVariant::fromValue(markSafe(QStringLiteral("a<b"))));
602
603 QTest::newRow("filter-stringformat01")
604 << "{% autoescape off %}.{{ a|stringformat:\"%1\" }}. .{{ "
605 "b|stringformat:\"%2\" }}.{% endautoescape %}"
606 << dict << QStringLiteral(".a<b. .a<b.") << NoError;
607 QTest::newRow("filter-stringformat02")
608 << ".{{ a|stringformat:\"%1\" }}. .{{ b|stringformat:\"%2\" }}." << dict
609 << QStringLiteral(".a&lt;b. .a<b.") << NoError;
610 QTest::newRow("filter-stringformat03")
611 << ".{{ a|stringformat:\"foo %1 bar\" }}. .{{ b|stringformat:\"baz %2 "
612 "bat\" }}."
613 << dict << QStringLiteral(".foo a&lt;b bar. .baz a<b bat.") << NoError;
614
615 dict.clear();
616 dict.insert(QStringLiteral("path"), QStringLiteral("www.cutelee.org"));
617 QTest::newRow("filter-stringformat04")
618 << "{% with path|stringformat:\"<a href=\\\"%1\\\">%1</a>\"|safe as "
619 "result %}{{ result }}{% endwith %}"
620 << dict << "<a href=\"www.cutelee.org\">www.cutelee.org</a>" << NoError;
621
622 dict.clear();
623 dict.insert(QStringLiteral("a"), QStringLiteral("JOE\'S CRAB SHACK"));
624 QTest::newRow("filter-title01")
625 << "{{ a|title }}" << dict << QStringLiteral("Joe&#39;s Crab Shack")
626 << NoError;
627
628 dict.clear();
629 dict.insert(QStringLiteral("a"), QStringLiteral("555 WEST 53RD STREET"));
630 QTest::newRow("filter-title02")
631 << "{{ a|title }}" << dict << QStringLiteral("555 West 53rd Street")
632 << NoError;
633
634 dict.clear();
635 dict.insert(QStringLiteral("a"), QStringLiteral("alpha & bravo"));
636 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(
637 QStringLiteral("alpha &amp; bravo"))));
638
639 QTest::newRow("filter-truncatewords01")
640 << "{% autoescape off %}{{ a|truncatewords:\"2\" }} {{ "
641 "b|truncatewords:\"2\"}}{% endautoescape %}"
642 << dict << QStringLiteral("alpha & ... alpha &amp; ...") << NoError;
643
644 QTest::newRow("filter-truncatewords02")
645 << "{{ a|truncatewords:\"2\" }} {{ b|truncatewords:\"2\"}}" << dict
646 << QStringLiteral("alpha &amp; ... alpha &amp; ...") << NoError;
647
648 // The "upper" filter messes up entities (which are case-sensitive),
649 // so it's not safe for non-escaping purposes.
650
651 dict.clear();
652 dict.insert(QStringLiteral("a"), QStringLiteral("a & b"));
653 dict.insert(QStringLiteral("b"),
654 QVariant::fromValue(markSafe(QStringLiteral("a &amp; b"))));
655
656 QTest::newRow("filter-upper01") << QStringLiteral(
657 "{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}")
658 << dict << QStringLiteral("A & B A &AMP; B")
659 << NoError;
660 QTest::newRow("filter-upper02")
661 << QStringLiteral("{{ a|upper }} {{ b|upper }}") << dict
662 << QStringLiteral("A &amp; B A &amp;AMP; B") << NoError;
663
664 // // {"a": "http://example.com/?x=&y=", "b":
665 // mark_safe("http://example.com?x=&amp;y=")
666 // QTest::newRow( "filter-urlize01") << QString::fromLatin1( "{%
667 // autoescape
668 // off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}" ) << dict <<
669 // "<a
670 // href=\"http://example.com/?x=&y=\"
671 // rel=\"nofollow\">http://example.com/?x=&y=</a> <a
672 // href=\"http://example.com?x=&amp;y=\"
673 // rel=\"nofollow\">http://example.com?x=&amp;y=</a>" << NoError;
674 //
675 // // {"a": "http://example.com/?x=&y=", "b":
676 // mark_safe("http://example.com?x=&amp;y=")
677 // QTest::newRow( "filter-urlize02") << QString::fromLatin1( "{{ a|urlize
678 // }}
679 // {{ b|urlize }}" ) << dict << "<a href=\"http://example.com/?x=&amp;y=\"
680 // rel=\"nofollow\">http://example.com/?x=&amp;y=</a> <a
681 // href=\"http://example.com?x=&amp;y=\"
682 // rel=\"nofollow\">http://example.com?x=&amp;y=</a>" << NoError;
683 //
684 // // {"a": mark_safe("a &amp; b")
685 // QTest::newRow( "filter-urlize03") << QString::fromLatin1( "{%
686 // autoescape
687 // off %}{{ a|urlize }}{% endautoescape %}" ) << dict <<
688 // QString::fromLatin1( "a &amp; b" ) << NoError;
689 //
690 // // {"a": mark_safe("a &amp; b")
691 // QTest::newRow( "filter-urlize04") << QString::fromLatin1( "{{ a|urlize
692 // }}" ) << dict << QString::fromLatin1( "a &amp; b" ) << NoError;
693 //
694 // // This will lead to a nonsense result, but at least it won't be
695 //
696 // // exploitable for XSS purposes when auto-escaping is on.
697 //
698 // // {"a": "<script>alert(\"foo\")</script>"
699 // QTest::newRow( "filter-urlize05") << QString::fromLatin1( "{%
700 // autoescape
701 // off %}{{ a|urlize }}{% endautoescape %}" ) << dict <<
702 // "<script>alert(\"foo\")</script>" << NoError;
703 //
704 // // {"a": "<script>alert(\"foo\")</script>"
705 // QTest::newRow( "filter-urlize06") << QString::fromLatin1( "{{ a|urlize
706 // }}" ) << dict << QString::fromLatin1(
707 // "&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;" ) << NoError;
708 //
709 // // mailto: testing for urlize
710 //
711 // // {"a": "Email me at me@example.com"
712 // QTest::newRow( "filter-urlize07") << QString::fromLatin1( "{{ a|urlize
713 // }}" ) << dict << "Email me at <a
714 // href=\"mailto:me@example.com\">me@example.com</a>" << NoError;
715 //
716 // // {"a": "Email me at <me@example.com>"
717 // QTest::newRow( "filter-urlize08") << QString::fromLatin1( "{{ a|urlize
718 // }}" ) << dict << "Email me at &lt;<a
719 // href=\"mailto:me@example.com\">me@example.com</a>&gt;" << NoError;
720 //
721 // // {"a": "\"Unsafe\" http://example.com/x=&y=", "b":
722 // mark_safe("&quot;Safe&quot; http://example.com?x=&amp;y=")
723 // QTest::newRow( "filter-urlizetrunc01") << "{% autoescape off %}{{
724 // a|urlizetrunc:\"8\" }} {{ b|urlizetrunc:\"8\" }}{% endautoescape %}" <<
725 // dict << "\"Unsafe\" <a href=\"http://example.com/x=&y=\"
726 // rel=\"nofollow\">http:...</a> &quot;Safe&quot; <a
727 // href=\"http://example.com?x=&amp;y=\" rel=\"nofollow\">http:...</a>" <<
728 // NoError;
729 //
730 // // {"a": "\"Unsafe\" http://example.com/x=&y=", "b":
731 // mark_safe("&quot;Safe&quot; http://example.com?x=&amp;y=")
732 // QTest::newRow( "filter-urlizetrunc02") << "{{ a|urlizetrunc:\"8\" }} {{
733 // b|urlizetrunc:\"8\" }}" << dict << "&quot;Unsafe&quot; <a
734 // href=\"http://example.com/x=&amp;y=\" rel=\"nofollow\">http:...</a>
735 // &quot;Safe&quot; <a href=\"http://example.com?x=&amp;y=\"
736 // rel=\"nofollow\">http:...</a>" << NoError;
737
738 // // Ensure iriencode keeps safe strings:
739 //
740 // // {"url": "?test=1&me=2"
741 // QTest::newRow( "filter-iriencode01") << QString::fromLatin1( "{{
742 // url|iriencode }}" ) << dict << QString::fromLatin1( "?test=1&amp;me=2"
743 // )
744 // << NoError;
745 //
746 // // {"url": "?test=1&me=2"
747 // QTest::newRow( "filter-iriencode02") << QString::fromLatin1( "{%
748 // autoescape off %}{{ url|iriencode }}{% endautoescape %}" ) << dict <<
749 // QString::fromLatin1( "?test=1&me=2" ) << NoError;
750 //
751 // // {"url": mark_safe("?test=1&me=2")
752 // QTest::newRow( "filter-iriencode03") << QString::fromLatin1( "{{
753 // url|iriencode }}" ) << dict << QString::fromLatin1( "?test=1&me=2" ) <<
754 // NoError;
755 //
756 // // {"url": mark_safe("?test=1&me=2")
757 // QTest::newRow( "filter-iriencode04") << QString::fromLatin1( "{%
758 // autoescape off %}{{ url|iriencode }}{% endautoescape %}" ) << dict <<
759 // QString::fromLatin1( "?test=1&me=2" ) << NoError;
760 //
761 dict.clear();
762 dict.insert(QStringLiteral("a"), QStringLiteral("a & b"));
763 dict.insert(QStringLiteral("b"),
764 QVariant::fromValue(markSafe(QStringLiteral("a &amp; b"))));
765
766 QTest::newRow("filter-wordcount01")
767 << QStringLiteral("{% autoescape off %}{{ a|wordcount }} {{ b|wordcount "
768 "}}{% endautoescape %}")
769 << dict << QStringLiteral("3 3") << NoError;
770
771 QTest::newRow("filter-wordcount02")
772 << QStringLiteral("{{ a|wordcount }} {{ b|wordcount }}") << dict
773 << QStringLiteral("3 3") << NoError;
774
775 dict.clear();
776 dict.insert(QStringLiteral("a"), QStringLiteral("a & b"));
777 dict.insert(QStringLiteral("b"),
778 QVariant::fromValue(markSafe(QStringLiteral("a & b"))));
779
780 QTest::newRow("filter-wordwrap01")
781 << QStringLiteral("{% autoescape off %}{{ a|wordwrap:3 }} {{ "
782 "b|wordwrap:3 }}{% endautoescape %}")
783 << dict << "a &\nb a &\nb" << NoError;
784
785 QTest::newRow("filter-wordwrap02")
786 << QStringLiteral("{{ a|wordwrap:3 }} {{ b|wordwrap:3 }}") << dict
787 << "a &amp;\nb a &\nb" << NoError;
788
789 dict.clear();
790 QTest::newRow("filter-wordwrap03")
791 << QStringLiteral("{{xx|wordwrap}}") << dict << "" << NoError;
792
793 QTest::newRow("filter-wordwrap04")
794 << QStringLiteral("{{|wordwrap}}") << dict << "" << NoError;
795
796 dict.clear();
797 dict.insert(QStringLiteral("a"), QStringLiteral("a&b"));
798 dict.insert(QStringLiteral("b"),
799 QVariant::fromValue(markSafe(QStringLiteral("a&b"))));
800
801 QTest::newRow("filter-ljust01")
802 << "{% autoescape off %}.{{ a|ljust:\"5\" }}. .{{ b|ljust:\"5\" }}.{% "
803 "endautoescape %}"
804 << dict << QStringLiteral(".a&b . .a&b .") << NoError;
805
806 QTest::newRow("filter-ljust02")
807 << ".{{ a|ljust:\"5\" }}. .{{ b|ljust:\"5\" }}." << dict
808 << QStringLiteral(".a&amp;b . .a&b .") << NoError;
809
810 QTest::newRow("filter-rjust01")
811 << "{% autoescape off %}.{{ a|rjust:\"5\" }}. .{{ b|rjust:\"5\" }}.{% "
812 "endautoescape %}"
813 << dict << QStringLiteral(". a&b. . a&b.") << NoError;
814
815 QTest::newRow("filter-rjust02")
816 << ".{{ a|rjust:\"5\" }}. .{{ b|rjust:\"5\" }}." << dict
817 << QStringLiteral(". a&amp;b. . a&b.") << NoError;
818
819 QTest::newRow("filter-center01")
820 << "{% autoescape off %}.{{ a|center:\"5\" }}. .{{ b|center:\"5\" "
821 "}}.{% "
822 "endautoescape %}"
823 << dict << QStringLiteral(". a&b . . a&b .") << NoError;
824
825 QTest::newRow("filter-center02")
826 << ".{{ a|center:\"5\" }}. .{{ b|center:\"5\" }}." << dict
827 << QStringLiteral(". a&amp;b . . a&b .") << NoError;
828
829 dict.clear();
830 dict.insert(QStringLiteral("a"), QStringLiteral("x&y"));
831 dict.insert(QStringLiteral("b"),
832 QVariant::fromValue(markSafe(QStringLiteral("x&amp;y"))));
833
834 QTest::newRow("filter-cut01")
835 << "{% autoescape off %}{{ a|cut:\"x\" }} {{ "
836 "b|cut:\"x\" }}{% endautoescape %}"
837 << dict << QStringLiteral("&y &amp;y") << NoError;
838 QTest::newRow("filter-cut02") << "{{ a|cut:\"x\" }} {{ b|cut:\"x\" }}" << dict
839 << QStringLiteral("&amp;y &amp;y") << NoError;
840 QTest::newRow("filter-cut03")
841 << "{% autoescape off %}{{ a|cut:\"&\" }} {{ "
842 "b|cut:\"&\" }}{% endautoescape %}"
843 << dict << QStringLiteral("xy xamp;y") << NoError;
844 QTest::newRow("filter-cut04") << "{{ a|cut:\"&\" }} {{ b|cut:\"&\" }}" << dict
845 << QStringLiteral("xy xamp;y") << NoError;
846
847 // Passing ";" to cut can break existing HTML entities, so those strings
848 // are auto-escaped.
849
850 QTest::newRow("filter-cut05")
851 << "{% autoescape off %}{{ a|cut:\";\" }} {{ "
852 "b|cut:\";\" }}{% endautoescape %}"
853 << dict << QStringLiteral("x&y x&ampy") << NoError;
854 QTest::newRow("filter-cut06")
855 << "{{ a|cut:\";\" }} {{ b|cut:\";\" }}" << dict
856 << QStringLiteral("x&amp;y x&amp;ampy") << NoError;
857
858 // The "escape" filter works the same whether autoescape is on or off,
859 // but it has no effect on strings already marked as safe.
860
861 dict.clear();
862 dict.insert(QStringLiteral("a"), QStringLiteral("x&y"));
863 dict.insert(QStringLiteral("b"),
864 QVariant::fromValue(markSafe(QStringLiteral("x&y"))));
865
866 QTest::newRow("filter-escape01")
867 << QStringLiteral("{{ a|escape }} {{ b|escape }}") << dict
868 << QStringLiteral("x&amp;y x&y") << NoError;
869 QTest::newRow("filter-escape02") << QStringLiteral(
870 "{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}")
871 << dict << QStringLiteral("x&amp;y x&y")
872 << NoError;
873
874 // It is only applied once, regardless of the number of times it
875 // appears in a chain.
876
877 dict.clear();
878 dict.insert(QStringLiteral("a"), QStringLiteral("x&y"));
879
880 QTest::newRow("filter-escape03")
881 << QStringLiteral(
882 "{% autoescape off %}{{ a|escape|escape }}{% endautoescape %}")
883 << dict << QStringLiteral("x&amp;y") << NoError;
884 QTest::newRow("filter-escape04")
885 << QStringLiteral("{{ a|escape|escape }}") << dict
886 << QStringLiteral("x&amp;y") << NoError;
887
888
889 // Force_escape is applied immediately. It can be used to provide
890 // double-escaping, for example.
891
892 QTest::newRow("filter-force-escape01")
893 << QStringLiteral(
894 "{% autoescape off %}{{ a|force_escape }}{% endautoescape %}")
895 << dict << QStringLiteral("x&amp;y") << NoError;
896 QTest::newRow("filter-force-escape02")
897 << QStringLiteral("{{ a|force_escape }}") << dict
898 << QStringLiteral("x&amp;y") << NoError;
899
900 QTest::newRow("filter-force-escape03")
901 << QStringLiteral("{% autoescape off %}{{ a|force_escape|force_escape "
902 "}}{% endautoescape %}")
903 << dict << QStringLiteral("x&amp;amp;y") << NoError;
904 QTest::newRow("filter-force-escape04")
905 << QStringLiteral("{{ a|force_escape|force_escape }}") << dict
906 << QStringLiteral("x&amp;amp;y") << NoError;
907
908 // Because the result of force_escape is "safe", an additional
909 // escape filter has no effect.
910
911 QTest::newRow("filter-force-escape05") << QStringLiteral(
912 "{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}")
913 << dict << QStringLiteral("x&amp;y")
914 << NoError;
915 QTest::newRow("filter-force-escape06")
916 << QStringLiteral("{{ a|force_escape|escape }}") << dict
917 << QStringLiteral("x&amp;y") << NoError;
918 QTest::newRow("filter-force-escape07") << QStringLiteral(
919 "{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}")
920 << dict << QStringLiteral("x&amp;y")
921 << NoError;
922 QTest::newRow("filter-force-escape08")
923 << QStringLiteral("{{ a|escape|force_escape }}") << dict
924 << QStringLiteral("x&amp;y") << NoError;
925
926 // The contents in "linebreaks" and "linebreaksbr" are escaped
927 // according to the current autoescape setting.
928
929 dict.clear();
930 dict.insert(QStringLiteral("a"), QStringLiteral("x&\ny"));
931 dict.insert(QStringLiteral("b"), markSafe(QStringLiteral("x&\ny")));
932
933 QTest::newRow("filter-linebreaks01")
934 << QStringLiteral("{{ a|linebreaks }} {{ b|linebreaks }}") << dict
935 << QStringLiteral("<p>x&amp;<br />y</p> <p>x&<br />y</p>") << NoError;
936 QTest::newRow("filter-linebreaks02")
937 << QStringLiteral("{% autoescape off %}{{ a|linebreaks }} {{ "
938 "b|linebreaks }}{% endautoescape %}")
939 << dict << QStringLiteral("<p>x&<br />y</p> <p>x&<br />y</p>") << NoError;
940 QTest::newRow("filter-linebreaksbr01")
941 << QStringLiteral("{{ a|linebreaksbr }} {{ b|linebreaksbr }}") << dict
942 << QStringLiteral("x&amp;<br />y x&<br />y") << NoError;
943 QTest::newRow("filter-linebreaksbr02")
944 << QStringLiteral("{% autoescape off %}{{ a|linebreaksbr }} {{ "
945 "b|linebreaksbr }}{% endautoescape %}")
946 << dict << QStringLiteral("x&<br />y x&<br />y") << NoError;
947
948 dict.clear();
949 dict.insert(QStringLiteral("a"), QStringLiteral("<b>hello</b>"));
950
951 QTest::newRow("filter-safe01")
952 << QStringLiteral("{{ a }} -- {{ a|safe }}") << dict
953 << QStringLiteral("&lt;b&gt;hello&lt;/b&gt; -- <b>hello</b>") << NoError;
954 QTest::newRow("filter-safe02")
955 << QStringLiteral(
956 "{% autoescape off %}{{ a }} -- {{ a|safe }}{% endautoescape %}")
957 << dict << QStringLiteral("<b>hello</b> -- <b>hello</b>") << NoError;
958
959 dict.clear();
960 dict.insert(QStringLiteral("a"),
961 QVariantList{QStringLiteral("&"), QStringLiteral("<")});
962
963 QTest::newRow("filter-safeseq01")
964 << "{{ a|join:\", \" }} -- {{ a|safeseq|join:\", \" }}" << dict
965 << QStringLiteral("&amp;, &lt; -- &, <") << NoError;
966 QTest::newRow("filter-safeseq02")
967 << "{% autoescape off %}{{ a|join:\", \" "
968 "}} -- {{ a|safeseq|join:\", \" "
969 "}}{% endautoescape %}"
970 << dict << QStringLiteral("&, < -- &, <") << NoError;
971
972 dict.clear();
973 dict.insert(QStringLiteral("a"), QStringLiteral("<a>x</a> <p><b>y</b></p>"));
974 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral(
975 "<a>x</a> <p><b>y</b></p>"))));
976
977 QTest::newRow("filter-removetags01")
978 << "{{ a|removetags:\"a b\" }} {{ b|removetags:\"a b\" }}" << dict
979 << QStringLiteral("x &lt;p&gt;y&lt;/p&gt; x <p>y</p>") << NoError;
980 QTest::newRow("filter-removetags02")
981 << "{% autoescape off %}{{ a|removetags:\"a b\" }} {{ b|removetags:\"a "
982 "b\" }}{% endautoescape %}"
983 << dict << QStringLiteral("x <p>y</p> x <p>y</p>") << NoError;
984 QTest::newRow("filter-striptags01")
985 << QStringLiteral("{{ a|striptags }} {{ b|striptags }}") << dict
986 << QStringLiteral("x y x y") << NoError;
987 QTest::newRow("filter-striptags02")
988 << QStringLiteral("{% autoescape off %}{{ a|striptags }} {{ b|striptags "
989 "}}{% endautoescape %}")
990 << dict << QStringLiteral("x y x y") << NoError;
991
992 dict.clear();
993 dict.insert(QStringLiteral("fs_int_mib"), 1048576);
994
995 QTest::newRow("filter-filesizeformat01")
996 << QStringLiteral("{{ fs_int_mib|filesizeformat }}") << dict
997 << QStringLiteral("1.05 MB") << NoError;
998
999 QTest::newRow("filter-filesizeformat02")
1000 << QStringLiteral("{{ fs_int_mib|filesizeformat:\"2\" }}") << dict
1001 << QStringLiteral("1.00 MiB") << NoError;
1002
1003 QTest::newRow("filter-filesizeformat03")
1004 << QStringLiteral("{{ fs_int_mib|filesizeformat:\"10,3\" }}") << dict
1005 << QStringLiteral("1.049 MB") << NoError;
1006
1007 QTest::newRow("filter-filesizeformat04")
1008 << QStringLiteral("{{ fs_int_mib|filesizeformat:\"10,2,1024\" }}") << dict
1009 << QStringLiteral("1.07 GB") << NoError;
1010
1011 dict.clear();
1012 dict.insert(QStringLiteral("fs_float_mib"), 1024.5);
1013
1014 QTest::newRow("filter-filesizeformat05")
1015 << QStringLiteral("{{ fs_float_mib|filesizeformat:\"10,2,1024\" }}") << dict
1016 << QStringLiteral("1.05 MB") << NoError;
1017
1018 dict.clear();
1019 dict.insert(QStringLiteral("fs_string_mib"), QStringLiteral("1024.5"));
1020
1021 QTest::newRow("filter-filesizeformat06")
1022 << QStringLiteral("{{ fs_string_mib|filesizeformat:\"10,2,1024\" }}") << dict
1023 << QStringLiteral("1.05 MB") << NoError;
1024
1025 dict.clear();
1026 dict.insert(QStringLiteral("fs_bytes"), 999);
1027 dict.insert(QStringLiteral("fs_kb"), 1000);
1028 dict.insert(QStringLiteral("fs_10kb"), 10 * 1000);
1029 dict.insert(QStringLiteral("fs_1000kb"), 1000 * 1000 -1);
1030 dict.insert(QStringLiteral("fs_mb"), 1000 * 1000);
1031 dict.insert(QStringLiteral("fs_50mb"), 1000 * 1000 * 50);
1032 dict.insert(QStringLiteral("fs_1000mb"), 1000 * 1000 * 1000 - 1);
1033 dict.insert(QStringLiteral("fs_gb"), 1000 * 1000 * 1000);
1034 dict.insert(QStringLiteral("fs_tb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0));
1035 dict.insert(QStringLiteral("fs_pb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0));
1036 dict.insert(QStringLiteral("fs_eb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 2000.0));
1037 dict.insert(QStringLiteral("fs_zb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0));
1038 dict.insert(QStringLiteral("fs_yb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0));
1039 dict.insert(QStringLiteral("fs_2000yb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 2000.0));
1040 dict.insert(QStringLiteral("fs_0b1"), 0.1);
1041 dict.insert(QStringLiteral("fs_0b2"), QString(QChar(0x03B1)));
1042 dict.insert(QStringLiteral("fs_neg_1"), -100);
1043 dict.insert(QStringLiteral("fs_neg_2"), -1000 * 1000 *50);
1044
1045 // fixes tests on MSVC2013
1046 QString fsInput;
1047 fsInput = QStringLiteral("{{ fs_bytes|filesizeformat }} {{ fs_kb|filesizeformat }} {{ fs_10kb|filesizeformat }} {{ fs_1000kb|filesizeformat }} ");
1048 fsInput += QStringLiteral("{{ fs_mb|filesizeformat }} {{ fs_50mb|filesizeformat }} {{ fs_1000mb|filesizeformat }} {{ fs_gb|filesizeformat }} ");
1049 fsInput += QStringLiteral("{{ fs_tb|filesizeformat }} {{ fs_pb|filesizeformat }} {{ fs_eb|filesizeformat }} {{ fs_zb|filesizeformat }} ");
1050 fsInput += QStringLiteral("{{ fs_yb|filesizeformat }} {{ fs_2000yb|filesizeformat }} {{ fs_0b1|filesizeformat }} {{ fs_0b2|filesizeformat }} ");
1051 fsInput += QStringLiteral("{{ fs_neg_1|filesizeformat }} {{ fs_neg_2|filesizeformat }}");
1052
1053 QString fsExpect;
1054 fsExpect = QStringLiteral("999 bytes 1.00 KB 10.00 KB 1000.00 KB ");
1055 fsExpect += QStringLiteral("1.00 MB 50.00 MB 1000.00 MB 1.00 GB ");
1056 fsExpect += QStringLiteral("1.00 TB 1.00 PB 2.00 EB 1.00 ZB ");
1057 fsExpect += QStringLiteral("1.00 YB 2000.00 YB 0 bytes 0 bytes ");
1058 fsExpect += QStringLiteral("-100 bytes -50.00 MB");
1059
1060 QTest::newRow("filter-filesizeformat07")
1061 << fsInput
1062 << dict
1063 << fsExpect
1064 << NoError;
1065}
1066
1067void TestFilters::testListFilters_data()
1068{
1069 QTest::addColumn<QString>("input");
1070 QTest::addColumn<Dict>("dict");
1071 QTest::addColumn<QString>("output");
1072 QTest::addColumn<Cutelee::Error>("error");
1073
1074 Dict dict;
1075
1076 dict.insert(QStringLiteral("a"),
1077 QVariantList{QStringLiteral("a&b"), QStringLiteral("x")});
1078 dict.insert(QStringLiteral("b"),
1079 QVariantList{QVariant::fromValue(markSafe(QStringLiteral("a&b"))),
1080 QStringLiteral("x")});
1081
1082 QTest::newRow("filter-first01")
1083 << QStringLiteral("{{ a|first }} {{ b|first }}") << dict
1084 << QStringLiteral("a&amp;b a&b") << NoError;
1085 QTest::newRow("filter-first02") << QStringLiteral(
1086 "{% autoescape off %}{{ a|first }} {{ b|first }}{% endautoescape %}")
1087 << dict << QStringLiteral("a&b a&b")
1088 << NoError;
1089
1090 dict.clear();
1091 dict.insert(QStringLiteral("a"),
1092 QVariantList{QStringLiteral("x"), QStringLiteral("a&b")});
1093 dict.insert(QStringLiteral("b"),
1094 QVariantList{QStringLiteral("x"), QVariant::fromValue(markSafe(
1095 QStringLiteral("a&b")))});
1096
1097 QTest::newRow("filter-last01")
1098 << QStringLiteral("{{ a|last }} {{ b|last }}") << dict
1099 << QStringLiteral("a&amp;b a&b") << NoError;
1100 QTest::newRow("filter-last02")
1101 << QStringLiteral(
1102 "{% autoescape off %}{{ a|last }} {{ b|last }}{% endautoescape %}")
1103 << dict << QStringLiteral("a&b a&b") << NoError;
1104
1105 dict.clear();
1106 dict.insert(QStringLiteral("a"),
1107 QVariantList{QStringLiteral("a&b"), QStringLiteral("a&b")});
1108 dict.insert(QStringLiteral("b"),
1109 QVariantList()
1110 << QVariant::fromValue(markSafe(QStringLiteral("a&b")))
1111 << QVariant::fromValue(markSafe(QStringLiteral("a&b"))));
1112 QTest::newRow("filter-random01")
1113 << QStringLiteral("{{ a|random }} {{ b|random }}") << dict
1114 << QStringLiteral("a&amp;b a&b") << NoError;
1115 QTest::newRow("filter-random02") << QStringLiteral(
1116 "{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}")
1117 << dict << QStringLiteral("a&b a&b")
1118 << NoError;
1119
1120 dict.clear();
1121 dict.insert(QStringLiteral("empty_list"), QVariantList());
1122 QTest::newRow("filter-random03") << QStringLiteral("{{empty_list|random}}")
1123 << dict << QStringLiteral("") << NoError;
1124 QTest::newRow("filter-random04")
1125 << QStringLiteral("{{|random}}") << dict << QStringLiteral("") << NoError;
1126
1127 dict.clear();
1128 dict.insert(QStringLiteral("a"), QStringLiteral("a&b"));
1129 dict.insert(QStringLiteral("b"),
1130 QVariant::fromValue(markSafe(QStringLiteral("a&b"))));
1131
1132 QTest::newRow("filter-slice01")
1133 << "{{ a|slice:\"1:3\" }} {{ b|slice:\"1:3\" }}" << dict
1134 << QStringLiteral("&amp;b &b") << NoError;
1135 QTest::newRow("filter-slice02")
1136 << "{% autoescape off %}{{ a|slice:\"1:3\" }} {{ b|slice:\"1:3\" }}{% "
1137 "endautoescape %}"
1138 << dict << QStringLiteral("&b &b") << NoError;
1139
1140 dict.clear();
1141 QTest::newRow("filter-slice03")
1142 << "{{xx|slice}}" << dict << QStringLiteral("") << NoError;
1143 QTest::newRow("filter-slice04")
1144 << "{{|slice}}" << dict << QStringLiteral("") << NoError;
1145
1146 dict.clear();
1147 QVariantList sublist{QStringLiteral("<y")};
1148 dict.insert(QStringLiteral("a"),
1149 QVariantList{QStringLiteral("x>"), QVariant(sublist)});
1150
1151 QTest::newRow("filter-unordered_list01")
1152 << QStringLiteral("{{ a|unordered_list }}") << dict
1153 << "\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>" << NoError;
1154 QTest::newRow("filter-unordered_list02")
1155 << QStringLiteral(
1156 "{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}")
1157 << dict << "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"
1158 << NoError;
1159
1160 dict.clear();
1161 sublist = {markSafe(QStringLiteral("<y"))};
1162 dict.insert(QStringLiteral("a"),
1163 QVariantList{QStringLiteral("x>"), QVariant(sublist)});
1164
1165 QTest::newRow("filter-unordered_list03")
1166 << QStringLiteral("{{ a|unordered_list }}") << dict
1167 << "\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>" << NoError;
1168 QTest::newRow("filter-unordered_list04")
1169 << QStringLiteral(
1170 "{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}")
1171 << dict << "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"
1172 << NoError;
1173
1174 dict.clear();
1175 sublist = {QStringLiteral("<y")};
1176 dict.insert(QStringLiteral("a"),
1177 QVariantList{QStringLiteral("x>"), QVariant(sublist)});
1178
1179 QTest::newRow("filter-unordered_list05")
1180 << QStringLiteral(
1181 "{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}")
1182 << dict << "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"
1183 << NoError;
1184
1185 // length filter.
1186 dict.clear();
1187 dict.insert(
1188 QStringLiteral("list"),
1189 QVariantList{QStringLiteral("4"), QVariant(), true, QVariantHash()});
1190
1191 QTest::newRow("length01") << QStringLiteral("{{ list|length }}") << dict
1192 << QStringLiteral("4") << NoError;
1193
1194 dict.clear();
1195 dict.insert(QStringLiteral("list"), QVariantList());
1196
1197 QTest::newRow("length02") << QStringLiteral("{{ list|length }}") << dict
1198 << QStringLiteral("0") << NoError;
1199
1200 dict.clear();
1201 dict.insert(QStringLiteral("string"), QStringLiteral(""));
1202
1203 QTest::newRow("length03") << QStringLiteral("{{ string|length }}") << dict
1204 << QStringLiteral("0") << NoError;
1205
1206 dict.clear();
1207 dict.insert(QStringLiteral("string"), QStringLiteral("django"));
1208
1209 QTest::newRow("length04") << QStringLiteral("{{ string|length }}") << dict
1210 << QStringLiteral("6") << NoError;
1211
1212 // Invalid uses that should fail silently.
1213
1214 dict.clear();
1215 dict.insert(QStringLiteral("int"), 7);
1216
1217 QTest::newRow("length05")
1218 << QStringLiteral("{{ int|length }}") << dict << QString() << NoError;
1219
1220 dict.clear();
1221 dict.insert(QStringLiteral("None"), QVariant());
1222
1223 QTest::newRow("length06")
1224 << QStringLiteral("{{ None|length }}") << dict << QString() << NoError;
1225
1226 // length_is filter.
1227
1228 dict.clear();
1229 dict.insert(
1230 QStringLiteral("some_list"),
1231 QVariantList{QStringLiteral("4"), QVariant(), true, QVariantHash()});
1232
1233 QTest::newRow("length_is01")
1234 << "{% if some_list|length_is:\"4\" %}Four{% endif %}" << dict
1235 << QStringLiteral("Four") << NoError;
1236
1237 dict.clear();
1238 dict.insert(
1239 QStringLiteral("some_list"),
1240 QVariantList{QStringLiteral("4"), QVariant(), true, QVariantHash(), 17});
1241
1242 QTest::newRow("length_is02")
1243 << "{% if some_list|length_is:\"4\" %}Four{% else %}Not Four{% endif %}"
1244 << dict << QStringLiteral("Not Four") << NoError;
1245
1246 dict.clear();
1247 dict.insert(QStringLiteral("mystring"), QStringLiteral("word"));
1248
1249 QTest::newRow("length_is03")
1250 << "{% if mystring|length_is:\"4\" %}Four{% endif %}" << dict
1251 << QStringLiteral("Four") << NoError;
1252
1253 dict.clear();
1254 dict.insert(QStringLiteral("mystring"), QStringLiteral("Python"));
1255
1256 QTest::newRow("length_is04")
1257 << "{% if mystring|length_is:\"4\" %}Four{% else %}Not Four{% endif %}"
1258 << dict << QStringLiteral("Not Four") << NoError;
1259
1260 dict.clear();
1261 dict.insert(QStringLiteral("mystring"), QStringLiteral(""));
1262
1263 QTest::newRow("length_is05")
1264 << "{% if mystring|length_is:\"4\" %}Four{% else %}Not Four{% endif %}"
1265 << dict << QStringLiteral("Not Four") << NoError;
1266
1267 dict.clear();
1268 dict.insert(QStringLiteral("var"), QStringLiteral("django"));
1269
1270 QTest::newRow("length_is06") << QStringLiteral(
1271 "{% with var|length as my_length %}{{ my_length }}{% endwith %}")
1272 << dict << QStringLiteral("6") << NoError;
1273
1274 // Boolean return value from length_is should not be coerced to a string
1275
1276 dict.clear();
1277 QTest::newRow("length_is07")
1278 << "{% if \"X\"|length_is:0 %}Length is 0{% "
1279 "else %}Length not 0{% endif %}"
1280 << dict << QStringLiteral("Length not 0") << NoError;
1281 QTest::newRow("length_is08")
1282 << "{% if \"X\"|length_is:1 %}Length is 1{% "
1283 "else %}Length not 1{% endif %}"
1284 << dict << QStringLiteral("Length is 1") << NoError;
1285
1286 // Invalid uses that should fail silently.
1287
1288 dict.clear();
1289 dict.insert(QStringLiteral("var"), QStringLiteral("django"));
1290
1291 QTest::newRow("length_is09")
1292 << "{{ var|length_is:\"fish\" }}" << dict << QString() << NoError;
1293
1294 dict.clear();
1295 dict.insert(QStringLiteral("int"), 7);
1296
1297 QTest::newRow("length_is10")
1298 << "{{ int|length_is:\"1\" }}" << dict << QString() << NoError;
1299
1300 dict.clear();
1301 dict.insert(QStringLiteral("none"), QVariant());
1302
1303 QTest::newRow("length_is11")
1304 << "{{ none|length_is:\"1\" }}" << dict << QString() << NoError;
1305
1306 dict.clear();
1307 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("alpha"),
1308 QStringLiteral("beta & me")});
1309
1310 QTest::newRow("join01") << "{{ a|join:\", \" }}" << dict
1311 << QStringLiteral("alpha, beta &amp; me") << NoError;
1312 QTest::newRow("join02")
1313 << "{% autoescape off %}{{ a|join:\", \" }}{% endautoescape %}" << dict
1314 << QStringLiteral("alpha, beta & me") << NoError;
1315 QTest::newRow("join03") << "{{ a|join:\" &amp; \" }}" << dict
1316 << QStringLiteral("alpha &amp; beta &amp; me")
1317 << NoError;
1318 QTest::newRow("join04")
1319 << "{% autoescape off %}{{ a|join:\" &amp; \" }}{% endautoescape %}"
1320 << dict << QStringLiteral("alpha &amp; beta & me") << NoError;
1321
1322 // Test that joining with unsafe joiners don't result in unsafe strings
1323 // (#11377)
1324 dict.insert(QStringLiteral("var"), QStringLiteral(" & "));
1325 QTest::newRow("join05") << "{{ a|join:var }}" << dict
1326 << QStringLiteral("alpha &amp; beta &amp; me")
1327 << NoError;
1328 dict.insert(QStringLiteral("var"), Cutelee::markSafe(QStringLiteral(" & ")));
1329 QTest::newRow("join06") << "{{ a|join:var }}" << dict
1330 << QStringLiteral("alpha & beta &amp; me") << NoError;
1331 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("Alpha"),
1332 QStringLiteral("Beta & Me")});
1333 dict.insert(QStringLiteral("var"), QStringLiteral(" & "));
1334 QTest::newRow("join07") << "{{ a|join:var|lower }}" << dict
1335 << QStringLiteral("alpha &amp; beta &amp; me")
1336 << NoError;
1337
1338 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("Alpha"),
1339 QStringLiteral("Beta & Me")});
1340 dict.insert(QStringLiteral("var"), Cutelee::markSafe(QStringLiteral(" & ")));
1341 QTest::newRow("join08") << "{{ a|join:var|lower }}" << dict
1342 << QStringLiteral("alpha & beta &amp; me") << NoError;
1343
1344 // arguments to filters are intended to be used unescaped.
1345 // dict.clear();
1346 // dict.insert( QStringLiteral("a"), QVariantList() <<
1347 // QString::fromLatin1( "alpha" ) << QString::fromLatin1( "beta & me" ) );
1348 // dict.insert( QStringLiteral("var"), QStringLiteral(" & ") );
1349 //
1350 // QTest::newRow( "join05" ) << QString::fromLatin1( "{{ a|join:var }}" )
1351 // <<
1352 // dict << QString::fromLatin1( "alpha &amp; beta &amp; me" ) << NoError;
1353 //
1354 // dict.clear();
1355 // dict.insert( QStringLiteral("a"), QVariantList() <<
1356 // QString::fromLatin1( "alpha" ) << QString::fromLatin1( "beta & me" ) );
1357 // dict.insert( QStringLiteral("var"), QVariant::fromValue( markSafe(
1358 // QString::fromLatin1( " & " ) ) ) );
1359 //
1360 // QTest::newRow( "join06" ) << QString::fromLatin1( "{{ a|join:var }}" )
1361 // <<
1362 // dict << QString::fromLatin1( "alpha & beta &amp; me" ) << NoError;
1363 //
1364 // dict.clear();
1365 // dict.insert( QStringLiteral("a"), QVariantList() <<
1366 // QString::fromLatin1( "Alpha" ) << QString::fromLatin1( "Beta & me" ) );
1367 // dict.insert( QStringLiteral("var"), QStringLiteral(" & ") );
1368 //
1369 // QTest::newRow( "join07" ) << QString::fromLatin1( "{{ a|join:var|lower
1370 // }}" ) << dict << QString::fromLatin1( "alpha &amp; beta &amp; me" ) <<
1371 // NoError;
1372 //
1373 // dict.clear();
1374 // dict.insert( QStringLiteral("a"), QVariantList() <<
1375 // QString::fromLatin1( "Alpha" ) << QString::fromLatin1( "Beta & me" ) );
1376 // dict.insert( QStringLiteral("var"), QVariant::fromValue( markSafe(
1377 // QString::fromLatin1( " & " ) ) ) );
1378 //
1379 // QTest::newRow( "join08" ) << QString::fromLatin1( "{{ a|join:var|lower
1380 // }}" ) << dict << QString::fromLatin1( "alpha & beta &amp; me" ) <<
1381 // NoError;
1382
1383 dict.clear();
1384
1385 QVariantList mapList;
1386 const auto cities
1387 = QStringList{QStringLiteral("London"), QStringLiteral("Berlin"),
1388 QStringLiteral("Paris"), QStringLiteral("Dublin")};
1389 Q_FOREACH (const QString &city, cities) {
1390 QVariantHash map;
1391 map.insert(QStringLiteral("city"), city);
1392 mapList << map;
1393 }
1394
1395 dict.insert(QStringLiteral("mapList"), mapList);
1396
1397 QTest::newRow("dictsort01")
1398 << "{% with mapList|dictsort:'city' as result %}{% for item in result "
1399 "%}{{ item.city }},{% endfor %}{% endwith %}"
1400 << dict << "Berlin,Dublin,London,Paris," << NoError;
1401
1402 {
1403 // Test duplication works
1404 QVariantHash map;
1405 map.insert(QStringLiteral("city"), QStringLiteral("Berlin"));
1406 mapList << map;
1407 }
1408 dict.insert(QStringLiteral("mapList"), mapList);
1409
1410 QTest::newRow("dictsort02")
1411 << "{% with mapList|dictsort:'city' as result %}{% for item in result "
1412 "%}{{ item.city }},{% endfor %}{% endwith %}"
1413 << dict << "Berlin,Berlin,Dublin,London,Paris," << NoError;
1414
1415 dict.clear();
1416
1417 QVariantList listList;
1418
1419 const auto countries
1420 = QStringList{QStringLiteral("England"), QStringLiteral("Germany"),
1421 QStringLiteral("France"), QStringLiteral("Ireland")};
1422
1423 const auto languages
1424 = QStringList{QStringLiteral("English"), QStringLiteral("German"),
1425 QStringLiteral("French"), QStringLiteral("Irish")};
1426
1427 for (auto i = 0; i < cities.size(); ++i) {
1428 listList << QVariant(
1429 QVariantList{cities.at(i), countries.at(i), languages.at(i)});
1430 }
1431
1432 dict.insert(QStringLiteral("listList"), listList);
1433
1434 QTest::newRow("dictsort03")
1435 << "{% with listList|dictsort:'0' as result %}{% for item in result "
1436 "%}{{ "
1437 "item.0 }};{{ item.1 }};{{ item.2 }},{% endfor %}{% endwith %}"
1438 << dict
1439 << "Berlin;Germany;German,Dublin;Ireland;Irish,London;England;"
1440 "English,Paris;France;French,"
1441 << NoError;
1442
1443 QTest::newRow("dictsort04")
1444 << "{% with listList|dictsort:'1' as result %}{% for item in result "
1445 "%}{{ "
1446 "item.0 }};{{ item.1 }};{{ item.2 }},{% endfor %}{% endwith %}"
1447 << dict
1448 << "London;England;English,Paris;France;French,Berlin;Germany;"
1449 "German,Dublin;Ireland;Irish,"
1450 << NoError;
1451}
1452
1453void TestFilters::testLogicFilters_data()
1454{
1455 QTest::addColumn<QString>("input");
1456 QTest::addColumn<Dict>("dict");
1457 QTest::addColumn<QString>("output");
1458 QTest::addColumn<Cutelee::Error>("error");
1459
1460 Dict dict;
1461
1462 // Literal string arguments to the default filter are always treated as
1463 // safe strings, regardless of the auto-escaping state.
1464
1465 // Note: we have to use {"a": ""} here, otherwise the invalid template
1466 // variable string interferes with the test result.
1467
1468 dict.insert(QStringLiteral("a"), QStringLiteral(""));
1469
1470 QTest::newRow("filter-default01")
1471 << "{{ a|default:\"x<\" }}" << dict << QStringLiteral("x<") << NoError;
1472 QTest::newRow("filter-default02")
1473 << "{% autoescape off %}{{ a|default:\"x<\" }}{% endautoescape %}" << dict
1474 << QStringLiteral("x<") << NoError;
1475
1476 dict.clear();
1477 dict.insert(QStringLiteral("a"),
1478 QVariant::fromValue(markSafe(QStringLiteral("x>"))));
1479
1480 QTest::newRow("filter-default03")
1481 << "{{ a|default:\"x<\" }}" << dict << QStringLiteral("x>") << NoError;
1482 QTest::newRow("filter-default04")
1483 << "{% autoescape off %}{{ a|default:\"x<\" }}{% endautoescape %}" << dict
1484 << QStringLiteral("x>") << NoError;
1485
1486 dict.clear();
1487 dict.insert(QStringLiteral("a"), QVariant());
1488
1489 QTest::newRow("filter-default_if_none01")
1490 << "{{ a|default:\"x<\" }}" << dict << QStringLiteral("x<") << NoError;
1491 QTest::newRow("filter-default_if_none02")
1492 << "{% autoescape off %}{{ a|default:\"x<\" }}{% endautoescape %}" << dict
1493 << QStringLiteral("x<") << NoError;
1494}
1495
1496void TestFilters::testMiscFilters_data()
1497{
1498 QTest::addColumn<QString>("input");
1499 QTest::addColumn<Dict>("dict");
1500 QTest::addColumn<QString>("output");
1501 QTest::addColumn<Cutelee::Error>("error");
1502
1503 Dict dict;
1504
1505 //
1506 // // {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>")
1507 // QTest::newRow( "filter-phone2numeric01") << QString::fromLatin1( "{{
1508 // a|phone2numeric }} {{ b|phone2numeric }}" ) << dict <<
1509 // QString::fromLatin1( "&lt;1-800-2255-63&gt; <1-800-2255-63>" ) <<
1510 // NoError;
1511 //
1512 // // {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>")
1513 // QTest::newRow( "filter-phone2numeric02") << QString::fromLatin1( "{%
1514 // autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{%
1515 // endautoescape %}" ) << dict << QString::fromLatin1( "<1-800-2255-63>
1516 // <1-800-2255-63>" ) << NoError;
1517 //
1518 // Chaining a bunch of safeness-preserving filters should not alter
1519 // the safe status either way.
1520
1521 dict.insert(QStringLiteral("a"), QStringLiteral("a < b"));
1522 dict.insert(QStringLiteral("b"),
1523 QVariant::fromValue(markSafe(QStringLiteral("a < b"))));
1524
1525 QTest::newRow("chaining01")
1526 << "{{ a|capfirst|center:\"7\" }}.{{ b|capfirst|center:\"7\" }}" << dict
1527 << QStringLiteral(" A &lt; b . A < b ") << NoError;
1528 QTest::newRow("chaining02")
1529 << "{% autoescape off %}{{ a|capfirst|center:\"7\" }}.{{ "
1530 "b|capfirst|center:\"7\" }}{% endautoescape %}"
1531 << dict << QStringLiteral(" A < b . A < b ") << NoError;
1532
1533 // Using a filter that forces a string back to unsafe:
1534
1535 QTest::newRow("chaining03")
1536 << "{{ a|cut:\"b\"|capfirst }}.{{ b|cut:\"b\"|capfirst }}" << dict
1537 << QStringLiteral("A &lt; .A < ") << NoError;
1538 QTest::newRow("chaining04")
1539 << "{% autoescape off %}{{ a|cut:\"b\"|capfirst }}.{{ "
1540 "b|cut:\"b\"|capfirst }}{% endautoescape %}"
1541 << dict << QStringLiteral("A < .A < ") << NoError;
1542
1543 dict.clear();
1544 dict.insert(QStringLiteral("a"), QStringLiteral("a < b"));
1545
1546 // Using a filter that forces safeness does not lead to double-escaping
1547
1548 QTest::newRow("chaining05") << QStringLiteral("{{ a|escape|capfirst }}")
1549 << dict << QStringLiteral("A &lt; b") << NoError;
1550 QTest::newRow("chaining06") << QStringLiteral(
1551 "{% autoescape off %}{{ a|escape|capfirst }}{% endautoescape %}")
1552 << dict << QStringLiteral("A &lt; b") << NoError;
1553
1554 // Force to safe, then back (also showing why using force_escape too
1555 // early in a chain can lead to unexpected results).
1556
1557 QTest::newRow("chaining07") << "{{ a|force_escape|cut:\";\" }}" << dict
1558 << QStringLiteral("a &amp;lt b") << NoError;
1559 QTest::newRow("chaining08")
1560 << "{% autoescape off %}{{ a|force_escape|cut:\";\" }}{% endautoescape "
1561 "%}"
1562 << dict << QStringLiteral("a &lt b") << NoError;
1563 QTest::newRow("chaining09") << "{{ a|cut:\";\"|force_escape }}" << dict
1564 << QStringLiteral("a &lt; b") << NoError;
1565 QTest::newRow("chaining10")
1566 << "{% autoescape off %}{{ a|cut:\";\"|force_escape }}{% endautoescape "
1567 "%}"
1568 << dict << QStringLiteral("a &lt; b") << NoError;
1569 QTest::newRow("chaining11")
1570 << "{{ a|cut:\"b\"|safe }}" << dict << QStringLiteral("a < ") << NoError;
1571 QTest::newRow("chaining12")
1572 << "{% autoescape off %}{{ a|cut:\"b\"|safe }}{% endautoescape %}" << dict
1573 << QStringLiteral("a < ") << NoError;
1574 QTest::newRow("chaining13") << QStringLiteral("{{ a|safe|force_escape }}")
1575 << dict << QStringLiteral("a &lt; b") << NoError;
1576 QTest::newRow("chaining14") << QStringLiteral(
1577 "{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}")
1578 << dict << QStringLiteral("a &lt; b") << NoError;
1579
1580 // // Filters decorated with stringfilter still respect is_safe.
1581 //
1582 // // {"unsafe": UnsafeClass()
1583 // QTest::newRow( "autoescape-stringfilter01") << QString::fromLatin1( "{{
1584 // unsafe|capfirst }}" ) << dict << QString::fromLatin1( "You &amp; me" )
1585 // <<
1586 // NoError;
1587 //
1588 // // {"unsafe": UnsafeClass()
1589 // QTest::newRow( "autoescape-stringfilter02") << QString::fromLatin1( "{%
1590 // autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}" ) << dict <<
1591 // QString::fromLatin1( "You & me" ) << NoError;
1592 //
1593 // // {"safe": SafeClass()
1594 // QTest::newRow( "autoescape-stringfilter03") << QString::fromLatin1( "{{
1595 // safe|capfirst }}" ) << dict << QString::fromLatin1( "You &gt; me" ) <<
1596 // NoError;
1597 //
1598 // // {"safe": SafeClass()
1599 // QTest::newRow( "autoescape-stringfilter04") << QString::fromLatin1( "{%
1600 // autoescape off %}{{ safe|capfirst }}{% endautoescape %}" ) << dict <<
1601 // QString::fromLatin1( "You &gt; me" ) << NoError;
1602 //
1603}
1604
1605void TestFilters::testIntegerFilters_data()
1606{
1607 QTest::addColumn<QString>("input");
1608 QTest::addColumn<Dict>("dict");
1609 QTest::addColumn<QString>("output");
1610 QTest::addColumn<Cutelee::Error>("error");
1611
1612 Dict dict;
1613
1614 dict.insert(QStringLiteral("i"), 2000);
1615
1616 QTest::newRow("add01") << QStringLiteral("{{ i|add:5 }}") << dict
1617 << QStringLiteral("2005") << NoError;
1618 QTest::newRow("add02") << QStringLiteral("{{ i|add:\"napis\" }}") << dict
1619 << QStringLiteral("2000") << NoError;
1620
1621 dict.clear();
1622 dict.insert(QStringLiteral("i"), QStringLiteral("not_an_int"));
1623
1624 QTest::newRow("add03") << QStringLiteral("{{ i|add:16 }}") << dict
1625 << QStringLiteral("not_an_int") << NoError;
1626 QTest::newRow("add04") << QStringLiteral("{{ i|add:\"16\" }}") << dict
1627 << QStringLiteral("not_an_int16") << NoError;
1628
1629 dict.clear();
1630 dict.insert(QStringLiteral("l1"), QVariantList{1, 2});
1631 dict.insert(QStringLiteral("l2"), QVariantList{3, 4});
1632
1633 QTest::newRow("add05") << QStringLiteral("{{ l1|add:l2 }}") << dict
1634 << QStringLiteral("[1, 2, 3, 4]") << NoError;
1635 // QTest::newRow( "add06" ) << QString::fromLatin1( "{{ t1|add:t2 }}" ) <<
1636 // dict << QString::fromLatin1( "2005" ) << NoError;
1637
1638 // QTest::newRow( "add07" ) << QString::fromLatin1( "{{ d|add:t }}" ) <<
1639 // dict
1640 // << QString::fromLatin1( "2005" ) << NoError;
1641
1642 QTest::newRow("add08") << QStringLiteral("{{ 1|add:2 }}") << dict
1643 << QStringLiteral("3") << NoError;
1644
1645 QTest::newRow("filter-getdigit01") << QStringLiteral("{{ 123|get_digit:1 }}")
1646 << dict << QStringLiteral("3") << NoError;
1647 QTest::newRow("filter-getdigit02") << QStringLiteral("{{ 123|get_digit:2 }}")
1648 << dict << QStringLiteral("2") << NoError;
1649 QTest::newRow("filter-getdigit03") << QStringLiteral("{{ 123|get_digit:3 }}")
1650 << dict << QStringLiteral("1") << NoError;
1651 QTest::newRow("filter-getdigit04")
1652 << QStringLiteral("{{ 123|get_digit:4 }}") << dict
1653 << QStringLiteral("123") << NoError;
1654}
1655
1656QTEST_MAIN(TestFilters)
1657#include "testfilters.moc"
1658
1659#endif
Cutelee::Engine is the main entry point for creating Cutelee Templates.
Definition engine.h:121
void setPluginPaths(const QStringList &dirs)
Definition engine.cpp:87
void addTemplateLoader(std::shared_ptr< AbstractTemplateLoader > loader)
Definition engine.cpp:68
The InMemoryTemplateLoader loads Templates set dynamically in memory.
The Cutelee namespace holds all public Cutelee API.
Definition Mainpage.dox:8
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Definition util.cpp:90
QString applicationDirPath()
QDateTime currentDateTimeUtc()
QString path() const const
QDir absoluteDir() const const
void clear()
iterator insert(const Key &key, const T &value)
Q_OBJECTQ_OBJECT
Q_SLOTSQ_SLOTS
QVariant fromValue(const T &value)
Utility functions used throughout Cutelee.