diff options
Diffstat (limited to 'tests')
38 files changed, 821 insertions, 76 deletions
diff --git a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp index 7bba0b710b..2c5a5c96a6 100644 --- a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp +++ b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp @@ -426,10 +426,10 @@ void tst_QtConcurrentRun::implicitConvertibleTypes() { QThreadPool pool; - double d; + double d = 0.0; run(doubleFunction, d).waitForFinished(); run(&pool, doubleFunction, d).waitForFinished(); - int i; + int i = 0; run(doubleFunction, d).waitForFinished(); run(&pool, doubleFunction, d).waitForFinished(); run(doubleFunction, i).waitForFinished(); diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp index 0f27901f94..084f8dc037 100644 --- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -58,6 +58,8 @@ private slots: #ifdef QT_BUILD_INTERNAL void cleanupFuncinfo_data(); void cleanupFuncinfo(); + void cleanupFuncinfoBad_data(); + void cleanupFuncinfoBad(); #endif void qMessagePattern_data(); @@ -672,6 +674,26 @@ void tst_qmessagehandler::cleanupFuncinfo_data() << "int TestClass1::operator>(int)" << "TestClass1::operator>"; + QTest::newRow("gcc_40") + << "Polymorphic<void (*)(int)>::~Polymorphic()" + << "Polymorphic::~Polymorphic"; + + QTest::newRow("gcc_41") + << "function<void (int*)>()::S::f()" + << "function()::S::f"; + + QTest::newRow("msvc_41") + << "void `void function<void __cdecl(int *)>(void)'::`2'::S::f(void)" + << "function(void)'::`2'::S::f"; + + QTest::newRow("gcc_42") + << "function<Polymorphic<void (int*)> >()::S::f(Polymorphic<void (int*)>*)" + << "function()::S::f"; + + QTest::newRow("msvc_42") + << "void `void function<Polymorphic<void __cdecl(int *)> >(void)'::`2'::S::f(Polymorphic<void __cdecl(int *)> *)" + << "function(void)'::`2'::S::f"; + QTest::newRow("objc_1") << "-[SomeClass someMethod:withArguments:]" << "-[SomeClass someMethod:withArguments:]"; @@ -687,6 +709,14 @@ void tst_qmessagehandler::cleanupFuncinfo_data() QTest::newRow("objc_4") << "__31-[SomeClass someMethodSchedulingBlock]_block_invoke" << "__31-[SomeClass someMethodSchedulingBlock]_block_invoke"; + + QTest::newRow("thunk-1") + << "non-virtual thunk to QFutureWatcherBasePrivate::postCallOutEvent(QFutureCallOutEvent const&)" + << "QFutureWatcherBasePrivate::postCallOutEvent"; + + QTest::newRow("thunk-2") + << "virtual thunk to std::basic_iostream<char, std::char_traits<char> >::~basic_iostream()" + << "std::basic_iostream::~basic_iostream"; } #endif @@ -707,6 +737,41 @@ void tst_qmessagehandler::cleanupFuncinfo() QEXPECT_FAIL("TestClass1::nested_struct_const", "Nested function processing is broken", Continue); QTEST(QString::fromLatin1(result), "expected"); } + +void tst_qmessagehandler::cleanupFuncinfoBad_data() +{ + QTest::addColumn<QByteArray>("funcinfo"); + + auto addBadFrame = [i = 0](const char *symbol) mutable { + QTest::addRow("%d", ++i) << QByteArray(symbol); + }; + addBadFrame("typeinfo for QEventLoop"); + addBadFrame("typeinfo name for QtPrivate::ResultStoreBase"); + addBadFrame("typeinfo name for ._anon_476"); + addBadFrame("typeinfo name for std::__1::__function::__base<bool (void*, void*)>"); + addBadFrame("vtable for BezierEase"); + addBadFrame("vtable for Polymorphic<void ()>"); + addBadFrame("vtable for Polymorphic<void (*)(int)>"); + addBadFrame("TLS wrapper function for (anonymous namespace)::jitStacks"); + addBadFrame("lcCheckIndex()::category"); + addBadFrame("guard variable for lcEPDetach()::category"); + addBadFrame("guard variable for QImageReader::read(QImage*)::disableNxImageLoading"); + addBadFrame("VTT for std::__1::ostrstream"); + addBadFrame("qIsRelocatable<(anonymous namespace)::Data>"); + addBadFrame("qt_incomplete_metaTypeArray<(anonymous namespace)::qt_meta_stringdata_CLASSQNonContiguousByteDeviceIoDeviceImplENDCLASS_t, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, true> > >"); + addBadFrame("f()::i"); +} + +void tst_qmessagehandler::cleanupFuncinfoBad() +{ + QFETCH(QByteArray, funcinfo); + + // A corrupted stack trace may find non-sensical symbols that aren't + // functions. The result doesn't matter, so long as we don't crash or hang. + + QByteArray result = qCleanupFuncinfo(funcinfo); + qDebug() << "Decode of" << funcinfo << "produced" << result; +} #endif void tst_qmessagehandler::qMessagePattern_data() diff --git a/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp b/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp index 6f37f85230..b02400e349 100644 --- a/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp +++ b/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp @@ -36,6 +36,7 @@ class tst_QBuffer : public QObject Q_OBJECT private slots: void open(); + void openWriteOnlyDoesNotTruncate(); void getSetCheck(); void readBlock(); void readBlockPastEnd(); @@ -131,6 +132,29 @@ void tst_QBuffer::open() b.close(); } +void tst_QBuffer::openWriteOnlyDoesNotTruncate() +{ + QBuffer b; + const auto data = QByteArrayLiteral("Hey, presto!"); + + { + QVERIFY(b.open(QIODevice::WriteOnly)); + b.write(data); + b.close(); + } + { + QVERIFY(b.open(QIODevice::ReadOnly)); + QCOMPARE(b.readAll(), data); + b.close(); + } + { + QVERIFY(b.open(QIODevice::WriteOnly)); + QCOMPARE(b.size(), data.size()); + QCOMPARE(b.pos(), 0); + b.close(); + } +} + // some status() tests, too void tst_QBuffer::readBlock() { diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 780b6165c3..c527f1ce3a 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -3470,12 +3470,10 @@ void tst_QUrl::effectiveTLDs_data() QTest::newRow("yes0") << QUrl::fromEncoded("http://test.co.uk") << ".co.uk"; QTest::newRow("yes1") << QUrl::fromEncoded("http://test.com") << ".com"; QTest::newRow("yes2") << QUrl::fromEncoded("http://www.test.de") << ".de"; - QTest::newRow("yes3") << QUrl::fromEncoded("http://test.ulm.museum") << ".ulm.museum"; QTest::newRow("yes4") << QUrl::fromEncoded("http://www.com.krodsherad.no") << ".krodsherad.no"; QTest::newRow("yes5") << QUrl::fromEncoded("http://www.co.uk.1.bg") << ".1.bg"; QTest::newRow("yes6") << QUrl::fromEncoded("http://www.com.com.cn") << ".com.cn"; QTest::newRow("yes7") << QUrl::fromEncoded("http://www.test.org.ws") << ".org.ws"; - QTest::newRow("yes9") << QUrl::fromEncoded("http://www.com.co.uk.wallonie.museum") << ".wallonie.museum"; QTest::newRow("yes10") << QUrl::fromEncoded("http://www.com.evje-og-hornnes.no") << ".evje-og-hornnes.no"; QTest::newRow("yes11") << QUrl::fromEncoded("http://www.bla.kamijima.ehime.jp") << ".kamijima.ehime.jp"; QTest::newRow("yes12") << QUrl::fromEncoded("http://www.bla.kakuda.miyagi.jp") << ".kakuda.miyagi.jp"; diff --git a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp index 533fcd96f5..a2349a5846 100644 --- a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +++ b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp @@ -1748,10 +1748,11 @@ static bool isValidSingleTextChar(const ushort c) void tst_QXmlStream::readBack() const { + QBuffer buffer; + for (ushort c = 0; c < std::numeric_limits<ushort>::max(); ++c) { - QBuffer buffer; - QVERIFY(buffer.open(QIODevice::WriteOnly)); + QVERIFY(buffer.open(QIODevice::WriteOnly|QIODevice::Truncate)); QXmlStreamWriter writer(&buffer); writer.writeStartDocument(); writer.writeTextElement("a", QString(QChar(c))); diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp index ba1c77231f..d8aa17d9ef 100644 --- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp @@ -914,7 +914,10 @@ void tst_QByteArray::qstrncpy() // src == nullptr QCOMPARE(::qstrncpy(dst.data(), 0, 0), (char*)0); + QCOMPARE(*dst.data(), 'b'); // must not have written to dst QCOMPARE(::qstrncpy(dst.data(), 0, 10), (char*)0); + QCOMPARE(*dst.data(), '\0'); // must have written to dst + *dst.data() = 'b'; // restore // valid pointers, but len == 0 QCOMPARE(::qstrncpy(dst.data(), src.data(), 0), dst.data()); diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index 4ee6c6df75..6bd9e5c25a 100644 --- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -2108,8 +2108,7 @@ void tst_QLocale::windowsDefaultLocale() QCOMPARE(locale.toString(QDate(1974, 12, 1), QLocale::NarrowFormat), locale.toString(QDate(1974, 12, 1), QLocale::ShortFormat)); QCOMPARE(locale.toString(QDate(1974, 12, 1), QLocale::LongFormat), QString("1@12@1974")); - const QString expectedFormattedShortTimeSeconds = QStringLiteral("1^2^3"); - const QString expectedFormattedShortTime = QStringLiteral("1^2"); + const QString expectedFormattedShortTime = QStringLiteral("1^2^3"); QCOMPARE(locale.toString(QTime(1,2,3), QLocale::ShortFormat), expectedFormattedShortTime); QCOMPARE(locale.toString(QTime(1,2,3), QLocale::NarrowFormat), locale.toString(QTime(1,2,3), QLocale::ShortFormat)); diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 878988d425..90f7f63192 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -4876,6 +4876,9 @@ void tst_QString::arg() QCOMPARE( s4.arg("foo", 10), QLatin1String("[ foo]") ); QCOMPARE( s4.arg("foo", -10), QLatin1String("[foo ]") ); + // QStringRef argument in multi-arg: + QCOMPARE(QString("%1;%2").arg(QStringRef(), QString()), ";"); + QString firstName( "James" ); QString lastName( "Bond" ); QString fullName = QString( "My name is %2, %1 %2" ) diff --git a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp index 412f092377..59b94179f4 100644 --- a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp @@ -65,6 +65,7 @@ private slots: void isValidId_data(); void isValidId(); void malformed(); + void serialize(); // Backend tests void utcTest(); void icuTest(); @@ -951,6 +952,33 @@ void tst_QTimeZone::malformed() barf.offsetFromUtc(now); } +void tst_QTimeZone::serialize() +{ + int parts = 0; +#ifndef QT_NO_DEBUG_STREAM + qDebug() << QTimeZone(); // to verify no crash + parts++; +#endif +#ifndef QT_NO_DATASTREAM + QByteArray blob; + { + QDataStream stream(&blob, QIODevice::WriteOnly); + stream << QTimeZone("Europe/Oslo") << QTimeZone(420) << QTimeZone() << qint64(-1); + } + QDataStream stream(&blob, QIODevice::ReadOnly); + QTimeZone invalid, offset, oslo; + qint64 minusone; + stream >> oslo >> offset >> invalid >> minusone; + QCOMPARE(oslo, QTimeZone("Europe/Oslo")); + QCOMPARE(offset, QTimeZone(420)); + QVERIFY(!invalid.isValid()); + QCOMPARE(minusone, qint64(-1)); + parts++; +#endif + if (!parts) + QSKIP("No serialization enabled"); +} + void tst_QTimeZone::utcTest() { #ifdef QT_BUILD_INTERNAL diff --git a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp index 3eef7631c8..3abd68857f 100644 --- a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp +++ b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp @@ -47,6 +47,12 @@ private slots: void files_data(); void files(); void hashLength(); + + // keep last + void keccakBufferOverflow(); +private: + void ensureLargeData(); + std::vector<char> large; }; void tst_QCryptographicHash::repeated_result_data() @@ -303,5 +309,52 @@ void tst_QCryptographicHash::hashLength() } } +void tst_QCryptographicHash::ensureLargeData() +{ +#if QT_POINTER_SIZE > 4 + QElapsedTimer timer; + timer.start(); + const size_t GiB = 1024 * 1024 * 1024; + if (large.size() == 4 * GiB + 1) + return; + try { + large.resize(4 * GiB + 1, '\0'); + } catch (const std::bad_alloc &) { + QSKIP("Could not allocate 4GiB plus one byte of RAM."); + } + QCOMPARE(large.size(), 4 * GiB + 1); + large.back() = '\1'; + qDebug("created dataset in %lld ms", timer.elapsed()); +#endif +} + +void tst_QCryptographicHash::keccakBufferOverflow() +{ +#if QT_POINTER_SIZE == 4 + QSKIP("This is a 64-bit-only test"); +#else + + ensureLargeData(); + if (large.empty()) + return; + + QElapsedTimer timer; + timer.start(); + const auto sg = qScopeGuard([&] { + qDebug() << "test finished in" << timer.restart() << "ms"; + }); + + constexpr qsizetype magic = INT_MAX/4; + QVERIFY(large.size() >= size_t(magic + 1)); + + QCryptographicHash hash(QCryptographicHash::Algorithm::Keccak_224); + + hash.addData(large.data(), 1); + hash.addData(large.data() + 1, magic); + (void)hash.result(); + QVERIFY(true); // didn't crash +#endif +} + QTEST_MAIN(tst_QCryptographicHash) #include "tst_qcryptographichash.moc" diff --git a/tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp b/tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp index 2f8052fd4a..920c70c461 100644 --- a/tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp +++ b/tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp @@ -34,6 +34,8 @@ class tst_QMessageAuthenticationCode : public QObject { Q_OBJECT private slots: + void repeated_setKey_data(); + void repeated_setKey(); void result_data(); void result(); void result_incremental_data(); @@ -42,6 +44,47 @@ private slots: Q_DECLARE_METATYPE(QCryptographicHash::Algorithm) +void tst_QMessageAuthenticationCode::repeated_setKey_data() +{ + using A = QCryptographicHash::Algorithm; + QTest::addColumn<A>("algo"); + + const auto me = QMetaEnum::fromType<A>(); + for (int i = 0, value; (value = me.value(i)) != -1; ++i) + QTest::addRow("%s", me.key(i)) << A(value); +} + +void tst_QMessageAuthenticationCode::repeated_setKey() +{ + QFETCH(const QCryptographicHash::Algorithm, algo); + + // GIVEN: two long keys, so we're sure the key needs to be hashed in order + // to fit into the hash algorithm's block + + static const QByteArray key1(1024, 'a'); + static const QByteArray key2(2048, 'b'); + + // WHEN: processing the same message + + QMessageAuthenticationCode macX(algo); + QMessageAuthenticationCode mac1(algo, key1); + QMessageAuthenticationCode mac2(algo, key2); + + const auto check = [](QMessageAuthenticationCode &mac) { + mac.addData("This is nonsense, ignore it, please."); + return mac.result(); + }; + + macX.setKey(key1); + QCOMPARE(check(macX), check(mac1)); + + // THEN: the result does not depend on whether a new QMAC instance was used + // or an old one re-used (iow: setKey() reset()s) + + macX.setKey(key2); + QCOMPARE(check(macX), check(mac2)); +} + void tst_QMessageAuthenticationCode::result_data() { QTest::addColumn<QCryptographicHash::Algorithm>("algo"); diff --git a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp index 0174885cf3..2347ea6d48 100644 --- a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp +++ b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp @@ -33,12 +33,29 @@ #include <memory> +class NonCopyable +{ + Q_DISABLE_COPY(NonCopyable) + int n; +public: + NonCopyable() : n(0) {} + explicit NonCopyable(int n) : n(n) {} + + friend bool operator==(const NonCopyable &lhs, const NonCopyable &rhs) noexcept + { return lhs.n == rhs.n; } + friend bool operator!=(const NonCopyable &lhs, const NonCopyable &rhs) noexcept + { return !operator==(lhs, rhs); } +}; + class tst_QVarLengthArray : public QObject { Q_OBJECT private slots: void defaultConstructor_int() { defaultConstructor<int>(); } void defaultConstructor_QString() { defaultConstructor<QString>(); } + void sizeConstructor_int() { sizeConstructor<int>(); } + void sizeConstructor_QString() { sizeConstructor<QString>(); } + void sizeConstructor_NonCopyable() { sizeConstructor<NonCopyable>(); } void append(); void removeLast(); void oldTests(); @@ -67,6 +84,8 @@ private slots: private: template <typename T> void defaultConstructor(); + template <typename T> + void sizeConstructor(); template<typename T> void initializeList(); }; @@ -103,6 +122,31 @@ void tst_QVarLengthArray::defaultConstructor() } } +template <typename T> +void tst_QVarLengthArray::sizeConstructor() +{ + { + QVarLengthArray<T, 123> vla(0); + QCOMPARE(vla.size(), 0); + QVERIFY(vla.empty()); + QVERIFY(vla.isEmpty()); + QCOMPARE(vla.begin(), vla.end()); + QCOMPARE(vla.capacity(), 123); + } + { + QVarLengthArray<T, 124> vla(124); + QCOMPARE(vla.size(), 124); + QVERIFY(!vla.empty()); + QCOMPARE(vla.capacity(), 124); + } + { + QVarLengthArray<T, 124> vla(125); + QCOMPARE(vla.size(), 125); + QVERIFY(!vla.empty()); + QVERIFY(vla.capacity() >= 125); + } +} + void tst_QVarLengthArray::append() { QVarLengthArray<QString, 2> v; @@ -412,6 +456,12 @@ struct MyBase bool hasMoved() const { return !wasConstructedAt(this); } protected: + void swap(MyBase &other) { + using std::swap; + swap(data, other.data); + swap(isCopy, other.isCopy); + } + MyBase(const MyBase *data, bool isCopy) : data(data), isCopy(isCopy) {} @@ -486,6 +536,14 @@ struct MyMovable return *this; } + void swap(MyMovable &other) noexcept + { + MyBase::swap(other); + std::swap(i, other.i); + } + + friend void swap(MyMovable &lhs, MyMovable &rhs) noexcept { lhs.swap(rhs); } + bool operator==(const MyMovable &other) const { return i == other.i; @@ -501,6 +559,15 @@ struct MyComplex { return i == other.i; } + + void swap(MyComplex &other) noexcept + { + MyBase::swap(other); + std::swap(i, other.i); + } + + friend void swap(MyComplex &lhs, MyComplex &rhs) noexcept { lhs.swap(rhs); } + char i; }; @@ -1066,6 +1133,17 @@ void tst_QVarLengthArray::insertMove() QCOMPARE(MyBase::copyCount, 0); { + MyMovable m1, m2; + QCOMPARE(MyBase::liveCount, 2); + QCOMPARE(MyBase::copyCount, 0); + using std::swap; + swap(m1, m2); + QCOMPARE(MyBase::liveCount, 2); + QCOMPARE(MyBase::movedCount, 0); + QCOMPARE(MyBase::copyCount, 0); + } + + { QVarLengthArray<MyMovable, 6> vec; MyMovable m1; MyMovable m2; diff --git a/tests/auto/gui/kernel/qguitimer/BLACKLIST b/tests/auto/gui/kernel/qguitimer/BLACKLIST index c6f1e9c892..cb678120cd 100644 --- a/tests/auto/gui/kernel/qguitimer/BLACKLIST +++ b/tests/auto/gui/kernel/qguitimer/BLACKLIST @@ -1,3 +1,7 @@ # See qtbase/src/testlib/qtestblacklist.cpp for format -[zeroTimer] -ci ubuntu-20.04 # QTBUG-108556 +[zeroTimer] # QTBUG-108556 +ci ubuntu-20.04 +ci sles-15.4 + +[singleShotToFunctors] +ci ubuntu-20.04 # QTBUG-108554 diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index db7e261243..0a767e57e2 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -17,6 +17,7 @@ osx windows-10 [testInputEvents] rhel-7.4 +sles-15.4 [modalWindowPosition] # QTBUG-69161 android diff --git a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp index 7dbd587451..ed7a6a4d5d 100644 --- a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp +++ b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp @@ -1113,6 +1113,35 @@ void tst_QQuaternion::fromEulerAngles_data() QTest::newRow("complex") << 30.0f << 240.0f << -45.0f << QQuaternion(-0.531976f, -0.43968f, 0.723317f, -0.02226f); + + // Three gimbal_lock cases are not unique for the conversions from quaternion + // to euler, Qt will use only XY rotations for these cases. + // For example, QQuaternion(0.5f, 0.5f, -0.5f, 0.5f) can be EulerXYZ(90.0f, 0.0f, 90.0f), too. + // But Qt will always convert it to EulerXYZ(90.0f, -90.0f, 0.0f) without Z-rotation. + QTest::newRow("gimbal_lock_1") + << 90.0f << -90.0f << 0.0f << QQuaternion(0.5f, 0.5f, -0.5f, 0.5f); + + QTest::newRow("gimbal_lock_2") + << 90.0f << 40.0f << 0.0f << QQuaternion(0.664463f, 0.664463f, 0.241845f, -0.241845f); + + QTest::newRow("gimbal_lock_3") << 90.0f << 170.0f << 0.0f + << QQuaternion(0.0616285f, 0.0616285f, 0.704416f, -0.704416f); + + // These four examples have a fraction of errors that would bypass normalize() threshold + // and could make Gimbal lock detection fail. + QTest::newRow("gimbal_lock_fraction_1") + << -90.0f << 90.001152f << 0.0f << QQuaternion(0.499989986f, -0.5f, 0.5f, 0.5f); + + QTest::newRow("gimbal_lock_fraction_2") + << -90.0f << -179.999985f << 0.0f + << QQuaternion(1.00000001e-07f, 1.00000001e-10f, -0.707106769f, -0.707105756f); + + QTest::newRow("gimbal_lock_fraction_3") + << -90.0f << 90.0011597f << 0.0f << QQuaternion(0.499989986f, -0.49999994f, 0.5f, 0.5f); + + QTest::newRow("gimbal_lock_fraction_4") + << -90.0f << -180.0f << 0.0f + << QQuaternion(9.99999996e-12f, 9.99999996e-12f, -0.707106769f, -0.707096756f); } void tst_QQuaternion::fromEulerAngles() { diff --git a/tests/auto/gui/text/qglyphrun/BLACKLIST b/tests/auto/gui/text/qglyphrun/BLACKLIST index 4c2eb315cf..c9d0900296 100644 --- a/tests/auto/gui/text/qglyphrun/BLACKLIST +++ b/tests/auto/gui/text/qglyphrun/BLACKLIST @@ -3,3 +3,5 @@ ubuntu-18.04 ubuntu-20.04 ubuntu-22.04 b2qt +[drawRightToLeft] +opensuse-leap-15.4 # QTBUG-89169 diff --git a/tests/auto/network/access/hsts/tst_qhsts.cpp b/tests/auto/network/access/hsts/tst_qhsts.cpp index d72991a2eb..c3c5f58c22 100644 --- a/tests/auto/network/access/hsts/tst_qhsts.cpp +++ b/tests/auto/network/access/hsts/tst_qhsts.cpp @@ -242,6 +242,12 @@ void tst_QHsts::testSTSHeaderParser() QVERIFY(parser.includeSubDomains()); list.pop_back(); + list << Header("strict-transport-security", "includeSubDomains;max-age=1000"); + QVERIFY(parser.parse(list)); + QVERIFY(parser.expirationDate() > QDateTime::currentDateTimeUtc()); + QVERIFY(parser.includeSubDomains()); + + list.pop_back(); // Invalid (includeSubDomains twice): list << Header("Strict-Transport-Security", "max-age = 1000 ; includeSubDomains;includeSubDomains"); QVERIFY(!parser.parse(list)); diff --git a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp index 55482fed97..0a78c8967a 100644 --- a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp +++ b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp @@ -413,13 +413,11 @@ void tst_QNetworkCookieJar::effectiveTLDs_data() QTest::newRow("yes1") << "com" << true; QTest::newRow("yes2") << "de" << true; - QTest::newRow("yes3") << "ulm.museum" << true; QTest::newRow("yes4") << "krodsherad.no" << true; QTest::newRow("yes5") << "1.bg" << true; QTest::newRow("yes6") << "com.cn" << true; QTest::newRow("yes7") << "org.ws" << true; QTest::newRow("yes8") << "co.uk" << true; - QTest::newRow("yes9") << "wallonie.museum" << true; QTest::newRow("yes10") << "hk.com" << true; QTest::newRow("yes11") << "hk.org" << true; @@ -436,33 +434,23 @@ void tst_QNetworkCookieJar::effectiveTLDs_data() QTest::newRow("no11") << "mosreg.ru" << false; const ushort s1[] = {0x74, 0x72, 0x61, 0x6e, 0xf8, 0x79, 0x2e, 0x6e, 0x6f, 0x00}; // xn--trany-yua.no - const ushort s2[] = {0x5d9, 0x5e8, 0x5d5, 0x5e9, 0x5dc, 0x5d9, 0x5dd, 0x2e, 0x6d, 0x75, 0x73, 0x65, 0x75, 0x6d, 0x00}; // xn--9dbhblg6di.museum const ushort s3[] = {0x7ec4, 0x7e54, 0x2e, 0x68, 0x6b, 0x00}; // xn--mk0axi.hk const ushort s4[] = {0x7f51, 0x7edc, 0x2e, 0x63, 0x6e, 0x00}; // xn--io0a7i.cn const ushort s5[] = {0x72, 0xe1, 0x68, 0x6b, 0x6b, 0x65, 0x72, 0xe1, 0x76, 0x6a, 0x75, 0x2e, 0x6e, 0x6f, 0x00}; // xn--rhkkervju-01af.no const ushort s6[] = {0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa, 0xbcd, 0xbaa, 0xbc2, 0xbb0, 0xbcd, 0x00}; // xn--clchc0ea0b2g2a9gcd const ushort s7[] = {0x627, 0x644, 0x627, 0x631, 0x62f, 0x646, 0x00}; // xn--mgbayh7gpa - const ushort s8[] = {0x63, 0x6f, 0x72, 0x72, 0x65, 0x69, 0x6f, 0x73, 0x2d, 0x65, 0x2d, 0x74, 0x65, 0x6c, 0x65, - 0x63, 0x6f, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0xe7, 0xf5, 0x65, 0x73, 0x2e, 0x6d, 0x75, - 0x73, 0x65, 0x75, 0x6d, 0x00}; // xn--correios-e-telecomunicaes-ghc29a.museum QTest::newRow("yes-specialchars1") << QString::fromUtf16(s1) << true; - QTest::newRow("yes-specialchars2") << QString::fromUtf16(s2) << true; QTest::newRow("yes-specialchars3") << QString::fromUtf16(s3) << true; QTest::newRow("yes-specialchars4") << QString::fromUtf16(s4) << true; QTest::newRow("yes-specialchars5") << QString::fromUtf16(s5) << true; QTest::newRow("yes-specialchars6") << QString::fromUtf16(s6) << true; QTest::newRow("yes-specialchars7") << QString::fromUtf16(s7) << true; - QTest::newRow("yes-specialchars8") << QString::fromUtf16(s8) << true; QTest::newRow("no-specialchars1") << QString::fromUtf16(s1).prepend("something") << false; - QTest::newRow("no-specialchars2") << QString::fromUtf16(s2).prepend(QString::fromUtf16(s2)) << false; - QTest::newRow("no-specialchars2.5") << QString::fromUtf16(s2).prepend("whatever") << false; QTest::newRow("no-specialchars3") << QString::fromUtf16(s3).prepend("foo") << false; QTest::newRow("no-specialchars4") << QString::fromUtf16(s4).prepend("bar") << false; - QTest::newRow("no-specialchars5") << QString::fromUtf16(s5).prepend(QString::fromUtf16(s2)) << false; QTest::newRow("no-specialchars6") << QString::fromUtf16(s6).prepend(QLatin1Char('.') + QString::fromUtf16(s6)) << false; QTest::newRow("no-specialchars7") << QString::fromUtf16(s7).prepend("bla") << false; - QTest::newRow("no-specialchars8") << QString::fromUtf16(s8).append("foo") << false; QTest::newRow("exception1") << "pref.iwate.jp" << false; QTest::newRow("exception2") << "omanpost.om" << false; diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/BLACKLIST b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/BLACKLIST new file mode 100644 index 0000000000..4207625536 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-63481 +[onDemandRootCertLoadingMemberMethods] +* diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp index 000f2f4da9..bfa610b083 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp @@ -219,6 +219,7 @@ static bool waitForEncrypted(QSslSocket *socket) void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMethods() { +#define ERR(socket) socket->errorString().toLatin1() const QString host("www.qt.io"); // not using any root certs -> should not work @@ -228,13 +229,13 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe sslConfig.setCaCertificates(QList<QSslCertificate>()); socket2->setSslConfiguration(sslConfig); socket2->connectToHostEncrypted(host, 443); - QVERIFY(!waitForEncrypted(socket2.data())); + QVERIFY2(!waitForEncrypted(socket2.data()), ERR(socket2)); // default: using on demand loading -> should work QSslSocketPtr socket = newSocket(); this->socket = socket.data(); socket->connectToHostEncrypted(host, 443); - QVERIFY2(waitForEncrypted(socket.data()), qPrintable(socket->errorString())); + QVERIFY2(waitForEncrypted(socket.data()), ERR(socket)); // not using any root certs again -> should not work QSslSocketPtr socket3 = newSocket(); @@ -243,7 +244,7 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe sslConfig.setCaCertificates(QList<QSslCertificate>()); socket3->setSslConfiguration(sslConfig); socket3->connectToHostEncrypted(host, 443); - QVERIFY(!waitForEncrypted(socket3.data())); + QVERIFY2(!waitForEncrypted(socket3.data()), ERR(socket3)); // setting empty SSL configuration explicitly -> depends on on-demand loading QSslSocketPtr socket4 = newSocket(); @@ -254,16 +255,20 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe #ifdef QT_BUILD_INTERNAL const bool works = QSslSocketPrivate::rootCertOnDemandLoadingSupported(); #if defined(Q_OS_LINUX) || defined(Q_OS_WIN) - QCOMPARE(works, true); + QVERIFY2(works, ERR(socket4)); #elif defined(Q_OS_MAC) - QCOMPARE(works, false); + QVERIFY2(!works, ERR(socket4)); #endif // other platforms: undecided. // When we *allow* on-demand loading, we enable it by default; so, on Unix, // it will work without setting any certificates. Otherwise, the configuration // contains an empty set of certificates, so on-demand loading shall fail. - QCOMPARE(waitForEncrypted(socket4.data()), works); + const bool result = waitForEncrypted(socket4.data()); + if (result != works) + qDebug() << socket4->errorString(); + QCOMPARE(waitForEncrypted(socket4.data()), works); #endif // QT_BUILD_INTERNAL } +#undef ERR #endif // QT_NO_OPENSSL diff --git a/tests/auto/other/android/testdata/top_level_dir/file_in_top_dir.txt b/tests/auto/other/android/testdata/top_level_dir/file_in_top_dir.txt new file mode 100644 index 0000000000..87b10bd8e6 --- /dev/null +++ b/tests/auto/other/android/testdata/top_level_dir/file_in_top_dir.txt @@ -0,0 +1 @@ +FooBar diff --git a/tests/auto/other/android/testdata/top_level_dir/sub_dir/file_in_sub_dir.txt b/tests/auto/other/android/testdata/top_level_dir/sub_dir/file_in_sub_dir.txt new file mode 100644 index 0000000000..87b10bd8e6 --- /dev/null +++ b/tests/auto/other/android/testdata/top_level_dir/sub_dir/file_in_sub_dir.txt @@ -0,0 +1 @@ +FooBar diff --git a/tests/auto/other/android/testdata/top_level_dir/sub_dir/sub_dir2/sub_dir3/file_in_sub_dir_3.txt b/tests/auto/other/android/testdata/top_level_dir/sub_dir/sub_dir2/sub_dir3/file_in_sub_dir_3.txt new file mode 100644 index 0000000000..87b10bd8e6 --- /dev/null +++ b/tests/auto/other/android/testdata/top_level_dir/sub_dir/sub_dir2/sub_dir3/file_in_sub_dir_3.txt @@ -0,0 +1 @@ +FooBar diff --git a/tests/auto/other/android/tst_android.cpp b/tests/auto/other/android/tst_android.cpp index 57d592d45f..389d465427 100644 --- a/tests/auto/other/android/tst_android.cpp +++ b/tests/auto/other/android/tst_android.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include <QtTest/QtTest> +#include <QtCore/qdiriterator.h> class tst_Android : public QObject { @@ -34,6 +35,7 @@ Q_OBJECT private slots: void assetsRead(); void assetsNotWritable(); + void assetsIterating(); }; void tst_Android::assetsRead() @@ -59,6 +61,25 @@ void tst_Android::assetsNotWritable() QVERIFY(!file.open(QIODevice::Append)); } +void tst_Android::assetsIterating() +{ + QStringList assets = {"assets:/top_level_dir/file_in_top_dir.txt", + "assets:/top_level_dir/sub_dir", + "assets:/top_level_dir/sub_dir/file_in_sub_dir.txt", + "assets:/top_level_dir/sub_dir/sub_dir_2", + "assets:/top_level_dir/sub_dir/sub_dir_2/sub_dir_3", + "assets:/top_level_dir/sub_dir/sub_dir_2/sub_dir_3/file_in_sub_dir_3.txt"}; + // Note that we have an "assets:/top_level_dir/sub_dir/empty_sub_dir" in the test's + // assets physical directory, but empty folders are not packaged in the built apk, + // so it's expected to not have such folder be listed in the assets on runtime + QDirIterator it("assets:/top_level_dir", QDirIterator::Subdirectories); + QStringList iteratorAssets; + while (it.hasNext()) + iteratorAssets.append(it.next()); + QVERIFY(assets == iteratorAssets); +} + + QTEST_MAIN(tst_Android) #include "tst_android.moc" diff --git a/tests/auto/other/gestures/BLACKLIST b/tests/auto/other/gestures/BLACKLIST index 0e35fb374b..1de0e369a9 100644 --- a/tests/auto/other/gestures/BLACKLIST +++ b/tests/auto/other/gestures/BLACKLIST @@ -3,35 +3,53 @@ rhel-7.4 rhel-7.6 ubuntu-18.04 sles-15 +sles-15.4 rhel-8.4 [customGesture] opensuse-leap # QTBUG-67254 opensuse-42.3 [graphicsItemGesture] +# QTBUG-103054 +ubuntu-20 ubuntu-18.04 rhel-7.4 rhel-7.6 sles-15 +sles-15.4 rhel-8.4 [graphicsItemTreeGesture] +# QTBUG-103054 +ubuntu-20 ubuntu-18.04 [graphicsView] +# QTBUG-103054 +ubuntu-20 ubuntu-18.04 rhel-7.4 rhel-7.6 sles-15 +sles-15.4 rhel-8.4 [explicitGraphicsObjectTarget] +# QTBUG-103054 +ubuntu-20 ubuntu-18.04 rhel-7.4 rhel-7.6 sles-15 +sles-15.4 rhel-8.4 [autoCancelGestures2] +# QTBUG-103054 +ubuntu-20 ubuntu-18.04 rhel-7.4 rhel-7.6 sles-15 +sles-15.4 rhel-8.4 +#QTBUG-103054 +[testReuseCanceledGestures] +ubuntu-20
\ No newline at end of file diff --git a/tests/auto/other/networkselftest/BLACKLIST b/tests/auto/other/networkselftest/BLACKLIST index 55ebad985d..8b59f391f3 100644 --- a/tests/auto/other/networkselftest/BLACKLIST +++ b/tests/auto/other/networkselftest/BLACKLIST @@ -2,4 +2,5 @@ [ftpProxyServer] windows-7sp1 windows-10 - +[smbServer] +opensuse-leap-15.4 # QTBUG-89209 diff --git a/tests/auto/widgets/graphicsview/qgraphicsanchorlayout/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsanchorlayout/BLACKLIST index ce0e42b3c7..94483628fd 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsanchorlayout/BLACKLIST +++ b/tests/auto/widgets/graphicsview/qgraphicsanchorlayout/BLACKLIST @@ -1,2 +1,3 @@ [layoutDirection] ubuntu-20.04 +sles-15.4 diff --git a/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST b/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST index 5eda888af6..d73129ee40 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST +++ b/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST @@ -4,3 +4,4 @@ opensuse-42.3 ci opensuse-42.3 ci [editorKeyPress] ubuntu-20.04 +sles-15.4 diff --git a/tests/auto/widgets/itemviews/qlistview/BLACKLIST b/tests/auto/widgets/itemviews/qlistview/BLACKLIST index 2d3ae59eb1..4925d0bdc4 100644 --- a/tests/auto/widgets/itemviews/qlistview/BLACKLIST +++ b/tests/auto/widgets/itemviews/qlistview/BLACKLIST @@ -1,3 +1,3 @@ [internalDragDropMove] opensuse ci - +sles-15.4 diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp index 67d8764b61..c7cde7e65a 100644 --- a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp @@ -33,6 +33,7 @@ #include <QSignalSpy> #include <QStyledItemDelegate> #include <QTest> +#include <QLabel> #include <private/qlistwidget_p.h> using IntList = QVector<int>; @@ -126,6 +127,7 @@ private slots: void moveRows(); void moveRowsInvalid_data(); void moveRowsInvalid(); + void noopDragDrop(); protected slots: void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last) @@ -1852,6 +1854,58 @@ void tst_QListWidget::QTBUG50891_ensureSelectionModelSignalConnectionsAreSet() } +// Test that dropping an item on or beneath itself remains a no-op +void tst_QListWidget::noopDragDrop() // QTBUG-100128 +{ + QListWidget listWidget; + QList<QListWidgetItem *> items; + for (int i = 0; i < 5; ++i) { + const QString number = QString::number(i); + QListWidgetItem *item = new QListWidgetItem(&listWidget); + item->setData(Qt::UserRole, number); + QLabel *label = new QLabel(number); + listWidget.setItemWidget(item, label); + items.append(item); + } + + listWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&listWidget)); + + const QRect &lastItemRect = listWidget.visualItemRect(items.at(4)); + const QPoint &dragStart = lastItemRect.center(); + const QPoint &dropPointNirvana = lastItemRect.center() + QPoint(20, 2 * lastItemRect.height()); + + // Implement check as a macro (not a method) to safely determine the error location. + // The macro checks that item data and item widget remain unchanged when drag&drop are executed. + // In order to verify that the assets do *not* change, we can't use QTRY*: These macros would + // spin the event loop only once, while 3/4 mouse events need to get processed. + // That's why we spin the event loop 13 times, to make sure other unexpected or pending events + // get processed. +#define CHECK_ITEM {\ + const QString number = QString::number(4);\ + for (int i = 0; i < 13; ++i)\ + QApplication::processEvents();\ + QLabel *label = qobject_cast<QLabel *>(listWidget.itemWidget(items.at(4)));\ + QVERIFY(label);\ + QCOMPARE(label->text(), number);\ + const QString &data = items.at(4)->data(Qt::UserRole).toString();\ + QCOMPARE(data, number);\ + } + + // Test dropping last item beneath itself + QTest::mousePress(&listWidget, Qt::LeftButton, Qt::KeyboardModifiers(), dragStart); + QTest::mouseMove(&listWidget, dropPointNirvana); + QTest::mouseRelease(&listWidget, Qt::LeftButton); + CHECK_ITEM; + + // Test dropping last item on itself + QTest::mousePress(&listWidget, Qt::LeftButton, Qt::KeyboardModifiers(), dragStart); + QTest::mouseMove(&listWidget, dropPointNirvana); + QTest::mouseMove(&listWidget, dragStart); + QTest::mouseRelease(&listWidget, Qt::LeftButton); + CHECK_ITEM; +} + #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void tst_QListWidget::clearItemData() { diff --git a/tests/auto/widgets/kernel/qapplication/BLACKLIST b/tests/auto/widgets/kernel/qapplication/BLACKLIST index 7f4dd88261..e04cceeea2 100644 --- a/tests/auto/widgets/kernel/qapplication/BLACKLIST +++ b/tests/auto/widgets/kernel/qapplication/BLACKLIST @@ -2,6 +2,7 @@ ubuntu-20.04 ubuntu-22.04 rhel-9.0 +sles-15.4 [touchEventPropagation] # QTBUG-66745 opensuse-leap diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index 16e8dc717d..a4337d15bc 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -39,7 +39,8 @@ sles-15 [windowState] # QTBUG-75270 winrt - +[widgetAt] +sles-15.4 # QTBUG-112760 [syntheticEnterLeave] macos # Can't move cursor (QTBUG-76312) [taskQTBUG_4055_sendSyntheticEnterLeave] diff --git a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST index b4d938d641..cea1f26e53 100644 --- a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST @@ -6,6 +6,9 @@ ubuntu-16.04 [mouseMoveWithPopup] winrt +[tst_dnd_events] +sles-15.4 # QTBUG-112760 + # QTBUG-96270 [tst_paintEventOnSecondShow] opensuse diff --git a/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST b/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST index b281eca3bf..6c31a8d1d6 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST +++ b/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST @@ -1,3 +1,4 @@ [stackWidgetOpaqueChildIsVisible] windows-10 msvc-2017 +sles-15.4 # QTBUG-104241 diff --git a/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp b/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp index 1d414161d1..a29c409a44 100644 --- a/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp +++ b/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2023 The Qt Company Ltd. ** Copyright (C) 2017 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -29,10 +30,15 @@ #include <QByteArray> #include <QCryptographicHash> #include <QFile> +#include <QMetaEnum> +#include <QMessageAuthenticationCode> #include <QRandomGenerator> #include <QString> #include <QtTest> +#include <functional> +#include <numeric> + #include <time.h> class tst_bench_QCryptographicHash : public QObject @@ -40,6 +46,8 @@ class tst_bench_QCryptographicHash : public QObject Q_OBJECT QByteArray blockOfData; + using Algorithm = QCryptographicHash::Algorithm; + public: tst_bench_QCryptographicHash(); @@ -50,47 +58,25 @@ private Q_SLOTS: void addData(); void addDataChunked_data() { hash_data(); } void addDataChunked(); + + // QMessageAuthenticationCode: + void hmac_hash_data() { hash_data(); } + void hmac_hash(); + void hmac_addData_data() { hash_data(); } + void hmac_addData(); + void hmac_setKey_data(); + void hmac_setKey(); }; -const int MaxCryptoAlgorithm = QCryptographicHash::Sha3_512; const int MaxBlockSize = 65536; -const char *algoname(int i) +static void for_each_algorithm(std::function<void(QCryptographicHash::Algorithm, const char*)> f) { - switch (QCryptographicHash::Algorithm(i)) { - case QCryptographicHash::Md4: - return "md4-"; - case QCryptographicHash::Md5: - return "md5-"; - case QCryptographicHash::Sha1: - return "sha1-"; - case QCryptographicHash::Sha224: - return "sha2_224-"; - case QCryptographicHash::Sha256: - return "sha2_256-"; - case QCryptographicHash::Sha384: - return "sha2_384-"; - case QCryptographicHash::Sha512: - return "sha2_512-"; - case QCryptographicHash::Sha3_224: - return "sha3_224-"; - case QCryptographicHash::Sha3_256: - return "sha3_256-"; - case QCryptographicHash::Sha3_384: - return "sha3_384-"; - case QCryptographicHash::Sha3_512: - return "sha3_512-"; - case QCryptographicHash::Keccak_224: - return "keccak_224-"; - case QCryptographicHash::Keccak_256: - return "keccak_256-"; - case QCryptographicHash::Keccak_384: - return "keccak_384-"; - case QCryptographicHash::Keccak_512: - return "keccak_512-"; - } - Q_UNREACHABLE(); - return 0; + Q_ASSERT(f); + using A = QCryptographicHash::Algorithm; + static const auto metaEnum = QMetaEnum::fromType<A>(); + for (int i = 0, value = metaEnum.value(i); value != -1; value = metaEnum.value(++i)) + f(A(value), metaEnum.key(i)); } tst_bench_QCryptographicHash::tst_bench_QCryptographicHash() @@ -110,7 +96,7 @@ tst_bench_QCryptographicHash::tst_bench_QCryptographicHash() void tst_bench_QCryptographicHash::hash_data() { - QTest::addColumn<int>("algorithm"); + QTest::addColumn<Algorithm>("algo"); QTest::addColumn<QByteArray>("data"); static const int datasizes[] = { 0, 1, 64, 65, 512, 4095, 4096, 4097, 65536 }; @@ -118,17 +104,17 @@ void tst_bench_QCryptographicHash::hash_data() Q_ASSERT(datasizes[i] < MaxBlockSize); QByteArray data = QByteArray::fromRawData(blockOfData.constData(), datasizes[i]); - for (int algo = QCryptographicHash::Md4; algo <= MaxCryptoAlgorithm; ++algo) - QTest::newRow(algoname(algo) + QByteArray::number(datasizes[i])) << algo << data; + for_each_algorithm([&] (Algorithm algo, const char *name) { + QTest::addRow("%s-%d", name, datasizes[i]) << algo << data; + }); } } void tst_bench_QCryptographicHash::hash() { - QFETCH(int, algorithm); + QFETCH(const Algorithm, algo); QFETCH(QByteArray, data); - QCryptographicHash::Algorithm algo = QCryptographicHash::Algorithm(algorithm); QBENCHMARK { QCryptographicHash::hash(data, algo); } @@ -136,10 +122,9 @@ void tst_bench_QCryptographicHash::hash() void tst_bench_QCryptographicHash::addData() { - QFETCH(int, algorithm); + QFETCH(const Algorithm, algo); QFETCH(QByteArray, data); - QCryptographicHash::Algorithm algo = QCryptographicHash::Algorithm(algorithm); QCryptographicHash hash(algo); QBENCHMARK { hash.reset(); @@ -150,10 +135,9 @@ void tst_bench_QCryptographicHash::addData() void tst_bench_QCryptographicHash::addDataChunked() { - QFETCH(int, algorithm); + QFETCH(const Algorithm, algo); QFETCH(QByteArray, data); - QCryptographicHash::Algorithm algo = QCryptographicHash::Algorithm(algorithm); QCryptographicHash hash(algo); QBENCHMARK { hash.reset(); @@ -167,6 +151,73 @@ void tst_bench_QCryptographicHash::addDataChunked() } } +static QByteArray hmacKey() { + static QByteArray key = [] { + QByteArray result(277, Qt::Uninitialized); + std::iota(result.begin(), result.end(), uchar(0)); // uchar so wraps after UCHAR_MAX + return result; + }(); + return key; +} + +void tst_bench_QCryptographicHash::hmac_hash() +{ + QFETCH(const Algorithm, algo); + QFETCH(const QByteArray, data); + + const auto key = hmacKey(); + QBENCHMARK { + auto r = QMessageAuthenticationCode::hash(data, key, algo); + Q_UNUSED(r); + } +} + +void tst_bench_QCryptographicHash::hmac_addData() +{ + QFETCH(const Algorithm, algo); + QFETCH(const QByteArray, data); + + const auto key = hmacKey(); + QMessageAuthenticationCode mac(algo, key); + QBENCHMARK { + mac.reset(); + mac.addData(data); + auto r = mac.result(); + Q_UNUSED(r); + } +} + +void tst_bench_QCryptographicHash::hmac_setKey_data() +{ + QTest::addColumn<Algorithm>("algo"); + for_each_algorithm([] (Algorithm algo, const char *name) { + QTest::addRow("%s", name) << algo; + }); +} + +void tst_bench_QCryptographicHash::hmac_setKey() +{ + QFETCH(const Algorithm, algo); + + const QByteArrayList keys = [] { + QByteArrayList result; + const auto fullKey = hmacKey(); + result.reserve(fullKey.size()); + for (auto i = fullKey.size(); i > 0; --i) + result.push_back(fullKey.mid(i)); + return result; + }(); + + QMessageAuthenticationCode mac(algo); + QBENCHMARK { + for (const auto &key : keys) { + mac.setKey(key); + mac.addData("abc", 3); // avoid lazy setKey() + } + } +} + + QTEST_APPLESS_MAIN(tst_bench_QCryptographicHash) #include "main.moc" diff --git a/tests/manual/android_content_uri/android_content_uri.pro b/tests/manual/android_content_uri/android_content_uri.pro new file mode 100644 index 0000000000..76109e6351 --- /dev/null +++ b/tests/manual/android_content_uri/android_content_uri.pro @@ -0,0 +1,4 @@ +TEMPLATE = app +QT = core testlib widgets + +SOURCES += tst_content_uris.cpp diff --git a/tests/manual/android_content_uri/tst_content_uris.cpp b/tests/manual/android_content_uri/tst_content_uris.cpp new file mode 100644 index 0000000000..07e1754235 --- /dev/null +++ b/tests/manual/android_content_uri/tst_content_uris.cpp @@ -0,0 +1,250 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include <QTest> +#include <QDirIterator> +#include <QFileDialog> +#include <QMessageBox> + +class tst_ContentUris: public QObject +{ + Q_OBJECT +private slots: + void dirFacilities(); + void readWriteFile(); + void readWriteNonExistingFile_data(); + void readWriteNonExistingFile(); + void createFileFromDirUrl_data(); + void createFileFromDirUrl(); + void fileOperations(); +}; + +static QStringList listFiles(const QDir &dir, QDirIterator::IteratorFlag flag = {}) +{ + QDirIterator it(dir, flag); + QStringList dirs; + while (it.hasNext()) + dirs << it.next(); + return dirs; +} + +void showInstructionsDialog(const QString &message) +{ + QMessageBox::information(nullptr, QLatin1String("Instructions"), message); +} + +void tst_ContentUris::dirFacilities() +{ + showInstructionsDialog(QLatin1String("Choose a folder with no content/files/subdirs")); + + auto url = QFileDialog::getExistingDirectory(); + QVERIFY(url.startsWith(QLatin1String("content"))); + QDir dir(url); + + QVERIFY(dir.exists()); + QVERIFY(!dir.dirName().isEmpty()); + QVERIFY(listFiles(dir).isEmpty()); + + QVERIFY(dir.mkdir(QLatin1String("Sub"))); + const auto dirList = listFiles(dir); + QVERIFY(dirList.size() == 1); + const QDir subDir = dirList.first(); + + QVERIFY(subDir.dirName() == QLatin1String("Sub")); + qWarning() << "subDir.absolutePath()" << subDir.absolutePath() << dirList.first(); + QVERIFY(subDir.absolutePath() == dirList.first()); + QVERIFY(subDir.path() == dirList.first()); + + QVERIFY(listFiles(dir, QDirIterator::Subdirectories).size() == 1); + QVERIFY(dir.mkdir(QLatin1String("Sub"))); // Create an existing dir + QVERIFY(dir.rmdir(QLatin1String("Sub"))); + + QVERIFY(dir.mkpath(QLatin1String("Sub/Sub2/Sub3"))); + QVERIFY(listFiles(dir).size() == 1); + QVERIFY(listFiles(dir, QDirIterator::Subdirectories).size() == 3); + QVERIFY(dir.mkpath(QLatin1String("Sub/Sub2/Sub3"))); // Create an existing dir hierarchy + QVERIFY(dir.rmdir(QLatin1String("Sub"))); +} + +void tst_ContentUris::readWriteFile() +{ + const QByteArray content = "Written to file"; + const QString fileName = QLatin1String("new_file.txt"); + + { + showInstructionsDialog(QLatin1String("Choose a name for new file to create")); + + auto url = QFileDialog::getSaveFileName(nullptr, tr("Save File"), fileName); + QFile file(url); + QVERIFY(file.exists()); + QVERIFY(file.size() == 0); + QVERIFY(file.fileName() == url); + QVERIFY(QFileInfo(url).fileName() == fileName); + + QVERIFY(file.open(QFile::WriteOnly)); + QVERIFY(file.isOpen()); + QVERIFY(file.isWritable()); + QVERIFY(file.fileTime(QFileDevice::FileModificationTime) != QDateTime()); + QVERIFY(file.write(content) > 0); + QVERIFY(file.size() == content.size()); + file.close(); + + // NOTE: The native file cursor is not returning an updated time or it takes long + // for it to get updated, for now just check that we actually received a valid QDateTime + QVERIFY(file.fileTime(QFileDevice::FileModificationTime) != QDateTime()); + } + + { + showInstructionsDialog(QLatin1String("Choose the file that was created")); + + auto url = QFileDialog::getOpenFileName(nullptr, tr("Open File"), fileName); + QFile file(url); + QVERIFY(file.exists()); + + QVERIFY(file.open(QFile::ReadOnly)); + QVERIFY(file.isOpen()); + QVERIFY(file.isReadable()); + QVERIFY(file.readAll() == content); + + QVERIFY(file.remove()); + } +} + +void tst_ContentUris::readWriteNonExistingFile_data() +{ + QTest::addColumn<QString>("path"); + + const QString fileName = "non-existing-file.txt"; + const QString uriSchemeAuthority = "content://com.android.externalstorage.documents"; + const QString id = "primary%3APictures"; + const QString encSlash = QUrl::toPercentEncoding(QLatin1String("/")); + + const QString docSlash = uriSchemeAuthority + QLatin1String("/document/") + id + QLatin1String("/") + fileName; + const QString docEncodedSlash = uriSchemeAuthority + QLatin1String("/document/") + id + encSlash + fileName; + + QTest::newRow("document_with_slash") << docSlash; + QTest::newRow("document_with_encoded_slash") << docEncodedSlash; +} + +void tst_ContentUris::readWriteNonExistingFile() +{ + QFETCH(QString, path); + + QFile file(path); + QVERIFY(!file.exists()); + QVERIFY(file.size() == 0); + + QVERIFY(!file.open(QFile::WriteOnly)); + QVERIFY(!file.isOpen()); + QVERIFY(!file.isWritable()); +} + +void tst_ContentUris::createFileFromDirUrl_data() +{ + QTest::addColumn<QString>("path"); + + showInstructionsDialog("Choose a folder with no content/files/subdirs"); + + const QString treeUrl = QFileDialog::getExistingDirectory(); + const QString fileName = "text.txt"; + const QString treeSlash = treeUrl + QLatin1String("/") + fileName; + QTest::newRow("tree_with_slash") << treeSlash; + + // TODO: This is not handled at the moment + // const QString encSlash = QUrl::toPercentEncoding("/"_L1); + // const QString treeEncodedSlash = treeUrl + encSlash + fileName; + // QTest::newRow("tree_with_encoded_slash") << treeEncodedSlash; +} + +void tst_ContentUris::createFileFromDirUrl() +{ + QFETCH(QString, path); + + const QByteArray content = "Written to file"; + + QFile file(path); + QVERIFY(!file.exists()); + QVERIFY(file.size() == 0); + + QVERIFY(file.open(QFile::WriteOnly)); + QVERIFY(file.isOpen()); + QVERIFY(file.isWritable()); + QVERIFY(file.exists()); + QVERIFY(file.write(content)); + QVERIFY(file.size() == content.size()); + file.close(); + + QVERIFY(file.open(QFile::ReadOnly)); + QVERIFY(file.isOpen()); + QVERIFY(file.isReadable()); + QVERIFY(file.readAll() == content); + + QVERIFY(file.remove()); +} + +void tst_ContentUris::fileOperations() +{ + showInstructionsDialog("Choose a name for new file to create"); + + const QString fileName = "new_file.txt"; + auto url = QFileDialog::getSaveFileName(nullptr, tr("Save File"), fileName); + QFile file(url); + QVERIFY(file.exists()); + + // Rename + { + const QString renamedFileName = "renamed_new_file.txt"; + QVERIFY(file.rename(renamedFileName)); + const auto renamedUrl = url.replace(fileName, renamedFileName); + QVERIFY(file.fileName() == renamedUrl); + + // NOTE: The uri doesn't seem to stay usable after a rename and it needs to get + // permission again via the SAF picker. + showInstructionsDialog("Choose the file that was renamed"); + QFileDialog::getOpenFileName(nullptr, tr("Open File")); + QVERIFY(file.exists()); + + // rename now with full content uri + const auto secondRenamedUrl = url.replace(renamedFileName, "second_nenamed_file.txt"); + QVERIFY(file.rename(secondRenamedUrl)); + QVERIFY(file.fileName() == secondRenamedUrl); + + // NOTE: The uri doesn't seem to stay usable after a rename and it needs to get + // permission again via the SAF picker. + showInstructionsDialog("Choose the file that was renamed"); + QFileDialog::getOpenFileName(nullptr, tr("Open File")); + QVERIFY(file.exists()); + } + + // Remove + QVERIFY(file.remove()); + QVERIFY(!file.exists()); + + // Move + { + showInstructionsDialog("Choose source directory of file to move"); + const QString srcDir = QFileDialog::getExistingDirectory(nullptr, tr("Choose Directory")); + + const QString fileName = QLatin1String("file_to_move.txt"); + + // Create a file + QFile file(srcDir + QLatin1Char('/') + fileName); + QVERIFY(file.open(QFile::WriteOnly)); + QVERIFY(file.exists()); + + showInstructionsDialog("Choose target directory to where to move the file"); + const QString destDir = QFileDialog::getExistingDirectory(nullptr, tr("Choose Directory")); + + QVERIFY(file.rename(destDir + QLatin1Char('/') + fileName)); + + // NOTE: The uri doesn't seem to stay usable after a rename and it needs to get + // permission again via the SAF picker. + showInstructionsDialog("Choose the file that was moved"); + QFileDialog::getOpenFileName(nullptr, tr("Open File")); + + QVERIFY(file.remove()); + } +} + +QTEST_MAIN(tst_ContentUris) +#include "tst_content_uris.moc" diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 42f9878e44..bb6c33acb2 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -58,6 +58,8 @@ unc \ qtabbar \ rhi +android: SUBDIRS += android_content_uri + !qtConfig(openssl): SUBDIRS -= qssloptions qtConfig(opengl) { |