Cutelee  6.1.0
testgenericcontainers.cpp
1 /*
2  This file is part of the Cutelee template system.
3 
4  Copyright (c) 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 #define MINIMAL_CONTAINER_TESTS
22 
23 #include "engine.h"
24 #include "cutelee_paths.h"
25 #include "metatype.h"
26 #include "test_macros.h"
27 
28 #include "coverageobject.h"
29 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
30 #include <QtCore/QLinkedList>
31 #endif
32 #include <QtCore/QQueue>
33 #include <QtCore/QStack>
34 #include <QtCore/QVariant>
35 #include <QtTest/QTest>
36 
38 {
39  Q_OBJECT
40 public:
41  explicit TestGenericContainers(QObject *parent = {});
42 
43 private Q_SLOTS:
44  void testContainer_Builtins();
45 };
46 
47 TestGenericContainers::TestGenericContainers(QObject *parent)
48  : CoverageObject(parent)
49 {
50 }
51 
52 template <typename T> QVector<T> getItems()
53 {
54  QVector<T> items;
55  items.push_back(9);
56  items.push_back(7);
57  items.push_back(5);
58  return items;
59 }
60 
61 template <> QVector<QString> getItems<QString>()
62 {
63  QVector<QString> items;
64  Q_FOREACH (const int item, getItems<int>())
65  items.push_back(QString::number(item));
66  return items;
67 }
68 
69 template <> QVector<QVariant> getItems<QVariant>()
70 {
71  QVector<QVariant> items;
72  Q_FOREACH (const int item, getItems<int>())
73  items.push_back(item);
74  return items;
75 }
76 
77 template <> QVector<QDateTime> getItems<QDateTime>()
78 {
79  QVector<QDateTime> items;
80  items.reserve(3);
81  for (auto i = 0; i < 3; ++i) {
82  QDateTime d;
83  d.setMSecsSinceEpoch(0);
84  d = d.addDays(i);
85  items.push_back(d);
86  }
87  return items;
88 }
89 
90 template <> QVector<QObject *> getItems<QObject *>()
91 {
92  QVector<QObject *> items;
93  items.reserve(3);
94  for (auto i = 9; i > 4; i -= 2) {
95  auto obj = new QObject;
96 
97  obj->setObjectName(QString::number(i));
98  items.push_back(obj);
99  }
100  return items;
101 }
102 
103 template <typename Container> struct ContainerPopulator {
104  static void populateSequential(Container &container)
105  {
106  Q_FOREACH (const typename Container::value_type item,
107  getItems<typename Container::value_type>())
108  container.push_back(item);
109  }
110  static void populateAssociative(Container &container)
111  {
112  auto i = 0;
113  Q_FOREACH (const typename Container::mapped_type item,
114  getItems<typename Container::mapped_type>())
115  container[i++] = item;
116  }
117 };
118 
119 template <typename T> struct ContainerPopulator<QSet<T>> {
120  static void populateSequential(QSet<T> &container)
121  {
122  Q_FOREACH (const T item, getItems<T>())
123  container.insert(item);
124  }
125 };
126 
127 template <typename T> struct ContainerPopulator<QMap<QString, T>> {
128  static void populateAssociative(QMap<QString, T> &container)
129  {
130  auto i = 0;
131  Q_FOREACH (const T item, getItems<T>())
132  container.insert(QString::number(i++), item);
133  }
134 };
135 
136 template <typename T> struct ContainerPopulator<QHash<QString, T>> {
137  static void populateAssociative(QHash<QString, T> &container)
138  {
139  auto i = 0;
140  Q_FOREACH (const T item, getItems<T>())
141  container.insert(QString::number(i++), item);
142  }
143 };
144 
145 template <typename T> struct ContainerPopulator<std::map<QString, T>> {
146  static void populateAssociative(std::map<QString, T> &container)
147  {
148  auto i = 0;
149  Q_FOREACH (const T item, getItems<T>())
150  container[QString::number(i++)] = item;
151  }
152 };
153 
154 template <typename T> QString getTemplate()
155 {
156  return QStringLiteral("{{ container.size }};{{ container.count }};{% for "
157  "item in container %}{{ item }},{% endfor %}");
158 }
159 
160 template <> QString getTemplate<QDateTime>()
161 {
162  return QStringLiteral("{{ container.size }};{{ container.count }};{% for "
163  "item in container %}{{ item|date }},{% endfor %}");
164 }
165 
166 template <> QString getTemplate<QObject *>()
167 {
168  return QStringLiteral(
169  "{{ container.size }};{{ container.count }};{% for item in container "
170  "%}{{ item.objectName }},{% endfor %}");
171 }
172 
173 template <typename T> QString getAssociativeTemplate()
174 {
175  return QStringLiteral("{{ container.size }};{{ container.count }};{% for "
176  "item in container.values %}{{ item }},{% endfor %}");
177 }
178 
179 template <> QString getAssociativeTemplate<QDateTime>()
180 {
181  return QStringLiteral(
182  "{{ container.size }};{{ container.count }};{% for item in "
183  "container.values %}{{ item|date }},{% endfor %}");
184 }
185 
186 template <> QString getAssociativeTemplate<QObject *>()
187 {
188  return QStringLiteral(
189  "{{ container.size }};{{ container.count }};{% for item in "
190  "container.values %}{{ item.objectName }},{% endfor %}");
191 }
192 
193 template <typename T> QStringList getResults()
194 {
195  return {QStringLiteral("3;3;"), QStringLiteral("9,"), QStringLiteral("7,"),
196  QStringLiteral("5,")};
197 }
198 
199 template <> QStringList getResults<QDateTime>()
200 {
201  return {QStringLiteral("3;3;"), QStringLiteral("Jan. 1, 1970,"),
202  QStringLiteral("Jan. 2, 1970,"), QStringLiteral("Jan. 3, 1970,")};
203 }
204 
205 template <typename Container, typename T = typename Container::value_type>
207  static void clean(Container &) {}
208 };
209 
210 template <typename Container, typename T = typename Container::mapped_type>
212  static void clean(Container &) {}
213 };
214 
215 template <typename Container>
216 struct CleanupSequentialContainer<Container, QObject *> {
217  static void clean(Container &c) { qDeleteAll(c); }
218 };
219 
220 template <typename Container>
221 struct CleanupAssociativeContainer<Container, QObject *> {
222  static void clean(Container &c) { qDeleteAll(c); }
223 };
224 
225 template <typename T>
226 struct CleanupAssociativeContainer<std::map<T, QObject *>, QObject *> {
227  static void clean(std::map<T, QObject *> &c)
228  {
229  typename std::map<T, QObject *>::iterator it = c.begin();
230  const typename std::map<T, QObject *>::iterator end = c.end();
231  for (; it != end; ++it) {
232  delete it->second;
233  it->second = 0;
234  }
235  }
236 };
237 
238 template <typename Container> void cleanupSequential(Container c)
239 {
241 }
242 
243 template <typename Container> void cleanupAssociative(Container c)
244 {
246 }
247 
248 void testContainer(const QString &stringTemplate,
249  const QVariant &containerVariant,
250  const QStringList &expectedResults, bool unordered)
251 {
252  Cutelee::Engine engine;
253 
254  engine.setPluginPaths({QStringLiteral(CUTELEE_PLUGIN_PATH)});
255 
257  c.insert(QStringLiteral("container"), containerVariant);
258 
259  auto t1 = engine.newTemplate(stringTemplate, QStringLiteral("template1"));
260 
261  auto result = t1->render(&c);
262  if (!unordered)
263  QCOMPARE(result, expectedResults.join(QString()));
264  else {
265  QVERIFY(result.size() == expectedResults.join(QString()).size());
266  Q_FOREACH (const QString &expectedResult, expectedResults)
267  QVERIFY(result.contains(expectedResult));
268  }
269 
270  auto t2 = engine.newTemplate(QStringLiteral("-{{ container.doesnotexist }}-"),
271  QStringLiteral("template2"));
272 
273  auto result2 = t2->render(&c);
274 
275  QCOMPARE(result2, QStringLiteral("--"));
276 }
277 
278 template <typename Container>
279 void doTestSequentialContainer(bool unordered = {})
280 {
281  Container container;
283 
284  testContainer(getTemplate<typename Container::value_type>(),
285  QVariant::fromValue(container),
286  getResults<typename Container::value_type>(), unordered);
287  cleanupSequential(container);
288 }
289 
290 template <typename Container>
291 void doTestAssociativeContainer(bool unordered = {})
292 {
293  Container container;
295 
296  testContainer(getAssociativeTemplate<typename Container::mapped_type>(),
297  QVariant::fromValue(container),
298  getResults<typename Container::mapped_type>(), unordered);
299  cleanupAssociative(container);
300 }
301 
302 template <typename T> void doTestNonHashableContainers()
303 {
304  doTestSequentialContainer<QVector<T>>();
305  doTestSequentialContainer<QList<T>>();
306 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
307  doTestSequentialContainer<QLinkedList<T>>();
308 #endif
309  doTestSequentialContainer<QQueue<T>>();
310  doTestSequentialContainer<QStack<T>>();
311  doTestSequentialContainer<std::list<T>>();
312 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
313  doTestAssociativeContainer<QMap<qint32, T>>();
314  doTestAssociativeContainer<std::map<qint32, T>>();
315  doTestAssociativeContainer<QHash<qint32, T>>(true);
316 #endif
317 #ifndef MINIMAL_CONTAINER_TESTS
318  doTestAssociativeContainer<QMap<qint16, T>>();
319  doTestAssociativeContainer<QMap<qint64, T>>();
320  doTestAssociativeContainer<QMap<quint16, T>>();
321  doTestAssociativeContainer<QMap<quint32, T>>();
322  doTestAssociativeContainer<QMap<quint64, T>>();
323  doTestAssociativeContainer<QMap<QString, T>>();
324  doTestAssociativeContainer<std::map<qint16, T>>();
325  doTestAssociativeContainer<std::map<qint64, T>>();
326  doTestAssociativeContainer<std::map<quint16, T>>();
327  doTestAssociativeContainer<std::map<quint32, T>>();
328  doTestAssociativeContainer<std::map<quint64, T>>();
329  doTestAssociativeContainer<std::map<QString, T>>();
330  doTestAssociativeContainer<QHash<qint16, T>>(true);
331  doTestAssociativeContainer<QHash<qint64, T>>(true);
332  doTestAssociativeContainer<QHash<quint16, T>>(true);
333  doTestAssociativeContainer<QHash<quint32, T>>(true);
334  doTestAssociativeContainer<QHash<quint64, T>>(true);
335  doTestAssociativeContainer<QHash<QString, T>>(true);
336 #endif
337 }
338 
339 template <typename T> void doTestContainers()
340 {
341  doTestNonHashableContainers<T>();
342  doTestSequentialContainer<QSet<T>>(true);
343 }
344 
345 void TestGenericContainers::testContainer_Builtins()
346 {
347  doTestContainers<qint32>();
348 #ifndef MINIMAL_CONTAINER_TESTS
349  doTestContainers<qint16>();
350  doTestContainers<qint64>();
351  doTestContainers<quint16>();
352  doTestContainers<quint32>();
353  doTestContainers<quint64>();
354  doTestNonHashableContainers<float>();
355  doTestNonHashableContainers<double>();
356  doTestContainers<QString>();
357  doTestNonHashableContainers<QVariant>();
358  doTestNonHashableContainers<QDateTime>();
359  doTestContainers<QObject *>();
360 #endif
361 }
362 
363 QTEST_MAIN(TestGenericContainers)
364 #include "testgenericcontainers.moc"
The Context class holds the context to render a Template with.
Definition: context.h:119
void insert(const QString &name, QObject *object)
Definition: context.cpp:145
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
QString render(Context *c) const
Definition: template.cpp:74