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