LeechCraft  0.6.70-10870-g558588d6ec
Modular cross-platform feature rich live environment.
oraltest.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #include "oraltest.h"
31 #include "common.h"
32 
33 QTEST_APPLESS_MAIN (LeechCraft::Util::OralTest)
34 
36 {
38  QString Value_;
39 
40  static QString ClassName ()
41  {
42  return "SimpleRecord";
43  }
44 
45  auto AsTuple () const
46  {
47  return std::tie (ID_, Value_);
48  }
49 };
50 
52  ID_,
53  Value_)
54 
56 
57 struct AutogenPKeyRecord
58 {
59  lco::PKey<int> ID_;
60  QString Value_;
61 
62  static QString ClassName ()
63  {
64  return "AutogenPKeyRecord";
65  }
66 
67  auto AsTuple () const
68  {
69  return std::tie (ID_, Value_);
70  }
71 };
72 
73 BOOST_FUSION_ADAPT_STRUCT (AutogenPKeyRecord,
74  ID_,
75  Value_)
76 
77 TOSTRING (AutogenPKeyRecord)
78 
79 struct NoPKeyRecord
80 {
81  int ID_;
82  QString Value_;
83 
84  static QString ClassName ()
85  {
86  return "NoPKeyRecord";
87  }
88 
89  auto AsTuple () const
90  {
91  return std::tie (ID_, Value_);
92  }
93 };
94 
96  ID_,
97  Value_)
98 
99 TOSTRING (NoPKeyRecord)
100 
101 struct NonInPlaceConstructibleRecord
102 {
103  int ID_;
104  QString Value_;
105 
106  NonInPlaceConstructibleRecord () = default;
107 
108  NonInPlaceConstructibleRecord (int id, const QString& value, double someExtraArgument)
109  : ID_ { id }
110  , Value_ { value }
111  {
112  Q_UNUSED (someExtraArgument)
113  }
114 
115  static QString ClassName ()
116  {
117  return "NonInPlaceConstructibleRecord";
118  }
119 
120  auto AsTuple () const
121  {
122  return std::tie (ID_, Value_);
123  }
124 };
125 
126 BOOST_FUSION_ADAPT_STRUCT (NonInPlaceConstructibleRecord,
127  ID_,
128  Value_)
129 
130 TOSTRING (NonInPlaceConstructibleRecord)
131 
132 struct ComplexConstraintsRecord
133 {
134  int ID_;
135  QString Value_;
136  int Age_;
137  int Weight_;
138 
139  static QString ClassName ()
140  {
141  return "ComplexConstraintsRecord";
142  }
143 
144  auto AsTuple () const
145  {
146  return std::tie (ID_, Value_, Age_, Weight_);
147  }
148 
152  >;
153 };
154 
155 BOOST_FUSION_ADAPT_STRUCT (ComplexConstraintsRecord,
156  ID_,
157  Value_,
158  Age_,
159  Weight_)
160 
161 TOSTRING (ComplexConstraintsRecord)
162 
163 namespace LeechCraft
164 {
165 namespace Util
166 {
167  namespace
168  {
169  template<typename T>
170  auto PrepareRecords (QSqlDatabase db)
171  {
172  auto adapted = Util::oral::AdaptPtr<T> (db);
173  for (int i = 0; i < 3; ++i)
174  adapted->Insert ({ i, QString::number (i) });
175  return adapted;
176  }
177  }
178 
179  namespace sph = oral::sph;
180 
181  void OralTest::testSimpleRecordInsertSelect ()
182  {
183  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
184  const auto& list = adapted->Select ();
185  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" }, { 1, "1" }, { 2, "2" } }));
186  }
187 
188  void OralTest::testSimpleRecordInsertReplaceSelect ()
189  {
190  auto db = MakeDatabase ();
191 
192  auto adapted = Util::oral::AdaptPtr<SimpleRecord> (db);
193  for (int i = 0; i < 3; ++i)
194  adapted->Insert ({ 0, QString::number (i) }, lco::InsertAction::Replace);
195 
196  const auto& list = adapted->Select ();
197  QCOMPARE (list, (QList<SimpleRecord> { { 0, "2" } }));
198  }
199 
200  void OralTest::testSimpleRecordInsertIgnoreSelect ()
201  {
202  auto db = MakeDatabase ();
203 
204  auto adapted = Util::oral::AdaptPtr<SimpleRecord> (db);
205  for (int i = 0; i < 3; ++i)
206  adapted->Insert ({ 0, QString::number (i) }, lco::InsertAction::Ignore);
207 
208  const auto& list = adapted->Select ();
209  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" } }));
210  }
211 
212  void OralTest::testSimpleRecordInsertSelectByPos ()
213  {
214  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
215  const auto& list = adapted->Select (sph::_0 == 1);
216  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
217  }
218 
219  void OralTest::testSimpleRecordInsertSelectByPos2 ()
220  {
221  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
222  const auto& list = adapted->Select (sph::_0 < 2);
223  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" }, { 1, "1" } }));
224  }
225 
226  void OralTest::testSimpleRecordInsertSelectByPos3 ()
227  {
228  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
229  const auto& list = adapted->Select (sph::_0 < 2 && sph::_1 == QString { "1" });
230  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
231  }
232 
233  void OralTest::testSimpleRecordInsertSelectOneByPos ()
234  {
235  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
236  const auto& single = adapted->SelectOne (sph::_0 == 1);
237  QCOMPARE (single, (boost::optional<SimpleRecord> { { 1, "1" } }));
238  }
239 
240  void OralTest::testSimpleRecordInsertSelectByFields ()
241  {
242  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
243  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> == 1);
244  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
245  }
246 
247  void OralTest::testSimpleRecordInsertSelectByFields2 ()
248  {
249  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
250  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> < 2);
251  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" }, { 1, "1" } }));
252  }
253 
254  void OralTest::testSimpleRecordInsertSelectByFields3 ()
255  {
256  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
257  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> < 2 && sph::f<&SimpleRecord::Value_> == QString { "1" });
258  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
259  }
260 
261  void OralTest::testSimpleRecordInsertSelectOneByFields ()
262  {
263  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
264  const auto& single = adapted->SelectOne (sph::f<&SimpleRecord::ID_> == 1);
265  QCOMPARE (single, (boost::optional<SimpleRecord> { { 1, "1" } }));
266  }
267 
268  void OralTest::testSimpleRecordInsertSelectSingleFieldByFields ()
269  {
270  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
271  const auto& list = adapted->Select (sph::fields<&SimpleRecord::Value_>, sph::f<&SimpleRecord::ID_> < 2);
272  QCOMPARE (list, (QList<QString> { "0", "1" }));
273  }
274 
275  void OralTest::testSimpleRecordInsertSelectFieldsByFields ()
276  {
277  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
278  const auto& list = adapted->Select (sph::fields<&SimpleRecord::ID_, &SimpleRecord::Value_>, sph::f<&SimpleRecord::ID_> < 2);
279  QCOMPARE (list, (QList<std::tuple<int, QString>> { { 0, "0" }, { 1, "1" } }));
280  }
281 
282  void OralTest::testSimpleRecordInsertSelectCount ()
283  {
284  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
285  const auto count = adapted->Select (sph::count);
286  QCOMPARE (count, 3);
287  }
288 
289  void OralTest::testSimpleRecordInsertSelectCountByFields ()
290  {
291  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
292  const auto count = adapted->Select (sph::count, sph::f<&SimpleRecord::ID_> < 2);
293  QCOMPARE (count, 2);
294  }
295 
296  void OralTest::testSimpleRecordUpdate ()
297  {
298  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
299  adapted->Update ({ 0, "meh" });
300  const auto updated = adapted->Select (sph::f<&SimpleRecord::ID_> == 0);
301  QCOMPARE (updated, (QList<SimpleRecord> { { 0, "meh" } }));
302  }
303 
304  void OralTest::testSimpleRecordUpdateExprTree ()
305  {
306  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
307  adapted->Update (sph::f<&SimpleRecord::Value_> = QString { "meh" }, sph::f<&SimpleRecord::ID_> == 0);
308  const auto updated = adapted->Select (sph::f<&SimpleRecord::ID_> == 0);
309  QCOMPARE (updated, (QList<SimpleRecord> { { 0, "meh" } }));
310  }
311 
312  void OralTest::testSimpleRecordUpdateMultiExprTree ()
313  {
314  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
315  adapted->Update ((sph::f<&SimpleRecord::Value_> = QString { "meh" }, sph::f<&SimpleRecord::ID_> = 10),
316  sph::f<&SimpleRecord::ID_> == 0);
317  const auto updated = adapted->Select (sph::f<&SimpleRecord::ID_> == 10);
318  QCOMPARE (updated, (QList<SimpleRecord> { { 10, "meh" } }));
319  }
320 
321  void OralTest::testAutoPKeyRecordInsertSelect ()
322  {
323  auto adapted = PrepareRecords<AutogenPKeyRecord> (MakeDatabase ());
324  const auto& list = adapted->Select ();
325  QCOMPARE (list, (QList<AutogenPKeyRecord> { { 1, "0" }, { 2, "1" }, { 3, "2" } }));
326  }
327 
328  void OralTest::testAutoPKeyRecordInsertRvalueReturnsPKey ()
329  {
330  auto adapted = Util::oral::AdaptPtr<AutogenPKeyRecord> (MakeDatabase ());
331 
332  QList<int> ids;
333  for (int i = 0; i < 3; ++i)
334  ids << adapted->Insert ({ 0, QString::number (i) });
335 
336  QCOMPARE (ids, (QList<int> { 1, 2, 3 }));
337  }
338 
339  void OralTest::testAutoPKeyRecordInsertConstLvalueReturnsPKey ()
340  {
341  auto adapted = Util::oral::AdaptPtr<AutogenPKeyRecord> (MakeDatabase ());
342 
343  QList<AutogenPKeyRecord> records;
344  for (int i = 0; i < 3; ++i)
345  records.push_back ({ 0, QString::number (i) });
346 
347  QList<int> ids;
348  for (const auto& record : records)
349  ids << adapted->Insert (record);
350 
351  QCOMPARE (ids, (QList<int> { 1, 2, 3 }));
352  }
353 
354  void OralTest::testAutoPKeyRecordInsertSetsPKey ()
355  {
356  auto adapted = Util::oral::AdaptPtr<AutogenPKeyRecord> (MakeDatabase ());
357 
358  QList<AutogenPKeyRecord> records;
359  for (int i = 0; i < 3; ++i)
360  records.push_back ({ 0, QString::number (i) });
361 
362  for (auto& record : records)
363  adapted->Insert (record);
364 
365  QCOMPARE (records, (QList<AutogenPKeyRecord> { { 1, "0" }, { 2, "1" }, { 3, "2" } }));
366  }
367 
368  void OralTest::testNoPKeyRecordInsertSelect ()
369  {
370  auto adapted = PrepareRecords<NoPKeyRecord> (MakeDatabase ());
371  const auto& list = adapted->Select ();
372  QCOMPARE (list, (QList<NoPKeyRecord> { { 0, "0" }, { 1, "1" }, { 2, "2" } }));
373  }
374 
375  void OralTest::testNonInPlaceConstructibleRecordInsertSelect ()
376  {
377  auto adapted = Util::oral::AdaptPtr<NonInPlaceConstructibleRecord> (MakeDatabase ());
378  for (int i = 0; i < 3; ++i)
379  adapted->Insert ({ i, QString::number (i), 0 });
380 
381  const auto& list = adapted->Select ();
382  QCOMPARE (list, (QList<NonInPlaceConstructibleRecord> { { 0, "0", 0 }, { 1, "1", 0 }, { 2, "2", 0 } }));
383  }
384 
385  namespace
386  {
387  template<typename Ex, typename F>
388  void ShallThrow (F&& f)
389  {
390  bool failed = false;
391  try
392  {
393  f ();
394  }
395  catch (const Ex&)
396  {
397  failed = true;
398  }
399 
400  QCOMPARE (failed, true);
401  }
402  }
403 
404  void OralTest::testComplexConstraintsRecordInsertSelect ()
405  {
406  auto adapted = Util::oral::AdaptPtr<ComplexConstraintsRecord> (MakeDatabase ());
407 
408  adapted->Insert ({ 0, "first", 1, 2 });
409  ShallThrow<oral::QueryException> ([&] { adapted->Insert ({ 0, "second", 1, 2 }); });
410  ShallThrow<oral::QueryException> ([&] { adapted->Insert ({ 0, "first", 1, 3 }); });
411  adapted->Insert ({ 0, "second", 1, 3 });
412  ShallThrow<oral::QueryException> ([&] { adapted->Insert ({ 0, "first", 1, 3 }); });
413 
414  const auto& list = adapted->Select ();
415  QCOMPARE (list, (QList<ComplexConstraintsRecord> { { 0, "first", 1, 2 }, { 0, "second", 1, 3 } }));
416  }
417 
418  void OralTest::benchSimpleRecordAdapt ()
419  {
420  auto db = MakeDatabase ();
421  Util::oral::Adapt<SimpleRecord> (db);
422 
423  QBENCHMARK { Util::oral::Adapt<SimpleRecord> (db); }
424  }
425 
426  void OralTest::benchBaselineInsert ()
427  {
428  auto db = MakeDatabase ();
429  Util::oral::Adapt<SimpleRecord> (db);
430 
431  QSqlQuery query { db };
432  query.prepare ("INSERT OR IGNORE INTO SimpleRecord (ID, Value) VALUES (:id, :val);");
433 
434  QBENCHMARK
435  {
436  query.bindValue (":id", 0);
437  query.bindValue (":val", "0");
438  query.exec ();
439  }
440  }
441 
442  void OralTest::benchSimpleRecordInsert ()
443  {
444  auto db = MakeDatabase ();
445  const auto& adapted = Util::oral::Adapt<SimpleRecord> (db);
446 
447  QBENCHMARK { adapted.Insert ({ 0, "0" }, lco::InsertAction::Ignore); }
448  }
449 
450  void OralTest::benchBaselineUpdate ()
451  {
452  auto db = MakeDatabase ();
453  const auto& adapted = Util::oral::Adapt<SimpleRecord> (db);
454  adapted.Insert ({ 0, "0" });
455 
456  QSqlQuery query { db };
457  query.prepare ("UPDATE SimpleRecord SET Value = :val WHERE Id = :id;");
458 
459  QBENCHMARK
460  {
461  query.bindValue (":id", 0);
462  query.bindValue (":val", "1");
463  query.exec ();
464  }
465  }
466 
467  void OralTest::benchSimpleRecordUpdate ()
468  {
469  auto db = MakeDatabase ();
470  auto adapted = Util::oral::Adapt<SimpleRecord> (db);
471  adapted.Insert ({ 0, "0" });
472 
473  QBENCHMARK { adapted.Update ({ 0, "1" }); }
474  }
475 }
476 }
lco::PKey< int, lco::NoAutogen > ID_
Definition: oraltest.cpp:37
constexpr detail::AggregateType< detail::AggregateFunction::Count > count
Definition: oral.h:936
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
Definition: oral.h:931
QString Value_
Definition: oraltest.cpp:38
Typelist< Args... > Constraints
Definition: oraltypes.h:216
static QString ClassName()
Definition: oraltest.cpp:40
QSqlDatabase MakeDatabase(const QString &name=":memory:")
Definition: common.h:74
BOOST_FUSION_ADAPT_STRUCT(SimpleRecord, ID_, Value_) struct AutogenPKeyRecord
Definition: oraltest.cpp:51
auto AsTuple() const
Definition: oraltest.cpp:45
#define TOSTRING(n)
Definition: common.h:53