1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qbs.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
41 
42 #include "tst_tools.h"
43 
44 #include "../shared.h"
45 
46 #include <tools/buildoptions.h>
47 #include <tools/error.h>
48 #include <tools/fileinfo.h>
49 #include <tools/filesaver.h>
50 #include <tools/hostosinfo.h>
51 #include <tools/processutils.h>
52 #include <tools/profile.h>
53 #include <tools/set.h>
54 #include <tools/settings.h>
55 #include <tools/setupprojectparameters.h>
56 #include <tools/stringutils.h>
57 #include <tools/version.h>
58 
59 #include <QtCore/qdir.h>
60 #include <QtCore/qfile.h>
61 #include <QtCore/qfileinfo.h>
62 #include <QtCore/qsettings.h>
63 #include <QtCore/qtemporarydir.h>
64 #include <QtCore/qtemporaryfile.h>
65 
66 #include <QtTest/qtest.h>
67 
68 using namespace qbs;
69 using namespace qbs::Internal;
70 
71 namespace std {
72 template<typename T> struct hash<std::vector<T>>
73 {
operator ()std::hash74     std::size_t operator()(const std::vector<T> &v) const noexcept
75     {
76         return hashRange(v);
77     }
78 };
79 } // namespace std
80 
TestTools(Settings * settings)81 TestTools::TestTools(Settings *settings)
82     : m_settings(settings), testDataDir(testWorkDir("tools"))
83 {
84 }
85 
~TestTools()86 TestTools::~TestTools()
87 {
88     qDeleteAll(m_tmpDirs);
89 }
90 
initTestCase()91 void TestTools::initTestCase()
92 {
93     QDir().mkpath(testDataDir);
94 }
95 
fileSaver()96 void TestTools::fileSaver()
97 {
98     QVERIFY(QDir::setCurrent(testDataDir));
99 
100     static const char *fn = "foo.txt";
101     const auto run = [](const std::function<void()> &func) {
102         if (QFile::exists(fn))
103             QVERIFY(QFile::remove(fn));
104         func();
105         if (QFile::exists(fn))
106             QVERIFY(QFile::remove(fn));
107     };
108 
109     // failing to open the file means nothing works
110     run([] {
111         Internal::FileSaver fs(fn);
112         QVERIFY(!fs.device());
113         QVERIFY(!fs.write("hello"));
114         QVERIFY(!fs.commit());
115         QVERIFY(!QFile::exists(fn));
116     });
117 
118     // verify that correct usage creates a file with the right contents
119     run([] {
120         Internal::FileSaver fs(fn);
121         QVERIFY(fs.open());
122         QVERIFY(fs.device());
123         QVERIFY(fs.write("hello"));
124         QVERIFY(fs.commit());
125         QVERIFY(QFile::exists(fn));
126         QFile f(fn);
127         QVERIFY(f.open(QIODevice::ReadOnly));
128         QCOMPARE(f.readAll(), QByteArrayLiteral("hello"));
129     });
130 
131     // failing to commit writes nothing
132     run([] {
133         Internal::FileSaver fs(fn);
134         QVERIFY(fs.open());
135         QVERIFY(fs.device());
136         QVERIFY(fs.write("hello"));
137         QVERIFY(!QFile::exists(fn));
138     });
139 
140     // verify that correct usage creates a file with the right contents and does not overwrite
141     run([] {
142         {
143             Internal::FileSaver fs(fn);
144             QVERIFY(fs.open());
145             QVERIFY(fs.device());
146             QVERIFY(fs.write("hello"));
147             QVERIFY(fs.commit());
148             QVERIFY(QFile::exists(fn));
149             QFile f(fn);
150             QVERIFY(f.open(QIODevice::ReadOnly));
151             QCOMPARE(f.readAll(), QByteArrayLiteral("hello"));
152         }
153 
154         const auto lm = QFileInfo(fn).lastModified();
155         QVERIFY(lm.isValid());
156 
157         waitForNewTimestamp(".");
158 
159         {
160             Internal::FileSaver fs(fn);
161             QVERIFY(fs.open());
162             QVERIFY(fs.device());
163             QVERIFY(fs.write("hello"));
164             QVERIFY(fs.commit());
165             QVERIFY(QFile::exists(fn));
166         }
167 
168         const auto lm2 = QFileInfo(fn).lastModified();
169         QVERIFY(lm2.isValid());
170 
171         QCOMPARE(lm, lm2); // timestamps should be the same since content did not change
172 
173         waitForNewTimestamp(".");
174 
175         {
176             Internal::FileSaver fs(fn);
177             QVERIFY(fs.open());
178             QVERIFY(fs.device());
179             QVERIFY(fs.write("hello2"));
180             QVERIFY(fs.commit());
181             QVERIFY(QFile::exists(fn));
182             QFile f(fn);
183             QVERIFY(f.open(QIODevice::ReadOnly));
184             QCOMPARE(f.readAll(), QByteArrayLiteral("hello2"));
185         }
186 
187         const auto lm3 = QFileInfo(fn).lastModified();
188         QVERIFY(lm3.isValid());
189 
190         QVERIFY(lm != lm3); // timestamps should differ since the content changed
191 
192         waitForNewTimestamp(".");
193 
194         {
195             // Test overwriteIfUnchanged
196             Internal::FileSaver fs(fn, true);
197             QVERIFY(fs.open());
198             QVERIFY(fs.device());
199             QVERIFY(fs.write("hello2"));
200             QVERIFY(fs.commit());
201             QVERIFY(QFile::exists(fn));
202             QFile f(fn);
203             QVERIFY(f.open(QIODevice::ReadOnly));
204             QCOMPARE(f.readAll(), QByteArrayLiteral("hello2"));
205         }
206 
207         const auto lm4 = QFileInfo(fn).lastModified();
208         QVERIFY(lm4.isValid());
209 
210         QVERIFY(lm3 != lm4); // timestamps should differ since we always overwrite
211     });
212 }
213 
testFileInfo()214 void TestTools::testFileInfo()
215 {
216     QCOMPARE(FileInfo::fileName("C:/waffl/copter.exe"), QString("copter.exe"));
217     QCOMPARE(FileInfo::baseName("C:/waffl/copter.exe.lib"), QString("copter"));
218     QCOMPARE(FileInfo::completeBaseName("C:/waffl/copter.exe.lib"), QString("copter.exe"));
219     QCOMPARE(FileInfo::suffix("C:/waffl/copter.exe.lib"), QString("lib"));
220     QCOMPARE(FileInfo::completeSuffix("C:/waffl/copter.exe.lib"), QString("exe.lib"));
221     QCOMPARE(FileInfo::path("abc"), QString("."));
222     QCOMPARE(FileInfo::path("/abc/lol"), QString("/abc"));
223     QCOMPARE(FileInfo::path("/fileInRoot"), QString(QLatin1Char('/')));
224     if (HostOsInfo::isWindowsHost())
225         QCOMPARE(FileInfo::path("C:/fileInDriveRoot"), QString("C:/"));
226     QVERIFY(!FileInfo::isAbsolute("bla/lol"));
227     QVERIFY(FileInfo::isAbsolute("/bla/lol"));
228     if (HostOsInfo::isWindowsHost()) {
229         QVERIFY(FileInfo::isAbsolute("C:\\bla\\lol"));
230         QVERIFY(FileInfo::isAbsolute("C:\\"));
231         QVERIFY(FileInfo::isAbsolute("C:/"));
232         QVERIFY(!FileInfo::isAbsolute("C:"));
233     }
234     QCOMPARE(FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl"));
235     QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../foo/bar"), QString("/abc/def/ghi/foo/bar"));
236     QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../../foo/bar"), QString("/abc/def/foo/bar"));
237     QCOMPARE(FileInfo::resolvePath("/abc", "../../../foo/bar"), QString("/foo/bar"));
238     if (HostOsInfo::isWindowsHost()) {
239         QCOMPARE(FileInfo::resolvePath("C:/share", ".."), QString("C:/"));
240         QCOMPARE(FileInfo::resolvePath("C:/share", "D:/"), QString("D:/"));
241         QCOMPARE(FileInfo::resolvePath("C:/share", "D:"), QString()); // should soft-assert
242     }
243     QCOMPARE(FileInfo("/does/not/exist").lastModified(), FileTime());
244 }
245 
fileCaseCheck()246 void TestTools::fileCaseCheck()
247 {
248     QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/CamelCase"));
249     QVERIFY2(tempFile.open(), qPrintable(tempFile.errorString()));
250     QFileInfo tempFileInfo(tempFile.fileName());
251     const QString lowerFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
252             + tempFileInfo.fileName().toLower();
253     const QString upperFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
254             + tempFileInfo.fileName().toUpper();
255     QVERIFY(FileInfo::isFileCaseCorrect(tempFileInfo.absoluteFilePath()));
256     if (QFile::exists(lowerFilePath))
257         QVERIFY(!FileInfo::isFileCaseCorrect(lowerFilePath));
258     if (QFile::exists(upperFilePath))
259         QVERIFY(!FileInfo::isFileCaseCorrect(upperFilePath));
260 }
261 
testProfiles()262 void TestTools::testProfiles()
263 {
264     TemporaryProfile tpp("parent", m_settings);
265     Profile parentProfile = tpp.p;
266     TemporaryProfile tpc("child", m_settings);
267     Profile childProfile = tpc.p;
268     parentProfile.removeBaseProfile();
269     parentProfile.remove("testKey");
270     QCOMPARE(parentProfile.value("testKey", "none").toString(), QLatin1String("none"));
271     parentProfile.setValue("testKey", "testValue");
272     QCOMPARE(parentProfile.value("testKey").toString(), QLatin1String("testValue"));
273 
274     childProfile.remove("testKey");
275     childProfile.removeBaseProfile();
276     QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("none"));
277     childProfile.setBaseProfile("parent");
278     QCOMPARE(childProfile.value("testKey").toString(), QLatin1String("testValue"));
279 
280     // Change base profile and check if the inherited value also changes.
281     TemporaryProfile tpf("foo", m_settings);
282     Profile fooProfile = tpf.p;
283     fooProfile.setValue("testKey", "gnampf");
284     childProfile.setBaseProfile("foo");
285     QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("gnampf"));
286 
287     ErrorInfo errorInfo;
288     childProfile.setBaseProfile("SmurfAlongWithMe");
289     childProfile.value("blubb", QString(), &errorInfo);
290     QVERIFY(errorInfo.hasError());
291 
292     errorInfo.clear();
293     childProfile.setBaseProfile("parent");
294     parentProfile.setBaseProfile("child");
295     QVERIFY(!childProfile.value("blubb", QString(), &errorInfo).isValid());
296     QVERIFY(errorInfo.hasError());
297 
298     QVERIFY(!childProfile.allKeys(Profile::KeySelectionNonRecursive).empty());
299 
300     errorInfo.clear();
301     QVERIFY(childProfile.allKeys(Profile::KeySelectionRecursive, &errorInfo).empty());
302     QVERIFY(errorInfo.hasError());
303 }
304 
testSettingsMigration()305 void TestTools::testSettingsMigration()
306 {
307     QFETCH(QString, baseDir);
308     QFETCH(bool, hasOldSettings);
309     Settings settings(baseDir);
310     if (hasOldSettings) {
311         // checks that we do not copy old "profiles/" dir anymore
312         QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles/right.txt")
313                 .exists());
314         QVERIFY(!settings.value("key", Settings::UserScope).toString().isEmpty());
315     } else {
316         QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles").exists());
317         QVERIFY(settings.allKeys(Settings::UserScope).empty());
318     }
319 }
320 
testSettingsMigration_data()321 void TestTools::testSettingsMigration_data()
322 {
323     QTest::addColumn<QString>("baseDir");
324     QTest::addColumn<bool>("hasOldSettings");
325     QTest::newRow("settings dir with lots of versions") << setupSettingsDir1() << true;
326     QTest::newRow("settings dir with only a fallback") << setupSettingsDir2() << true;
327     QTest::newRow("no previous settings") << setupSettingsDir3() << false;
328 }
329 
setupSettingsDir1()330 QString TestTools::setupSettingsDir1()
331 {
332     const auto baseDir = new QTemporaryDir;
333     m_tmpDirs.push_back(baseDir);
334 
335     const Version thisVersion = Version::fromString(QBS_VERSION);
336     Version predecessor;
337     if (thisVersion.patchLevel() > 0) {
338         predecessor.setMajorVersion(thisVersion.majorVersion());
339         predecessor.setMinorVersion(thisVersion.minorVersion());
340         predecessor.setPatchLevel(thisVersion.patchLevel() - 1);
341     } else if (thisVersion.minorVersion() > 0) {
342         predecessor.setMajorVersion(thisVersion.majorVersion());
343         predecessor.setMinorVersion(thisVersion.minorVersion() - 1);
344         predecessor.setPatchLevel(99);
345     } else {
346         predecessor.setMajorVersion(thisVersion.majorVersion() - 1);
347         predecessor.setMajorVersion(99);
348         predecessor.setPatchLevel(99);
349     }
350     const auto versions = QList<Version>() << Version(0, 1, 0) << Version(1, 0, 5) << predecessor
351             << Version(thisVersion.majorVersion() + 1, thisVersion.minorVersion(),
352                        thisVersion.patchLevel())
353             << Version(thisVersion.majorVersion(), thisVersion.minorVersion() + 1,
354                        thisVersion.patchLevel())
355             << Version(thisVersion.majorVersion(), thisVersion.minorVersion(),
356                        thisVersion.patchLevel() + 1)
357             << Version(99, 99, 99);
358     for (const Version &v : versions) {
359         const QString settingsDir = baseDir->path() + "/qbs/" + v.toString();
360         QSettings s(settingsDir + "/qbs.conf",
361                     HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
362         const QString profilesDir = settingsDir + "/profiles";
363         QDir::root().mkpath(profilesDir);
364         const QString magicString = v == predecessor ? "right" : "wrong";
365         QFile f(profilesDir + '/' + magicString + ".txt");
366         f.open(QIODevice::WriteOnly);
367         s.setValue("org/qt-project/qbs/key", profilesDir + magicString);
368     }
369 
370     return baseDir->path();
371 }
372 
setupSettingsDir2()373 QString TestTools::setupSettingsDir2()
374 {
375     const auto baseDir = new QTemporaryDir;
376     m_tmpDirs.push_back(baseDir);
377     const QString settingsDir = baseDir->path();
378     QSettings s(settingsDir + QLatin1String("/qbs.conf"),
379                 HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
380     const QString profilesDir = settingsDir + QLatin1String("/qbs/profiles");
381     QDir::root().mkpath(profilesDir);
382     QFile f(profilesDir + "/right.txt");
383     f.open(QIODevice::WriteOnly);
384     s.setValue("org/qt-project/qbs/key", profilesDir + "right");
385 
386     return baseDir->path();
387 }
388 
setupSettingsDir3()389 QString TestTools::setupSettingsDir3()
390 {
391     const auto baseDir = new QTemporaryDir;
392     m_tmpDirs.push_back(baseDir);
393     return baseDir->path();
394 }
395 
testBuildConfigMerging()396 void TestTools::testBuildConfigMerging()
397 {
398     TemporaryProfile tp(QLatin1String("tst_tools_profile"), m_settings);
399     Profile profile = tp.p;
400     profile.setValue(QStringLiteral("topLevelKey"), QStringLiteral("topLevelValue"));
401     profile.setValue(QStringLiteral("qbs.toolchain"), QStringLiteral("gcc"));
402     profile.setValue(QStringLiteral("qbs.architecture"),
403                      QStringLiteral("Jean-Claude Pillemann"));
404     profile.setValue(QStringLiteral("cpp.treatWarningsAsErrors"), true);
405     QVariantMap overrideMap;
406     overrideMap.insert(QStringLiteral("qbs.toolchain"), QStringLiteral("clang"));
407     overrideMap.insert(QStringLiteral("qbs.installRoot"), QStringLiteral("/blubb"));
408     SetupProjectParameters params;
409     params.setSettingsDirectory(m_settings->baseDirectory());
410     params.setTopLevelProfile(profile.name());
411     params.setConfigurationName(QStringLiteral("debug"));
412     params.setOverriddenValues(overrideMap);
413     const ErrorInfo error = params.expandBuildConfiguration();
414     QVERIFY2(!error.hasError(), qPrintable(error.toString()));
415     const QVariantMap finalMap = params.finalBuildConfigurationTree();
416     QCOMPARE(finalMap.size(), 3);
417     QCOMPARE(finalMap.value(QStringLiteral("topLevelKey")).toString(),
418              QStringLiteral("topLevelValue"));
419     const QVariantMap finalQbsMap = finalMap.value(QStringLiteral("qbs")).toMap();
420     QCOMPARE(finalQbsMap.size(), 4);
421     QCOMPARE(finalQbsMap.value(QStringLiteral("toolchain")).toString(),
422              QStringLiteral("clang"));
423     QCOMPARE(finalQbsMap.value(QStringLiteral("configurationName")).toString(),
424              QStringLiteral("debug"));
425     QCOMPARE(finalQbsMap.value(QStringLiteral("architecture")).toString(),
426              QStringLiteral("Jean-Claude Pillemann"));
427     QCOMPARE(finalQbsMap.value(QStringLiteral("installRoot")).toString(), QLatin1String("/blubb"));
428     const QVariantMap finalCppMap = finalMap.value(QStringLiteral("cpp")).toMap();
429     QCOMPARE(finalCppMap.size(), 1);
430     QCOMPARE(finalCppMap.value(QStringLiteral("treatWarningsAsErrors")).toBool(), true);
431 }
432 
testProcessNameByPid()433 void TestTools::testProcessNameByPid()
434 {
435     QCOMPARE(qAppName(), processNameByPid(QCoreApplication::applicationPid()));
436 }
437 
438 
toNumber(const QString & str)439 int toNumber(const QString &str)
440 {
441     int res = 0;
442     for (const QChar &c : str)
443         res = (res * 10) + c.digitValue();
444     return res;
445 }
446 
set_operator_eq()447 void TestTools::set_operator_eq()
448 {
449     {
450         Set<int> set1, set2;
451         QVERIFY(set1 == set2);
452         QVERIFY(!(set1 != set2));
453 
454         set1.insert(1);
455         QVERIFY(set1 != set2);
456         QVERIFY(!(set1 == set2));
457 
458         set2.insert(1);
459         QVERIFY(set1 == set2);
460         QVERIFY(!(set1 != set2));
461 
462         set2.insert(1);
463         QVERIFY(set1 == set2);
464         QVERIFY(!(set1 != set2));
465 
466         set1.insert(2);
467         QVERIFY(set1 != set2);
468         QVERIFY(!(set1 == set2));
469     }
470 
471     {
472         Set<QString> set1, set2;
473         QVERIFY(set1 == set2);
474         QVERIFY(!(set1 != set2));
475 
476         set1.insert("one");
477         QVERIFY(set1 != set2);
478         QVERIFY(!(set1 == set2));
479 
480         set2.insert("one");
481         QVERIFY(set1 == set2);
482         QVERIFY(!(set1 != set2));
483 
484         set2.insert("one");
485         QVERIFY(set1 == set2);
486         QVERIFY(!(set1 != set2));
487 
488         set1.insert("two");
489         QVERIFY(set1 != set2);
490         QVERIFY(!(set1 == set2));
491     }
492 
493     {
494         Set<QString> a;
495         Set<QString> b;
496 
497         a += "otto";
498         b += "willy";
499 
500         QVERIFY(a != b);
501         QVERIFY(!(a == b));
502     }
503 
504     {
505         Set<int> s1, s2;
506         s1.reserve(100);
507         s2.reserve(4);
508         QVERIFY(s1 == s2);
509         s1 << 100 << 200 << 300 << 400;
510         s2 << 400 << 300 << 200 << 100;
511         QVERIFY(s1 == s2);
512     }
513 }
514 
set_swap()515 void TestTools::set_swap()
516 {
517     Set<int> s1, s2;
518     s1.insert(1);
519     s2.insert(2);
520     s1.swap(s2);
521     QCOMPARE(*s1.begin(),2);
522     QCOMPARE(*s2.begin(),1);
523 }
524 
set_size()525 void TestTools::set_size()
526 {
527     Set<int> set;
528     QVERIFY(set.size() == 0);
529     QVERIFY(set.empty());
530     QVERIFY(set.size() == set.size());
531 
532     set.insert(1);
533     QVERIFY(set.size() == 1);
534     QVERIFY(!set.empty());
535     QVERIFY(set.size() == set.size());
536 
537     set.insert(1);
538     QVERIFY(set.size() == 1);
539     QVERIFY(!set.empty());
540     QVERIFY(set.size() == set.size());
541 
542     set.insert(2);
543     QVERIFY(set.size() == 2);
544     QVERIFY(!set.empty());
545     QVERIFY(set.size() == set.size());
546 
547     set.remove(1);
548     QVERIFY(set.size() == 1);
549     QVERIFY(!set.empty());
550     QVERIFY(set.size() == set.size());
551 
552     set.remove(1);
553     QVERIFY(set.size() == 1);
554     QVERIFY(!set.empty());
555     QVERIFY(set.size() == set.size());
556 
557     set.remove(2);
558     QVERIFY(set.size() == 0);
559     QVERIFY(set.empty());
560     QVERIFY(set.size() == set.size());
561 }
562 
set_capacity()563 void TestTools::set_capacity()
564 {
565     Set<int> set;
566     size_t n = set.capacity();
567     QVERIFY(n == 0);
568 
569     for (int i = 0; i < 1000; ++i) {
570         set.insert(i);
571         QVERIFY(set.capacity() >= set.size());
572     }
573 }
574 
set_reserve()575 void TestTools::set_reserve()
576 {
577     Set<int> set;
578 
579     set.reserve(1000);
580     QVERIFY(set.capacity() >= 1000);
581 
582     for (int i = 0; i < 500; ++i)
583         set.insert(i);
584 
585     QVERIFY(set.capacity() >= 1000);
586 
587     for (int j = 0; j < 500; ++j)
588         set.remove(j);
589 
590     QVERIFY(set.capacity() >= 1000);
591 }
592 
set_clear()593 void TestTools::set_clear()
594 {
595     Set<QString> set1, set2;
596     QVERIFY(set1.size() == 0);
597 
598     set1.clear();
599     QVERIFY(set1.size() == 0);
600 
601     set1.insert("foo");
602     QVERIFY(set1.size() != 0);
603 
604     set2 = set1;
605 
606     set1.clear();
607     QVERIFY(set1.size() == 0);
608     QVERIFY(set2.size() != 0);
609 
610     set2.clear();
611     QVERIFY(set1.size() == 0);
612     QVERIFY(set2.size() == 0);
613 }
614 
set_remove()615 void TestTools::set_remove()
616 {
617     Set<QString> set1;
618 
619     const size_t max = 500;
620 
621     for (size_t i = 0; i < max; ++i)
622         set1.insert(QString::number(i));
623 
624     QCOMPARE(set1.size(), max);
625 
626     for (size_t j = 0; j < max; ++j) {
627         set1.remove(QString::number((j * 17) % max));
628         QCOMPARE(set1.size(), max - j - 1);
629     }
630 }
631 
set_contains()632 void TestTools::set_contains()
633 {
634     Set<QString> set1;
635 
636     for (int i = 0; i < 500; ++i) {
637         QVERIFY(!set1.contains(QString::number(i)));
638         set1.insert(QString::number(i));
639         QVERIFY(set1.contains(QString::number(i)));
640     }
641 
642     QCOMPARE(set1.size(), size_t { 500 });
643 
644     for (int j = 0; j < 500; ++j) {
645         int i = (j * 17) % 500;
646         QVERIFY(set1.contains(QString::number(i)));
647         set1.remove(QString::number(i));
648         QVERIFY(!set1.contains(QString::number(i)));
649     }
650 }
651 
set_containsSet()652 void TestTools::set_containsSet()
653 {
654     Set<QString> set1;
655     Set<QString> set2;
656 
657     // empty set contains the empty set
658     QVERIFY(set1.contains(set2));
659 
660     for (int i = 0; i < 500; ++i) {
661         set1.insert(QString::number(i));
662         set2.insert(QString::number(i));
663     }
664     QVERIFY(set1.contains(set2));
665 
666     set2.remove(QString::number(19));
667     set2.remove(QString::number(82));
668     set2.remove(QString::number(7));
669     QVERIFY(set1.contains(set2));
670 
671     set1.remove(QString::number(23));
672     QVERIFY(!set1.contains(set2));
673 
674     // filled set contains the empty set as well
675     Set<QString> set3;
676     QVERIFY(set1.contains(set3));
677 
678     // the empty set doesn't contain a filled set
679     QVERIFY(!set3.contains(set1));
680 
681     // verify const signature
682     const Set<QString> set4;
683     QVERIFY(set3.contains(set4));
684 }
685 
set_find()686 void TestTools::set_find()
687 {
688     Set<QString> set1;
689 
690     for (int i = 0; i < 500; ++i) {
691         QVERIFY(set1.find(QString::number(i)) == set1.end());
692         set1.insert(QString::number(i));
693         const auto it = set1.find(QString::number(i));
694         QVERIFY(it != set1.end());
695         QVERIFY(*it == QString::number(i));
696     }
697 
698     QCOMPARE(set1.size(), size_t { 500 });
699 
700     for (int j = 0; j < 500; ++j) {
701         int i = (j * 17) % 500;
702         const auto it = set1.find(QString::number(i));
703         QVERIFY(it != set1.end());
704         QVERIFY(*it == QString::number(i));
705         set1.remove(QString::number(i));
706         QVERIFY(set1.find(QString::number(i)) == set1.end());
707     }
708 }
709 
set_begin()710 void TestTools::set_begin()
711 {
712     Set<int> set1;
713     Set<int> set2 = set1;
714 
715     {
716         const auto i = set1.constBegin();
717         const auto j = set1.cbegin();
718         const auto k = set2.constBegin();
719         const auto ell = set2.cbegin();
720 
721         QVERIFY(i == j);
722         QVERIFY(k == ell);
723     }
724 
725     set1.insert(44);
726 
727     {
728         const auto i = set1.constBegin();
729         const auto j = set1.cbegin();
730         const auto k = set2.constBegin();
731         const auto ell = set2.cbegin();
732 
733         QVERIFY(i == j);
734         QVERIFY(k == ell);
735     }
736 
737     set2 = set1;
738 
739     {
740         const auto i = set1.constBegin();
741         const auto j = set1.cbegin();
742         const auto k = set2.constBegin();
743         const auto ell = set2.cbegin();
744 
745         QVERIFY(i == j);
746         QVERIFY(k == ell);
747     }
748 }
749 
set_end()750 void TestTools::set_end()
751 {
752     Set<int> set1;
753     Set<int> set2 = set1;
754 
755     {
756         const auto i = set1.constEnd();
757         const auto j = set1.cend();
758         const auto k = set2.constEnd();
759         const auto ell = set2.cend();
760 
761         QVERIFY(i == j);
762         QVERIFY(k == ell);
763 
764         QVERIFY(set1.constBegin() == set1.constEnd());
765         QVERIFY(set2.constBegin() == set2.constEnd());
766     }
767 
768     set1.insert(44);
769 
770     {
771         const auto i = set1.constEnd();
772         const auto j = set1.cend();
773         const auto k = set2.constEnd();
774         const auto ell = set2.cend();
775 
776         QVERIFY(i == j);
777         QVERIFY(k == ell);
778 
779         QVERIFY(set1.constBegin() != set1.constEnd());
780         QVERIFY(set2.constBegin() == set2.constEnd());
781     }
782 
783     set2 = set1;
784 
785     {
786         const auto i = set1.constEnd();
787         const auto j = set1.cend();
788         const auto k = set2.constEnd();
789         const auto ell = set2.cend();
790 
791         QVERIFY(i == j);
792         QVERIFY(k == ell);
793 
794         QVERIFY(set1.constBegin() != set1.constEnd());
795         QVERIFY(set2.constBegin() != set2.constEnd());
796     }
797 
798     set1.clear();
799     set2.clear();
800     QVERIFY(set1.constBegin() == set1.constEnd());
801     QVERIFY(set2.constBegin() == set2.constEnd());
802 }
803 
804 struct IdentityTracker {
805     int value, id;
806 };
operator ==(IdentityTracker lhs,IdentityTracker rhs)807 inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; }
operator <(IdentityTracker lhs,IdentityTracker rhs)808 inline bool operator<(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value < rhs.value; }
809 
set_insert()810 void TestTools::set_insert()
811 {
812     {
813         Set<int> set1;
814         QVERIFY(set1.size() == 0);
815         set1.insert(1);
816         QVERIFY(set1.size() == 1);
817         set1.insert(2);
818         QVERIFY(set1.size() == 2);
819         set1.insert(2);
820         QVERIFY(set1.size() == 2);
821         QVERIFY(set1.contains(2));
822         set1.remove(2);
823         QVERIFY(set1.size() == 1);
824         QVERIFY(!set1.contains(2));
825         set1.insert(2);
826         QVERIFY(set1.size() == 2);
827         QVERIFY(set1.contains(2));
828     }
829 
830     {
831         Set<int> set1;
832         QVERIFY(set1.size() == 0);
833         set1 << 1;
834         QVERIFY(set1.size() == 1);
835         set1 << 2;
836         QVERIFY(set1.size() == 2);
837         set1 << 2;
838         QVERIFY(set1.size() == 2);
839         QVERIFY(set1.contains(2));
840         set1.remove(2);
841         QVERIFY(set1.size() == 1);
842         QVERIFY(!set1.contains(2));
843         set1 << 2;
844         QVERIFY(set1.size() == 2);
845         QVERIFY(set1.contains(2));
846     }
847 
848     {
849         Set<IdentityTracker> set;
850         QCOMPARE(set.size(), size_t { 0 });
851         const int dummy = -1;
852         IdentityTracker id00 = {0, 0}, id01 = {0, 1}, searchKey = {0, dummy};
853         QCOMPARE(set.insert(id00).first->id, id00.id);
854         QCOMPARE(set.size(), size_t { 1 });
855         QCOMPARE(set.insert(id01).first->id, id00.id); // first inserted is kept
856         QCOMPARE(set.size(), size_t { 1 });
857         QCOMPARE(set.find(searchKey)->id, id00.id);
858     }
859 }
860 
set_reverseIterators()861 void TestTools::set_reverseIterators()
862 {
863     Set<int> s;
864     s << 1 << 17 << 61 << 127 << 911;
865     std::vector<int> v(s.begin(), s.end());
866     std::reverse(v.begin(), v.end());
867     const Set<int> &cs = s;
868     QVERIFY(std::equal(v.begin(), v.end(), s.rbegin()));
869     QVERIFY(std::equal(v.begin(), v.end(), s.crbegin()));
870     QVERIFY(std::equal(v.begin(), v.end(), cs.rbegin()));
871     QVERIFY(std::equal(s.rbegin(), s.rend(), v.begin()));
872     QVERIFY(std::equal(s.crbegin(), s.crend(), v.begin()));
873     QVERIFY(std::equal(cs.rbegin(), cs.rend(), v.begin()));
874 }
875 
set_stlIterator()876 void TestTools::set_stlIterator()
877 {
878     Set<QString> set1;
879     for (int i = 0; i < 25000; ++i)
880         set1.insert(QString::number(i));
881 
882     {
883         int sum = 0;
884         auto i = set1.cbegin();
885         while (i != set1.end()) {
886             sum += toNumber(*i);
887             ++i;
888         }
889         QVERIFY(sum == 24999 * 25000 / 2);
890     }
891 
892     {
893         int sum = 0;
894         auto i = set1.cend();
895         while (i != set1.begin()) {
896             --i;
897             sum += toNumber(*i);
898         }
899         QVERIFY(sum == 24999 * 25000 / 2);
900     }
901 }
902 
set_stlMutableIterator()903 void TestTools::set_stlMutableIterator()
904 {
905     Set<QString> set1;
906     for (int i = 0; i < 25000; ++i)
907         set1.insert(QString::number(i));
908 
909     {
910         int sum = 0;
911         auto i = set1.begin();
912         while (i != set1.end()) {
913             sum += toNumber(*i);
914             ++i;
915         }
916         QVERIFY(sum == 24999 * 25000 / 2);
917     }
918 
919     {
920         int sum = 0;
921         auto i = set1.end();
922         while (i != set1.begin()) {
923             --i;
924             sum += toNumber(*i);
925         }
926         QVERIFY(sum == 24999 * 25000 / 2);
927     }
928 
929     {
930         Set<QString> set2 = set1;
931         Set<QString> set3 = set2;
932 
933         auto i = set2.begin();
934         auto j = set3.begin();
935 
936         while (i != set2.end()) {
937             i = set2.erase(i);
938         }
939         QVERIFY(set2.empty());
940         QVERIFY(!set3.empty());
941 
942         j = set3.end();
943         while (j != set3.begin()) {
944             j--;
945             if (j + 1 != set3.end())
946                 set3.erase(j + 1);
947         }
948         if (set3.begin() != set3.end())
949             set3.erase(set3.begin());
950 
951         QVERIFY(set2.empty());
952         QVERIFY(set3.empty());
953 
954         i = set2.insert("foo").first;
955         QCOMPARE(*i, QLatin1String("foo"));
956     }
957 }
958 
set_setOperations()959 void TestTools::set_setOperations()
960 {
961     Set<QString> set1, set2;
962     set1 << "alpha" << "beta" << "gamma" << "delta"              << "zeta"           << "omega";
963     set2            << "beta" << "gamma" << "delta" << "epsilon"           << "iota" << "omega";
964 
965     Set<QString> set3 = set1;
966     set3.unite(set2);
967     QVERIFY(set3.size() == 8);
968     QVERIFY(set3.contains("alpha"));
969     QVERIFY(set3.contains("beta"));
970     QVERIFY(set3.contains("gamma"));
971     QVERIFY(set3.contains("delta"));
972     QVERIFY(set3.contains("epsilon"));
973     QVERIFY(set3.contains("zeta"));
974     QVERIFY(set3.contains("iota"));
975     QVERIFY(set3.contains("omega"));
976 
977     Set<QString> set4 = set2;
978     set4.unite(set1);
979     QVERIFY(set4.size() == 8);
980     QVERIFY(set4.contains("alpha"));
981     QVERIFY(set4.contains("beta"));
982     QVERIFY(set4.contains("gamma"));
983     QVERIFY(set4.contains("delta"));
984     QVERIFY(set4.contains("epsilon"));
985     QVERIFY(set4.contains("zeta"));
986     QVERIFY(set4.contains("iota"));
987     QVERIFY(set4.contains("omega"));
988 
989     QVERIFY(set3 == set4);
990 
991     Set<QString> set5 = set1;
992     set5.intersect(set2);
993     QVERIFY(set5.size() == 4);
994     QVERIFY(set5.contains("beta"));
995     QVERIFY(set5.contains("gamma"));
996     QVERIFY(set5.contains("delta"));
997     QVERIFY(set5.contains("omega"));
998 
999     Set<QString> set6 = set2;
1000     set6.intersect(set1);
1001     QVERIFY(set6.size() == 4);
1002     QVERIFY(set6.contains("beta"));
1003     QVERIFY(set6.contains("gamma"));
1004     QVERIFY(set6.contains("delta"));
1005     QVERIFY(set6.contains("omega"));
1006 
1007     QVERIFY(set5 == set6);
1008 
1009     Set<QString> set7 = set1;
1010     set7.subtract(set2);
1011     QVERIFY(set7.size() == 2);
1012     QVERIFY(set7.contains("alpha"));
1013     QVERIFY(set7.contains("zeta"));
1014 
1015     Set<QString> set8 = set2;
1016     set8.subtract(set1);
1017     QVERIFY(set8.size() == 2);
1018     QVERIFY(set8.contains("epsilon"));
1019     QVERIFY(set8.contains("iota"));
1020 
1021     Set<QString> set9 = set1 | set2;
1022     QVERIFY(set9 == set3);
1023 
1024     Set<QString> set10 = set1 & set2;
1025     QVERIFY(set10 == set5);
1026 
1027     Set<QString> set11 = set1 + set2;
1028     QVERIFY(set11 == set3);
1029 
1030     Set<QString> set12 = set1 - set2;
1031     QVERIFY(set12 == set7);
1032 
1033     Set<QString> set13 = set2 - set1;
1034     QVERIFY(set13 == set8);
1035 
1036     Set<QString> set14 = set1;
1037     set14 |= set2;
1038     QVERIFY(set14 == set3);
1039 
1040     Set<QString> set15 = set1;
1041     set15 &= set2;
1042     QVERIFY(set15 == set5);
1043 
1044     Set<QString> set16 = set1;
1045     set16 += set2;
1046     QVERIFY(set16 == set3);
1047 
1048     Set<QString> set17 = set1;
1049     set17 -= set2;
1050     QVERIFY(set17 == set7);
1051 
1052     Set<QString> set18 = set2;
1053     set18 -= set1;
1054     QVERIFY(set18 == set8);
1055 }
1056 
set_makeSureTheComfortFunctionsCompile()1057 void TestTools::set_makeSureTheComfortFunctionsCompile()
1058 {
1059     Set<int> set1, set2, set3;
1060     set1 << 5;
1061     set1 |= set2;
1062     set1 |= 5;
1063     set1 &= set2;
1064     set1 &= 5;
1065     set1 += set2;
1066     set1 += 5;
1067     set1 -= set2;
1068     set1 -= 5;
1069     set1 = set2 | set3;
1070     set1 = set2 & set3;
1071     set1 = set2 + set3;
1072     set1 = set2 - set3;
1073 }
1074 
set_initializerList()1075 void TestTools::set_initializerList()
1076 {
1077     Set<int> set = {1, 1, 2, 3, 4, 5};
1078     QCOMPARE(set.size(), size_t { 5 });
1079     QVERIFY(set.contains(1));
1080     QVERIFY(set.contains(2));
1081     QVERIFY(set.contains(3));
1082     QVERIFY(set.contains(4));
1083     QVERIFY(set.contains(5));
1084 
1085     // check _which_ of the equal elements gets inserted (in the QHash/QMap case, it's the last):
1086     const Set<IdentityTracker> set2 = {{1, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
1087     QCOMPARE(set2.size(), size_t { 5 });
1088     const int dummy = -1;
1089     const IdentityTracker searchKey = {1, dummy};
1090     QCOMPARE(set2.find(searchKey)->id, 0);
1091 
1092     Set<int> emptySet{};
1093     QVERIFY(emptySet.empty());
1094 
1095     Set<int> set3{{}, {}, {}};
1096     QVERIFY(!set3.empty());
1097 }
1098 
set_intersects()1099 void TestTools::set_intersects()
1100 {
1101     Set<int> s1;
1102     Set<int> s2;
1103 
1104     QVERIFY(!s1.intersects(s1));
1105     QVERIFY(!s1.intersects(s2));
1106 
1107     s1 << 100;
1108     QVERIFY(s1.intersects(s1));
1109     QVERIFY(!s1.intersects(s2));
1110 
1111     s2 << 200;
1112     QVERIFY(!s1.intersects(s2));
1113 
1114     s1 << 200;
1115     QVERIFY(s1.intersects(s2));
1116 
1117     Set<int> s3;
1118     s3 << 500;
1119     QVERIFY(!s1.intersects(s3));
1120     s3 << 200;
1121     QVERIFY(s1.intersects(s3));
1122 }
1123 
stringutils_join()1124 void TestTools::stringutils_join()
1125 {
1126     QFETCH(std::vector<std::string>, input);
1127     QFETCH(std::string, separator);
1128     QFETCH(std::string, expectedResult);
1129 
1130     QCOMPARE(join(input, separator), expectedResult);
1131 }
1132 
stringutils_join_data()1133 void TestTools::stringutils_join_data()
1134 {
1135     QTest::addColumn<std::vector<std::string>>("input");
1136     QTest::addColumn<std::string>("separator");
1137     QTest::addColumn<std::string>("expectedResult");
1138 
1139     QTest::newRow("data1")
1140                 << std::vector<std::string>()
1141                 << std::string()
1142                 << std::string();
1143 
1144     QTest::newRow("data2")
1145                 << std::vector<std::string>()
1146                 << std::string("separator")
1147                 << std::string();
1148 
1149     QTest::newRow("data3")
1150                 << std::vector<std::string>({"one"})
1151                 << std::string("separator")
1152                 << std::string("one");
1153 
1154     QTest::newRow("data4")
1155                 << std::vector<std::string>({"one"})
1156                 << std::string("separator")
1157                 << std::string("one");
1158 
1159 
1160     QTest::newRow("data5")
1161                 << std::vector<std::string>({"a", "b"})
1162                 << std::string(" ")
1163                 << std::string("a b");
1164 
1165     QTest::newRow("data6")
1166                 << std::vector<std::string>({"a", "b", "c"})
1167                 << std::string(" ")
1168                 << std::string("a b c");
1169 }
1170 
stringutils_join_empty()1171 void TestTools::stringutils_join_empty()
1172 {
1173     std::vector<std::string> list;
1174     std::string string = join(list, std::string());
1175 
1176     QVERIFY(string.empty());
1177 }
1178 
stringutils_join_char()1179 void TestTools::stringutils_join_char()
1180 {
1181     QFETCH(std::vector<std::string>, input);
1182     QFETCH(char, separator);
1183     QFETCH(std::string, expectedResult);
1184 
1185     QCOMPARE(join(input, separator), expectedResult);
1186 }
1187 
stringutils_join_char_data()1188 void TestTools::stringutils_join_char_data()
1189 {
1190     QTest::addColumn<std::vector<std::string>>("input");
1191     QTest::addColumn<char>("separator");
1192     QTest::addColumn<std::string>("expectedResult");
1193 
1194     QTest::newRow("data1")
1195                 << std::vector<std::string>()
1196                 << ' '
1197                 << std::string();
1198 
1199     QTest::newRow("data5")
1200                 << std::vector<std::string>({"a", "b"})
1201                 << ' '
1202                 << std::string("a b");
1203 
1204     QTest::newRow("data6")
1205                 << std::vector<std::string>({"a", "b", "c"})
1206                 << ' '
1207                 << std::string("a b c");
1208 }
1209 
stringutils_startsWith()1210 void TestTools::stringutils_startsWith()
1211 {
1212     std::string a;
1213     a = "AB";
1214     QVERIFY( startsWith(a, "A") );
1215     QVERIFY( startsWith(a, "AB") );
1216     QVERIFY( !startsWith(a, "C") );
1217     QVERIFY( !startsWith(a, "ABCDEF") );
1218     QVERIFY( startsWith(a, "") );
1219     QVERIFY( startsWith(a, 'A') );
1220     QVERIFY( !startsWith(a, 'C') );
1221     QVERIFY( !startsWith(a, char()) );
1222 
1223     QVERIFY( startsWith(a, "A") );
1224     QVERIFY( startsWith(a, "AB") );
1225     QVERIFY( !startsWith(a, "C") );
1226     QVERIFY( !startsWith(a, "ABCDEF") );
1227     QVERIFY( startsWith(a, "") );
1228 
1229     a = "";
1230     QVERIFY( startsWith(a, "") );
1231     QVERIFY( !startsWith(a, "ABC") );
1232 
1233     QVERIFY( startsWith(a, "") );
1234     QVERIFY( !startsWith(a, "ABC") );
1235 
1236     QVERIFY( !startsWith(a, 'x') );
1237     QVERIFY( !startsWith(a, char()) );
1238 
1239     a = std::string();
1240     QVERIFY( startsWith(a, "") ); // different from QString::startsWith
1241     QVERIFY( !startsWith(a, "ABC") );
1242 
1243     QVERIFY( !startsWith(a, 'x') );
1244     QVERIFY( !startsWith(a, char()) );
1245 
1246     a = u8"\xc3\xa9";
1247     QVERIFY( startsWith(a, u8"\xc3\xa9") );
1248     QVERIFY( !startsWith(a, u8"\xc3\xa1") );
1249 }
1250 
stringutils_endsWith()1251 void TestTools::stringutils_endsWith()
1252 {
1253     std::string a;
1254     a = "AB";
1255     QVERIFY( endsWith(a, "B") );
1256     QVERIFY( endsWith(a, "AB") );
1257     QVERIFY( !endsWith(a, "C") );
1258     QVERIFY( !endsWith(a, "ABCDEF") );
1259     QVERIFY( endsWith(a, "") );
1260     QVERIFY( endsWith(a, 'B') );
1261     QVERIFY( !endsWith(a, 'C') );
1262     QVERIFY( !endsWith(a, char()) );
1263 
1264     QVERIFY( endsWith(a, "B") );
1265     QVERIFY( endsWith(a, "AB") );
1266     QVERIFY( !endsWith(a, "C") );
1267     QVERIFY( !endsWith(a, "ABCDEF") );
1268     QVERIFY( endsWith(a, "") );
1269 
1270     a = "";
1271     QVERIFY( endsWith(a, "") );
1272     QVERIFY( !endsWith(a, "ABC") );
1273     QVERIFY( !endsWith(a, 'x') );
1274     QVERIFY( !endsWith(a, char()) );
1275 
1276     QVERIFY( endsWith(a, "") );
1277     QVERIFY( !endsWith(a, "ABC") );
1278 
1279     a = std::string();
1280     QVERIFY( endsWith(a, "") ); // different from QString::endsWith
1281     QVERIFY( !endsWith(a, "ABC") );
1282 
1283     QVERIFY( !endsWith(a, 'x') );
1284     QVERIFY( !endsWith(a, char()) );
1285 
1286     a = u8"\xc3\xa9";
1287     QVERIFY( endsWith(a, u8"\xc3\xa9") );
1288     QVERIFY( !endsWith(a, u8"\xc3\xa1") );
1289 }
1290 
stringutils_trimmed()1291 void TestTools::stringutils_trimmed()
1292 {
1293     std::string a;
1294     a = "Text";
1295     QCOMPARE(a, std::string("Text"));
1296     QCOMPARE(trimmed(a), std::string("Text"));
1297     QCOMPARE(a, std::string("Text"));
1298     a = " ";
1299     QCOMPARE(trimmed(a), std::string(""));
1300     QCOMPARE(a, std::string(" "));
1301     a = " a   ";
1302     QCOMPARE(trimmed(a), std::string("a"));
1303 
1304     a = "Text";
1305     QCOMPARE(trimmed(std::move(a)), std::string("Text"));
1306     a = " ";
1307     QCOMPARE(trimmed(std::move(a)), std::string(""));
1308     a = " a   ";
1309     QCOMPARE(trimmed(std::move(a)), std::string("a"));
1310 }
1311 
hash_tuple()1312 void TestTools::hash_tuple()
1313 {
1314     using Key = std::tuple<int, int>;
1315 
1316     Key key0{0, 5};
1317     Key key1{10, 20};
1318     Key key2{30, 40};
1319 
1320     std::unordered_map<Key, int> map;
1321     map.insert({key1, 1});
1322     map.insert({key2, 2});
1323 
1324     QCOMPARE(map[key0], 0);
1325     QCOMPARE(map[key1], 1);
1326     QCOMPARE(map[key2], 2);
1327 }
1328 
hash_range()1329 void TestTools::hash_range()
1330 {
1331     using Key = std::vector<int>;
1332 
1333     Key key0;
1334     Key key1{1};
1335     Key key2{1, 2};
1336 
1337     std::unordered_map<Key, int> map;
1338     map.insert({key1, 1});
1339     map.insert({key2, 2});
1340 
1341     QCOMPARE(map[key0], 0);
1342     QCOMPARE(map[key1], 1);
1343     QCOMPARE(map[key2], 2);
1344 }
1345 
main(int argc,char * argv[])1346 int main(int argc, char *argv[])
1347 {
1348     QCoreApplication app(argc, argv);
1349     const SettingsPtr s = settings();
1350     TestTools tt(s.get());
1351     return QTest::qExec(&tt, argc, argv);
1352 }
1353