File indexing completed on 2024-11-17 03:42:08
0001 /* 0002 This file is part of the KTextTemplate library 0003 0004 SPDX-FileCopyrightText: 2010 Stephen Kelly <steveire@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.1-or-later 0007 0008 */ 0009 0010 #define MINIMAL_CONTAINER_TESTS 0011 0012 #include "engine.h" 0013 #include "ktexttemplate_paths.h" 0014 0015 #include <QQueue> 0016 #include <QStack> 0017 #include <QTest> 0018 #include <QVariant> 0019 0020 class TestGenericContainers : public QObject 0021 { 0022 Q_OBJECT 0023 public: 0024 explicit TestGenericContainers(QObject *parent = {}); 0025 0026 private Q_SLOTS: 0027 void testContainer_Builtins(); 0028 }; 0029 0030 TestGenericContainers::TestGenericContainers(QObject *parent) 0031 : QObject(parent) 0032 { 0033 } 0034 0035 template<typename T> 0036 QList<T> getItems() 0037 { 0038 QList<T> items; 0039 items.push_back(9); 0040 items.push_back(7); 0041 items.push_back(5); 0042 return items; 0043 } 0044 0045 template<> 0046 QList<QString> getItems<QString>() 0047 { 0048 QList<QString> items; 0049 for (const int item : getItems<int>()) 0050 items.push_back(QString::number(item)); 0051 return items; 0052 } 0053 0054 template<> 0055 QList<QVariant> getItems<QVariant>() 0056 { 0057 QList<QVariant> items; 0058 for (const int item : getItems<int>()) 0059 items.push_back(item); 0060 return items; 0061 } 0062 0063 template<> 0064 QList<QDateTime> getItems<QDateTime>() 0065 { 0066 QList<QDateTime> items; 0067 items.reserve(3); 0068 for (auto i = 0; i < 3; ++i) { 0069 QDateTime d; 0070 d.setSecsSinceEpoch(0); 0071 d = d.addDays(i); 0072 items.push_back(d); 0073 } 0074 return items; 0075 } 0076 0077 template<> 0078 QList<QObject *> getItems<QObject *>() 0079 { 0080 QList<QObject *> items; 0081 items.reserve(3); 0082 for (auto i = 9; i > 4; i -= 2) { 0083 auto obj = new QObject; 0084 0085 obj->setObjectName(QString::number(i)); 0086 items.push_back(obj); 0087 } 0088 return items; 0089 } 0090 0091 template<typename Container> 0092 struct ContainerPopulator { 0093 static void populateSequential(Container &container) 0094 { 0095 for (const typename Container::value_type item : getItems<typename Container::value_type>()) 0096 container.push_back(item); 0097 } 0098 static void populateAssociative(Container &container) 0099 { 0100 auto i = 0; 0101 for (const typename Container::mapped_type item : getItems<typename Container::mapped_type>()) 0102 container[i++] = item; 0103 } 0104 }; 0105 0106 template<typename T> 0107 struct ContainerPopulator<QSet<T>> { 0108 static void populateSequential(QSet<T> &container) 0109 { 0110 for (const T item : getItems<T>()) 0111 container.insert(item); 0112 } 0113 }; 0114 0115 template<typename T> 0116 struct ContainerPopulator<QMap<QString, T>> { 0117 static void populateAssociative(QMap<QString, T> &container) 0118 { 0119 auto i = 0; 0120 for (const T item : getItems<T>()) 0121 container.insert(QString::number(i++), item); 0122 } 0123 }; 0124 0125 template<typename T> 0126 struct ContainerPopulator<QHash<QString, T>> { 0127 static void populateAssociative(QHash<QString, T> &container) 0128 { 0129 auto i = 0; 0130 for (const T item : getItems<T>()) 0131 container.insert(QString::number(i++), item); 0132 } 0133 }; 0134 0135 template<typename T> 0136 struct ContainerPopulator<std::map<QString, T>> { 0137 static void populateAssociative(std::map<QString, T> &container) 0138 { 0139 auto i = 0; 0140 for (const T item : getItems<T>()) 0141 container[QString::number(i++)] = item; 0142 } 0143 }; 0144 0145 template<typename T> 0146 QString getTemplate() 0147 { 0148 return QStringLiteral( 0149 "{{ container.size }};{{ container.count }};{% for " 0150 "item in container %}{{ item }},{% endfor %}"); 0151 } 0152 0153 template<> 0154 QString getTemplate<QDateTime>() 0155 { 0156 return QStringLiteral( 0157 "{{ container.size }};{{ container.count }};{% for " 0158 "item in container %}{{ item|date }},{% endfor %}"); 0159 } 0160 0161 template<> 0162 QString getTemplate<QObject *>() 0163 { 0164 return QStringLiteral( 0165 "{{ container.size }};{{ container.count }};{% for item in container " 0166 "%}{{ item.objectName }},{% endfor %}"); 0167 } 0168 0169 template<typename T> 0170 QString getAssociativeTemplate() 0171 { 0172 return QStringLiteral( 0173 "{{ container.size }};{{ container.count }};{% for " 0174 "item in container.values %}{{ item }},{% endfor %}"); 0175 } 0176 0177 template<> 0178 QString getAssociativeTemplate<QDateTime>() 0179 { 0180 return QStringLiteral( 0181 "{{ container.size }};{{ container.count }};{% for item in " 0182 "container.values %}{{ item|date }},{% endfor %}"); 0183 } 0184 0185 template<> 0186 QString getAssociativeTemplate<QObject *>() 0187 { 0188 return QStringLiteral( 0189 "{{ container.size }};{{ container.count }};{% for item in " 0190 "container.values %}{{ item.objectName }},{% endfor %}"); 0191 } 0192 0193 template<typename T> 0194 QStringList getResults() 0195 { 0196 return {QStringLiteral("3;3;"), QStringLiteral("9,"), QStringLiteral("7,"), QStringLiteral("5,")}; 0197 } 0198 0199 template<> 0200 QStringList getResults<QDateTime>() 0201 { 0202 return {QStringLiteral("3;3;"), QStringLiteral("Jan. 1, 1970,"), QStringLiteral("Jan. 2, 1970,"), QStringLiteral("Jan. 3, 1970,")}; 0203 } 0204 0205 template<typename Container, typename T = typename Container::value_type> 0206 struct CleanupSequentialContainer { 0207 static void clean(Container &) 0208 { 0209 } 0210 }; 0211 0212 template<typename Container, typename T = typename Container::mapped_type> 0213 struct CleanupAssociativeContainer { 0214 static void clean(Container &) 0215 { 0216 } 0217 }; 0218 0219 template<typename Container> 0220 struct CleanupSequentialContainer<Container, QObject *> { 0221 static void clean(Container &c) 0222 { 0223 qDeleteAll(c); 0224 } 0225 }; 0226 0227 template<typename Container> 0228 struct CleanupAssociativeContainer<Container, QObject *> { 0229 static void clean(Container &c) 0230 { 0231 qDeleteAll(c); 0232 } 0233 }; 0234 0235 template<typename T> 0236 struct CleanupAssociativeContainer<std::map<T, QObject *>, QObject *> { 0237 static void clean(std::map<T, QObject *> &c) 0238 { 0239 typename std::map<T, QObject *>::iterator it = c.begin(); 0240 const typename std::map<T, QObject *>::iterator end = c.end(); 0241 for (; it != end; ++it) { 0242 delete it->second; 0243 it->second = 0; 0244 } 0245 } 0246 }; 0247 0248 template<typename Container> 0249 void cleanupSequential(Container c) 0250 { 0251 CleanupSequentialContainer<Container>::clean(c); 0252 } 0253 0254 template<typename Container> 0255 void cleanupAssociative(Container c) 0256 { 0257 CleanupAssociativeContainer<Container>::clean(c); 0258 } 0259 0260 void testContainer(const QString &stringTemplate, const QVariant &containerVariant, const QStringList &expectedResults, bool unordered) 0261 { 0262 KTextTemplate::Engine engine; 0263 0264 engine.setPluginPaths({QStringLiteral(KTEXTTEMPLATE_PLUGIN_PATH)}); 0265 0266 KTextTemplate::Context c; 0267 c.insert(QStringLiteral("container"), containerVariant); 0268 0269 auto t1 = engine.newTemplate(stringTemplate, QStringLiteral("template1")); 0270 0271 auto result = t1->render(&c); 0272 if (!unordered) 0273 QCOMPARE(result, expectedResults.join(QString())); 0274 else { 0275 QCOMPARE(result.size(), expectedResults.join(QString()).size()); 0276 for (const QString &expectedResult : expectedResults) 0277 QVERIFY(result.contains(expectedResult)); 0278 } 0279 0280 auto t2 = engine.newTemplate(QStringLiteral("-{{ container.doesnotexist }}-"), QStringLiteral("template2")); 0281 0282 auto result2 = t2->render(&c); 0283 0284 QCOMPARE(result2, QStringLiteral("--")); 0285 } 0286 0287 template<typename Container> 0288 void doTestSequentialContainer(bool unordered = {}) 0289 { 0290 Container container; 0291 ContainerPopulator<Container>::populateSequential(container); 0292 0293 testContainer(getTemplate<typename Container::value_type>(), QVariant::fromValue(container), getResults<typename Container::value_type>(), unordered); 0294 cleanupSequential(container); 0295 } 0296 0297 template<typename Container> 0298 void doTestAssociativeContainer(bool unordered = {}) 0299 { 0300 Container container; 0301 ContainerPopulator<Container>::populateAssociative(container); 0302 0303 testContainer(getAssociativeTemplate<typename Container::mapped_type>(), 0304 QVariant::fromValue(container), 0305 getResults<typename Container::mapped_type>(), 0306 unordered); 0307 cleanupAssociative(container); 0308 } 0309 0310 template<typename T> 0311 void doTestNonHashableContainers() 0312 { 0313 doTestSequentialContainer<QList<T>>(); 0314 doTestSequentialContainer<QList<T>>(); 0315 doTestSequentialContainer<QQueue<T>>(); 0316 doTestSequentialContainer<QStack<T>>(); 0317 doTestSequentialContainer<std::list<T>>(); 0318 doTestAssociativeContainer<QMap<qint32, T>>(); 0319 doTestAssociativeContainer<std::map<qint32, T>>(); 0320 doTestAssociativeContainer<QHash<qint32, T>>(true); 0321 #ifndef MINIMAL_CONTAINER_TESTS 0322 doTestAssociativeContainer<QMap<qint16, T>>(); 0323 doTestAssociativeContainer<QMap<qint64, T>>(); 0324 doTestAssociativeContainer<QMap<quint16, T>>(); 0325 doTestAssociativeContainer<QMap<quint32, T>>(); 0326 doTestAssociativeContainer<QMap<quint64, T>>(); 0327 doTestAssociativeContainer<QMap<QString, T>>(); 0328 doTestAssociativeContainer<std::map<qint16, T>>(); 0329 doTestAssociativeContainer<std::map<qint64, T>>(); 0330 doTestAssociativeContainer<std::map<quint16, T>>(); 0331 doTestAssociativeContainer<std::map<quint32, T>>(); 0332 doTestAssociativeContainer<std::map<quint64, T>>(); 0333 doTestAssociativeContainer<std::map<QString, T>>(); 0334 doTestAssociativeContainer<QHash<qint16, T>>(true); 0335 doTestAssociativeContainer<QHash<qint64, T>>(true); 0336 doTestAssociativeContainer<QHash<quint16, T>>(true); 0337 doTestAssociativeContainer<QHash<quint32, T>>(true); 0338 doTestAssociativeContainer<QHash<quint64, T>>(true); 0339 doTestAssociativeContainer<QHash<QString, T>>(true); 0340 #endif 0341 } 0342 0343 template<typename T> 0344 void doTestContainers() 0345 { 0346 doTestNonHashableContainers<T>(); 0347 doTestSequentialContainer<QSet<T>>(true); 0348 } 0349 0350 void TestGenericContainers::testContainer_Builtins() 0351 { 0352 doTestContainers<qint32>(); 0353 #ifndef MINIMAL_CONTAINER_TESTS 0354 doTestContainers<qint16>(); 0355 doTestContainers<qint64>(); 0356 doTestContainers<quint16>(); 0357 doTestContainers<quint32>(); 0358 doTestContainers<quint64>(); 0359 doTestNonHashableContainers<float>(); 0360 doTestNonHashableContainers<double>(); 0361 doTestContainers<QString>(); 0362 doTestNonHashableContainers<QVariant>(); 0363 doTestNonHashableContainers<QDateTime>(); 0364 doTestContainers<QObject *>(); 0365 #endif 0366 } 0367 0368 QTEST_MAIN(TestGenericContainers) 0369 #include "testgenericcontainers.moc"