From 4f9b2cb026e334eb24dd35b05422b9dad6d8a2f3 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 21 Sep 2017 13:14:40 +0200 Subject: Remove duplicate qnx from the platform file selector names Update the QFileSelector tests for QNX. Co-authored-by: James McDonnell Change-Id: I68a8fde86725596323b539433287ac1a18fac1eb Reviewed-by: Thiago Macieira --- tests/auto/corelib/io/qfileselector/platforms/+qnx/test | 0 tests/auto/corelib/io/qfileselector/platforms/+qnx/test2 | 0 tests/auto/corelib/io/qfileselector/platforms/+unix/+qnx/test | 0 tests/auto/corelib/io/qfileselector/qfileselector.qrc | 3 +++ tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp | 2 +- 5 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 tests/auto/corelib/io/qfileselector/platforms/+qnx/test create mode 100644 tests/auto/corelib/io/qfileselector/platforms/+qnx/test2 create mode 100644 tests/auto/corelib/io/qfileselector/platforms/+unix/+qnx/test (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qfileselector/platforms/+qnx/test b/tests/auto/corelib/io/qfileselector/platforms/+qnx/test new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/corelib/io/qfileselector/platforms/+qnx/test2 b/tests/auto/corelib/io/qfileselector/platforms/+qnx/test2 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/corelib/io/qfileselector/platforms/+unix/+qnx/test b/tests/auto/corelib/io/qfileselector/platforms/+unix/+qnx/test new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/corelib/io/qfileselector/qfileselector.qrc b/tests/auto/corelib/io/qfileselector/qfileselector.qrc index ea9b8270e0..54b2e0a0e2 100644 --- a/tests/auto/corelib/io/qfileselector/qfileselector.qrc +++ b/tests/auto/corelib/io/qfileselector/qfileselector.qrc @@ -21,6 +21,7 @@ platforms/+unix/+darwin/test platforms/+unix/+haiku/test platforms/+unix/+linux/test + platforms/+unix/+qnx/test platforms/+unix/test platforms/+windows/+wince/test platforms/+windows/+winnt/test @@ -34,6 +35,7 @@ platforms/+mac/test platforms/+haiku/test platforms/+linux/test + platforms/+qnx/test platforms/+wince/test platforms/+winrt/test @@ -44,6 +46,7 @@ platforms/+macos/test2 platforms/+haiku/test2 platforms/+linux/test2 + platforms/+qnx/test2 platforms/+wince/test2 platforms/+winnt/test2 platforms/+winrt/test2 diff --git a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp index c537e43802..c9f1e3d9f6 100644 --- a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp +++ b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp @@ -86,7 +86,7 @@ void tst_QFileSelector::basicTest_data() QString expectedPlatform2File(""); //Only the last selector QString expectedPlatform3File; // Only the first selector (the family) #if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID) && \ - !defined(Q_OS_DARWIN) && !defined(Q_OS_LINUX) && !defined(Q_OS_HAIKU) + !defined(Q_OS_DARWIN) && !defined(Q_OS_LINUX) && !defined(Q_OS_HAIKU) && !defined(Q_OS_QNX) /* We are only aware of specific unixes, and do not have test files for any of the others. However those unixes can get a selector added from the result of a uname call, so this will lead to a case where we don't have that file so we can't expect the concatenation of platform -- cgit v1.2.3 From 9574436666c1806a69fdd5f7a83f41ad0f6152ac Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 21 Sep 2017 13:59:05 -0700 Subject: QUrl: make sure setPort(nonnegative) is taken as part of authority There were a couple of corner cases where doing setPort() would result in QUrl thinking that an authority was not present. Since the full URL parsing implies that a host is always present if the authority is present, then we also imply that setting the port number makes the host be present too. Change-Id: I69f37f9304f24709a823fffd14e67c12da18d69f Reviewed-by: David Faure --- tests/auto/corelib/io/qurl/tst_qurl.cpp | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 1ff85fc6dc..0bbd1b9f15 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -2080,6 +2080,11 @@ void tst_QUrl::isValid() QVERIFY(!url.isValid()); QVERIFY(url.toString().isEmpty()); QVERIFY(url.errorString().contains("Path component starts with '//' and authority is absent")); + + // should disappear if we set a port + url.setPort(80); + QVERIFY(url.isValid()); + QCOMPARE(url.toString(), QString("http://:80//example.com")); } { @@ -2088,6 +2093,13 @@ void tst_QUrl::isValid() QVERIFY(!url.isValid()); QVERIFY(url.toString().isEmpty()); QVERIFY(url.errorString().contains("':' before any '/'")); + + // this specific error disappears if we set anything in the authority, + // but then we run into another error + url.setPort(80); + QVERIFY(!url.isValid()); + QVERIFY(url.toString().isEmpty()); + QVERIFY(url.errorString().contains("Path component is relative and authority is present")); } { @@ -2827,6 +2839,29 @@ void tst_QUrl::setPort() QCOMPARE(url.port(), -1); QVERIFY(url.errorString().contains("out of range")); } + + { + QUrl reference("//:80"); + QUrl piecewise; + piecewise.setPort(80); + QCOMPARE(piecewise, reference); + } + + { + // setAuthority must clear the port + QUrl url("http://example.com:80"); + url.setAuthority("example.org"); + QCOMPARE(url.port(), -1); + QCOMPARE(url.toString(), QString("http://example.org")); + } + + { + // setAuthority must clear the port + QUrl url("http://example.com:80"); + url.setAuthority(QString()); + QCOMPARE(url.port(), -1); + QCOMPARE(url.toString(), QString("http:")); + } } void tst_QUrl::port_data() -- cgit v1.2.3 From cd45d0f712f844d05b88801bc000550db0856043 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 25 Oct 2017 13:36:33 +0200 Subject: tst_QFile: Introduce StdioFileGuard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guard the FILE * obtained by fopen() by a RAI class ensuring the file is closed on destruction. Change-Id: I9297f91ca2120238f3a44bad92bca5f920e01aa8 Reviewed-by: Jędrzej Nowacki --- tests/auto/corelib/io/qfile/tst_qfile.cpp | 64 +++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 21 deletions(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 32165ad2b8..450229e01e 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -109,6 +109,30 @@ QT_END_NAMESPACE Q_DECLARE_METATYPE(QFile::FileError) + +class StdioFileGuard +{ + Q_DISABLE_COPY(StdioFileGuard) +public: + explicit StdioFileGuard(FILE *f = nullptr) : m_file(f) {} + ~StdioFileGuard() { close(); } + + operator FILE *() const { return m_file; } + + void close(); + +private: + FILE * m_file; +}; + +void StdioFileGuard::close() +{ + if (m_file != nullptr) { + fclose(m_file); + m_file = nullptr; + } +} + class tst_QFile : public QObject { Q_OBJECT @@ -660,14 +684,13 @@ void tst_QFile::size() } { - QFile f; - FILE* stream = QT_FOPEN(filename.toLocal8Bit().constData(), "rb"); + StdioFileGuard stream(QT_FOPEN(filename.toLocal8Bit().constData(), "rb")); QVERIFY( stream ); + QFile f; QVERIFY( f.open(stream, QIODevice::ReadOnly) ); QCOMPARE( f.size(), size ); f.close(); - fclose(stream); } { @@ -1598,6 +1621,7 @@ void tst_QFile::largeUncFileSupport() qint64 dataOffset = Q_INT64_C(8589914592); QByteArray knownData("LargeFile content at offset 8589914592"); QString largeFile("//" + QtNetworkSettings::winServerName() + "/testsharelargefile/file.bin"); + const QByteArray largeFileEncoded = QFile::encodeName(largeFile); { // 1) Native file handling. @@ -1612,24 +1636,24 @@ void tst_QFile::largeUncFileSupport() } { // 2) stdlib file handling. + StdioFileGuard fh(fopen(largeFileEncoded.constData(), "rb")); + QVERIFY(fh); QFile file; - FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb"); QVERIFY(file.open(fh, QIODevice::ReadOnly)); QCOMPARE(file.size(), size); QVERIFY(file.seek(dataOffset)); QCOMPARE(file.read(knownData.size()), knownData); - fclose(fh); } { // 3) stdio file handling. - QFile file; - FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb"); + StdioFileGuard fh(fopen(largeFileEncoded.constData(), "rb")); + QVERIFY(fh); int fd = int(_fileno(fh)); + QFile file; QVERIFY(file.open(fd, QIODevice::ReadOnly)); QCOMPARE(file.size(), size); QVERIFY(file.seek(dataOffset)); QCOMPARE(file.read(knownData.size()), knownData); - fclose(fh); } } #endif @@ -1670,7 +1694,7 @@ void tst_QFile::bufferedRead() file.write("abcdef"); file.close(); - FILE *stdFile = fopen("stdfile.txt", "r"); + StdioFileGuard stdFile(fopen("stdfile.txt", "r")); QVERIFY(stdFile); char c; QCOMPARE(int(fread(&c, 1, 1, stdFile)), 1); @@ -1685,8 +1709,6 @@ void tst_QFile::bufferedRead() QCOMPARE(c, 'b'); QCOMPARE(file.pos(), qlonglong(2)); } - - fclose(stdFile); } #ifdef Q_OS_UNIX @@ -1815,7 +1837,7 @@ void tst_QFile::FILEReadWrite() f.close(); } - FILE *fp = fopen("FILEReadWrite.txt", "r+b"); + StdioFileGuard fp(fopen("FILEReadWrite.txt", "r+b")); QVERIFY(fp); QFile file; QVERIFY2(file.open(fp, QFile::ReadWrite), msgOpenFailed(file).constData()); @@ -1850,7 +1872,7 @@ void tst_QFile::FILEReadWrite() } file.close(); - fclose(fp); + fp.close(); // check modified file { @@ -2435,11 +2457,10 @@ void tst_QFile::virtualFile() void tst_QFile::textFile() { -#if defined(Q_OS_WIN) - FILE *fs = ::fopen("writeabletextfile", "wt"); -#else - FILE *fs = ::fopen("writeabletextfile", "w"); -#endif + const char *openMode = QOperatingSystemVersion::current().type() != QOperatingSystemVersion::Windows + ? "w" : "wt"; + StdioFileGuard fs(fopen("writeabletextfile", openMode)); + QVERIFY(fs); QFile f; QByteArray part1("This\nis\na\nfile\nwith\nnewlines\n"); QByteArray part2("Add\nsome\nmore\nnewlines\n"); @@ -2448,7 +2469,7 @@ void tst_QFile::textFile() f.write(part1); f.write(part2); f.close(); - ::fclose(fs); + fs.close(); QFile file("writeabletextfile"); QVERIFY2(file.open(QIODevice::ReadOnly), msgOpenFailed(file).constData()); @@ -2704,11 +2725,12 @@ void tst_QFile::handle() //test round trip of adopted stdio file handle QFile file2; - FILE *fp = fopen(qPrintable(m_testSourceFile), "r"); + StdioFileGuard fp(fopen(qPrintable(m_testSourceFile), "r")); + QVERIFY(fp); file2.open(fp, QIODevice::ReadOnly); QCOMPARE(int(file2.handle()), int(fileno(fp))); QCOMPARE(int(file2.handle()), int(fileno(fp))); - fclose(fp); + fp.close(); //test round trip of adopted posix file handle #ifdef Q_OS_UNIX -- cgit v1.2.3 From 1c3dc8cfb8e72770d56f2fbe131adbfe542a51c7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 25 Oct 2017 13:57:26 +0200 Subject: tst_QFile::largeUncFileSupport(): Use QTRY_VERIFY() to open the file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Open failures due to sharing violations have been observed in Coin. Change-Id: If7fbe01a454b3c343c0b87f73db50c28eae901c3 Reviewed-by: Edward Welbourne Reviewed-by: Jędrzej Nowacki --- tests/auto/corelib/io/qfile/tst_qfile.cpp | 36 ++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 450229e01e..5f3ebeadd7 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -1615,6 +1615,27 @@ void tst_QFile::writeTextFile() } #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +// Helper for executing QFile::open() with warning in QTRY_VERIFY(), which evaluates the condition +// multiple times +static bool qFileOpen(QFile &file, QIODevice::OpenMode ioFlags) +{ + const bool result = file.isOpen() || file.open(ioFlags); + if (!result) + qWarning() << "Cannot open" << file.fileName() << ':' << file.errorString(); + return result; +} + +// Helper for executing fopen() with warning in QTRY_VERIFY(), which evaluates the condition +// multiple times +static bool fOpen(const QByteArray &fileName, const char *mode, FILE **file) +{ + if (*file == nullptr) + *file = fopen(fileName.constData(), mode); + if (*file == nullptr) + qWarning("Cannot open %s: %s", fileName.constData(), strerror(errno)); + return *file != nullptr; +} + void tst_QFile::largeUncFileSupport() { qint64 size = Q_INT64_C(8589934592); @@ -1629,15 +1650,18 @@ void tst_QFile::largeUncFileSupport() QVERIFY2(file.exists(), msgFileDoesNotExist(largeFile)); QCOMPARE(file.size(), size); - QVERIFY2(file.open(QIODevice::ReadOnly), msgOpenFailed(file).constData()); + // Retry in case of sharing violation + QTRY_VERIFY2(qFileOpen(file, QIODevice::ReadOnly), msgOpenFailed(file).constData()); QCOMPARE(file.size(), size); QVERIFY(file.seek(dataOffset)); QCOMPARE(file.read(knownData.size()), knownData); } { // 2) stdlib file handling. - StdioFileGuard fh(fopen(largeFileEncoded.constData(), "rb")); - QVERIFY(fh); + FILE *fhF = nullptr; + // Retry in case of sharing violation + QTRY_VERIFY(fOpen(largeFileEncoded, "rb", &fhF)); + StdioFileGuard fh(fhF); QFile file; QVERIFY(file.open(fh, QIODevice::ReadOnly)); QCOMPARE(file.size(), size); @@ -1646,8 +1670,10 @@ void tst_QFile::largeUncFileSupport() } { // 3) stdio file handling. - StdioFileGuard fh(fopen(largeFileEncoded.constData(), "rb")); - QVERIFY(fh); + FILE *fhF = nullptr; + // Retry in case of sharing violation + QTRY_VERIFY(fOpen(largeFileEncoded, "rb", &fhF)); + StdioFileGuard fh(fhF); int fd = int(_fileno(fh)); QFile file; QVERIFY(file.open(fd, QIODevice::ReadOnly)); -- cgit v1.2.3 From 254849b62a4aa5a34f18bf8e47a9cb9293d3f8b9 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 30 Oct 2017 09:15:23 +0100 Subject: macOS: Blacklist tst_QSequentialAnimationGroup::groupWithZeroDurationAnimations() Task-number: QTBUG-64109 Change-Id: Iebe5a07d108ba647baa74ded71b730c867bd1c41 Reviewed-by: Jesus Fernandez --- tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST b/tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST index 391e3f67af..2a31afd735 100644 --- a/tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST +++ b/tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST @@ -3,3 +3,5 @@ windows [finishWithUncontrolledAnimation] windows osx-10.12 +[groupWithZeroDurationAnimations] +osx -- cgit v1.2.3 From ad36da8ff416501e249beb098e5b84eaa2fba43d Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Mon, 30 Oct 2017 13:45:18 +0100 Subject: testlib: start sharing common helper functions ... by moving them in QTestPrivate namespace (qtesthelpers_p.h). This header file is a convenient staging area for helper APIs, eventually some could be moved to public QTest API. This header file utilizes the same pattern as other qtestlib header files - wrapping functions with QT_${LIBNAME}_LIB to automatically enable certain APIs based on what is in the projects dependencies, e.g. QT += widgets. Change-Id: Ic0266429939c1f3788912ad8b84fc6e0d5edd68b Reviewed-by: Edward Welbourne --- tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro | 2 +- .../auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp | 13 ++----------- tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro | 2 +- .../corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp | 16 ++++------------ 4 files changed, 8 insertions(+), 25 deletions(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro b/tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro index 351e263093..5908648378 100644 --- a/tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro +++ b/tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro @@ -4,4 +4,4 @@ SOURCES += tst_qtemporarydir.cpp INCLUDEPATH += ../../../../shared/ HEADERS += ../../../../shared/emulationdetector.h -QT = core testlib +QT = core testlib testlib-private diff --git a/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp index 4bed8d0fd6..4cb3bfe549 100644 --- a/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp +++ b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef Q_OS_WIN # include #endif @@ -112,16 +113,6 @@ void tst_QTemporaryDir::getSetCheck() QCOMPARE(true, obj1.autoRemove()); } -static inline bool canHandleUnicodeFileNames() -{ -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) - return true; -#else - // Check for UTF-8 by converting the Euro symbol (see tst_utf8) - return QFile::encodeName(QString(QChar(0x20AC))) == QByteArrayLiteral("\342\202\254"); -#endif -} - static QString hanTestText() { QString text; @@ -160,7 +151,7 @@ void tst_QTemporaryDir::fileTemplate_data() QTest::newRow("constructor with XXXX suffix") << "qt_XXXXXX_XXXX" << "qt_"; QTest::newRow("constructor with XXXX prefix") << "qt_XXXX" << "qt_"; QTest::newRow("constructor with XXXXX prefix") << "qt_XXXXX" << "qt_"; - if (canHandleUnicodeFileNames()) { + if (QTestPrivate::canHandleUnicodeFileNames()) { // Test Umlauts (contained in Latin1) QString prefix = "qt_" + umlautTestText(); QTest::newRow("Umlauts") << (prefix + "XXXXXX") << prefix; diff --git a/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro b/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro index a89e5c66ff..e17cb05cd8 100644 --- a/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro +++ b/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro @@ -1,6 +1,6 @@ CONFIG += testcase TARGET = tst_qtemporaryfile -QT = core testlib +QT = core testlib testlib-private SOURCES = tst_qtemporaryfile.cpp TESTDATA += tst_qtemporaryfile.cpp RESOURCES += qtemporaryfile.qrc diff --git a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp index ab6b435125..64b61839c1 100644 --- a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp @@ -36,6 +36,8 @@ #include #include +#include + #if defined(Q_OS_WIN) # include #endif @@ -141,16 +143,6 @@ void tst_QTemporaryFile::getSetCheck() QCOMPARE(true, obj1.autoRemove()); } -static inline bool canHandleUnicodeFileNames() -{ -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) - return true; -#else - // Check for UTF-8 by converting the Euro symbol (see tst_utf8) - return QFile::encodeName(QString(QChar(0x20AC))) == QByteArrayLiteral("\342\202\254"); -#endif -} - static QString hanTestText() { QString text; @@ -199,7 +191,7 @@ void tst_QTemporaryFile::fileTemplate_data() QTest::newRow("set template, with xxx") << "" << "qt_" << ".xxx" << "qt_XXXXXX.xxx"; QTest::newRow("set template, with >6 X's") << "" << "qt_" << ".xxx" << "qt_XXXXXXXXXXXXXX.xxx"; QTest::newRow("set template, with >6 X's, no suffix") << "" << "qt_" << "" << "qt_XXXXXXXXXXXXXX"; - if (canHandleUnicodeFileNames()) { + if (QTestPrivate::canHandleUnicodeFileNames()) { // Test Umlauts (contained in Latin1) QString prefix = "qt_" + umlautTestText(); QTest::newRow("Umlauts") << (prefix + "XXXXXX") << prefix << QString() << QString(); @@ -761,7 +753,7 @@ void tst_QTemporaryFile::QTBUG_4796_data() QTest::newRow("XXXXXXbla") << QString() << QString("bla") << true; QTest::newRow("does-not-exist/qt_temp.XXXXXX") << QString("does-not-exist/qt_temp") << QString() << false; - if (canHandleUnicodeFileNames()) { + if (QTestPrivate::canHandleUnicodeFileNames()) { QTest::newRow("XXXXXX") << QString() << unicode << true; QTest::newRow("XXXXXX") << unicode << QString() << true; QTest::newRow("XXXXXX") << unicode << unicode << true; -- cgit v1.2.3 From 19b0ce5daa31e2ffebfcf2701143742302f1deb4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 13 Apr 2017 21:13:52 -0700 Subject: Change almost all other uses of qrand() to QRandomGenerator The vast majority is actually switched to QRandomGenerator::bounded(), which gives a mostly uniform distribution over the [0, bound) range. There are very few floating point cases left, as many of those that did use floating point did not need to, after all. (I did leave some that were too ugly for me to understand) This commit also found a couple of calls to rand() instead of qrand(). This commit does not include changes to SSL code that continues to use qrand() (job for someone else): src/network/ssl/qsslkey_qt.cpp src/network/ssl/qsslsocket_mac.cpp tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp Change-Id: Icd0e0d4b27cb4e5eb892fffd14b5285d43f4afbf Reviewed-by: Lars Knoll --- tests/auto/corelib/io/largefile/tst_largefile.cpp | 4 ++-- tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 4 ++-- .../corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp | 1 - .../auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp | 3 --- tests/auto/corelib/thread/qfuture/tst_qfuture.cpp | 3 ++- tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp | 11 ++++++----- .../auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp | 5 ++--- 7 files changed, 14 insertions(+), 17 deletions(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/largefile/tst_largefile.cpp b/tests/auto/corelib/io/largefile/tst_largefile.cpp index 5975303ca6..2d13e6166d 100644 --- a/tests/auto/corelib/io/largefile/tst_largefile.cpp +++ b/tests/auto/corelib/io/largefile/tst_largefile.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -174,8 +175,7 @@ static inline QByteArray generateDataBlock(int blockSize, QString text, qint64 u static qint64 counter = 0; - qint64 randomBits = ((qint64)qrand() << 32) - | ((qint64)qrand() & 0x00000000ffffffff); + qint64 randomBits = QRandomGenerator::global()->generate64(); appendRaw(block, randomBits); appendRaw(block, userBits); diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 3a52c684d0..5ecdd92228 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -2362,8 +2362,8 @@ void tst_QObject::testUserData() // Randomize the table a bit for (int i=0; i<100; ++i) { - int p1 = rand() % USER_DATA_COUNT; - int p2 = rand() % USER_DATA_COUNT; + int p1 = QRandomGenerator::global()->bounded(USER_DATA_COUNT); + int p2 = QRandomGenerator::global()->bounded(USER_DATA_COUNT); int tmp = user_data_ids[p1]; user_data_ids[p1] = user_data_ids[p2]; diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp index 8a46bc1c55..8883b6360f 100644 --- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp +++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp @@ -115,7 +115,6 @@ Q_CONSTRUCTOR_FUNCTION(initializeLang) static QString seedAndTemplate() { - qsrand(QDateTime::currentSecsSinceEpoch()); return QDir::tempPath() + "/tst_qmimedatabase-XXXXXX"; } diff --git a/tests/auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp b/tests/auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp index daf9b1579a..d1e138d8eb 100644 --- a/tests/auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp +++ b/tests/auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp @@ -35,9 +35,6 @@ int main(int argc, char **argv) Q_UNUSED(argc) Q_UNUSED(argv) - // First, break QUuid. - qrand(); - // Now print a few uuids. printf("%s", qPrintable(QUuid::createUuid().toString())); printf("%s", qPrintable(QUuid::createUuid().toString())); diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index 37b052bf1d..58bebe19ac 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include // COM interface macro. @@ -1456,7 +1457,7 @@ void tst_QFuture::nonGlobalThreadPool() void run() Q_DECL_OVERRIDE { - const int ms = 100 + (qrand() % 100 - 100/2); + const int ms = 100 + (QRandomGenerator::global()->bounded(100) - 100/2); QThread::msleep(ms); reportResult(Answer); reportFinished(); diff --git a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp index e13c2894af..72299402f0 100644 --- a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp +++ b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #define Q_TEST_PERFORMANCE 0 @@ -133,7 +134,7 @@ QVector generateData(QString dataSetType, const int length) QVector container; if (dataSetType == "Random") { for (int i = 0; i < length; ++i) - container.append(rand()); + container.append(QRandomGenerator::global()->generate()); } else if (dataSetType == "Ascending") { for (int i = 0; i < length; ++i) container.append(i); @@ -1082,12 +1083,12 @@ void tst_QAlgorithms::popCount_data_impl(size_t sizeof_T_Int) // and some random ones: if (sizeof_T_Int >= 8) for (size_t i = 0; i < 1000; ++i) { - const quint64 input = quint64(qrand()) << 32 | quint32(qrand()); + const quint64 input = QRandomGenerator::global()->generate64(); QTest::addRow("0x%016llx", input) << input << bitsSetInInt64(input); } else if (sizeof_T_Int >= 2) for (size_t i = 0; i < 1000 ; ++i) { - const quint32 input = qrand(); + const quint32 input = QRandomGenerator::global()->generate(); if (sizeof_T_Int >= 4) QTest::addRow("0x%08x", input) << quint64(input) << bitsSetInInt(input); else @@ -1129,7 +1130,7 @@ void tst_QAlgorithms::countTrailing_data_impl(size_t sizeof_T_Int) // and some random ones: for (uint i = 0; i < sizeof_T_Int*8; ++i) { for (uint j = 0; j < sizeof_T_Int*3; ++j) { // 3 is arbitrary - const quint64 r = quint64(qrand()) << 32 | quint32(qrand()); + const quint64 r = QRandomGenerator::global()->generate64(); const quint64 b = Q_UINT64_C(1) << i; const quint64 mask = ((~(b-1)) ^ b) & type_mask; const quint64 input = (r&mask) | b; @@ -1166,7 +1167,7 @@ void tst_QAlgorithms::countLeading_data_impl(size_t sizeof_T_Int) // and some random ones: for (uint i = 0; i < sizeof_T_Int*8; ++i) { for (uint j = 0; j < sizeof_T_Int*3; ++j) { // 3 is arbitrary - const quint64 r = quint64(qrand()) << 32 | quint32(qrand()); + const quint64 r = QRandomGenerator::global()->generate64(); const quint64 b = Q_UINT64_C(1) << i; const quint64 mask = b-1; const quint64 input = (r&mask) | b; diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index 442d4d089c..e1dcdb8407 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -1884,7 +1884,7 @@ class StrongThread: public QThread protected: void run() { - usleep(rand() % 2000); + usleep(QRandomGenerator::global()->bounded(2000)); ptr->ref(); ptr.clear(); } @@ -1897,7 +1897,7 @@ class WeakThread: public QThread protected: void run() { - usleep(rand() % 2000); + usleep(QRandomGenerator::global()->bounded(2000)); QSharedPointer ptr = weak; if (ptr) ptr->ref(); @@ -1959,7 +1959,6 @@ void tst_QSharedPointer::threadStressTest() base.clear(); - srand(time(NULL)); // start threads for (int i = 0; i < allThreads.count(); ++i) if (allThreads[i]) allThreads[i]->start(); -- cgit v1.2.3 From e27bd981373cc3d22e54d8cbe030e5c329f9beda Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 8 Nov 2017 12:10:29 +0100 Subject: qfile tests: Make sure files are writable before deleting them On some platforms (like UWP) files that are copied during qfile auto tests are not writable by default. The cleanup will fail for these files if the permissions are not set accordingly. Change-Id: Id925dcadfc6b505c87f1f55d5ea05e286b60a5a5 Reviewed-by: Maurice Kalinowski Reviewed-by: Friedemann Kleint --- tests/auto/corelib/io/qfile/tst_qfile.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 5f3ebeadd7..8db89b9f05 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -405,6 +405,8 @@ void tst_QFile::cleanup() QDir remainingDir(absoluteFilePath); QVERIFY2(remainingDir.removeRecursively(), qPrintable(absoluteFilePath)); } else { + if (!(QFile::permissions(absoluteFilePath) & QFile::WriteUser)) + QVERIFY2(QFile::setPermissions(absoluteFilePath, QFile::WriteUser), qPrintable(absoluteFilePath)); QVERIFY2(QFile::remove(absoluteFilePath), qPrintable(absoluteFilePath)); } } -- cgit v1.2.3 From bbc68dc815122e6be9ea44adadd93ffb715c7792 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 8 Nov 2017 12:12:06 +0100 Subject: Fix tst_QFile::useQFileInAFileHandler for systems using resources for test data Resource files are extracted to m_dataDir in tst_QFile::initTestCase. Instead of trying to access the file from the resource on systems that use qrc for bundling the test data, we have to use the files that were extracted at the beginning of the test. Change-Id: I35453fbdeb27e317d1342ff1cb7bbea9cebea14d Reviewed-by: Maurice Kalinowski Reviewed-by: Friedemann Kleint --- tests/auto/corelib/io/qfile/tst_qfile.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 8db89b9f05..8a3d490925 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -2190,12 +2190,20 @@ public: if (fileName.startsWith(":!")) { QDir dir; - QString realFile = QFINDTESTDATA(fileName.mid(2)); +#ifndef BUILTIN_TESTDATA + const QString realFile = QFINDTESTDATA(fileName.mid(2)); +#else + const QString realFile = m_dataDir->filePath(fileName.mid(2)); +#endif if (dir.exists(realFile)) return new QFSFileEngine(realFile); } return 0; } + +#ifdef BUILTIN_TESTDATA + QSharedPointer m_dataDir; +#endif }; #endif @@ -2204,6 +2212,9 @@ void tst_QFile::useQFileInAFileHandler() { // This test should not dead-lock MyRecursiveHandler handler; +#ifdef BUILTIN_TESTDATA + handler.m_dataDir = m_dataDir; +#endif QFile file(":!tst_qfile.cpp"); QVERIFY(file.exists()); } -- cgit v1.2.3 From 82c3c9d45d5fad0ed18e096f09729579a0902a71 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 8 Nov 2017 13:58:19 +0100 Subject: Fix tst_QFile::handle for systems using builtin test data To obtain the file's handle, we need to obtain it from the extracted test data instead of qrc. Change-Id: I89c5c3f3a7da7e36205a439581a6d83efffdc07c Reviewed-by: Maurice Kalinowski Reviewed-by: Friedemann Kleint --- tests/auto/corelib/io/qfile/tst_qfile.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 8a3d490925..16a3cfd766 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -445,8 +445,6 @@ void tst_QFile::initTestCase() m_stdinProcessDir = QFINDTESTDATA("stdinprocess"); QVERIFY(!m_stdinProcessDir.isEmpty()); #endif - m_testSourceFile = QFINDTESTDATA("tst_qfile.cpp"); - QVERIFY(!m_testSourceFile.isEmpty()); m_testLogFile = QFINDTESTDATA("testlog.txt"); QVERIFY(!m_testLogFile.isEmpty()); m_dosFile = QFINDTESTDATA("dosfile.txt"); @@ -459,12 +457,15 @@ void tst_QFile::initTestCase() QVERIFY(!m_twoDotsFile.isEmpty()); #ifndef BUILTIN_TESTDATA + m_testSourceFile = QFINDTESTDATA("tst_qfile.cpp"); + QVERIFY(!m_testSourceFile.isEmpty()); m_testFile = QFINDTESTDATA("testfile.txt"); QVERIFY(!m_testFile.isEmpty()); #else m_dataDir = QEXTRACTTESTDATA("/"); QVERIFY2(!m_dataDir.isNull(), qPrintable("Could not extract test data")); m_testFile = m_dataDir->path() + "/testfile.txt"; + m_testSourceFile = m_dataDir->path() + "/tst_qfile.cpp"; #endif m_resourcesDir = QFINDTESTDATA("resources"); QVERIFY(!m_resourcesDir.isEmpty()); -- cgit v1.2.3 From 579d0cb2bed193ccb1901b121a360f85d1c57a54 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 8 Nov 2017 14:09:11 +0100 Subject: Fix tst_QFile::openDirectory for systems using builtin test data To obtain "proper" directory behavior, we have to check against the extracted "resources" directory instead of its qrc counterpart. Change-Id: I4996ba74419945f78d356ad953a5b826ff663687 Reviewed-by: Maurice Kalinowski --- tests/auto/corelib/io/qfile/tst_qfile.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 16a3cfd766..5f0eae6fc3 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -461,14 +461,15 @@ void tst_QFile::initTestCase() QVERIFY(!m_testSourceFile.isEmpty()); m_testFile = QFINDTESTDATA("testfile.txt"); QVERIFY(!m_testFile.isEmpty()); + m_resourcesDir = QFINDTESTDATA("resources"); + QVERIFY(!m_resourcesDir.isEmpty()); #else m_dataDir = QEXTRACTTESTDATA("/"); QVERIFY2(!m_dataDir.isNull(), qPrintable("Could not extract test data")); m_testFile = m_dataDir->path() + "/testfile.txt"; m_testSourceFile = m_dataDir->path() + "/tst_qfile.cpp"; + m_resourcesDir = m_dataDir->path() + "/resources"; #endif - m_resourcesDir = QFINDTESTDATA("resources"); - QVERIFY(!m_resourcesDir.isEmpty()); m_noEndOfLineFile = QFINDTESTDATA("noendofline.txt"); QVERIFY(!m_noEndOfLineFile.isEmpty()); -- cgit v1.2.3 From 4502999ff054f16aab1fdd99fbd9256b22ecadf9 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 12 Oct 2017 21:58:51 -0700 Subject: QRandomGenerator: remove the per-thread buffer Since we're adding a deterministic generator that inherently does not use syscalls, and people should really use that one by default, there is no point in optimizing the secure generator wrt syscalls. Besides, keeping the random data in memory for longer than needed is likely inadviseable. Change-Id: Ib17dde1a1dbb49a7bba8fffd14ed0871117fe930 Reviewed-by: Lars Knoll --- tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp index 4b38d46317..e583766f21 100644 --- a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp +++ b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp @@ -119,7 +119,6 @@ void tst_QRandomGenerator::generate32_data() QTest::addColumn("control"); QTest::newRow("default") << 0U; #ifdef QT_BUILD_INTERNAL - QTest::newRow("direct") << uint(SkipMemfill); QTest::newRow("system") << uint(SkipHWRNG); # ifdef HAVE_FALLBACK_ENGINE QTest::newRow("fallback") << uint(SkipHWRNG | SkipSystemRNG); -- cgit v1.2.3 From af456842e13ab83cfeb44f3638b62652b201281c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 11 Oct 2017 15:28:40 +0200 Subject: Change QRandomGenerator to have a deterministic mode Now only QRandomGenerator::system() will access the system-wide RNG, which we document to be cryptographically-safe and possibly backed by a true HWRNG. Everything else just wraps a Mersenne Twister. Change-Id: I0a103569c81b4711a649fffd14ec8cd3469425df Reviewed-by: Lars Knoll --- .../qrandomgenerator/tst_qrandomgenerator.cpp | 334 ++++++++++++++++----- 1 file changed, 253 insertions(+), 81 deletions(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp index e583766f21..f9b3ce5390 100644 --- a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp +++ b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp @@ -43,8 +43,8 @@ #define COMMA , #define QVERIFY_3TIMES(statement) \ do {\ - if (!QTest::qVerify(static_cast(statement), #statement, "1st try", __FILE__, __LINE__))\ - if (!QTest::qVerify(static_cast(statement), #statement, "2nd try", __FILE__, __LINE__))\ + if (!static_cast(statement))\ + if (!static_cast(statement))\ if (!QTest::qVerify(static_cast(statement), #statement, "3rd try", __FILE__, __LINE__))\ return;\ } while (0) @@ -71,6 +71,13 @@ public slots: void cleanup() { setRNGControl(0); } private slots: + void basics(); + void knownSequence(); + void copying(); + void copyingGlobal(); + void copyingSystem(); + void systemRng(); + void generate32_data(); void generate32(); void generate64_data() { generate32_data(); } @@ -110,18 +117,154 @@ private slots: void stdRandomDistributions(); }; +// The first 20 results of the sequence: +static const quint32 defaultRngResults[] = { + 853323747U, 2396352728U, 3025954838U, 2985633182U, 2815751046U, + 340588426U, 3587208406U, 298087538U, 2912478009U, 3642122814U, + 3202916223U, 799257577U, 1872145992U, 639469699U, 3201121432U, + 2388658094U, 1735523408U, 2215232359U, 668106566U, 2554687763U +}; + + using namespace std; QT_WARNING_DISABLE_GCC("-Wfloat-equal") QT_WARNING_DISABLE_CLANG("-Wfloat-equal") +struct RandomGenerator : public QRandomGenerator +{ + RandomGenerator(uint control) + : QRandomGenerator(control ? + QRandomGenerator(control & RandomDataMask) : + *QRandomGenerator::global()) + { + setRNGControl(control); + } +}; + +void tst_QRandomGenerator::basics() +{ + // default constructible + QRandomGenerator rng; + + // copyable && movable + rng = rng; + rng = std::move(rng); + + // 64-bit + QRandomGenerator64 rng64; + rng64 = rng64; + rng64 = std::move(rng64); + + // 32- and 64-bit should be interchangeable: + rng = rng64; + rng64 = rng; + rng = std::move(rng64); + rng64 = std::move(rng); + + // access global + QRandomGenerator *global = QRandomGenerator::global(); + QRandomGenerator globalCopy = *global; + globalCopy = *global; + QRandomGenerator64 *global64 = QRandomGenerator64::global(); + QRandomGenerator64 globalCopy64 = *global64; + globalCopy64 = *global64; + + // access system + QRandomGenerator *system = QRandomGenerator::system(); + QRandomGenerator systemRng = *system; + systemRng = *system; + + QRandomGenerator64 *system64 = QRandomGenerator64::system(); + QRandomGenerator64 systemRng64 = *system64; + systemRng64 = *system64; + + Q_STATIC_ASSERT(std::is_same::value); + Q_STATIC_ASSERT(std::is_samegenerate()) COMMA quint64>::value); +} + +void tst_QRandomGenerator::knownSequence() +{ + QRandomGenerator rng; + for (quint32 x : defaultRngResults) + QCOMPARE(rng(), x); +} + +void tst_QRandomGenerator::copying() +{ + QRandomGenerator rng1; + QRandomGenerator rng2 = rng1; + + quint32 samples[20]; + rng1.fillRange(samples); + + // should produce the same sequence, whichever it was + for (quint32 x : samples) + QCOMPARE(rng2(), x); +} + +void tst_QRandomGenerator::copyingGlobal() +{ + QRandomGenerator &global = *QRandomGenerator::global(); + QRandomGenerator copy = global; + + quint32 samples[20]; + global.fillRange(samples); + + // should produce the same sequence, whichever it was + for (quint32 x : samples) + QCOMPARE(copy(), x); +} + +void tst_QRandomGenerator::copyingSystem() +{ + QRandomGenerator &system = *QRandomGenerator::system(); + QRandomGenerator copy = system; + QRandomGenerator copy2 = copy; + copy2 = copy; + + quint32 samples[20]; + copy2.fillRange(samples); + + // should NOT produce the same sequence, whichever it was + int sameCount = 0; + for (quint32 x : samples) + sameCount += (copy() == x); + QVERIFY(sameCount < 20); +} + +void tst_QRandomGenerator::systemRng() +{ + QRandomGenerator *rng = QRandomGenerator::system(); + rng->generate(); + rng->generate64(); + rng->generateDouble(); + rng->bounded(100); + rng->bounded(100U); + +#ifdef QT_BUILD_INTERNAL + quint32 setpoint = std::numeric_limits::max(); + ++setpoint; + quint64 setpoint64 = quint64(setpoint) << 32 | setpoint; + setRNGControl(SetRandomData | setpoint); + + QCOMPARE(rng->generate(), setpoint); + QCOMPARE(rng->generate64(), setpoint64); + QCOMPARE(rng->generateDouble(), ldexp(setpoint64, -64)); + QCOMPARE(rng->bounded(100), 50); +#endif +} + void tst_QRandomGenerator::generate32_data() { QTest::addColumn("control"); - QTest::newRow("default") << 0U; + QTest::newRow("fixed") << (RandomValue32 & RandomDataMask); + QTest::newRow("global") << 0U; #ifdef QT_BUILD_INTERNAL - QTest::newRow("system") << uint(SkipHWRNG); + if (qt_has_hwrng()) + QTest::newRow("hwrng") << uint(UseSystemRNG); + QTest::newRow("system") << uint(UseSystemRNG | SkipHWRNG); # ifdef HAVE_FALLBACK_ENGINE - QTest::newRow("fallback") << uint(SkipHWRNG | SkipSystemRNG); + QTest::newRow("system-fallback") << uint(UseSystemRNG | SkipHWRNG | SkipSystemRNG); # endif #endif } @@ -129,39 +272,40 @@ void tst_QRandomGenerator::generate32_data() void tst_QRandomGenerator::generate32() { QFETCH(uint, control); - setRNGControl(control); + RandomGenerator rng(control); for (int i = 0; i < 4; ++i) { - QVERIFY_3TIMES([] { - quint32 value = QRandomGenerator::generate(); + QVERIFY_3TIMES([&] { + quint32 value = rng.generate(); return value != 0 && value != RandomValue32; }()); } // and should hopefully be different from repeated calls for (int i = 0; i < 4; ++i) - QVERIFY_3TIMES(QRandomGenerator::generate() != QRandomGenerator::generate()); + QVERIFY_3TIMES(rng.generate() != rng.generate()); } void tst_QRandomGenerator::generate64() { QFETCH(uint, control); - setRNGControl(control); + RandomGenerator rng(control); + QVERIFY_3TIMES(rng.generate64() > std::numeric_limits::max()); for (int i = 0; i < 4; ++i) { - QVERIFY_3TIMES([] { - quint64 value = QRandomGenerator::generate(); + QVERIFY_3TIMES([&] { + quint64 value = rng.generate64(); return value != 0 && value != RandomValue32 && value != RandomValue64; }()); } // and should hopefully be different from repeated calls for (int i = 0; i < 4; ++i) - QVERIFY_3TIMES(QRandomGenerator::generate64() != QRandomGenerator::generate64()); + QVERIFY_3TIMES(rng.generate64() != rng.generate64()); for (int i = 0; i < 4; ++i) - QVERIFY_3TIMES(QRandomGenerator::generate() != quint32(QRandomGenerator::generate64())); + QVERIFY_3TIMES(rng.generate() != quint32(rng.generate64())); for (int i = 0; i < 4; ++i) - QVERIFY_3TIMES(QRandomGenerator::generate() != (QRandomGenerator::generate64() >> 32)); + QVERIFY_3TIMES(rng.generate() != (rng.generate64() >> 32)); } void tst_QRandomGenerator::quality() @@ -190,7 +334,9 @@ void tst_QRandomGenerator::quality() Q_STATIC_ASSERT(FailureThreshold > AcceptableThreshold); QFETCH(uint, control); - setRNGControl(control); + if (control & RandomDataMask) + return; + RandomGenerator rng(control); int histogram[UCHAR_MAX + 1]; memset(histogram, 0, sizeof(histogram)); @@ -199,7 +345,7 @@ void tst_QRandomGenerator::quality() // test the quality of the generator quint32 buffer[BufferCount]; memset(buffer, 0xcc, sizeof(buffer)); - generate_n(buffer, +BufferCount, [] { return QRandomGenerator::generate(); }); + generate_n(buffer, +BufferCount, [&] { return rng.generate(); }); quint8 *ptr = reinterpret_cast(buffer); quint8 *end = ptr + sizeof(buffer); @@ -224,20 +370,20 @@ void tst_QRandomGenerator::quality() template void fillRange_template() { QFETCH(uint, control); - setRNGControl(control); + RandomGenerator rng(control); for (int i = 0; i < 4; ++i) { - QVERIFY_3TIMES([] { + QVERIFY_3TIMES([&] { T value[1] = { RandomValue32 }; - QRandomGenerator::fillRange(value); + rng.fillRange(value); return value[0] != 0 && value[0] != RandomValue32; }()); } for (int i = 0; i < 4; ++i) { - QVERIFY_3TIMES([] { + QVERIFY_3TIMES([&] { T array[2] = {}; - QRandomGenerator::fillRange(array); + rng.fillRange(array); return array[0] != array[1]; }()); } @@ -245,18 +391,18 @@ template void fillRange_template() if (sizeof(T) > sizeof(quint32)) { // just to shut up a warning about shifting uint more than the width enum { Shift = sizeof(T) / 2 * CHAR_BIT }; - QVERIFY_3TIMES([] { + QVERIFY_3TIMES([&] { T value[1] = { }; - QRandomGenerator::fillRange(value); + rng.fillRange(value); return quint32(value[0] >> Shift) != quint32(value[0]); }()); } // fill in a longer range - auto longerArrayCheck = [] { + auto longerArrayCheck = [&] { T array[32]; memset(array, 0, sizeof(array)); - QRandomGenerator::fillRange(array); + rng.fillRange(array); if (sizeof(T) == sizeof(RandomValue64) && find(begin(array), end(array), RandomValue64) != end(array)) return false; @@ -273,11 +419,11 @@ void tst_QRandomGenerator::fillRangeULLong() { fillRange_template(); template void generate_template() { QFETCH(uint, control); - setRNGControl(control); + RandomGenerator rng(control); // almost the same as fillRange, but limited to 32 bits for (int i = 0; i < 4; ++i) { - QVERIFY_3TIMES([] { + QVERIFY_3TIMES([&] { T value[1] = { RandomValue32 }; QRandomGenerator().generate(begin(value), end(value)); return value[0] != 0 && value[0] != RandomValue32 @@ -286,10 +432,10 @@ template void generate_template() } // fill in a longer range - auto longerArrayCheck = [] { + auto longerArrayCheck = [&] { T array[72] = {}; // at least 256 bytes QRandomGenerator().generate(begin(array), end(array)); - return find_if(begin(array), end(array), [](T cur) { + return find_if(begin(array), end(array), [&](T cur) { return cur == 0 || cur == RandomValue32 || cur == RandomValue64 || cur > numeric_limits::max(); }) == end(array); @@ -303,12 +449,12 @@ void tst_QRandomGenerator::generateULLong() { generate_template(); } void tst_QRandomGenerator::generateNonContiguous() { QFETCH(uint, control); - setRNGControl(control); + RandomGenerator rng(control); QLinkedList list = { 0, 0, 0, 0, 0, 0, 0, 0 }; auto longerArrayCheck = [&] { QRandomGenerator().generate(list.begin(), list.end()); - return find_if(list.begin(), list.end(), [](quint64 cur) { + return find_if(list.begin(), list.end(), [&](quint64 cur) { return cur == 0 || cur == RandomValue32 || cur == RandomValue64 || cur > numeric_limits::max(); }) == list.end(); @@ -326,7 +472,7 @@ void tst_QRandomGenerator::bounded_data() QTest::addColumn("sup"); QTest::addColumn("expected"); - auto newRow = [](quint32 val, quint32 sup) { + auto newRow = [&](quint32 val, quint32 sup) { // calculate the scaled value quint64 scaled = val; scaled <<= 32; @@ -352,31 +498,31 @@ void tst_QRandomGenerator::bounded() QFETCH(uint, control); QFETCH(quint32, sup); QFETCH(quint32, expected); - setRNGControl(control); + RandomGenerator rng(control); - quint32 value = QRandomGenerator::bounded(sup); + quint32 value = rng.bounded(sup); QVERIFY(value < sup); QCOMPARE(value, expected); - int ivalue = QRandomGenerator::bounded(sup); + int ivalue = rng.bounded(sup); QVERIFY(ivalue < int(sup)); QCOMPARE(ivalue, int(expected)); // confirm only the bound now - setRNGControl(control & (SkipHWRNG|SkipSystemRNG)); - value = QRandomGenerator::bounded(sup); + setRNGControl(control & (SkipHWRNG|SkipSystemRNG|UseSystemRNG)); + value = rng.bounded(sup); QVERIFY(value < sup); - value = QRandomGenerator::bounded(sup / 2, 3 * sup / 2); + value = rng.bounded(sup / 2, 3 * sup / 2); QVERIFY(value >= sup / 2); QVERIFY(value < 3 * sup / 2); - ivalue = QRandomGenerator::bounded(-int(sup), int(sup)); + ivalue = rng.bounded(-int(sup), int(sup)); QVERIFY(ivalue >= -int(sup)); QVERIFY(ivalue < int(sup)); // wholly negative range - ivalue = QRandomGenerator::bounded(-int(sup), 0); + ivalue = rng.bounded(-int(sup), 0); QVERIFY(ivalue >= -int(sup)); QVERIFY(ivalue < 0); } @@ -407,7 +553,9 @@ void tst_QRandomGenerator::boundedQuality() Q_STATIC_ASSERT(FailureThreshold > AcceptableThreshold); QFETCH(uint, control); - setRNGControl(control); + if (control & RandomDataMask) + return; + RandomGenerator rng(control); int histogram[Bound]; memset(histogram, 0, sizeof(histogram)); @@ -415,7 +563,7 @@ void tst_QRandomGenerator::boundedQuality() { // test the quality of the generator QVector buffer(BufferCount, 0xcdcdcdcd); - generate(buffer.begin(), buffer.end(), [] { return QRandomGenerator::bounded(Bound); }); + generate(buffer.begin(), buffer.end(), [&] { return rng.bounded(Bound); }); for (quint32 value : qAsConst(buffer)) { QVERIFY(value < Bound); @@ -441,24 +589,26 @@ void tst_QRandomGenerator::boundedQuality() void tst_QRandomGenerator::generateReal() { QFETCH(uint, control); - setRNGControl(control); + RandomGenerator rng(control); for (int i = 0; i < 4; ++i) { - QVERIFY_3TIMES([] { - qreal value = QRandomGenerator::generateDouble(); + QVERIFY_3TIMES([&] { + qreal value = rng.generateDouble(); return value >= 0 && value < 1 && value != RandomValueFP; }()); } // and should hopefully be different from repeated calls for (int i = 0; i < 4; ++i) - QVERIFY_3TIMES(QRandomGenerator::generateDouble() != QRandomGenerator::generateDouble()); + QVERIFY_3TIMES(rng.generateDouble() != rng.generateDouble()); } void tst_QRandomGenerator::qualityReal() { QFETCH(uint, control); - setRNGControl(control); + if (control & RandomDataMask) + return; + RandomGenerator rng(control); enum { SampleSize = 160, @@ -474,7 +624,7 @@ void tst_QRandomGenerator::qualityReal() }; double data[SampleSize]; - std::generate(std::begin(data), std::end(data), &QRandomGenerator::generateDouble); + std::generate(std::begin(data), std::end(data), [&rng] { return rng.generateDouble(); }); int aboveHalf = 0; int belowOneEighth = 0; @@ -503,12 +653,22 @@ void tst_QRandomGenerator::qualityReal() template void seedStdRandomEngine() { - QRandomGenerator rd; - Engine e(rd); - QVERIFY_3TIMES(e() != 0); + { + QRandomGenerator &rd = *QRandomGenerator::system(); + Engine e(rd); + QVERIFY_3TIMES(e() != 0); + + e.seed(rd); + QVERIFY_3TIMES(e() != 0); + } + { + QRandomGenerator64 &rd = *QRandomGenerator64::system(); + Engine e(rd); + QVERIFY_3TIMES(e() != 0); - e.seed(rd); - QVERIFY_3TIMES(e() != 0); + e.seed(rd); + QVERIFY_3TIMES(e() != 0); + } } void tst_QRandomGenerator::seedStdRandomEngines() @@ -533,12 +693,16 @@ void tst_QRandomGenerator::stdUniformIntDistribution_data() QTest::addColumn("control"); QTest::addColumn("max"); - auto newRow = [](quint32 max) { - QTest::addRow("default:%u", max) << 0U << max; - QTest::addRow("system:%u", max) << uint(SkipHWRNG) << max; - #ifdef HAVE_FALLBACK_ENGINE - QTest::addRow("fallback:%u", max) << uint(SkipHWRNG | SkipSystemRNG) << max; - #endif + auto newRow = [&](quint32 max) { +#ifdef QT_BUILD_INTERNAL + if (qt_has_hwrng()) + QTest::addRow("hwrng:%u", max) << uint(UseSystemRNG) << max; + QTest::addRow("system:%u", max) << uint(UseSystemRNG | SkipHWRNG) << max; +# ifdef HAVE_FALLBACK_ENGINE + QTest::addRow("system-fallback:%u", max) << uint(UseSystemRNG | SkipHWRNG | SkipSystemRNG) << max; +# endif +#endif + QTest::addRow("global:%u", max) << 0U << max; }; // useless: we can only generate zeroes: @@ -553,7 +717,7 @@ void tst_QRandomGenerator::stdUniformIntDistribution() { QFETCH(uint, control); QFETCH(quint32, max); - setRNGControl(control & (SkipHWRNG|SkipSystemRNG)); + RandomGenerator rng(control); { QRandomGenerator rd; @@ -621,21 +785,19 @@ void tst_QRandomGenerator::stdGenerateCanonical() QSKIP("MSVC 2013's std::generate_canonical is broken"); #else QFETCH(uint, control); - setRNGControl(control); + RandomGenerator rng(control); for (int i = 0; i < 4; ++i) { - QVERIFY_3TIMES([] { - QRandomGenerator rd; - qreal value = std::generate_canonical(rd); + QVERIFY_3TIMES([&] { + qreal value = std::generate_canonical(rng); return value > 0 && value < 1 && value != RandomValueFP; }()); } // and should hopefully be different from repeated calls - QRandomGenerator rd; for (int i = 0; i < 4; ++i) - QVERIFY_3TIMES(std::generate_canonical(rd) != - std::generate_canonical(rd)); + QVERIFY_3TIMES(std::generate_canonical(rng) != + std::generate_canonical(rng)); #endif } @@ -649,12 +811,16 @@ void tst_QRandomGenerator::stdUniformRealDistribution_data() QTest::addColumn("min"); QTest::addColumn("sup"); - auto newRow = [](double min, double sup) { - QTest::addRow("default:%g-%g", min, sup) << 0U << min << sup; - QTest::addRow("system:%g-%g", min, sup) << uint(SkipHWRNG) << min << sup; - #ifdef HAVE_FALLBACK_ENGINE - QTest::addRow("fallback:%g-%g", min, sup) << uint(SkipHWRNG | SkipSystemRNG) << min << sup; - #endif + auto newRow = [&](double min, double sup) { +#ifdef QT_BUILD_INTERNAL + if (qt_has_hwrng()) + QTest::addRow("hwrng:%g-%g", min, sup) << uint(UseSystemRNG) << min << sup; + QTest::addRow("system:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG) << min << sup; +# ifdef HAVE_FALLBACK_ENGINE + QTest::addRow("system-fallback:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG | SkipSystemRNG) << min << sup; +# endif +#endif + QTest::addRow("global:%g-%g", min, sup) << 0U << min << sup; }; newRow(0, 0); // useless: we can only generate zeroes @@ -670,7 +836,7 @@ void tst_QRandomGenerator::stdUniformRealDistribution() QFETCH(uint, control); QFETCH(double, min); QFETCH(double, sup); - setRNGControl(control & (SkipHWRNG|SkipSystemRNG)); + RandomGenerator rng(control & (SkipHWRNG|SkipSystemRNG|UseSystemRNG)); { QRandomGenerator rd; @@ -695,13 +861,9 @@ void tst_QRandomGenerator::stdUniformRealDistribution() } } -void tst_QRandomGenerator::stdRandomDistributions() +template void stdRandomDistributions_template() { - // just a compile check for some of the distributions, besides - // std::uniform_int_distribution and std::uniform_real_distribution (tested - // above) - - QRandomGenerator rd; + Generator rd; std::bernoulli_distribution()(rd); @@ -723,6 +885,16 @@ void tst_QRandomGenerator::stdRandomDistributions() } } +void tst_QRandomGenerator::stdRandomDistributions() +{ + // just a compile check for some of the distributions, besides + // std::uniform_int_distribution and std::uniform_real_distribution (tested + // above) + + stdRandomDistributions_template(); + stdRandomDistributions_template(); +} + QTEST_APPLESS_MAIN(tst_QRandomGenerator) #include "tst_qrandomgenerator.moc" -- cgit v1.2.3 From cfad4e298f4d65fe26c3a4109d19839bdfcd30c2 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 23 Oct 2017 19:39:45 -0700 Subject: QRandomGenerator: add securelySeeded(), to ensure appropriate seeding Since we don't document how many bytes one needs (it's 2496), it's difficult for the caller to provide just enough data in the seed sequence. Moreover, since std::mt19937 doesn't make it easy to provide the ideal size either, we can't actually write code that operates optimally given a quint32 range either -- we only provide it via std::seed_seq, which is inefficient. However, we can do it internally by passing QRandomGenerator to the std::mersenne_twister_engine constructor, as it's designed to work. Change-Id: Icaa86fc7b54d4b368c0efffd14f0613c10998321 Reviewed-by: Lars Knoll --- .../global/qrandomgenerator/tst_qrandomgenerator.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp index f9b3ce5390..9c1828d1dd 100644 --- a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp +++ b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp @@ -77,6 +77,7 @@ private slots: void copyingGlobal(); void copyingSystem(); void systemRng(); + void securelySeeding(); void generate32_data(); void generate32(); @@ -161,6 +162,9 @@ void tst_QRandomGenerator::basics() rng = std::move(rng64); rng64 = std::move(rng); + rng = QRandomGenerator64::securelySeeded(); + rng64 = QRandomGenerator::securelySeeded(); + // access global QRandomGenerator *global = QRandomGenerator::global(); QRandomGenerator globalCopy = *global; @@ -254,6 +258,21 @@ void tst_QRandomGenerator::systemRng() #endif } +void tst_QRandomGenerator::securelySeeding() +{ + QRandomGenerator rng1 = QRandomGenerator::securelySeeded(); + QRandomGenerator rng2 = QRandomGenerator::securelySeeded(); + + quint32 samples[20]; + rng1.fillRange(samples); + + // should NOT produce the same sequence, whichever it was + int sameCount = 0; + for (quint32 x : samples) + sameCount += (rng2() == x); + QVERIFY(sameCount < 20); +} + void tst_QRandomGenerator::generate32_data() { QTest::addColumn("control"); -- cgit v1.2.3 From 08bf28de03f16e5b014b23e228dfc3cfc2ac7feb Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 23 Oct 2017 19:16:34 -0700 Subject: QRandomGenerator: add more of the std Random Engine API This brings us to almost parity with the C++11 Random Engine API requirements (see chapter 26.5.1.4 [rand.req.eng]). We don't implement the templated Sseq requirements because it would require moving the implementation details to the public API. And we don't implement the code because we don't want to. Change-Id: Icaa86fc7b54d4b368c0efffd14f05ff813ebd759 Reviewed-by: Lars Knoll --- .../qrandomgenerator/tst_qrandomgenerator.cpp | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp index 9c1828d1dd..220ec9a2f8 100644 --- a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp +++ b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp @@ -73,6 +73,7 @@ public slots: private slots: void basics(); void knownSequence(); + void discard(); void copying(); void copyingGlobal(); void copyingSystem(); @@ -191,32 +192,63 @@ void tst_QRandomGenerator::knownSequence() QRandomGenerator rng; for (quint32 x : defaultRngResults) QCOMPARE(rng(), x); + + // should work again if we reseed it + rng.seed(); + for (quint32 x : defaultRngResults) + QCOMPARE(rng(), x); +} + +void tst_QRandomGenerator::discard() +{ + QRandomGenerator rng; + rng.discard(1); + QCOMPARE(rng(), defaultRngResults[1]); + + rng.discard(9); + QCOMPARE(rng(), defaultRngResults[11]); } void tst_QRandomGenerator::copying() { QRandomGenerator rng1; QRandomGenerator rng2 = rng1; + QCOMPARE(rng1, rng2); quint32 samples[20]; rng1.fillRange(samples); + // not equal anymore + QVERIFY(rng1 != rng2); + // should produce the same sequence, whichever it was for (quint32 x : samples) QCOMPARE(rng2(), x); + + // now they should compare equal again + QCOMPARE(rng1, rng2); } void tst_QRandomGenerator::copyingGlobal() { QRandomGenerator &global = *QRandomGenerator::global(); QRandomGenerator copy = global; + QCOMPARE(copy, global); + QCOMPARE(global, copy); quint32 samples[20]; global.fillRange(samples); + // not equal anymore + QVERIFY(copy != global); + // should produce the same sequence, whichever it was for (quint32 x : samples) QCOMPARE(copy(), x); + + // equal again + QCOMPARE(copy, global); + QCOMPARE(global, copy); } void tst_QRandomGenerator::copyingSystem() @@ -225,15 +257,24 @@ void tst_QRandomGenerator::copyingSystem() QRandomGenerator copy = system; QRandomGenerator copy2 = copy; copy2 = copy; + QCOMPARE(system, copy); + QCOMPARE(copy, copy2); quint32 samples[20]; copy2.fillRange(samples); + // they still compre equally + QCOMPARE(system, copy); + QCOMPARE(copy, copy2); + // should NOT produce the same sequence, whichever it was int sameCount = 0; for (quint32 x : samples) sameCount += (copy() == x); QVERIFY(sameCount < 20); + + QCOMPARE(system, copy); + QCOMPARE(copy, copy2); } void tst_QRandomGenerator::systemRng() -- cgit v1.2.3 From 3c63c8d2f233c2d2ad02a4be185bda25c82b532b Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Thu, 9 Nov 2017 17:07:55 +0200 Subject: Blacklist tst_qstandardpaths::testFindExecutable for b2qt/arm64 Task-number: QTBUG-64404 Change-Id: Ie04cf67574c4eb8b8e5bdb78e8e30173042edab7 Reviewed-by: Liang Qi --- tests/auto/corelib/io/qstandardpaths/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/auto/corelib/io/qstandardpaths/BLACKLIST (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/io/qstandardpaths/BLACKLIST b/tests/auto/corelib/io/qstandardpaths/BLACKLIST new file mode 100644 index 0000000000..d5ee9650cd --- /dev/null +++ b/tests/auto/corelib/io/qstandardpaths/BLACKLIST @@ -0,0 +1,3 @@ +[testFindExecutable] +# QTBUG-64404 +b2qt 64bit -- cgit v1.2.3