diff options
author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2022-09-12 18:29:34 +0300 |
---|---|---|
committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2022-09-12 18:29:34 +0300 |
commit | 6efece8c8fe18ec3cc01dbc9c02fed3f17208ef4 (patch) | |
tree | 243504aa152967c5586bc848f9f62679d51551d0 /tests | |
parent | a5984e059385e93ab06eb95cbe12bea5215f7b9d (diff) | |
parent | dbf21da8a66e4cf1a050792c3a5816d2c686a846 (diff) |
Merge remote-tracking branch 'origin/tqtc/lts-5.15.7' into tqtc/lts-5.15-opensource
Change-Id: I976ce0c3664c9953dd0019b7d76d3f603583634f
Diffstat (limited to 'tests')
26 files changed, 751 insertions, 71 deletions
diff --git a/tests/auto/corelib/codecs/qtextcodec/test.pro b/tests/auto/corelib/codecs/qtextcodec/test.pro index 7505c5ad51..07c1e4e2bd 100644 --- a/tests/auto/corelib/codecs/qtextcodec/test.pro +++ b/tests/auto/corelib/codecs/qtextcodec/test.pro @@ -1,5 +1,5 @@ CONFIG += testcase -QT = core testlib +QT = core-private testlib SOURCES = tst_qtextcodec.cpp TARGET = tst_qtextcodec diff --git a/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp b/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp index 78b6449a69..62a8321844 100644 --- a/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp +++ b/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp @@ -38,6 +38,11 @@ #endif #include <QThreadPool> +#include <private/qglobal_p.h> // for the icu feature test +#if QT_CONFIG(icu) +# include <unicode/uvernum.h> +#endif + class tst_QTextCodec : public QObject { Q_OBJECT @@ -96,6 +101,9 @@ private slots: void shiftJis(); void userCodec(); + + void canEncode(); + void canEncode_data(); }; void tst_QTextCodec::toUnicode_data() @@ -2455,6 +2463,67 @@ void tst_QTextCodec::userCodec() QCOMPARE(pcodec, nullptr); } +void tst_QTextCodec::canEncode() +{ + QFETCH(QString, codecName); + QFETCH(QString, inputString); + QFETCH(QByteArray, expectedData); + QFETCH(bool, canEncode); + + QTextCodec *codec = QTextCodec::codecForName(codecName.toLatin1()); + QVERIFY(codec != nullptr); + + QCOMPARE(codec->canEncode(inputString), canEncode); + QByteArray encoded = codec->fromUnicode(inputString); + QCOMPARE(encoded, expectedData); +} + +void tst_QTextCodec::canEncode_data() +{ + QTest::addColumn<QString>("codecName"); + QTest::addColumn<QString>("inputString"); + QTest::addColumn<QByteArray>("expectedData"); + QTest::addColumn<bool>("canEncode"); + + QTest::newRow("English ISO-8859-1") << "ISO-8859-1" << "Hello World" + << QByteArray("Hello World") << true; + QTest::newRow("English big5") << "Big5" << "Hello World" << QByteArray("Hello World") << true; + + QTest::newRow("Greek win1252") + << "Windows-1252" + << QString("\u03c0\u03bf\u03bb\u03cd\u03c4\u03c1\u03bf\u03c0\u03bf\u03bd") + << QByteArray("??????????") << false; + QTest::newRow("Greek win1253") + << "Windows-1253" + << QString("\u03c0\u03bf\u03bb\u03cd\u03c4\u03c1\u03bf\u03c0\u03bf\u03bd") + << QByteArray("\xF0\xEF\xEB\xFD\xF4\xF1\xEF\xF0\xEF\xED") << true; + + QTest::newRow("Russian win1252") + << "Windows-1252" << QString("\u041f\u0440\u0438\u0432\u0435\u0442 \u043c\u0438\u0440") + << QByteArray("?????? ???") << false; + QTest::newRow("Russian win1251") + << "Windows-1251" << QString("\u041f\u0440\u0438\u0432\u0435\u0442 \u043c\u0438\u0440") + << QByteArray("\xCF\xF0\xE8\xE2\xE5\xF2 \xEC\xE8\xF0") << true; + + QTest::newRow("English from ucs4") + << "ISO-8859-1" << QString("\u0048\u0065\u006c\u006c\u006f\u0021") + << QByteArray("Hello!") << true; + + // ICU on Linux RHEL 7.6 seems to be old, and does not handle NULL + // characters properly. It returns 0x01 instead of 0x00 for it, so + // we just skip the test. +#if !QT_CONFIG(icu) || (U_ICU_VERSION_MAJOR_NUM > 56) + QTest::newRow("With null") << "ISO-8859-1" << QString::fromUcs4(U"Hello\u0000World", 11) + << QByteArray("Hello\x00World", 11) << true; +#endif + + QTest::newRow("With special chars") + << "ISO-8859-1" << QString("\u0001\u0002\u0003\u0008\u0009\u000a\u000b\u000d") + << QByteArray("\x01\x02\x03\b\t\n\x0B\r") << true; + + QTest::newRow("Pencil icon") << "ISO-8859-1" << QString("\u270f") << QByteArray("?") << false; +} + struct DontCrashAtExit { ~DontCrashAtExit() { QTextCodec *c = QTextCodec::codecForName("utf8"); diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index bc9df3f1f3..db60bead64 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Copyright (C) 2020 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -39,6 +39,7 @@ #include <QtCore/QRegExp> #include <QtCore/QDebug> #include <QtCore/QMetaType> +#include <QtCore/QScopeGuard> #include <QtNetwork/QHostInfo> #include <qplatformdefs.h> @@ -1271,17 +1272,15 @@ void tst_QProcess::processesInMultipleThreads() threadCount = qMax(threadCount, QThread::idealThreadCount() + 2); QVector<TestThread *> threads(threadCount); + auto cleanup = qScopeGuard([&threads]() { qDeleteAll(threads); }); for (int j = 0; j < threadCount; ++j) threads[j] = new TestThread; for (int j = 0; j < threadCount; ++j) threads[j]->start(); - for (int j = 0; j < threadCount; ++j) { + for (int j = 0; j < threadCount; ++j) QVERIFY(threads[j]->wait(10000)); - } - for (int j = 0; j < threadCount; ++j) { + for (int j = 0; j < threadCount; ++j) QCOMPARE(threads[j]->code(), 0); - } - qDeleteAll(threads); } } diff --git a/tests/auto/corelib/kernel/qtranslator/android_testdata.qrc b/tests/auto/corelib/kernel/qtranslator/android_testdata.qrc deleted file mode 100644 index 39b85db664..0000000000 --- a/tests/auto/corelib/kernel/qtranslator/android_testdata.qrc +++ /dev/null @@ -1,8 +0,0 @@ -<RCC> - <qresource prefix="/android_testdata"> - <file>hellotr_la.qm</file> - <file>hellotr_empty.qm</file> - <file>msgfmt_from_po.qm</file> - <file>dependencies_la.qm</file> - </qresource> -</RCC> diff --git a/tests/auto/corelib/kernel/qtranslator/qtranslator.qrc b/tests/auto/corelib/kernel/qtranslator/qtranslator.qrc index cb82c6cc95..6c99335215 100644 --- a/tests/auto/corelib/kernel/qtranslator/qtranslator.qrc +++ b/tests/auto/corelib/kernel/qtranslator/qtranslator.qrc @@ -1,6 +1,8 @@ <RCC> <qresource prefix="/tst_qtranslator"> + <file>dependencies_la.qm</file> <file>hellotr_la.qm</file> <file>hellotr_empty.qm</file> + <file>msgfmt_from_po.qm</file> </qresource> </RCC> diff --git a/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp b/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp index 4a4fd89987..c47b25eadb 100644 --- a/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp +++ b/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp @@ -41,6 +41,7 @@ protected: bool eventFilter(QObject *obj, QEvent *event); private slots: void initTestCase(); + void init(); void load_data(); void load(); @@ -66,38 +67,14 @@ tst_QTranslator::tst_QTranslator() void tst_QTranslator::initTestCase() { -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) - QString sourceDir(":/android_testdata/"); - QDirIterator it(sourceDir, QDirIterator::Subdirectories); - while (it.hasNext()) { - it.next(); - - QFileInfo sourceFileInfo = it.fileInfo(); - if (!sourceFileInfo.isDir()) { - QFileInfo destinationFileInfo(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1Char('/') + sourceFileInfo.filePath().mid(sourceDir.length())); - - if (!destinationFileInfo.exists()) { - QVERIFY(QDir().mkpath(destinationFileInfo.path())); - QVERIFY(QFile::copy(sourceFileInfo.filePath(), destinationFileInfo.filePath())); - } - } - } - - QDir::setCurrent(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); -#endif - - // chdir into the directory containing our testdata, - // to make the code simpler (load testdata via relative paths) -#ifdef Q_OS_WINRT - // ### TODO: Use this for all platforms in 5.7 - dataDir = QEXTRACTTESTDATA(QStringLiteral("/")); + dataDir = QEXTRACTTESTDATA(QStringLiteral("/tst_qtranslator")); QVERIFY2(!dataDir.isNull(), qPrintable("Could not extract test data")); - QVERIFY2(QDir::setCurrent(dataDir->path()), qPrintable("Could not chdir to " + dataDir->path())); -#else // !Q_OS_WINRT - QString testdata_dir = QFileInfo(QFINDTESTDATA("hellotr_la.qm")).absolutePath(); - QVERIFY2(QDir::setCurrent(testdata_dir), qPrintable("Could not chdir to " + testdata_dir)); -#endif // !Q_OS_WINRT +} +void tst_QTranslator::init() +{ + QVERIFY2(QDir::setCurrent(dataDir->path()), + qPrintable("Could not chdir to " + dataDir->path())); } bool tst_QTranslator::eventFilter(QObject *, QEvent *event) @@ -376,6 +353,15 @@ void tst_QTranslator::dependencies() QVERIFY(!tor.isEmpty()); QCOMPARE(tor.translate("QPushButton", "Hello world!"), QLatin1String("Hallo Welt!")); } + + { + // Test resolution of paths relative to main file + const QString absoluteFile = QFileInfo("dependencies_la").absoluteFilePath(); + QDir::setCurrent(QDir::tempPath()); + QTranslator tor; + QVERIFY(tor.load(absoluteFile)); + QVERIFY(!tor.isEmpty()); + } } struct TranslateThread : public QThread diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index 43698e5a19..33fcb156b6 100644 --- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -2477,6 +2477,10 @@ void tst_QLocale::dateFormat() const QLocale ir("ga_IE"); QCOMPARE(ir.dateFormat(QLocale::ShortFormat), QLatin1String("dd/MM/yyyy")); + + const auto sys = QLocale::system(); // QTBUG-92018, ru_RU on MS + const QDate date(2021, 3, 17); + QCOMPARE(sys.toString(date, sys.dateFormat(QLocale::LongFormat)), sys.toString(date)); } void tst_QLocale::timeFormat() @@ -2535,18 +2539,21 @@ void tst_QLocale::monthName() // 'de' locale doesn't have narrow month name QCOMPARE(de.monthName(12, QLocale::NarrowFormat), QLatin1String("D")); - QLocale ru("ru_RU"); + const QLocale ru("ru_RU"); QCOMPARE(ru.monthName(1, QLocale::LongFormat), QString::fromUtf8("\321\217\320\275\320\262\320\260\321\200\321\217")); QCOMPARE(ru.monthName(1, QLocale::ShortFormat), QString::fromUtf8("\321\217\320\275\320\262\56")); QCOMPARE(ru.monthName(1, QLocale::NarrowFormat), QString::fromUtf8("\320\257")); + const auto sys = QLocale::system(); + if (sys.language() == QLocale::Russian) // QTBUG-92018 + QVERIFY(sys.monthName(3) != sys.standaloneMonthName(3)); - QLocale ir("ga_IE"); + const QLocale ir("ga_IE"); QCOMPARE(ir.monthName(1, QLocale::ShortFormat), QLatin1String("Ean")); QCOMPARE(ir.monthName(12, QLocale::ShortFormat), QLatin1String("Noll")); - QLocale cz("cs_CZ"); + const QLocale cz("cs_CZ"); QCOMPARE(cz.monthName(1, QLocale::ShortFormat), QLatin1String("led")); QCOMPARE(cz.monthName(12, QLocale::ShortFormat), QLatin1String("pro")); } diff --git a/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp b/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp index b4c2657c84..f2d07c0fed 100644 --- a/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp +++ b/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp @@ -51,6 +51,9 @@ private slots: void lineBoundariesDefault(); #endif + void graphemeBoundaries_manual_data(); + void graphemeBoundaries_manual(); + void wordBoundaries_manual_data(); void wordBoundaries_manual(); void sentenceBoundaries_manual_data(); @@ -286,6 +289,104 @@ void tst_QTextBoundaryFinder::lineBoundariesDefault() } #endif // QT_BUILD_INTERNAL +void tst_QTextBoundaryFinder::graphemeBoundaries_manual_data() +{ + QTest::addColumn<QString>("testString"); + QTest::addColumn<QList<int>>("expectedBreakPositions"); + + { + // QTBUG-94951 + QChar s[] = { QChar(0x2764), // U+2764 HEAVY BLACK HEART + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0xD83D), QChar(0xDCF2), // U+1F4F2 MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT + QChar(0xD83D), QChar(0xDCE9), // U+1F4E9 ENVELOPE WITH DOWNWARDS ARROW ABOVE + }; + QString testString(s, sizeof(s)/sizeof(s[0])); + + QList<int> expectedBreakPositions{0, 2, 4, 6}; + QTest::newRow("+EXTPICxEXT+EXTPIC+EXTPIC+") << testString << expectedBreakPositions; + } + + { + QChar s[] = { QChar(0x2764), // U+2764 HEAVY BLACK HEART + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0x2764), // U+2764 HEAVY BLACK HEART + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + }; + QString testString(s, sizeof(s)/sizeof(s[0])); + + QList<int> expectedBreakPositions{0, 2, 4}; + QTest::newRow("+EXTPICxEXT+EXTPICxEXT+") << testString << expectedBreakPositions; + } + + { + QChar s[] = { QChar(0x2764), // U+2764 HEAVY BLACK HEART + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0x2764), // U+2764 HEAVY BLACK HEART + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + }; + QString testString(s, sizeof(s)/sizeof(s[0])); + + QList<int> expectedBreakPositions{0, 4, 7}; + QTest::newRow("+EXTPICxEXTxEXTxEXT+EXTPICxEXTxEXT+") << testString << expectedBreakPositions; + } + + { + QChar s[] = { QChar(0x2764), // U+2764 HEAVY BLACK HEART + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0x200D), // U+200D ZERO WIDTH JOINER + QChar(0xD83D), QChar(0xDCF2), // U+1F4F2 MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + }; + QString testString(s, sizeof(s)/sizeof(s[0])); + + QList<int> expectedBreakPositions{0, 7}; + QTest::newRow("+EXTPICxEXTxEXTxZWJxEXTPICxEXTxEXT+") << testString << expectedBreakPositions; + } + + { + QChar s[] = { QChar(0x2764), // U+2764 HEAVY BLACK HEART + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0x200D), // U+200D ZERO WIDTH JOINER + QChar(0x0041), // U+0041 LATIN CAPITAL LETTER A + QChar(0xD83D), QChar(0xDCF2), // U+1F4F2 MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT + }; + QString testString(s, sizeof(s)/sizeof(s[0])); + + QList<int> expectedBreakPositions{0, 4, 5, 7}; + QTest::newRow("+EXTPICxEXTxEXTxZWJ+Any+EXTPIC+") << testString << expectedBreakPositions; + } + + { + QChar s[] = { QChar(0x2764), // U+2764 HEAVY BLACK HEART + QChar(0xFE0F), // U+FE0F VARIATION SELECTOR-16 + QChar(0xD83C), QChar(0xDDEA), // U+1F1EA REGIONAL INDICATOR SYMBOL LETTER E + QChar(0xD83C), QChar(0xDDFA), // U+1F1FA REGIONAL INDICATOR SYMBOL LETTER U + QChar(0xD83C), QChar(0xDDEA), // U+1F1EA REGIONAL INDICATOR SYMBOL LETTER E + QChar(0xD83C), QChar(0xDDFA), // U+1F1FA REGIONAL INDICATOR SYMBOL LETTER U + QChar(0xD83C), QChar(0xDDEA), // U+1F1EA REGIONAL INDICATOR SYMBOL LETTER E + QChar(0x0041), // U+0041 LATIN CAPITAL LETTER A + }; + QString testString(s, sizeof(s)/sizeof(s[0])); + + QList<int> expectedBreakPositions{0, 2, 6, 10, 12, 13}; + QTest::newRow("+EXTPICxEXT+RIxRI+RIxRI+RI+ANY+") << testString << expectedBreakPositions; + } +} + +void tst_QTextBoundaryFinder::graphemeBoundaries_manual() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Grapheme); +} + void tst_QTextBoundaryFinder::wordBoundaries_manual_data() { QTest::addColumn<QString>("testString"); diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp index 7be2f48758..b868f65268 100644 --- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp +++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -36,6 +36,7 @@ #include <qwaitcondition.h> #include <qdebug.h> #include <qmetaobject.h> +#include <qscopeguard.h> #ifdef Q_OS_UNIX #include <pthread.h> @@ -106,6 +107,7 @@ private slots: void quitLock(); void create(); + void threadIdReuse(); }; enum { one_minute = 60 * 1000, five_minutes = 5 * one_minute }; @@ -1082,8 +1084,8 @@ void tst_QThread::wait2() qPrintable(msgElapsed(elapsed))); } - -class SlowSlotObject : public QObject { +class SlowSlotObject : public QObject +{ Q_OBJECT public: QMutex mutex; @@ -1099,22 +1101,23 @@ void tst_QThread::wait3_slowDestructor() { SlowSlotObject slow; QThread thread; - QObject::connect(&thread, SIGNAL(finished()), &slow, SLOT(slowSlot()), Qt::DirectConnection); - - enum { WaitTime = 1800 }; + QObject::connect(&thread, &QThread::finished, + &slow, &SlowSlotObject::slowSlot, Qt::DirectConnection); QElapsedTimer timer; thread.start(); thread.quit(); - //the quit function will cause the thread to finish and enter the slowSlot that is blocking + // Calling quit() will cause the thread to finish and enter the blocking slowSlot(). timer.start(); - QVERIFY(!thread.wait(Waiting_Thread::WaitTime)); - qint64 elapsed = timer.elapsed(); - QVERIFY2(elapsed >= Waiting_Thread::WaitTime - 1, qPrintable(QString::fromLatin1("elapsed: %1").arg(elapsed))); - - slow.cond.wakeOne(); - //now the thread should finish quickly + { + // Ensure thread finishes quickly after the checks - regardless of success: + const auto wakeSlow = qScopeGuard([&slow]() -> void { slow.cond.wakeOne(); }); + QVERIFY(!thread.wait(Waiting_Thread::WaitTime)); + const qint64 elapsed = timer.elapsed(); + QVERIFY2(elapsed >= Waiting_Thread::WaitTime - 1, + qPrintable(QString::fromLatin1("elapsed: %1").arg(elapsed))); + } QVERIFY(thread.wait(one_minute)); } @@ -1631,5 +1634,71 @@ void tst_QThread::requestTermination() QVERIFY(!thread.isInterruptionRequested()); } +/* + This is a regression test for QTBUG-96846. + + Incorrect system thread ID cleanup can cause QThread::wait() to report that + a thread is trying to wait for itself. +*/ +void tst_QThread::threadIdReuse() +{ + class Thread1 : public QThread { + public: + // It's important that those thread ID's are not accessed concurrently + Qt::HANDLE savedThreadId; + + void run() override { savedThreadId = QThread::currentThreadId(); } + }; + + class Thread2 : public Thread1 { + public: + bool waitOk; + Thread2(QThread *otherThread) : Thread1(), waitOk(false), otherThread(otherThread) {} + + void run() override { + Thread1::run(); + waitOk = otherThread->wait(); + } + + private: + QThread *const otherThread; + }; + + Thread1 thread1; + thread1.start(); + QVERIFY(thread1.wait()); + + // If the system thread allocated for thread1 is destroyed before thread2 is + // started, at least on some versions of Linux the system thread ID for + // thread2 would be the same as one that was used for thread1. + + // The system thread may be alive for some time after returning from + // QThread::wait() because the implementation is using detachable threads, so + // some additional time is required for the system thread to terminate. Not + // waiting long enough here would result in a new system thread ID being + // allocated for thread2 and this test passing even without a fix for + // QTBUG-96846. + bool threadIdReused = false; + + for (int i = 0; i < 42; i++) { + QThread::msleep(1); + + Thread2 thread2(&thread1); + thread2.start(); + QVERIFY(thread2.wait()); + QVERIFY(thread2.waitOk); + + if (thread1.savedThreadId == thread2.savedThreadId) { + qDebug("Thread ID reused at iteration %d", i); + threadIdReused = true; + break; + } + } + + if (!threadIdReused) { + QSKIP("Thread ID was not reused"); + } +} + QTEST_MAIN(tst_QThread) #include "tst_qthread.moc" diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp index cd245030db..e85fb5ea88 100644 --- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp +++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp @@ -104,6 +104,7 @@ private slots: void stressTest(); void takeAllAndIncreaseMaxThreadCount(); void waitForDoneAfterTake(); + void threadReuse(); private: QMutex m_functionTestMutex; @@ -803,7 +804,7 @@ void tst_QThreadPool::tryStartPeakThreadCount() CounterTask task; QThreadPool threadPool; - for (int i = 0; i < 20; ++i) { + for (int i = 0; i < 4*QThread::idealThreadCount(); ++i) { if (threadPool.tryStart(&task) == false) QTest::qWait(10); } @@ -1385,5 +1386,29 @@ void tst_QThreadPool::waitForDoneAfterTake() } +/* + Try trigger reuse of expired threads and check that all tasks execute. + + This is a regression test for QTBUG-72872. +*/ +void tst_QThreadPool::threadReuse() +{ + QThreadPool manager; + manager.setExpiryTimeout(-1); + manager.setMaxThreadCount(1); + + constexpr int repeatCount = 10000; + constexpr int timeoutMs = 1000; + QSemaphore sem; + + for (int i = 0; i < repeatCount; i++) { + manager.start([&sem]() { sem.release(); }); + manager.start([&sem]() { sem.release(); }); + manager.releaseThread(); + QVERIFY(sem.tryAcquire(2, timeoutMs)); + manager.reserveThread(); + } +} + QTEST_MAIN(tst_QThreadPool); #include "tst_qthreadpool.moc" diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index a36f538515..01971ee3c1 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -3572,6 +3572,13 @@ void tst_QImage::metadataPassthrough() QCOMPARE(converted.dotsPerMeterY(), a.dotsPerMeterY()); QCOMPARE(converted.devicePixelRatio(), a.devicePixelRatio()); + QVector<QRgb> clut({ 0xFFFF0000, 0xFF00FF00, 0xFF0000FF }); + QImage convertedWithClut = a.convertToFormat(QImage::Format_Indexed8, clut); + QCOMPARE(convertedWithClut.text(QStringLiteral("Test")), a.text(QStringLiteral("Test"))); + QCOMPARE(convertedWithClut.dotsPerMeterX(), a.dotsPerMeterX()); + QCOMPARE(convertedWithClut.dotsPerMeterY(), a.dotsPerMeterY()); + QCOMPARE(convertedWithClut.devicePixelRatio(), a.devicePixelRatio()); + QImage copied = a.copy(0, 0, a.width() / 2, a.height() / 2); QCOMPARE(copied.text(QStringLiteral("Test")), a.text(QStringLiteral("Test"))); QCOMPARE(copied.dotsPerMeterX(), a.dotsPerMeterX()); diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index bbb7276bfb..edbb090e42 100644 --- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -277,7 +277,7 @@ void tst_QFontDatabase::addAppFont() QVERIFY(QFontDatabase::removeApplicationFont(id)); QCOMPARE(fontDbChangedSpy.count(), 2); - QCOMPARE(db.families(), oldFamilies); + QVERIFY(db.families().count() <= oldFamilies.count()); } void tst_QFontDatabase::addTwoAppFontsFromFamily() diff --git a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp index a32fb1d25b..704215a24a 100644 --- a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp @@ -654,6 +654,7 @@ void tst_QRawFont::fromFont_data() QTest::addColumn<QFont::HintingPreference>("hintingPreference"); QTest::addColumn<QString>("familyName"); QTest::addColumn<QFontDatabase::WritingSystem>("writingSystem"); + QTest::addColumn<QFont::StyleStrategy>("styleStrategy"); for (int i=QFont::PreferDefaultHinting; i<=QFont::PreferFullHinting; ++i) { QString titleBase = QString::fromLatin1("%2, hintingPreference=%1, writingSystem=%3") @@ -667,7 +668,8 @@ void tst_QRawFont::fromFont_data() << fileName << QFont::HintingPreference(i) << "QtBidiTestFont" - << writingSystem; + << writingSystem + << QFont::PreferDefault; } { @@ -679,7 +681,8 @@ void tst_QRawFont::fromFont_data() << fileName << QFont::HintingPreference(i) << "QtBidiTestFont" - << writingSystem; + << writingSystem + << QFont::PreferDefault; } { @@ -691,9 +694,24 @@ void tst_QRawFont::fromFont_data() << fileName << QFont::HintingPreference(i) << "QtBidiTestFont" - << writingSystem; + << writingSystem + << QFont::PreferDefault; } } + + { + QString fileName = testFont; + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Arabic; + + QString title = QStringLiteral("No font merging + unsupported script"); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::PreferDefaultHinting + << "QtBidiTestFont" + << writingSystem + << QFont::NoFontMerging; + } + } void tst_QRawFont::fromFont() @@ -702,6 +720,7 @@ void tst_QRawFont::fromFont() QFETCH(QFont::HintingPreference, hintingPreference); QFETCH(QString, familyName); QFETCH(QFontDatabase::WritingSystem, writingSystem); + QFETCH(QFont::StyleStrategy, styleStrategy); QFontDatabase fontDatabase; int id = fontDatabase.addApplicationFont(fileName); @@ -710,6 +729,8 @@ void tst_QRawFont::fromFont() QFont font(familyName); font.setHintingPreference(hintingPreference); font.setPixelSize(26.0); + if (styleStrategy != QFont::PreferDefault) + font.setStyleStrategy(styleStrategy); QRawFont rawFont = QRawFont::fromFont(font, writingSystem); QVERIFY(rawFont.isValid()); diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 392419e066..0610d0a301 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -110,6 +110,7 @@ private slots: void connectToHost_data(); void connectToHost(); void maxFrameSize(); + void http2DATAFrames(); void authenticationRequired_data(); void authenticationRequired(); @@ -780,6 +781,89 @@ void tst_Http2::maxFrameSize() QVERIFY(serverGotSettingsACK); } +void tst_Http2::http2DATAFrames() +{ + using namespace Http2; + + { + // 0. DATA frame with payload, no padding. + + FrameWriter writer(FrameType::DATA, FrameFlag::EMPTY, 1); + writer.append(uchar(1)); + writer.append(uchar(2)); + writer.append(uchar(3)); + + const Frame frame = writer.outboundFrame(); + const auto &buffer = frame.buffer; + // Frame's header is 9 bytes + 3 bytes of payload + // (+ 0 bytes of padding and no padding length): + QCOMPARE(int(buffer.size()), 12); + + QVERIFY(!frame.padding()); + QCOMPARE(int(frame.payloadSize()), 3); + QCOMPARE(int(frame.dataSize()), 3); + QCOMPARE(frame.dataBegin() - buffer.data(), 9); + QCOMPARE(char(*frame.dataBegin()), uchar(1)); + } + + { + // 1. DATA with padding. + + const int padLength = 10; + FrameWriter writer(FrameType::DATA, FrameFlag::END_STREAM | FrameFlag::PADDED, 1); + writer.append(uchar(padLength)); // The length of padding is 1 byte long. + writer.append(uchar(1)); + for (int i = 0; i < padLength; ++i) + writer.append(uchar(0)); + + const Frame frame = writer.outboundFrame(); + const auto &buffer = frame.buffer; + // Frame's header is 9 bytes + 1 byte for padding length + // + 1 byte of data + 10 bytes of padding: + QCOMPARE(int(buffer.size()), 21); + + QCOMPARE(frame.padding(), padLength); + QCOMPARE(int(frame.payloadSize()), 12); // Includes padding, its length + data. + QCOMPARE(int(frame.dataSize()), 1); + + // Skipping 9 bytes long header and padding length: + QCOMPARE(frame.dataBegin() - buffer.data(), 10); + + QCOMPARE(char(frame.dataBegin()[0]), uchar(1)); + QCOMPARE(char(frame.dataBegin()[1]), uchar(0)); + + QVERIFY(frame.flags().testFlag(FrameFlag::END_STREAM)); + QVERIFY(frame.flags().testFlag(FrameFlag::PADDED)); + } + { + // 2. DATA with PADDED flag, but 0 as padding length. + + FrameWriter writer(FrameType::DATA, FrameFlag::END_STREAM | FrameFlag::PADDED, 1); + + writer.append(uchar(0)); // Number of padding bytes is 1 byte long. + writer.append(uchar(1)); + + const Frame frame = writer.outboundFrame(); + const auto &buffer = frame.buffer; + + // Frame's header is 9 bytes + 1 byte for padding length + 1 byte of data + // + 0 bytes of padding: + QCOMPARE(int(buffer.size()), 11); + + QCOMPARE(frame.padding(), 0); + QCOMPARE(int(frame.payloadSize()), 2); // Includes padding (0 bytes), its length + data. + QCOMPARE(int(frame.dataSize()), 1); + + // Skipping 9 bytes long header and padding length: + QCOMPARE(frame.dataBegin() - buffer.data(), 10); + + QCOMPARE(char(*frame.dataBegin()), uchar(1)); + + QVERIFY(frame.flags().testFlag(FrameFlag::END_STREAM)); + QVERIFY(frame.flags().testFlag(FrameFlag::PADDED)); + } +} + void tst_Http2::authenticationRequired_data() { QTest::addColumn<bool>("success"); @@ -796,6 +880,7 @@ void tst_Http2::authenticationRequired_data() void tst_Http2::authenticationRequired() { clearHTTP2State(); + serverPort = 0; QFETCH(const bool, responseHEADOnly); POSTResponseHEADOnly = responseHEADOnly; @@ -864,6 +949,10 @@ void tst_Http2::authenticationRequired() QCOMPARE(isAuthenticated(reqAuthHeader), success); if (success) QCOMPARE(receivedBody, expectedBody); + // In the `!success` case we need to wait for the server to emit this or it might cause issues + // in the next test running after this. In the `success` case we anyway expect it to have been + // received. + QTRY_VERIFY(serverGotSettingsACK); } void tst_Http2::serverStarted(quint16 port) diff --git a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST index 61fff6ee00..930d4b1a3b 100644 --- a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST +++ b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST @@ -9,3 +9,6 @@ ubuntu windows-10 msvc-2015 windows-7sp1 +# QTBUG-96345 +[simpleConnectToIMAP] +ubuntu diff --git a/tests/auto/opengl/qgl/BLACKLIST b/tests/auto/opengl/qgl/BLACKLIST index 705d8f8926..6ad3dba4a8 100644 --- a/tests/auto/opengl/qgl/BLACKLIST +++ b/tests/auto/opengl/qgl/BLACKLIST @@ -7,3 +7,6 @@ rhel-7.4 opensuse-42.3 sles +# QTBUG-96271 +[closeAndThenShow] +macos-11 diff --git a/tests/auto/other/lancelot/paintcommands.cpp b/tests/auto/other/lancelot/paintcommands.cpp index e98df3781e..0dab5376a0 100644 --- a/tests/auto/other/lancelot/paintcommands.cpp +++ b/tests/auto/other/lancelot/paintcommands.cpp @@ -376,6 +376,10 @@ void PaintCommands::staticInit() "^drawLine\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$", "drawLine <x1> <y1> <x2> <y2>", "drawLine 10.0 10.0 20.0 20.0"); + DECL_PAINTCOMMAND("drawLines", command_drawLines, + "^drawLines\\s+\\[([\\w\\s\\-.]*)\\]$", + "drawLines <[ <l1x1> <l1y1> <l1x2> <l1y2> <l2x1> <l2y1> ... ]>", + "drawLines [ 10 10 50 10 50 20 10 20 ]"); DECL_PAINTCOMMAND("drawRect", command_drawRect, "^drawRect\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$", "drawRect <x> <y> <w> <h>", @@ -433,7 +437,7 @@ void PaintCommands::staticInit() "drawConvexPolygon <[ <x1> <y1> ... <xn> <yn> ]>", "drawConvexPolygon [ 1 4 6 8 5 3 ]"); DECL_PAINTCOMMAND("drawPolyline", command_drawPolyline, - "^drawPolyline\\s+\\[([\\w\\s]*)\\]$", + "^drawPolyline\\s+\\[([\\w\\s\\-.]*)\\]$", "drawPolyline <[ <x1> <y1> ... <xn> <yn> ]>", "drawPolyline [ 1 4 6 8 5 3 ]"); DECL_PAINTCOMMAND("drawText", command_drawText, @@ -975,6 +979,25 @@ void PaintCommands::command_drawLine(QRegularExpressionMatch re) } /***************************************************************************************************/ +void PaintCommands::command_drawLines(QRegularExpressionMatch re) +{ + static QRegularExpression separators("\\s"); + QStringList numbers = re.captured(1).split(separators, Qt::SkipEmptyParts); + + QVector<QLineF> array; + for (int i = 0; i + 3 < numbers.size(); i += 4) { + QPointF pt1(numbers.at(i).toFloat(), numbers.at(i + 1).toFloat()); + QPointF pt2(numbers.at(i + 2).toFloat(), numbers.at(i + 3).toFloat()); + array.append(QLineF(pt1, pt2)); + } + + if (m_verboseMode) + printf(" -(lance) drawLines(size=%zd)\n", size_t(array.size())); + + m_painter->drawLines(array); +} + +/***************************************************************************************************/ void PaintCommands::command_drawPath(QRegularExpressionMatch re) { if (m_verboseMode) diff --git a/tests/auto/other/lancelot/paintcommands.h b/tests/auto/other/lancelot/paintcommands.h index 816ecd6fa2..4a1a89556d 100644 --- a/tests/auto/other/lancelot/paintcommands.h +++ b/tests/auto/other/lancelot/paintcommands.h @@ -187,6 +187,7 @@ private: void command_drawEllipse(QRegularExpressionMatch re); void command_drawImage(QRegularExpressionMatch re); void command_drawLine(QRegularExpressionMatch re); + void command_drawLines(QRegularExpressionMatch re); void command_drawPath(QRegularExpressionMatch re); void command_drawPie(QRegularExpressionMatch re); void command_drawPixmap(QRegularExpressionMatch re); diff --git a/tests/auto/other/lancelot/scripts/cosmetic.qps b/tests/auto/other/lancelot/scripts/cosmetic.qps new file mode 100644 index 0000000000..3c730cf26f --- /dev/null +++ b/tests/auto/other/lancelot/scripts/cosmetic.qps @@ -0,0 +1,55 @@ +drawRect 0 0 800 800 + +setRenderHint Antialiasing true +image_load dome_argb32.png img + +save +setBrush springgreen SolidPattern + +begin_block primitives + +setPen black 2 DashLine +pen_setCosmetic true +drawLine 10 60 60 10 +drawRect 80 10.0 30 50 +drawText 130 50 "Foo" +drawImage img 160 10 50 50 + +pen_setCosmetic false +drawLine 10 160 60 110 +drawRect 80 110.0 30 50 +drawText 130 150 "Foo" +drawImage img 160 110 50 50 + +setPen NoPen +drawLine 10 260 60 210 +drawRect 80 210.0 30 50 +drawText 130 250 "Foo" +drawImage img 160 210 50 50 + +end_block primitives + + +translate 250 0 +rotate 10 +scale 2.5 1 +repeat_block primitives + +resetMatrix +# Force non-simple pen in Pdf +setOpacity 0.5 +translate 0 400 +repeat_block primitives + +translate 250 0 +rotate 10 +scale 2.5 1 +repeat_block primitives + +restore +setPen blue 4 DotLine +setBrush olive SolidPattern +pen_setCosmetic true +translate 50 720 +scale 2 2 +drawRect 0 0 30 30 diff --git a/tests/auto/other/lancelot/scripts/linedashes2.qps b/tests/auto/other/lancelot/scripts/linedashes2.qps index 1dc4fd310e..b9a4cb9566 100644 --- a/tests/auto/other/lancelot/scripts/linedashes2.qps +++ b/tests/auto/other/lancelot/scripts/linedashes2.qps @@ -111,8 +111,9 @@ translate 0 780 repeat_block vertical resetMatrix -translate 40 400 -setPen 0xffff0000 5 dashdotline flatcap +translate 20 380 +setPen 0xffff00ff 5 dashdotline flatcap +begin_block offset pen_setDashPattern [1 1 4 1 1 4] pen_setDashOffset -4 drawLine 0 0 300 0 @@ -146,9 +147,50 @@ drawLine 0 0 300 0 translate 0 8 pen_setDashOffset 16 drawLine 0 0 300 0 +end_block offset + +resetMatrix +translate 420 380 +setPen 0xffff00ff 5 dashdotline roundcap +repeat_block offset resetMatrix setPen black 3 dashdotline pen_setCosmetic true translate 0 -150 -drawLine 500 160 500 410
\ No newline at end of file +drawLine 500 160 500 410 + +resetMatrix +translate 300 480 +setPen blue 0 + +begin_block clip_lines +pen_setDashPattern [ 20 4 5 4 1 4 ] +pen_setDashOffset 26.0 +drawLines [0 0 1000000 10 1000000 10 -1000000 20 -1000000 20 0 30] +end_block clip_lines + +translate 0 45 +setPen blue 5 +repeat_block clip_lines + +translate 0 45 +setPen blue 5 SolidLine RoundCap +repeat_block clip_lines + +translate 0 45 +setPen green 0 + +begin_block clip_poly +pen_setDashPattern [ 20 4 5 4 1 4 ] +pen_setDashOffset 26.0 +drawPolyline [0 0 1000000 10 -1000000 20 0 30] +end_block clip_poly + +translate 0 45 +setPen green 5 +repeat_block clip_poly + +translate 0 45 +setPen green 5 SolidLine RoundCap +repeat_block clip_poly diff --git a/tests/auto/other/lancelot/tst_lancelot.cpp b/tests/auto/other/lancelot/tst_lancelot.cpp index 7c0d809c01..516cf09f2f 100644 --- a/tests/auto/other/lancelot/tst_lancelot.cpp +++ b/tests/auto/other/lancelot/tst_lancelot.cpp @@ -30,6 +30,9 @@ #include <qbaselinetest.h> #include <QDir> #include <QPainter> +#include <QPdfWriter> +#include <QTemporaryFile> +#include <QProcess> #ifndef QT_NO_OPENGL #include <QOpenGLFramebufferObjectFormat> @@ -53,7 +56,8 @@ public: private: enum GraphicsEngine { Raster = 0, - OpenGL = 1 + OpenGL = 1, + Pdf = 2 }; void setupTestSuite(const QStringList& blacklist = QStringList()); @@ -88,6 +92,9 @@ private slots: void testRasterRGBA64PM_data(); void testRasterRGBA64PM(); + void testPdf_data(); + void testPdf(); + #ifndef QT_NO_OPENGL void testOpenGL_data(); void testOpenGL(); @@ -239,6 +246,21 @@ void tst_Lancelot::testRasterRGBA64PM() } +void tst_Lancelot::testPdf_data() +{ +#ifdef Q_OS_MACOS + setupTestSuite(); +#else + QSKIP("Pdf testing only implemented for macOS"); +#endif +} + +void tst_Lancelot::testPdf() +{ + runTestSuite(Pdf, QImage::Format_RGB32); +} + + #ifndef QT_NO_OPENGL bool tst_Lancelot::checkSystemGLSupport() { @@ -370,6 +392,28 @@ void tst_Lancelot::runTestSuite(GraphicsEngine engine, QImage::Format format, co paint(&pdv, engine, format, script, QFileInfo(filePath).absoluteFilePath()); rendered = fbo.toImage().convertToFormat(format); #endif + } else if (engine == Pdf) { + QString tempStem(QDir::tempPath() + QLatin1String("/lancelot_XXXXXX_") + qpsFile.chopped(4)); + + QTemporaryFile pdfFile(tempStem + QLatin1String(".pdf")); + pdfFile.open(); + QPdfWriter writer(&pdfFile); + writer.setPdfVersion(QPdfWriter::PdfVersion_1_6); + writer.setResolution(150); + paint(&writer, engine, format, script, QFileInfo(filePath).absoluteFilePath()); + pdfFile.close(); + + // Convert pdf to something we can read into a QImage, using macOS' sips utility + QTemporaryFile pngFile(tempStem + QLatin1String(".png")); + pngFile.open(); // Just create the file name + pngFile.close(); + QProcess proc; + const char *rawArgs = "-s format png --cropOffset 20 20 -c 800 800 -o"; + QStringList argList = QString::fromLatin1(rawArgs).split(QLatin1Char(' ')); + proc.start(QLatin1String("sips"), argList << pngFile.fileName() << pdfFile.fileName()); + proc.waitForFinished(2 * 60 * 1000); // May need some time + + rendered = QImage(pngFile.fileName()); } QBASELINE_TEST(rendered); @@ -384,6 +428,9 @@ void tst_Lancelot::paint(QPaintDevice *device, GraphicsEngine engine, QImage::Fo case OpenGL: pcmd.setType(OpenGLBufferType); // version/profile is communicated through the context's format() break; + case Pdf: + pcmd.setType(PdfType); + break; case Raster: // fallthrough default: pcmd.setType(ImageType); diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index db7d1449d3..eaa00d9173 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -223,6 +223,7 @@ private slots: void replayMouseMove(); void itemsUnderMouse(); void embeddedViews(); + void embeddedViewsWithFocus(); void scrollAfterResize_data(); void scrollAfterResize(); void moveItemWhileScrolling_data(); @@ -3519,6 +3520,60 @@ void tst_QGraphicsView::embeddedViews() delete v1; } +/*! + Verify that a nested graphics view and embedded widgets receive window + activation and focus correctly. + + See QTBUG-94091. +*/ +void tst_QGraphicsView::embeddedViewsWithFocus() +{ + class FocusWidget : public QWidget + { + public: + FocusWidget() { setFocusPolicy(Qt::StrongFocus); } + QSize sizeHint() const override { return QSize(100, 100); } + + int focusCount = 0; + protected: + void mousePressEvent(QMouseEvent *) override {} // accept event to avoid warning + void focusInEvent(QFocusEvent *) override { ++focusCount; } + void focusOutEvent(QFocusEvent *) override { --focusCount; } + }; + + QGraphicsScene *innerScene = new QGraphicsScene; + FocusWidget *innerWidget = new FocusWidget; + innerScene->addWidget(innerWidget); + QGraphicsView *innerView = new QGraphicsView(innerScene); + + QGraphicsScene outerScene; + FocusWidget *outerWidget = new FocusWidget; + QGraphicsProxyWidget *outerProxy = outerScene.addWidget(outerWidget); + QGraphicsProxyWidget *nestedProxy = outerScene.addWidget(innerView); + outerProxy->setPos(0, 0); + nestedProxy->setPos(0, outerWidget->sizeHint().height()); + QGraphicsView outerView(&outerScene); + outerView.show(); + outerView.activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(&outerView)); + const QPoint outerCenter(QPoint(innerWidget->sizeHint().width() / 2, + innerWidget->sizeHint().height() / 2)); + const QPoint innerCenter(outerCenter + QPoint(0, innerWidget->sizeHint().height())); + QCOMPARE(outerView.itemAt(outerCenter), outerProxy); + QCOMPARE(outerView.itemAt(innerCenter), nestedProxy); + QVERIFY(outerScene.isActive()); + QVERIFY(innerScene->isActive()); + + QCOMPARE(outerWidget->focusCount, 0); + QCOMPARE(innerWidget->focusCount, 0); + QTest::mouseClick(outerView.viewport(), Qt::LeftButton, {}, outerCenter); + QCOMPARE(outerWidget->focusCount, 1); + QCOMPARE(innerWidget->focusCount, 0); + QTest::mouseClick(outerView.viewport(), Qt::LeftButton, {}, innerCenter); + QCOMPARE(outerWidget->focusCount, 0); + QCOMPARE(innerWidget->focusCount, 1); +} + void tst_QGraphicsView::scrollAfterResize_data() { QTest::addColumn<bool>("reverse"); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 431433c7d6..1a72ca298f 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -421,6 +421,8 @@ private slots: void receivesLanguageChangeEvent(); void deleteWindowInCloseEvent(); + void activateWhileModalHidden(); + private: bool ensureScreenSize(int width, int height); @@ -11803,5 +11805,24 @@ void tst_QWidget::deleteWindowInCloseEvent() QVERIFY(true); } +void tst_QWidget::activateWhileModalHidden() +{ + QDialog dialog; + dialog.setWindowModality(Qt::ApplicationModal); + dialog.show(); + QVERIFY(QTest::qWaitForWindowActive(&dialog)); + QVERIFY(dialog.isActiveWindow()); + QCOMPARE(QApplication::activeWindow(), &dialog); + + dialog.hide(); + QTRY_VERIFY(!dialog.isVisible()); + + QMainWindow window; + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QVERIFY(window.isActiveWindow()); + QCOMPARE(QApplication::activeWindow(), &window); +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" diff --git a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST index 70a7889257..b4d938d641 100644 --- a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST @@ -5,3 +5,7 @@ ubuntu-16.04 [mouseMoveWithPopup] winrt + +# QTBUG-96270 +[tst_paintEventOnSecondShow] +opensuse diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index b11faef30a..586b429338 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -405,6 +405,7 @@ void tst_QWidget_window::tst_paintEventOnSecondShow() { PaintTestWidget w; w.show(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); w.hide(); w.paintEventCount = 0; diff --git a/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp b/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp index 9f08bd337b..d817d84710 100644 --- a/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp +++ b/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp @@ -33,6 +33,7 @@ #include <qdebug.h> #include <qscrollarea.h> #include <qlayout.h> +#include <qscrollbar.h> class tst_QScrollArea : public QObject { @@ -46,6 +47,7 @@ private slots: void getSetCheck(); void ensureMicroFocusVisible_Task_167838(); void checkHFW_Task_197736(); + void stableHeightForWidth(); }; tst_QScrollArea::tst_QScrollArea() @@ -165,5 +167,61 @@ void tst_QScrollArea::checkHFW_Task_197736() QCOMPARE(w->height(), 200); } + +/* + If the scroll area rides the size where, due to the height-for-width + implementation of the widget, the vertical scrollbar is needed only + if the vertical scrollbar is visible, then we don't want it to flip + back and forth, but rather constrain the width of the widget. + See QTBUG-92958. +*/ +void tst_QScrollArea::stableHeightForWidth() +{ + struct HeightForWidthWidget : public QWidget + { + HeightForWidthWidget() + { + QSizePolicy policy = sizePolicy(); + policy.setHeightForWidth(true); + setSizePolicy(policy); + } + // Aspect ratio 1:1 + int heightForWidth(int width) const override { return width; } + }; + + class HeightForWidthArea : public QScrollArea + { + public: + HeightForWidthArea() + { + this->verticalScrollBar()->installEventFilter(this); + } + protected: + bool eventFilter(QObject *obj, QEvent *e) override + { + if (obj == verticalScrollBar() && e->type() == QEvent::Hide) + ++m_hideCount; + return QScrollArea::eventFilter(obj,e); + } + public: + int m_hideCount = 0; + }; + + HeightForWidthArea area; + HeightForWidthWidget equalWHWidget; + area.setWidget(&equalWHWidget); + area.setWidgetResizable(true); + // at this size, the widget wants to be 501 pixels high, + // requiring a vertical scrollbar in a 499 pixel high area. + // but the width resulting from showing the scrollbar would + // be less than 499, so no scrollbars would be needed anymore. + area.resize(501, 499); + area.show(); + QTest::qWait(500); + // if the scrollbar got hidden more than once, then the layout + // isn't stable. + QVERIFY(area.m_hideCount <= 1); +} + QTEST_MAIN(tst_QScrollArea) #include "tst_qscrollarea.moc" |