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"