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