File indexing completed on 2024-06-09 03:58:20
0001 /* 0002 This file is part of the KTextTemplate library 0003 0004 SPDX-FileCopyrightText: 2009, 2010 Stephen Kelly <steveire@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.1-or-later 0007 0008 */ 0009 0010 #ifndef FILTERSTEST_H 0011 #define FILTERSTEST_H 0012 0013 #include <QDebug> 0014 #include <QDir> 0015 #include <QFileInfo> 0016 #include <QTest> 0017 0018 #include "context.h" 0019 #include "engine.h" 0020 #include "ktexttemplate_paths.h" 0021 #include "template.h" 0022 #include <util.h> 0023 0024 using Dict = QHash<QString, QVariant>; 0025 0026 Q_DECLARE_METATYPE(KTextTemplate::Error) 0027 0028 using namespace KTextTemplate; 0029 0030 class TestFilters : public QObject 0031 { 0032 Q_OBJECT 0033 0034 private Q_SLOTS: 0035 void initTestCase(); 0036 void cleanupTestCase(); 0037 0038 void testDateBasedFilters_data(); 0039 void testDateBasedFilters() 0040 { 0041 doTest(); 0042 } 0043 0044 void testStringFilters_data(); 0045 void testStringFilters() 0046 { 0047 doTest(); 0048 } 0049 0050 void testListFilters_data(); 0051 void testListFilters() 0052 { 0053 doTest(); 0054 } 0055 0056 void testLogicFilters_data(); 0057 void testLogicFilters() 0058 { 0059 doTest(); 0060 } 0061 0062 void testMiscFilters_data(); 0063 void testMiscFilters() 0064 { 0065 doTest(); 0066 } 0067 0068 void testIntegerFilters_data(); 0069 void testIntegerFilters() 0070 { 0071 doTest(); 0072 } 0073 0074 private: 0075 void doTest(); 0076 0077 QSharedPointer<InMemoryTemplateLoader> loader; 0078 Engine *m_engine = nullptr; 0079 }; 0080 0081 void TestFilters::initTestCase() 0082 { 0083 m_engine = new Engine(this); 0084 0085 loader = QSharedPointer<InMemoryTemplateLoader>(new InMemoryTemplateLoader()); 0086 m_engine->addTemplateLoader(loader); 0087 0088 auto appDirPath = QFileInfo(QCoreApplication::applicationDirPath()).absoluteDir().path(); 0089 m_engine->setPluginPaths({ 0090 QStringLiteral(KTEXTTEMPLATE_PLUGIN_PATH), 0091 appDirPath + QStringLiteral("/tests/") // For testtags.qs 0092 }); 0093 } 0094 0095 void TestFilters::cleanupTestCase() 0096 { 0097 delete m_engine; 0098 } 0099 0100 void TestFilters::doTest() 0101 { 0102 QFETCH(QString, input); 0103 QFETCH(Dict, dict); 0104 QFETCH(QString, output); 0105 QFETCH(KTextTemplate::Error, error); 0106 0107 auto t = m_engine->newTemplate(input, QLatin1String(QTest::currentDataTag())); 0108 0109 Context context(dict); 0110 0111 auto result = t->render(&context); 0112 0113 if (t->error() != NoError) { 0114 if (t->error() != error) 0115 qDebug() << t->errorString(); 0116 QCOMPARE(t->error(), error); 0117 return; 0118 } 0119 0120 // Didn't catch any errors, so make sure I didn't expect any. 0121 QCOMPARE(NoError, error); 0122 0123 QCOMPARE(t->error(), NoError); 0124 0125 QCOMPARE(result, output); 0126 } 0127 0128 void TestFilters::testDateBasedFilters_data() 0129 { 0130 QTest::addColumn<QString>("input"); 0131 QTest::addColumn<Dict>("dict"); 0132 QTest::addColumn<QString>("output"); 0133 QTest::addColumn<KTextTemplate::Error>("error"); 0134 0135 Dict dict; 0136 auto now = QDateTime::currentDateTimeUtc(); 0137 0138 dict.insert(QStringLiteral("a"), now.addSecs(-70)); 0139 0140 QTest::newRow("filter-timesince01") << QStringLiteral("{{ a|timesince }}") << dict << QStringLiteral("1 minute") << NoError; 0141 0142 dict.clear(); 0143 0144 dict.insert(QStringLiteral("a"), now.addDays(-1).addSecs(-60)); 0145 0146 QTest::newRow("filter-timesince02") << QStringLiteral("{{ a|timesince }}") << dict << QStringLiteral("1 day") << NoError; 0147 0148 dict.clear(); 0149 0150 dict.insert(QStringLiteral("a"), now.addSecs(-1 * 60 * 60).addSecs(-1 * 25 * 60).addSecs(-1 * 10)); 0151 QTest::newRow("filter-timesince03") << QStringLiteral("{{ a|timesince }}") << dict << QStringLiteral("1 hour, 25 minutes") << NoError; 0152 0153 dict.clear(); 0154 0155 // Compare to a given parameter 0156 0157 dict.insert(QStringLiteral("a"), now.addDays(-2)); 0158 dict.insert(QStringLiteral("b"), now.addDays(-1)); 0159 0160 QTest::newRow("filter-timesince04") << QStringLiteral("{{ a|timesince:b }}") << dict << QStringLiteral("1 day") << NoError; 0161 0162 dict.clear(); 0163 0164 dict.insert(QStringLiteral("a"), now.addDays(-2).addSecs(-60)); 0165 dict.insert(QStringLiteral("b"), now.addDays(-2)); 0166 0167 QTest::newRow("filter-timesince05") << QStringLiteral("{{ a|timesince:b }}") << dict << QStringLiteral("1 minute") << NoError; 0168 0169 dict.clear(); 0170 0171 // Check that timezone is respected 0172 0173 // {"a":now_tz - timedelta(hours=8), "b":now_tz 0174 // QTest::newRow( "filter-timesince06" ) << QString::fromLatin1( "{{ 0175 // a|timesince:b }}" ) << dict << QString::fromLatin1( "8 hours" ) << 0176 // NoError; 0177 0178 dict.insert(QStringLiteral("earlier"), now.addDays(-7)); 0179 QTest::newRow("filter-timesince07") << QStringLiteral("{{ earlier|timesince }}") << dict << QStringLiteral("1 week") << NoError; 0180 0181 dict.clear(); 0182 0183 dict.insert(QStringLiteral("now"), now); 0184 dict.insert(QStringLiteral("earlier"), now.addDays(-7)); 0185 0186 QTest::newRow("filter-timesince08") << QStringLiteral("{{ earlier|timesince:now }}") << dict << QStringLiteral("1 week") << NoError; 0187 0188 dict.clear(); 0189 0190 dict.insert(QStringLiteral("later"), now.addDays(7)); 0191 0192 QTest::newRow("filter-timesince09") << QStringLiteral("{{ later|timesince }}") << dict << QStringLiteral("0 minutes") << NoError; 0193 0194 dict.clear(); 0195 0196 dict.insert(QStringLiteral("now"), now); 0197 dict.insert(QStringLiteral("later"), now.addDays(7)); 0198 0199 QTest::newRow("filter-timesince10") << QStringLiteral("{{ later|timesince:now }}") << dict << QStringLiteral("0 minutes") << NoError; 0200 0201 // Ensures that differing timezones are calculated correctly 0202 0203 // {"a": now 0204 // QTest::newRow( "filter-timesince11" ) << QString::fromLatin1( "{{ 0205 // a|timesince }}" ) << dict << QString::fromLatin1( "0 minutes" ) << 0206 // NoError; 0207 0208 // {"a": now_tz 0209 // QTest::newRow( "filter-timesince12" ) << QString::fromLatin1( "{{ 0210 // a|timesince }}" ) << dict << QString::fromLatin1( "0 minutes" ) << 0211 // NoError; 0212 0213 // {"a": now_tz_i 0214 // QTest::newRow( "filter-timesince13" ) << QString::fromLatin1( "{{ 0215 // a|timesince }}" ) << dict << QString::fromLatin1( "0 minutes" ) << 0216 // NoError; 0217 0218 // {"a": now_tz, "b": now_tz_i 0219 // QTest::newRow( "filter-timesince14" ) << QString::fromLatin1( "{{ 0220 // a|timesince:b }}" ) << dict << QString::fromLatin1( "0 minutes" ) << 0221 // NoError; 0222 0223 // {"a": now, "b": now_tz_i 0224 // QTest::newRow( "filter-timesince15" ) << QString::fromLatin1( "{{ 0225 // a|timesince:b }}" ) << dict << QString() << NoError; 0226 0227 // {"a": now_tz_i, "b": now 0228 // QTest::newRow( "filter-timesince16" ) << QString::fromLatin1( "{{ 0229 // a|timesince:b }}" ) << dict << QString() << NoError; 0230 0231 dict.clear(); 0232 0233 dict.insert(QStringLiteral("a"), now); 0234 dict.insert(QStringLiteral("b"), now); 0235 0236 QTest::newRow("filter-timesince17") << QStringLiteral("{{ a|timesince:b }}") << dict << QStringLiteral("0 minutes") << NoError; 0237 0238 dict.clear(); 0239 0240 dict.insert(QStringLiteral("a"), now); 0241 dict.insert(QStringLiteral("b"), now.addDays(1)); 0242 0243 QTest::newRow("filter-timesince18") << QStringLiteral("{{ a|timesince:b }}") << dict << QStringLiteral("1 day") << NoError; 0244 0245 dict.clear(); 0246 QTest::newRow("filter-timesince19") << QStringLiteral("{{xx|timesince}}") << dict << QStringLiteral("") << NoError; 0247 QTest::newRow("filter-timesince20") << QStringLiteral("{{|timesince}}") << dict << QStringLiteral("") << NoError; 0248 0249 // Default compare with datetime.now() 0250 0251 dict.clear(); 0252 dict.insert(QStringLiteral("a"), now.addSecs(130)); 0253 0254 QTest::newRow("filter-timeuntil01") << QStringLiteral("{{ a|timeuntil }}") << dict << QStringLiteral("2 minutes") << NoError; 0255 0256 dict.clear(); 0257 dict.insert(QStringLiteral("a"), now.addDays(1).addSecs(10)); 0258 0259 QTest::newRow("filter-timeuntil02") << QStringLiteral("{{ a|timeuntil }}") << dict << QStringLiteral("1 day") << NoError; 0260 0261 dict.clear(); 0262 dict.insert(QStringLiteral("a"), now.addSecs(60 * 60 * 8).addSecs(610)); 0263 0264 QTest::newRow("filter-timeuntil03") << QStringLiteral("{{ a|timeuntil }}") << dict << QStringLiteral("8 hours, 10 minutes") << NoError; 0265 0266 // Compare to a given parameter 0267 0268 dict.clear(); 0269 dict.insert(QStringLiteral("a"), now.addDays(-1)); 0270 dict.insert(QStringLiteral("b"), now.addDays(-2)); 0271 0272 QTest::newRow("filter-timeuntil04") << QStringLiteral("{{ a|timeuntil:b }}") << dict << QStringLiteral("1 day") << NoError; 0273 0274 dict.clear(); 0275 dict.insert(QStringLiteral("a"), now.addDays(-1)); 0276 dict.insert(QStringLiteral("b"), now.addDays(-1).addSecs(-60)); 0277 0278 QTest::newRow("filter-timeuntil05") << QStringLiteral("{{ a|timeuntil:b }}") << dict << QStringLiteral("1 minute") << NoError; 0279 0280 dict.clear(); 0281 dict.insert(QStringLiteral("earlier"), now.addDays(-7)); 0282 0283 QTest::newRow("filter-timeuntil06") << QStringLiteral("{{ earlier|timeuntil }}") << dict << QStringLiteral("0 minutes") << NoError; 0284 0285 dict.clear(); 0286 dict.insert(QStringLiteral("now"), now); 0287 dict.insert(QStringLiteral("earlier"), now.addDays(-7)); 0288 0289 QTest::newRow("filter-timeuntil07") << QStringLiteral("{{ earlier|timeuntil:now }}") << dict << QStringLiteral("0 minutes") << NoError; 0290 0291 dict.clear(); 0292 dict.insert(QStringLiteral("later"), now.addDays(7).addSecs(5)); 0293 0294 QTest::newRow("filter-timeuntil08") << QStringLiteral("{{ later|timeuntil }}") << dict << QStringLiteral("1 week") << NoError; 0295 0296 dict.clear(); 0297 dict.insert(QStringLiteral("now"), now); 0298 dict.insert(QStringLiteral("later"), now.addDays(7)); 0299 0300 QTest::newRow("filter-timeuntil09") << QStringLiteral("{{ later|timeuntil:now }}") << dict << QStringLiteral("1 week") << NoError; 0301 0302 // Ensures that differing timezones are calculated correctly 0303 // 0304 // // {"a": now_tz_i 0305 // QTest::newRow( "filter-timeuntil10" ) << QString::fromLatin1( "{{ 0306 // a|timeuntil }}" ) << dict << QString::fromLatin1( "0 minutes" ) << 0307 // NoError; 0308 // 0309 // // {"a": now_tz_i, "b": now_tz 0310 // QTest::newRow( "filter-timeuntil11" ) << QString::fromLatin1( "{{ 0311 // a|timeuntil:b }}" ) << dict << QString::fromLatin1( "0 minutes" ) << 0312 // NoError; 0313 0314 dict.clear(); 0315 dict.insert(QStringLiteral("a"), now); 0316 dict.insert(QStringLiteral("b"), now); 0317 QTest::newRow("filter-timeuntil12") << QStringLiteral("{{ a|timeuntil:b }}") << dict << QStringLiteral("0 minutes") << NoError; 0318 0319 dict.clear(); 0320 dict.insert(QStringLiteral("a"), now); 0321 dict.insert(QStringLiteral("b"), now.addDays(-1)); 0322 0323 QTest::newRow("filter-timeuntil13") << QStringLiteral("{{ a|timeuntil:b }}") << dict << QStringLiteral("1 day") << NoError; 0324 0325 dict.clear(); 0326 QTest::newRow("filter-timeuntil14") << QStringLiteral("{{xx|timeuntil}}") << dict << QStringLiteral("") << NoError; 0327 QTest::newRow("filter-timeuntil15") << QStringLiteral("{{|timeuntil}}") << dict << QStringLiteral("") << NoError; 0328 0329 QDateTime d(QDate(2008, 1, 1), {}); 0330 0331 dict.clear(); 0332 dict.insert(QStringLiteral("d"), d); 0333 0334 QTest::newRow("date01") << "{{ d|date:\"MM\" }}" << dict << QStringLiteral("01") << NoError; 0335 QTest::newRow("date02") << QStringLiteral("{{ d|date }}") << dict << d.toString(QStringLiteral("MMM. d, yyyy")) << NoError; 0336 0337 dict.clear(); 0338 dict.insert(QStringLiteral("d"), QStringLiteral("fail_string")); 0339 QTest::newRow("date03") << "{{ d|date:\"MM\" }}" << dict << QString() << NoError; 0340 } 0341 0342 void TestFilters::testStringFilters_data() 0343 { 0344 QTest::addColumn<QString>("input"); 0345 QTest::addColumn<Dict>("dict"); 0346 QTest::addColumn<QString>("output"); 0347 QTest::addColumn<KTextTemplate::Error>("error"); 0348 0349 Dict dict; 0350 0351 dict.clear(); 0352 dict.insert(QStringLiteral("a"), QStringLiteral("<a>\'")); 0353 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("<a>\'")))); 0354 0355 QTest::newRow("filter-addslash01") << QStringLiteral( 0356 "{% autoescape off %}{{ a|addslashes }} {{ " 0357 "b|addslashes }}{% endautoescape %}") 0358 << dict << R"(<a>\' <a>\')" << NoError; 0359 0360 dict.clear(); 0361 dict.insert(QStringLiteral("a"), QStringLiteral("<a>\'")); 0362 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("<a>\'")))); 0363 0364 QTest::newRow("filter-addslash02") << QStringLiteral("{{ a|addslashes }} {{ b|addslashes }}") << dict << R"(<a>\' <a>\')" << NoError; 0365 0366 dict.clear(); 0367 dict.insert(QStringLiteral("a"), QStringLiteral("fred>")); 0368 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("fred>")))); 0369 0370 QTest::newRow("filter-capfirst01") << QStringLiteral( 0371 "{% autoescape off %}{{ a|capfirst }} {{ b|capfirst " 0372 "}}{% endautoescape %}") << dict 0373 << QStringLiteral("Fred> Fred>") << NoError; 0374 0375 dict.clear(); 0376 dict.insert(QStringLiteral("a"), QStringLiteral("fred>")); 0377 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("fred>")))); 0378 0379 QTest::newRow("filter-capfirst02") << QStringLiteral("{{ a|capfirst }} {{ b|capfirst }}") << dict << QStringLiteral("Fred> Fred>") << NoError; 0380 0381 // Note that applying fix_ampsersands in autoescape mode leads to 0382 // double escaping. 0383 0384 dict.clear(); 0385 dict.insert(QStringLiteral("a"), QStringLiteral("a&b")); 0386 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a&b")))); 0387 0388 QTest::newRow("filter-fix_ampersands01") << QStringLiteral( 0389 "{% autoescape off %}{{ a|fix_ampersands }} {{ " 0390 "b|fix_ampersands }}{% endautoescape %}") 0391 << dict << QStringLiteral("a&b a&b") << NoError; 0392 0393 dict.clear(); 0394 dict.insert(QStringLiteral("a"), QStringLiteral("a&b")); 0395 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a&b")))); 0396 0397 QTest::newRow("filter-fix_ampersands02") << QStringLiteral("{{ a|fix_ampersands }} {{ b|fix_ampersands }}") << dict << QStringLiteral("a&amp;b a&b") 0398 << NoError; 0399 0400 dict.clear(); 0401 dict.insert(QStringLiteral("a"), QStringLiteral("1.42")); 0402 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("1.42")))); 0403 0404 QTest::newRow("filter-floatformat01") << QStringLiteral( 0405 "{% autoescape off %}{{ a|floatformat }} {{ " 0406 "b|floatformat }}{% endautoescape %}") 0407 << dict << QStringLiteral("1.4 1.4") << NoError; 0408 0409 dict.clear(); 0410 dict.insert(QStringLiteral("a"), QStringLiteral("1.42")); 0411 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("1.42")))); 0412 0413 QTest::newRow("filter-floatformat02") << QStringLiteral("{{ a|floatformat }} {{ b|floatformat }}") << dict << QStringLiteral("1.4 1.4") << NoError; 0414 0415 dict.clear(); 0416 dict.insert(QStringLiteral("a"), double(1234.54321)); 0417 dict.insert(QStringLiteral("b"), int(1234)); 0418 0419 QTest::newRow("filter-floatformat03") << QStringLiteral("{{ a|floatformat }} {{ b|floatformat }}") << dict << QStringLiteral("1234.5 1234.0") << NoError; 0420 QTest::newRow("filter-floatformat04") << QStringLiteral("{{ a|floatformat:2 }} {{ b|floatformat:2 }}") << dict << QStringLiteral("1234.54 1234.00") 0421 << NoError; 0422 QTest::newRow("filter-floatformat04") << QStringLiteral("{{ a|floatformat:0 }} {{ b|floatformat:0 }}") << dict << QStringLiteral("1235 1234") << NoError; 0423 0424 // The contents of "linenumbers" is escaped according to the current 0425 // autoescape setting. 0426 0427 dict.clear(); 0428 dict.insert(QStringLiteral("a"), QStringLiteral("one\n<two>\nthree")); 0429 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("one\n<two>\nthree")))); 0430 0431 QTest::newRow("filter-linenumbers01") << QStringLiteral("{{ a|linenumbers }} {{ b|linenumbers }}") << dict 0432 << "1. one\n2. <two>\n3. three 1. one\n2. <two>\n3. three" << NoError; 0433 0434 dict.clear(); 0435 dict.insert(QStringLiteral("a"), QStringLiteral("one\n<two>\nthree")); 0436 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("one\n<two>\nthree")))); 0437 QTest::newRow("filter-linenumbers02") << QStringLiteral( 0438 "{% autoescape off %}{{ a|linenumbers }} {{ " 0439 "b|linenumbers }}{% endautoescape %}") 0440 << dict << "1. one\n2. <two>\n3. three 1. one\n2. <two>\n3. three" << NoError; 0441 0442 dict.clear(); 0443 dict.insert(QStringLiteral("a"), QStringLiteral("Apple & banana")); 0444 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("Apple & banana")))); 0445 0446 QTest::newRow("filter-lower01") << QStringLiteral("{% autoescape off %}{{ a|lower }} {{ b|lower }}{% endautoescape %}") << dict 0447 << QStringLiteral("apple & banana apple & banana") << NoError; 0448 0449 dict.clear(); 0450 dict.insert(QStringLiteral("a"), QStringLiteral("Apple & banana")); 0451 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("Apple & banana")))); 0452 0453 QTest::newRow("filter-lower02") << QStringLiteral("{{ a|lower }} {{ b|lower }}") << dict << QStringLiteral("apple & banana apple & banana") 0454 << NoError; 0455 0456 // The make_list filter can destroy existing escaping, so the results are 0457 // escaped. 0458 0459 dict.clear(); 0460 dict.insert(QStringLiteral("a"), markSafe(QStringLiteral("&"))); 0461 0462 QTest::newRow("filter-make_list01") << QStringLiteral("{% autoescape off %}{{ a|make_list }}{% endautoescape %}") << dict << "[u\'&\']" << NoError; 0463 QTest::newRow("filter-make_list02") << QStringLiteral("{{ a|make_list }}") << dict << QStringLiteral("[u'&']") << NoError; 0464 0465 QTest::newRow("filter-make_list03") << QStringLiteral( 0466 "{% autoescape off %}{{ a|make_list|stringformat:\"%1\"|safe }}{% " 0467 "endautoescape %}") << dict << QStringLiteral("[u\'&\']") 0468 << NoError; 0469 QTest::newRow("filter-make_list04") << QStringLiteral("{{ a|make_list|stringformat:\"%1\"|safe }}") << dict << QStringLiteral("[u\'&\']") << NoError; 0470 0471 // Running slugify on a pre-escaped string leads to odd behaviour, 0472 // but the result is still safe. 0473 0474 dict.clear(); 0475 dict.insert(QStringLiteral("a"), QStringLiteral("a & b")); 0476 dict.insert(QStringLiteral("b"), markSafe(QStringLiteral("a & b"))); 0477 0478 QTest::newRow("filter-slugify01") << QStringLiteral("{% autoescape off %}{{ a|slugify }} {{ b|slugify }}{% endautoescape %}") << dict 0479 << QStringLiteral("a-b a-amp-b") << NoError; 0480 QTest::newRow("filter-slugify02") << QStringLiteral("{{ a|slugify }} {{ b|slugify }}") << dict << QStringLiteral("a-b a-amp-b") << NoError; 0481 0482 dict.clear(); 0483 dict.insert(QStringLiteral("a"), QStringLiteral("Schöne Grüße")); 0484 0485 QTest::newRow("filter-slugify03") << QStringLiteral("{{ a|slugify }}") << dict << QStringLiteral("schone-grue") << NoError; 0486 0487 dict.clear(); 0488 dict.insert(QStringLiteral("a"), QStringLiteral("testing\r\njavascript \'string\" <b>escaping</b>")); 0489 QTest::newRow("escapejs01") << QStringLiteral("{{ a|escapejs }}") << dict 0490 << "testing\\u000D\\u000Ajavascript \\u0027string\\u0022 " 0491 "\\u003Cb\\u003Eescaping\\u003C/b\\u003E" 0492 << NoError; 0493 QTest::newRow("escapejs02") << QStringLiteral("{% autoescape off %}{{ a|escapejs }}{% endautoescape %}") << dict 0494 << "testing\\u000D\\u000Ajavascript \\u0027string\\u0022 " 0495 "\\u003Cb\\u003Eescaping\\u003C/b\\u003E" 0496 << NoError; 0497 0498 // Notice that escaping is applied *after* any filters, so the string 0499 // formatting here only needs to deal with pre-escaped characters. 0500 0501 dict.clear(); 0502 dict.insert(QStringLiteral("a"), QStringLiteral("a<b")); 0503 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a<b")))); 0504 0505 QTest::newRow("filter-stringformat01") << "{% autoescape off %}.{{ a|stringformat:\"%1\" }}. .{{ " 0506 "b|stringformat:\"%2\" }}.{% endautoescape %}" 0507 << dict << QStringLiteral(".a<b. .a<b.") << NoError; 0508 QTest::newRow("filter-stringformat02") << R"(.{{ a|stringformat:"%1" }}. .{{ b|stringformat:"%2" }}.)" << dict << QStringLiteral(".a<b. .a<b.") 0509 << NoError; 0510 QTest::newRow("filter-stringformat03") << ".{{ a|stringformat:\"foo %1 bar\" }}. .{{ b|stringformat:\"baz %2 " 0511 "bat\" }}." 0512 << dict << QStringLiteral(".foo a<b bar. .baz a<b bat.") << NoError; 0513 0514 dict.clear(); 0515 dict.insert(QStringLiteral("path"), QStringLiteral("www.kde.org")); 0516 QTest::newRow("filter-stringformat04") << "{% with path|stringformat:\"<a href=\\\"%1\\\">%1</a>\"|safe as " 0517 "result %}{{ result }}{% endwith %}" 0518 << dict << "<a href=\"www.kde.org\">www.kde.org</a>" << NoError; 0519 0520 dict.clear(); 0521 dict.insert(QStringLiteral("a"), QStringLiteral("JOE\'S CRAB SHACK")); 0522 QTest::newRow("filter-title01") << "{{ a|title }}" << dict << QStringLiteral("Joe's Crab Shack") << NoError; 0523 0524 dict.clear(); 0525 dict.insert(QStringLiteral("a"), QStringLiteral("555 WEST 53RD STREET")); 0526 QTest::newRow("filter-title02") << "{{ a|title }}" << dict << QStringLiteral("555 West 53rd Street") << NoError; 0527 0528 dict.clear(); 0529 dict.insert(QStringLiteral("a"), QStringLiteral("alpha & bravo")); 0530 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("alpha & bravo")))); 0531 0532 QTest::newRow("filter-truncatewords01") << "{% autoescape off %}{{ a|truncatewords:\"2\" }} {{ " 0533 "b|truncatewords:\"2\"}}{% endautoescape %}" 0534 << dict << QStringLiteral("alpha & ... alpha & ...") << NoError; 0535 0536 QTest::newRow("filter-truncatewords02") << R"({{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}})" << dict 0537 << QStringLiteral("alpha & ... alpha & ...") << NoError; 0538 0539 // The "upper" filter messes up entities (which are case-sensitive), 0540 // so it's not safe for non-escaping purposes. 0541 0542 dict.clear(); 0543 dict.insert(QStringLiteral("a"), QStringLiteral("a & b")); 0544 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a & b")))); 0545 0546 QTest::newRow("filter-upper01") << QStringLiteral("{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}") << dict 0547 << QStringLiteral("A & B A & B") << NoError; 0548 QTest::newRow("filter-upper02") << QStringLiteral("{{ a|upper }} {{ b|upper }}") << dict << QStringLiteral("A & B A &AMP; B") << NoError; 0549 0550 // // {"a": "http://example.com/?x=&y=", "b": 0551 // mark_safe("http://example.com?x=&y=") 0552 // QTest::newRow( "filter-urlize01") << QString::fromLatin1( "{% 0553 // autoescape 0554 // off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}" ) << dict << 0555 // "<a 0556 // href=\"http://example.com/?x=&y=\" 0557 // rel=\"nofollow\">http://example.com/?x=&y=</a> <a 0558 // href=\"http://example.com?x=&y=\" 0559 // rel=\"nofollow\">http://example.com?x=&y=</a>" << NoError; 0560 // 0561 // // {"a": "http://example.com/?x=&y=", "b": 0562 // mark_safe("http://example.com?x=&y=") 0563 // QTest::newRow( "filter-urlize02") << QString::fromLatin1( "{{ a|urlize 0564 // }} 0565 // {{ b|urlize }}" ) << dict << "<a href=\"http://example.com/?x=&y=\" 0566 // rel=\"nofollow\">http://example.com/?x=&y=</a> <a 0567 // href=\"http://example.com?x=&y=\" 0568 // rel=\"nofollow\">http://example.com?x=&y=</a>" << NoError; 0569 // 0570 // // {"a": mark_safe("a & b") 0571 // QTest::newRow( "filter-urlize03") << QString::fromLatin1( "{% 0572 // autoescape 0573 // off %}{{ a|urlize }}{% endautoescape %}" ) << dict << 0574 // QString::fromLatin1( "a & b" ) << NoError; 0575 // 0576 // // {"a": mark_safe("a & b") 0577 // QTest::newRow( "filter-urlize04") << QString::fromLatin1( "{{ a|urlize 0578 // }}" ) << dict << QString::fromLatin1( "a & b" ) << NoError; 0579 // 0580 // // This will lead to a nonsense result, but at least it won't be 0581 // 0582 // // exploitable for XSS purposes when auto-escaping is on. 0583 // 0584 // // {"a": "<script>alert(\"foo\")</script>" 0585 // QTest::newRow( "filter-urlize05") << QString::fromLatin1( "{% 0586 // autoescape 0587 // off %}{{ a|urlize }}{% endautoescape %}" ) << dict << 0588 // "<script>alert(\"foo\")</script>" << NoError; 0589 // 0590 // // {"a": "<script>alert(\"foo\")</script>" 0591 // QTest::newRow( "filter-urlize06") << QString::fromLatin1( "{{ a|urlize 0592 // }}" ) << dict << QString::fromLatin1( 0593 // "<script>alert('foo')</script>" ) << NoError; 0594 // 0595 // // mailto: testing for urlize 0596 // 0597 // // {"a": "Email me at me@example.com" 0598 // QTest::newRow( "filter-urlize07") << QString::fromLatin1( "{{ a|urlize 0599 // }}" ) << dict << "Email me at <a 0600 // href=\"mailto:me@example.com\">me@example.com</a>" << NoError; 0601 // 0602 // // {"a": "Email me at <me@example.com>" 0603 // QTest::newRow( "filter-urlize08") << QString::fromLatin1( "{{ a|urlize 0604 // }}" ) << dict << "Email me at <<a 0605 // href=\"mailto:me@example.com\">me@example.com</a>>" << NoError; 0606 // 0607 // // {"a": "\"Unsafe\" http://example.com/x=&y=", "b": 0608 // mark_safe(""Safe" http://example.com?x=&y=") 0609 // QTest::newRow( "filter-urlizetrunc01") << "{% autoescape off %}{{ 0610 // a|urlizetrunc:\"8\" }} {{ b|urlizetrunc:\"8\" }}{% endautoescape %}" << 0611 // dict << "\"Unsafe\" <a href=\"http://example.com/x=&y=\" 0612 // rel=\"nofollow\">http:...</a> "Safe" <a 0613 // href=\"http://example.com?x=&y=\" rel=\"nofollow\">http:...</a>" << 0614 // NoError; 0615 // 0616 // // {"a": "\"Unsafe\" http://example.com/x=&y=", "b": 0617 // mark_safe(""Safe" http://example.com?x=&y=") 0618 // QTest::newRow( "filter-urlizetrunc02") << "{{ a|urlizetrunc:\"8\" }} {{ 0619 // b|urlizetrunc:\"8\" }}" << dict << ""Unsafe" <a 0620 // href=\"http://example.com/x=&y=\" rel=\"nofollow\">http:...</a> 0621 // "Safe" <a href=\"http://example.com?x=&y=\" 0622 // rel=\"nofollow\">http:...</a>" << NoError; 0623 0624 // // Ensure iriencode keeps safe strings: 0625 // 0626 // // {"url": "?test=1&me=2" 0627 // QTest::newRow( "filter-iriencode01") << QString::fromLatin1( "{{ 0628 // url|iriencode }}" ) << dict << QString::fromLatin1( "?test=1&me=2" 0629 // ) 0630 // << NoError; 0631 // 0632 // // {"url": "?test=1&me=2" 0633 // QTest::newRow( "filter-iriencode02") << QString::fromLatin1( "{% 0634 // autoescape off %}{{ url|iriencode }}{% endautoescape %}" ) << dict << 0635 // QString::fromLatin1( "?test=1&me=2" ) << NoError; 0636 // 0637 // // {"url": mark_safe("?test=1&me=2") 0638 // QTest::newRow( "filter-iriencode03") << QString::fromLatin1( "{{ 0639 // url|iriencode }}" ) << dict << QString::fromLatin1( "?test=1&me=2" ) << 0640 // NoError; 0641 // 0642 // // {"url": mark_safe("?test=1&me=2") 0643 // QTest::newRow( "filter-iriencode04") << QString::fromLatin1( "{% 0644 // autoescape off %}{{ url|iriencode }}{% endautoescape %}" ) << dict << 0645 // QString::fromLatin1( "?test=1&me=2" ) << NoError; 0646 // 0647 dict.clear(); 0648 dict.insert(QStringLiteral("a"), QStringLiteral("a & b")); 0649 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a & b")))); 0650 0651 QTest::newRow("filter-wordcount01") << QStringLiteral( 0652 "{% autoescape off %}{{ a|wordcount }} {{ b|wordcount " 0653 "}}{% endautoescape %}") << dict << QStringLiteral("3 3") 0654 << NoError; 0655 0656 QTest::newRow("filter-wordcount02") << QStringLiteral("{{ a|wordcount }} {{ b|wordcount }}") << dict << QStringLiteral("3 3") << NoError; 0657 0658 dict.clear(); 0659 dict.insert(QStringLiteral("a"), QStringLiteral("a & b")); 0660 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a & b")))); 0661 0662 QTest::newRow("filter-wordwrap01") << QStringLiteral( 0663 "{% autoescape off %}{{ a|wordwrap:3 }} {{ " 0664 "b|wordwrap:3 }}{% endautoescape %}") 0665 << dict << "a &\nb a &\nb" << NoError; 0666 0667 QTest::newRow("filter-wordwrap02") << QStringLiteral("{{ a|wordwrap:3 }} {{ b|wordwrap:3 }}") << dict << "a &\nb a &\nb" << NoError; 0668 0669 dict.clear(); 0670 QTest::newRow("filter-wordwrap03") << QStringLiteral("{{xx|wordwrap}}") << dict << "" << NoError; 0671 0672 QTest::newRow("filter-wordwrap04") << QStringLiteral("{{|wordwrap}}") << dict << "" << NoError; 0673 0674 dict.clear(); 0675 dict.insert(QStringLiteral("a"), QStringLiteral("a&b")); 0676 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a&b")))); 0677 0678 QTest::newRow("filter-ljust01") << "{% autoescape off %}.{{ a|ljust:\"5\" }}. .{{ b|ljust:\"5\" }}.{% " 0679 "endautoescape %}" 0680 << dict << QStringLiteral(".a&b . .a&b .") << NoError; 0681 0682 QTest::newRow("filter-ljust02") << R"(.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.)" << dict << QStringLiteral(".a&b . .a&b .") << NoError; 0683 0684 QTest::newRow("filter-rjust01") << "{% autoescape off %}.{{ a|rjust:\"5\" }}. .{{ b|rjust:\"5\" }}.{% " 0685 "endautoescape %}" 0686 << dict << QStringLiteral(". a&b. . a&b.") << NoError; 0687 0688 QTest::newRow("filter-rjust02") << R"(.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.)" << dict << QStringLiteral(". a&b. . a&b.") << NoError; 0689 0690 QTest::newRow("filter-center01") << "{% autoescape off %}.{{ a|center:\"5\" }}. .{{ b|center:\"5\" " 0691 "}}.{% " 0692 "endautoescape %}" 0693 << dict << QStringLiteral(". a&b . . a&b .") << NoError; 0694 0695 QTest::newRow("filter-center02") << R"(.{{ a|center:"5" }}. .{{ b|center:"5" }}.)" << dict << QStringLiteral(". a&b . . a&b .") << NoError; 0696 0697 dict.clear(); 0698 dict.insert(QStringLiteral("a"), QStringLiteral("x&y")); 0699 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("x&y")))); 0700 0701 QTest::newRow("filter-cut01") << "{% autoescape off %}{{ a|cut:\"x\" }} {{ " 0702 "b|cut:\"x\" }}{% endautoescape %}" 0703 << dict << QStringLiteral("&y &y") << NoError; 0704 QTest::newRow("filter-cut02") << R"({{ a|cut:"x" }} {{ b|cut:"x" }})" << dict << QStringLiteral("&y &y") << NoError; 0705 QTest::newRow("filter-cut03") << "{% autoescape off %}{{ a|cut:\"&\" }} {{ " 0706 "b|cut:\"&\" }}{% endautoescape %}" 0707 << dict << QStringLiteral("xy xamp;y") << NoError; 0708 QTest::newRow("filter-cut04") << R"({{ a|cut:"&" }} {{ b|cut:"&" }})" << dict << QStringLiteral("xy xamp;y") << NoError; 0709 0710 // Passing ";" to cut can break existing HTML entities, so those strings 0711 // are auto-escaped. 0712 0713 QTest::newRow("filter-cut05") << "{% autoescape off %}{{ a|cut:\";\" }} {{ " 0714 "b|cut:\";\" }}{% endautoescape %}" 0715 << dict << QStringLiteral("x&y x&y") << NoError; 0716 QTest::newRow("filter-cut06") << R"({{ a|cut:";" }} {{ b|cut:";" }})" << dict << QStringLiteral("x&y x&ampy") << NoError; 0717 0718 // The "escape" filter works the same whether autoescape is on or off, 0719 // but it has no effect on strings already marked as safe. 0720 0721 dict.clear(); 0722 dict.insert(QStringLiteral("a"), QStringLiteral("x&y")); 0723 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("x&y")))); 0724 0725 QTest::newRow("filter-escape01") << QStringLiteral("{{ a|escape }} {{ b|escape }}") << dict << QStringLiteral("x&y x&y") << NoError; 0726 QTest::newRow("filter-escape02") << QStringLiteral("{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}") << dict 0727 << QStringLiteral("x&y x&y") << NoError; 0728 0729 // It is only applied once, regardless of the number of times it 0730 // appears in a chain. 0731 0732 dict.clear(); 0733 dict.insert(QStringLiteral("a"), QStringLiteral("x&y")); 0734 0735 QTest::newRow("filter-escape03") << QStringLiteral("{% autoescape off %}{{ a|escape|escape }}{% endautoescape %}") << dict << QStringLiteral("x&y") 0736 << NoError; 0737 QTest::newRow("filter-escape04") << QStringLiteral("{{ a|escape|escape }}") << dict << QStringLiteral("x&y") << NoError; 0738 0739 // Force_escape is applied immediately. It can be used to provide 0740 // double-escaping, for example. 0741 0742 QTest::newRow("filter-force-escape01") << QStringLiteral("{% autoescape off %}{{ a|force_escape }}{% endautoescape %}") << dict << QStringLiteral("x&y") 0743 << NoError; 0744 QTest::newRow("filter-force-escape02") << QStringLiteral("{{ a|force_escape }}") << dict << QStringLiteral("x&y") << NoError; 0745 QTest::newRow("filter-force-escape03") << QStringLiteral( 0746 "{% autoescape off %}{{ a|force_escape|force_escape " 0747 "}}{% endautoescape %}") << dict << QStringLiteral("x&amp;y") 0748 << NoError; 0749 QTest::newRow("filter-force-escape04") << QStringLiteral("{{ a|force_escape|force_escape }}") << dict << QStringLiteral("x&amp;y") << NoError; 0750 0751 // Because the result of force_escape is "safe", an additional 0752 // escape filter has no effect. 0753 0754 QTest::newRow("filter-force-escape05") << QStringLiteral("{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}") << dict 0755 << QStringLiteral("x&y") << NoError; 0756 QTest::newRow("filter-force-escape06") << QStringLiteral("{{ a|force_escape|escape }}") << dict << QStringLiteral("x&y") << NoError; 0757 QTest::newRow("filter-force-escape07") << QStringLiteral("{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}") << dict 0758 << QStringLiteral("x&y") << NoError; 0759 QTest::newRow("filter-force-escape08") << QStringLiteral("{{ a|escape|force_escape }}") << dict << QStringLiteral("x&y") << NoError; 0760 0761 // The contents in "linebreaks" and "linebreaksbr" are escaped 0762 // according to the current autoescape setting. 0763 0764 dict.clear(); 0765 dict.insert(QStringLiteral("a"), QStringLiteral("x&\ny")); 0766 dict.insert(QStringLiteral("b"), markSafe(QStringLiteral("x&\ny"))); 0767 0768 QTest::newRow("filter-linebreaks01") << QStringLiteral("{{ a|linebreaks }} {{ b|linebreaks }}") << dict 0769 << QStringLiteral("<p>x&<br />y</p> <p>x&<br />y</p>") << NoError; 0770 QTest::newRow("filter-linebreaks02") << QStringLiteral( 0771 "{% autoescape off %}{{ a|linebreaks }} {{ " 0772 "b|linebreaks }}{% endautoescape %}") 0773 << dict << QStringLiteral("<p>x&<br />y</p> <p>x&<br />y</p>") << NoError; 0774 QTest::newRow("filter-linebreaksbr01") << QStringLiteral("{{ a|linebreaksbr }} {{ b|linebreaksbr }}") << dict << QStringLiteral("x&<br />y x&<br />y") 0775 << NoError; 0776 QTest::newRow("filter-linebreaksbr02") << QStringLiteral( 0777 "{% autoescape off %}{{ a|linebreaksbr }} {{ " 0778 "b|linebreaksbr }}{% endautoescape %}") 0779 << dict << QStringLiteral("x&<br />y x&<br />y") << NoError; 0780 0781 dict.clear(); 0782 dict.insert(QStringLiteral("a"), QStringLiteral("<b>hello</b>")); 0783 0784 QTest::newRow("filter-safe01") << QStringLiteral("{{ a }} -- {{ a|safe }}") << dict << QStringLiteral("<b>hello</b> -- <b>hello</b>") 0785 << NoError; 0786 QTest::newRow("filter-safe02") << QStringLiteral("{% autoescape off %}{{ a }} -- {{ a|safe }}{% endautoescape %}") << dict 0787 << QStringLiteral("<b>hello</b> -- <b>hello</b>") << NoError; 0788 0789 dict.clear(); 0790 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("&"), QStringLiteral("<")}); 0791 0792 QTest::newRow("filter-safeseq01") << R"({{ a|join:", " }} -- {{ a|safeseq|join:", " }})" << dict << QStringLiteral("&, < -- &, <") << NoError; 0793 QTest::newRow("filter-safeseq02") << "{% autoescape off %}{{ a|join:\", \" " 0794 "}} -- {{ a|safeseq|join:\", \" " 0795 "}}{% endautoescape %}" 0796 << dict << QStringLiteral("&, < -- &, <") << NoError; 0797 0798 dict.clear(); 0799 dict.insert(QStringLiteral("a"), QStringLiteral("<a>x</a> <p><b>y</b></p>")); 0800 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("<a>x</a> <p><b>y</b></p>")))); 0801 0802 QTest::newRow("filter-removetags01") << R"({{ a|removetags:"a b" }} {{ b|removetags:"a b" }})" << dict 0803 << QStringLiteral("x <p>y</p> x <p>y</p>") << NoError; 0804 QTest::newRow("filter-removetags02") << "{% autoescape off %}{{ a|removetags:\"a b\" }} {{ b|removetags:\"a " 0805 "b\" }}{% endautoescape %}" 0806 << dict << QStringLiteral("x <p>y</p> x <p>y</p>") << NoError; 0807 QTest::newRow("filter-striptags01") << QStringLiteral("{{ a|striptags }} {{ b|striptags }}") << dict << QStringLiteral("x y x y") << NoError; 0808 QTest::newRow("filter-striptags02") << QStringLiteral( 0809 "{% autoescape off %}{{ a|striptags }} {{ b|striptags " 0810 "}}{% endautoescape %}") << dict << QStringLiteral("x y x y") 0811 << NoError; 0812 0813 dict.clear(); 0814 dict.insert(QStringLiteral("fs_int_mib"), 1048576); 0815 0816 QTest::newRow("filter-filesizeformat01") << QStringLiteral("{{ fs_int_mib|filesizeformat }}") << dict << QStringLiteral("1.05 MB") << NoError; 0817 0818 QTest::newRow("filter-filesizeformat02") << QStringLiteral("{{ fs_int_mib|filesizeformat:\"2\" }}") << dict << QStringLiteral("1.00 MiB") << NoError; 0819 0820 QTest::newRow("filter-filesizeformat03") << QStringLiteral("{{ fs_int_mib|filesizeformat:\"10,3\" }}") << dict << QStringLiteral("1.049 MB") << NoError; 0821 0822 QTest::newRow("filter-filesizeformat04") << QStringLiteral("{{ fs_int_mib|filesizeformat:\"10,2,1024\" }}") << dict << QStringLiteral("1.07 GB") << NoError; 0823 0824 dict.clear(); 0825 dict.insert(QStringLiteral("fs_float_mib"), 1024.5); 0826 0827 QTest::newRow("filter-filesizeformat05") << QStringLiteral("{{ fs_float_mib|filesizeformat:\"10,2,1024\" }}") << dict << QStringLiteral("1.05 MB") 0828 << NoError; 0829 0830 dict.clear(); 0831 dict.insert(QStringLiteral("fs_string_mib"), QStringLiteral("1024.5")); 0832 0833 QTest::newRow("filter-filesizeformat06") << QStringLiteral("{{ fs_string_mib|filesizeformat:\"10,2,1024\" }}") << dict << QStringLiteral("1.05 MB") 0834 << NoError; 0835 0836 dict.clear(); 0837 dict.insert(QStringLiteral("fs_bytes"), 999); 0838 dict.insert(QStringLiteral("fs_kb"), 1000); 0839 dict.insert(QStringLiteral("fs_10kb"), 10 * 1000); 0840 dict.insert(QStringLiteral("fs_1000kb"), 1000 * 1000 - 1); 0841 dict.insert(QStringLiteral("fs_mb"), 1000 * 1000); 0842 dict.insert(QStringLiteral("fs_50mb"), 1000 * 1000 * 50); 0843 dict.insert(QStringLiteral("fs_1000mb"), 1000 * 1000 * 1000 - 1); 0844 dict.insert(QStringLiteral("fs_gb"), 1000 * 1000 * 1000); 0845 dict.insert(QStringLiteral("fs_tb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0)); 0846 dict.insert(QStringLiteral("fs_pb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0)); 0847 dict.insert(QStringLiteral("fs_eb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 2000.0)); 0848 dict.insert(QStringLiteral("fs_zb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0)); 0849 dict.insert(QStringLiteral("fs_yb"), static_cast<double>(1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0)); 0850 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)); 0851 dict.insert(QStringLiteral("fs_0b1"), 0.1); 0852 dict.insert(QStringLiteral("fs_0b2"), QString(QChar(0x03B1))); 0853 dict.insert(QStringLiteral("fs_neg_1"), -100); 0854 dict.insert(QStringLiteral("fs_neg_2"), -1000 * 1000 * 50); 0855 0856 // fixes tests on MSVC2013 0857 QString fsInput; 0858 fsInput = QStringLiteral( 0859 "{{ fs_bytes|filesizeformat }} {{ fs_kb|filesizeformat }} {{ " 0860 "fs_10kb|filesizeformat }} {{ fs_1000kb|filesizeformat }} "); 0861 fsInput += QStringLiteral( 0862 "{{ fs_mb|filesizeformat }} {{ fs_50mb|filesizeformat }} {{ " 0863 "fs_1000mb|filesizeformat }} {{ fs_gb|filesizeformat }} "); 0864 fsInput += QStringLiteral( 0865 "{{ fs_tb|filesizeformat }} {{ fs_pb|filesizeformat }} {{ " 0866 "fs_eb|filesizeformat }} {{ fs_zb|filesizeformat }} "); 0867 fsInput += QStringLiteral( 0868 "{{ fs_yb|filesizeformat }} {{ fs_2000yb|filesizeformat }} {{ " 0869 "fs_0b1|filesizeformat }} {{ fs_0b2|filesizeformat }} "); 0870 fsInput += QStringLiteral("{{ fs_neg_1|filesizeformat }} {{ fs_neg_2|filesizeformat }}"); 0871 0872 QString fsExpect; 0873 fsExpect = QStringLiteral("999 bytes 1.00 KB 10.00 KB 1000.00 KB "); 0874 fsExpect += QStringLiteral("1.00 MB 50.00 MB 1000.00 MB 1.00 GB "); 0875 fsExpect += QStringLiteral("1.00 TB 1.00 PB 2.00 EB 1.00 ZB "); 0876 fsExpect += QStringLiteral("1.00 YB 2000.00 YB 0 bytes 0 bytes "); 0877 fsExpect += QStringLiteral("-100 bytes -50.00 MB"); 0878 0879 QTest::newRow("filter-filesizeformat07") << fsInput << dict << fsExpect << NoError; 0880 } 0881 0882 void TestFilters::testListFilters_data() 0883 { 0884 QTest::addColumn<QString>("input"); 0885 QTest::addColumn<Dict>("dict"); 0886 QTest::addColumn<QString>("output"); 0887 QTest::addColumn<KTextTemplate::Error>("error"); 0888 0889 Dict dict; 0890 0891 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("a&b"), QStringLiteral("x")}); 0892 dict.insert(QStringLiteral("b"), QVariantList{QVariant::fromValue(markSafe(QStringLiteral("a&b"))), QStringLiteral("x")}); 0893 0894 QTest::newRow("filter-first01") << QStringLiteral("{{ a|first }} {{ b|first }}") << dict << QStringLiteral("a&b a&b") << NoError; 0895 QTest::newRow("filter-first02") << QStringLiteral("{% autoescape off %}{{ a|first }} {{ b|first }}{% endautoescape %}") << dict << QStringLiteral("a&b a&b") 0896 << NoError; 0897 0898 dict.clear(); 0899 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("x"), QStringLiteral("a&b")}); 0900 dict.insert(QStringLiteral("b"), QVariantList{QStringLiteral("x"), QVariant::fromValue(markSafe(QStringLiteral("a&b")))}); 0901 0902 QTest::newRow("filter-last01") << QStringLiteral("{{ a|last }} {{ b|last }}") << dict << QStringLiteral("a&b a&b") << NoError; 0903 QTest::newRow("filter-last02") << QStringLiteral("{% autoescape off %}{{ a|last }} {{ b|last }}{% endautoescape %}") << dict << QStringLiteral("a&b a&b") 0904 << NoError; 0905 0906 dict.clear(); 0907 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("a&b"), QStringLiteral("a&b")}); 0908 dict.insert(QStringLiteral("b"), 0909 QVariantList() << QVariant::fromValue(markSafe(QStringLiteral("a&b"))) << QVariant::fromValue(markSafe(QStringLiteral("a&b")))); 0910 QTest::newRow("filter-random01") << QStringLiteral("{{ a|random }} {{ b|random }}") << dict << QStringLiteral("a&b a&b") << NoError; 0911 QTest::newRow("filter-random02") << QStringLiteral("{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}") << dict 0912 << QStringLiteral("a&b a&b") << NoError; 0913 0914 dict.clear(); 0915 dict.insert(QStringLiteral("empty_list"), QVariantList()); 0916 QTest::newRow("filter-random03") << QStringLiteral("{{empty_list|random}}") << dict << QStringLiteral("") << NoError; 0917 QTest::newRow("filter-random04") << QStringLiteral("{{|random}}") << dict << QStringLiteral("") << NoError; 0918 0919 dict.clear(); 0920 dict.insert(QStringLiteral("a"), QStringLiteral("a&b")); 0921 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a&b")))); 0922 0923 QTest::newRow("filter-slice01") << R"({{ a|slice:"1:3" }} {{ b|slice:"1:3" }})" << dict << QStringLiteral("&b &b") << NoError; 0924 QTest::newRow("filter-slice02") << "{% autoescape off %}{{ a|slice:\"1:3\" }} {{ b|slice:\"1:3\" }}{% " 0925 "endautoescape %}" 0926 << dict << QStringLiteral("&b &b") << NoError; 0927 0928 dict.clear(); 0929 QTest::newRow("filter-slice03") << "{{xx|slice}}" << dict << QStringLiteral("") << NoError; 0930 QTest::newRow("filter-slice04") << "{{|slice}}" << dict << QStringLiteral("") << NoError; 0931 0932 dict.clear(); 0933 QVariantList sublist{QStringLiteral("<y")}; 0934 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("x>"), QVariant(sublist)}); 0935 0936 QTest::newRow("filter-unordered_list01") << QStringLiteral("{{ a|unordered_list }}") << dict << "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>" 0937 << NoError; 0938 QTest::newRow("filter-unordered_list02") << QStringLiteral("{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}") << dict 0939 << "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>" << NoError; 0940 0941 dict.clear(); 0942 sublist = {markSafe(QStringLiteral("<y"))}; 0943 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("x>"), QVariant(sublist)}); 0944 0945 QTest::newRow("filter-unordered_list03") << QStringLiteral("{{ a|unordered_list }}") << dict << "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>" 0946 << NoError; 0947 QTest::newRow("filter-unordered_list04") << QStringLiteral("{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}") << dict 0948 << "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>" << NoError; 0949 0950 dict.clear(); 0951 sublist = {QStringLiteral("<y")}; 0952 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("x>"), QVariant(sublist)}); 0953 0954 QTest::newRow("filter-unordered_list05") << QStringLiteral("{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}") << dict 0955 << "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>" << NoError; 0956 0957 // length filter. 0958 dict.clear(); 0959 dict.insert(QStringLiteral("list"), QVariantList{QStringLiteral("4"), QVariant(), true, QVariantHash()}); 0960 0961 QTest::newRow("length01") << QStringLiteral("{{ list|length }}") << dict << QStringLiteral("4") << NoError; 0962 0963 dict.clear(); 0964 dict.insert(QStringLiteral("list"), QVariantList()); 0965 0966 QTest::newRow("length02") << QStringLiteral("{{ list|length }}") << dict << QStringLiteral("0") << NoError; 0967 0968 dict.clear(); 0969 dict.insert(QStringLiteral("string"), QStringLiteral("")); 0970 0971 QTest::newRow("length03") << QStringLiteral("{{ string|length }}") << dict << QStringLiteral("0") << NoError; 0972 0973 dict.clear(); 0974 dict.insert(QStringLiteral("string"), QStringLiteral("django")); 0975 0976 QTest::newRow("length04") << QStringLiteral("{{ string|length }}") << dict << QStringLiteral("6") << NoError; 0977 0978 // Invalid uses that should fail silently. 0979 0980 dict.clear(); 0981 dict.insert(QStringLiteral("int"), 7); 0982 0983 QTest::newRow("length05") << QStringLiteral("{{ int|length }}") << dict << QString() << NoError; 0984 0985 dict.clear(); 0986 dict.insert(QStringLiteral("None"), QVariant()); 0987 0988 QTest::newRow("length06") << QStringLiteral("{{ None|length }}") << dict << QString() << NoError; 0989 0990 // length_is filter. 0991 0992 dict.clear(); 0993 dict.insert(QStringLiteral("some_list"), QVariantList{QStringLiteral("4"), QVariant(), true, QVariantHash()}); 0994 0995 QTest::newRow("length_is01") << "{% if some_list|length_is:\"4\" %}Four{% endif %}" << dict << QStringLiteral("Four") << NoError; 0996 0997 dict.clear(); 0998 dict.insert(QStringLiteral("some_list"), QVariantList{QStringLiteral("4"), QVariant(), true, QVariantHash(), 17}); 0999 1000 QTest::newRow("length_is02") << "{% if some_list|length_is:\"4\" %}Four{% else %}Not Four{% endif %}" << dict << QStringLiteral("Not Four") << NoError; 1001 1002 dict.clear(); 1003 dict.insert(QStringLiteral("mystring"), QStringLiteral("word")); 1004 1005 QTest::newRow("length_is03") << "{% if mystring|length_is:\"4\" %}Four{% endif %}" << dict << QStringLiteral("Four") << NoError; 1006 1007 dict.clear(); 1008 dict.insert(QStringLiteral("mystring"), QStringLiteral("Python")); 1009 1010 QTest::newRow("length_is04") << "{% if mystring|length_is:\"4\" %}Four{% else %}Not Four{% endif %}" << dict << QStringLiteral("Not Four") << NoError; 1011 1012 dict.clear(); 1013 dict.insert(QStringLiteral("mystring"), QStringLiteral("")); 1014 1015 QTest::newRow("length_is05") << "{% if mystring|length_is:\"4\" %}Four{% else %}Not Four{% endif %}" << dict << QStringLiteral("Not Four") << NoError; 1016 1017 dict.clear(); 1018 dict.insert(QStringLiteral("var"), QStringLiteral("django")); 1019 1020 QTest::newRow("length_is06") << QStringLiteral("{% with var|length as my_length %}{{ my_length }}{% endwith %}") << dict << QStringLiteral("6") << NoError; 1021 1022 // Boolean return value from length_is should not be coerced to a string 1023 1024 dict.clear(); 1025 QTest::newRow("length_is07") << "{% if \"X\"|length_is:0 %}Length is 0{% " 1026 "else %}Length not 0{% endif %}" 1027 << dict << QStringLiteral("Length not 0") << NoError; 1028 QTest::newRow("length_is08") << "{% if \"X\"|length_is:1 %}Length is 1{% " 1029 "else %}Length not 1{% endif %}" 1030 << dict << QStringLiteral("Length is 1") << NoError; 1031 1032 // Invalid uses that should fail silently. 1033 1034 dict.clear(); 1035 dict.insert(QStringLiteral("var"), QStringLiteral("django")); 1036 1037 QTest::newRow("length_is09") << "{{ var|length_is:\"fish\" }}" << dict << QString() << NoError; 1038 1039 dict.clear(); 1040 dict.insert(QStringLiteral("int"), 7); 1041 1042 QTest::newRow("length_is10") << "{{ int|length_is:\"1\" }}" << dict << QString() << NoError; 1043 1044 dict.clear(); 1045 dict.insert(QStringLiteral("none"), QVariant()); 1046 1047 QTest::newRow("length_is11") << "{{ none|length_is:\"1\" }}" << dict << QString() << NoError; 1048 1049 dict.clear(); 1050 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("alpha"), QStringLiteral("beta & me")}); 1051 1052 QTest::newRow("join01") << "{{ a|join:\", \" }}" << dict << QStringLiteral("alpha, beta & me") << NoError; 1053 QTest::newRow("join02") << "{% autoescape off %}{{ a|join:\", \" }}{% endautoescape %}" << dict << QStringLiteral("alpha, beta & me") << NoError; 1054 QTest::newRow("join03") << "{{ a|join:\" & \" }}" << dict << QStringLiteral("alpha & beta & me") << NoError; 1055 QTest::newRow("join04") << "{% autoescape off %}{{ a|join:\" & \" }}{% endautoescape %}" << dict << QStringLiteral("alpha & beta & me") << NoError; 1056 1057 // Test that joining with unsafe joiners don't result in unsafe strings 1058 // (#11377) 1059 dict.insert(QStringLiteral("var"), QStringLiteral(" & ")); 1060 QTest::newRow("join05") << "{{ a|join:var }}" << dict << QStringLiteral("alpha & beta & me") << NoError; 1061 dict.insert(QStringLiteral("var"), KTextTemplate::markSafe(QStringLiteral(" & "))); 1062 QTest::newRow("join06") << "{{ a|join:var }}" << dict << QStringLiteral("alpha & beta & me") << NoError; 1063 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("Alpha"), QStringLiteral("Beta & Me")}); 1064 dict.insert(QStringLiteral("var"), QStringLiteral(" & ")); 1065 QTest::newRow("join07") << "{{ a|join:var|lower }}" << dict << QStringLiteral("alpha & beta & me") << NoError; 1066 1067 dict.insert(QStringLiteral("a"), QVariantList{QStringLiteral("Alpha"), QStringLiteral("Beta & Me")}); 1068 dict.insert(QStringLiteral("var"), KTextTemplate::markSafe(QStringLiteral(" & "))); 1069 QTest::newRow("join08") << "{{ a|join:var|lower }}" << dict << QStringLiteral("alpha & beta & me") << NoError; 1070 1071 // arguments to filters are intended to be used unescaped. 1072 // dict.clear(); 1073 // dict.insert( QStringLiteral("a"), QVariantList() << 1074 // QString::fromLatin1( "alpha" ) << QString::fromLatin1( "beta & me" ) ); 1075 // dict.insert( QStringLiteral("var"), QStringLiteral(" & ") ); 1076 // 1077 // QTest::newRow( "join05" ) << QString::fromLatin1( "{{ a|join:var }}" ) 1078 // << 1079 // dict << QString::fromLatin1( "alpha & beta & me" ) << NoError; 1080 // 1081 // dict.clear(); 1082 // dict.insert( QStringLiteral("a"), QVariantList() << 1083 // QString::fromLatin1( "alpha" ) << QString::fromLatin1( "beta & me" ) ); 1084 // dict.insert( QStringLiteral("var"), QVariant::fromValue( markSafe( 1085 // QString::fromLatin1( " & " ) ) ) ); 1086 // 1087 // QTest::newRow( "join06" ) << QString::fromLatin1( "{{ a|join:var }}" ) 1088 // << 1089 // dict << QString::fromLatin1( "alpha & beta & me" ) << NoError; 1090 // 1091 // dict.clear(); 1092 // dict.insert( QStringLiteral("a"), QVariantList() << 1093 // QString::fromLatin1( "Alpha" ) << QString::fromLatin1( "Beta & me" ) ); 1094 // dict.insert( QStringLiteral("var"), QStringLiteral(" & ") ); 1095 // 1096 // QTest::newRow( "join07" ) << QString::fromLatin1( "{{ a|join:var|lower 1097 // }}" ) << dict << QString::fromLatin1( "alpha & beta & me" ) << 1098 // NoError; 1099 // 1100 // dict.clear(); 1101 // dict.insert( QStringLiteral("a"), QVariantList() << 1102 // QString::fromLatin1( "Alpha" ) << QString::fromLatin1( "Beta & me" ) ); 1103 // dict.insert( QStringLiteral("var"), QVariant::fromValue( markSafe( 1104 // QString::fromLatin1( " & " ) ) ) ); 1105 // 1106 // QTest::newRow( "join08" ) << QString::fromLatin1( "{{ a|join:var|lower 1107 // }}" ) << dict << QString::fromLatin1( "alpha & beta & me" ) << 1108 // NoError; 1109 1110 dict.clear(); 1111 1112 QVariantList mapList; 1113 const auto cities = QStringList{QStringLiteral("London"), QStringLiteral("Berlin"), QStringLiteral("Paris"), QStringLiteral("Dublin")}; 1114 for (const QString &city : cities) { 1115 QVariantHash map; 1116 map.insert(QStringLiteral("city"), city); 1117 mapList << map; 1118 } 1119 1120 dict.insert(QStringLiteral("mapList"), mapList); 1121 1122 QTest::newRow("dictsort01") << "{% with mapList|dictsort:'city' as result %}{% for item in result " 1123 "%}{{ item.city }},{% endfor %}{% endwith %}" 1124 << dict << "Berlin,Dublin,London,Paris," << NoError; 1125 1126 { 1127 // Test duplication works 1128 QVariantHash map; 1129 map.insert(QStringLiteral("city"), QStringLiteral("Berlin")); 1130 mapList << map; 1131 } 1132 dict.insert(QStringLiteral("mapList"), mapList); 1133 1134 QTest::newRow("dictsort02") << "{% with mapList|dictsort:'city' as result %}{% for item in result " 1135 "%}{{ item.city }},{% endfor %}{% endwith %}" 1136 << dict << "Berlin,Berlin,Dublin,London,Paris," << NoError; 1137 1138 dict.clear(); 1139 1140 QVariantList listList; 1141 1142 const auto countries = QStringList{QStringLiteral("England"), QStringLiteral("Germany"), QStringLiteral("France"), QStringLiteral("Ireland")}; 1143 1144 const auto languages = QStringList{QStringLiteral("English"), QStringLiteral("German"), QStringLiteral("French"), QStringLiteral("Irish")}; 1145 1146 for (auto i = 0; i < cities.size(); ++i) { 1147 listList << QVariant(QVariantList{cities.at(i), countries.at(i), languages.at(i)}); 1148 } 1149 1150 dict.insert(QStringLiteral("listList"), listList); 1151 1152 QTest::newRow("dictsort03") << "{% with listList|dictsort:'0' as result %}{% for item in result " 1153 "%}{{ " 1154 "item.0 }};{{ item.1 }};{{ item.2 }},{% endfor %}{% endwith %}" 1155 << dict 1156 << "Berlin;Germany;German,Dublin;Ireland;Irish,London;England;" 1157 "English,Paris;France;French," 1158 << NoError; 1159 1160 QTest::newRow("dictsort04") << "{% with listList|dictsort:'1' as result %}{% for item in result " 1161 "%}{{ " 1162 "item.0 }};{{ item.1 }};{{ item.2 }},{% endfor %}{% endwith %}" 1163 << dict 1164 << "London;England;English,Paris;France;French,Berlin;Germany;" 1165 "German,Dublin;Ireland;Irish," 1166 << NoError; 1167 } 1168 1169 void TestFilters::testLogicFilters_data() 1170 { 1171 QTest::addColumn<QString>("input"); 1172 QTest::addColumn<Dict>("dict"); 1173 QTest::addColumn<QString>("output"); 1174 QTest::addColumn<KTextTemplate::Error>("error"); 1175 1176 Dict dict; 1177 1178 // Literal string arguments to the default filter are always treated as 1179 // safe strings, regardless of the auto-escaping state. 1180 1181 // Note: we have to use {"a": ""} here, otherwise the invalid template 1182 // variable string interferes with the test result. 1183 1184 dict.insert(QStringLiteral("a"), QStringLiteral("")); 1185 1186 QTest::newRow("filter-default01") << "{{ a|default:\"x<\" }}" << dict << QStringLiteral("x<") << NoError; 1187 QTest::newRow("filter-default02") << "{% autoescape off %}{{ a|default:\"x<\" }}{% endautoescape %}" << dict << QStringLiteral("x<") << NoError; 1188 1189 dict.clear(); 1190 dict.insert(QStringLiteral("a"), QVariant::fromValue(markSafe(QStringLiteral("x>")))); 1191 1192 QTest::newRow("filter-default03") << "{{ a|default:\"x<\" }}" << dict << QStringLiteral("x>") << NoError; 1193 QTest::newRow("filter-default04") << "{% autoescape off %}{{ a|default:\"x<\" }}{% endautoescape %}" << dict << QStringLiteral("x>") << NoError; 1194 1195 dict.clear(); 1196 dict.insert(QStringLiteral("a"), QVariant()); 1197 1198 QTest::newRow("filter-default_if_none01") << "{{ a|default:\"x<\" }}" << dict << QStringLiteral("x<") << NoError; 1199 QTest::newRow("filter-default_if_none02") << "{% autoescape off %}{{ a|default:\"x<\" }}{% endautoescape %}" << dict << QStringLiteral("x<") << NoError; 1200 } 1201 1202 void TestFilters::testMiscFilters_data() 1203 { 1204 QTest::addColumn<QString>("input"); 1205 QTest::addColumn<Dict>("dict"); 1206 QTest::addColumn<QString>("output"); 1207 QTest::addColumn<KTextTemplate::Error>("error"); 1208 1209 Dict dict; 1210 1211 // 1212 // // {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") 1213 // QTest::newRow( "filter-phone2numeric01") << QString::fromLatin1( "{{ 1214 // a|phone2numeric }} {{ b|phone2numeric }}" ) << dict << 1215 // QString::fromLatin1( "<1-800-2255-63> <1-800-2255-63>" ) << 1216 // NoError; 1217 // 1218 // // {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") 1219 // QTest::newRow( "filter-phone2numeric02") << QString::fromLatin1( "{% 1220 // autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% 1221 // endautoescape %}" ) << dict << QString::fromLatin1( "<1-800-2255-63> 1222 // <1-800-2255-63>" ) << NoError; 1223 // 1224 // Chaining a bunch of safeness-preserving filters should not alter 1225 // the safe status either way. 1226 1227 dict.insert(QStringLiteral("a"), QStringLiteral("a < b")); 1228 dict.insert(QStringLiteral("b"), QVariant::fromValue(markSafe(QStringLiteral("a < b")))); 1229 1230 QTest::newRow("chaining01") << R"({{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }})" << dict << QStringLiteral(" A < b . A < b ") << NoError; 1231 QTest::newRow("chaining02") << "{% autoescape off %}{{ a|capfirst|center:\"7\" }}.{{ " 1232 "b|capfirst|center:\"7\" }}{% endautoescape %}" 1233 << dict << QStringLiteral(" A < b . A < b ") << NoError; 1234 1235 // Using a filter that forces a string back to unsafe: 1236 1237 QTest::newRow("chaining03") << R"({{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }})" << dict << QStringLiteral("A < .A < ") << NoError; 1238 QTest::newRow("chaining04") << "{% autoescape off %}{{ a|cut:\"b\"|capfirst }}.{{ " 1239 "b|cut:\"b\"|capfirst }}{% endautoescape %}" 1240 << dict << QStringLiteral("A < .A < ") << NoError; 1241 1242 dict.clear(); 1243 dict.insert(QStringLiteral("a"), QStringLiteral("a < b")); 1244 1245 // Using a filter that forces safeness does not lead to double-escaping 1246 1247 QTest::newRow("chaining05") << QStringLiteral("{{ a|escape|capfirst }}") << dict << QStringLiteral("A < b") << NoError; 1248 QTest::newRow("chaining06") << QStringLiteral("{% autoescape off %}{{ a|escape|capfirst }}{% endautoescape %}") << dict << QStringLiteral("A < b") 1249 << NoError; 1250 1251 // Force to safe, then back (also showing why using force_escape too 1252 // early in a chain can lead to unexpected results). 1253 1254 QTest::newRow("chaining07") << "{{ a|force_escape|cut:\";\" }}" << dict << QStringLiteral("a &lt b") << NoError; 1255 QTest::newRow("chaining08") << "{% autoescape off %}{{ a|force_escape|cut:\";\" }}{% endautoescape " 1256 "%}" 1257 << dict << QStringLiteral("a < b") << NoError; 1258 QTest::newRow("chaining09") << "{{ a|cut:\";\"|force_escape }}" << dict << QStringLiteral("a < b") << NoError; 1259 QTest::newRow("chaining10") << "{% autoescape off %}{{ a|cut:\";\"|force_escape }}{% endautoescape " 1260 "%}" 1261 << dict << QStringLiteral("a < b") << NoError; 1262 QTest::newRow("chaining11") << "{{ a|cut:\"b\"|safe }}" << dict << QStringLiteral("a < ") << NoError; 1263 QTest::newRow("chaining12") << "{% autoescape off %}{{ a|cut:\"b\"|safe }}{% endautoescape %}" << dict << QStringLiteral("a < ") << NoError; 1264 QTest::newRow("chaining13") << QStringLiteral("{{ a|safe|force_escape }}") << dict << QStringLiteral("a < b") << NoError; 1265 QTest::newRow("chaining14") << QStringLiteral("{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}") << dict << QStringLiteral("a < b") 1266 << NoError; 1267 1268 // // Filters decorated with stringfilter still respect is_safe. 1269 // 1270 // // {"unsafe": UnsafeClass() 1271 // QTest::newRow( "autoescape-stringfilter01") << QString::fromLatin1( "{{ 1272 // unsafe|capfirst }}" ) << dict << QString::fromLatin1( "You & me" ) 1273 // << 1274 // NoError; 1275 // 1276 // // {"unsafe": UnsafeClass() 1277 // QTest::newRow( "autoescape-stringfilter02") << QString::fromLatin1( "{% 1278 // autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}" ) << dict << 1279 // QString::fromLatin1( "You & me" ) << NoError; 1280 // 1281 // // {"safe": SafeClass() 1282 // QTest::newRow( "autoescape-stringfilter03") << QString::fromLatin1( "{{ 1283 // safe|capfirst }}" ) << dict << QString::fromLatin1( "You > me" ) << 1284 // NoError; 1285 // 1286 // // {"safe": SafeClass() 1287 // QTest::newRow( "autoescape-stringfilter04") << QString::fromLatin1( "{% 1288 // autoescape off %}{{ safe|capfirst }}{% endautoescape %}" ) << dict << 1289 // QString::fromLatin1( "You > me" ) << NoError; 1290 // 1291 } 1292 1293 void TestFilters::testIntegerFilters_data() 1294 { 1295 QTest::addColumn<QString>("input"); 1296 QTest::addColumn<Dict>("dict"); 1297 QTest::addColumn<QString>("output"); 1298 QTest::addColumn<KTextTemplate::Error>("error"); 1299 1300 Dict dict; 1301 1302 dict.insert(QStringLiteral("i"), 2000); 1303 1304 QTest::newRow("add01") << QStringLiteral("{{ i|add:5 }}") << dict << QStringLiteral("2005") << NoError; 1305 QTest::newRow("add02") << QStringLiteral("{{ i|add:\"napis\" }}") << dict << QStringLiteral("2000") << NoError; 1306 1307 dict.clear(); 1308 dict.insert(QStringLiteral("i"), QStringLiteral("not_an_int")); 1309 1310 QTest::newRow("add03") << QStringLiteral("{{ i|add:16 }}") << dict << QStringLiteral("not_an_int") << NoError; 1311 QTest::newRow("add04") << QStringLiteral("{{ i|add:\"16\" }}") << dict << QStringLiteral("not_an_int16") << NoError; 1312 1313 dict.clear(); 1314 dict.insert(QStringLiteral("l1"), QVariantList{1, 2}); 1315 dict.insert(QStringLiteral("l2"), QVariantList{3, 4}); 1316 1317 QTest::newRow("add05") << QStringLiteral("{{ l1|add:l2 }}") << dict << QStringLiteral("[1, 2, 3, 4]") << NoError; 1318 // QTest::newRow( "add06" ) << QString::fromLatin1( "{{ t1|add:t2 }}" ) << 1319 // dict << QString::fromLatin1( "2005" ) << NoError; 1320 1321 // QTest::newRow( "add07" ) << QString::fromLatin1( "{{ d|add:t }}" ) << 1322 // dict 1323 // << QString::fromLatin1( "2005" ) << NoError; 1324 1325 QTest::newRow("add08") << QStringLiteral("{{ 1|add:2 }}") << dict << QStringLiteral("3") << NoError; 1326 dict.clear(); 1327 dict.insert(QStringLiteral("l1"), QStringList{QStringLiteral("one"), QStringLiteral("two")}); 1328 dict.insert(QStringLiteral("l2"), QStringList{QStringLiteral("three"), QStringLiteral("four")}); 1329 1330 QTest::newRow("add09") << QStringLiteral("{{ l1|add:l2|join:\", \" }}") << dict << QStringLiteral("one, two, three, four") << NoError; 1331 1332 QTest::newRow("filter-getdigit01") << QStringLiteral("{{ 123|get_digit:1 }}") << dict << QStringLiteral("3") << NoError; 1333 QTest::newRow("filter-getdigit02") << QStringLiteral("{{ 123|get_digit:2 }}") << dict << QStringLiteral("2") << NoError; 1334 QTest::newRow("filter-getdigit03") << QStringLiteral("{{ 123|get_digit:3 }}") << dict << QStringLiteral("1") << NoError; 1335 QTest::newRow("filter-getdigit04") << QStringLiteral("{{ 123|get_digit:4 }}") << dict << QStringLiteral("123") << NoError; 1336 } 1337 1338 QTEST_MAIN(TestFilters) 1339 #include "testfilters.moc" 1340 1341 #endif