diff options
Diffstat (limited to 'tests/auto/corelib/kernel')
9 files changed, 254 insertions, 61 deletions
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 19b3289390..2e2209ac5d 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -369,7 +369,7 @@ protected: const char *nm = name.constData(); int tp = qRegisterMetaType<Bar>(nm); #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) - pthread_yield(); + sched_yield(); #endif QMetaType info(tp); if (!info.isValid()) { diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 9bd66c0835..471d73e512 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -158,6 +158,7 @@ private slots: void nullReceiver(); void functorReferencesConnection(); void disconnectDisconnects(); + void declarativeData(); }; struct QObjectCreatedOnShutdown @@ -3024,6 +3025,16 @@ void tst_QObject::recursiveSignalEmission() QSKIP("No qprocess support", SkipAll); #else QProcess proc; + + // Add the executable's directory to path so that we can find the test helper next to it + // in a cross-platform way. We must do this because the CWD is not pointing to this directory + // in debug-and-release builds. + QByteArray pathEnv = qgetenv("PATH"); + qputenv("PATH", + pathEnv + QDir::listSeparator().toLatin1() + + QCoreApplication::applicationDirPath().toLocal8Bit()); + auto restore = qScopeGuard([&] { qputenv("PATH", pathEnv); }); + // signalbug helper app should always be next to this test binary const QString path = QStringLiteral("signalbug_helper"); proc.start(path); @@ -7679,5 +7690,77 @@ void tst_QObject::disconnectDisconnects() Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value); Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value); +#ifdef QT_BUILD_INTERNAL +/* + Since QObjectPrivate stores the declarativeData pointer in a union with the pointer + to the currently destroyed child, calls to the QtDeclarative handlers need to be + correctly guarded. QTBUG-105286 +*/ +namespace QtDeclarative { +static QAbstractDeclarativeData *theData; + +static void destroyed(QAbstractDeclarativeData *data, QObject *) +{ + QCOMPARE(data, theData); +} +static void signalEmitted(QAbstractDeclarativeData *data, QObject *, int, void **) +{ + QCOMPARE(data, theData); +} +// we can't use QCOMPARE in the next two functions, as they don't return void +static int receivers(QAbstractDeclarativeData *data, const QObject *, int) +{ + QTest::qCompare(data, theData, "data", "theData", __FILE__, __LINE__); + return 0; +} +static bool isSignalConnected(QAbstractDeclarativeData *data, const QObject *, int) +{ + QTest::qCompare(data, theData, "data", "theData", __FILE__, __LINE__); + return true; +} + +class Object : public QObject +{ + Q_OBJECT +public: + using QObject::QObject; + ~Object() + { + if (Object *p = static_cast<Object *>(parent())) + p->emitSignal(); + } + + void emitSignal() + { + emit theSignal(); + } + +signals: + void theSignal(); +}; + +} +#endif + +void tst_QObject::declarativeData() +{ +#ifdef QT_BUILD_INTERNAL + QAbstractDeclarativeData::destroyed = QtDeclarative::destroyed; + QAbstractDeclarativeData::signalEmitted = QtDeclarative::signalEmitted; + QAbstractDeclarativeData::receivers = QtDeclarative::receivers; + QAbstractDeclarativeData::isSignalConnected = QtDeclarative::isSignalConnected; + + QtDeclarative::Object p; + QObjectPrivate *priv = QObjectPrivate::get(&p); + priv->declarativeData = QtDeclarative::theData = new QAbstractDeclarativeData; + + connect(&p, &QtDeclarative::Object::theSignal, &p, []{ + }); + + QtDeclarative::Object *child = new QtDeclarative::Object; + child->setParent(&p); +#endif +} + QTEST_MAIN(tst_QObject) #include "tst_qobject.moc" diff --git a/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp b/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp index fa2d5e3723..6be2744f3e 100644 --- a/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp +++ b/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp @@ -35,6 +35,7 @@ #include <QTest> #include <QThread> #include <QElapsedTimer> +#include <QScopeGuard> #define EXISTING_SHARE "existing" #define EXISTING_SIZE 1024 @@ -444,8 +445,20 @@ void tst_QSharedMemory::readOnly() QSKIP("No qprocess support", SkipAll); #elif defined(Q_OS_MACOS) QSKIP("QTBUG-59936: Times out on macOS", SkipAll); +#elif defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) + QSKIP("ASan prevents the crash this test is looking for.", SkipAll); #else rememberKey("readonly_segfault"); + + // Add the executable's directory to path so that we can find the test helper next to it + // in a cross-platform way. We must do this because the CWD is not pointing to this directory + // in debug-and-release builds. + QByteArray path = qgetenv("PATH"); + qputenv("PATH", + path + QDir::listSeparator().toLatin1() + + QCoreApplication::applicationDirPath().toLocal8Bit()); + auto restore = qScopeGuard([&] { qputenv("PATH", path); }); + // ### on windows disable the popup somehow QProcess p; p.start(m_helperBinary, QStringList("readonly_segfault")); @@ -747,6 +760,15 @@ void tst_QSharedMemory::simpleProcessProducerConsumer() rememberKey("market"); + // Add the executable's directory to path so that we can find the test helper next to it + // in a cross-platform way. We must do this because the CWD is not pointing to this directory + // in debug-and-release builds. + QByteArray path = qgetenv("PATH"); + qputenv("PATH", + path + QDir::listSeparator().toLatin1() + + QCoreApplication::applicationDirPath().toLocal8Bit()); + auto restore = qScopeGuard([&] { qputenv("PATH", path); }); + QProcess producer; producer.start(m_helperBinary, QStringList("producer")); QVERIFY2(producer.waitForStarted(), "Could not start helper binary"); diff --git a/tests/auto/corelib/kernel/qsystemsemaphore/tst_qsystemsemaphore.cpp b/tests/auto/corelib/kernel/qsystemsemaphore/tst_qsystemsemaphore.cpp index 5f010ae3d1..a73d806067 100644 --- a/tests/auto/corelib/kernel/qsystemsemaphore/tst_qsystemsemaphore.cpp +++ b/tests/auto/corelib/kernel/qsystemsemaphore/tst_qsystemsemaphore.cpp @@ -70,7 +70,14 @@ private: }; tst_QSystemSemaphore::tst_QSystemSemaphore() - : m_helperBinary("acquirerelease_helper") + : +#ifdef Q_OS_WIN + // On windows the CWD is not the same as the test binary, so we cannot use the ./ path. + m_helperBinary("acquirerelease_helper") +#else + // But on Unix we *must* + m_helperBinary("./acquirerelease_helper") +#endif { } diff --git a/tests/auto/corelib/kernel/qtimer/BLACKLIST b/tests/auto/corelib/kernel/qtimer/BLACKLIST new file mode 100644 index 0000000000..2af0df9432 --- /dev/null +++ b/tests/auto/corelib/kernel/qtimer/BLACKLIST @@ -0,0 +1,3 @@ +[zeroTimer] +ubuntu-20.04 + diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 1bd27cd0ce..3c0adda5de 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -135,24 +135,53 @@ void tst_QTimer::timeout() void tst_QTimer::remainingTime() { - QTimer timer; - QSignalSpy timeoutSpy(&timer, &QTimer::timeout); - timer.setTimerType(Qt::PreciseTimer); - timer.start(200); - - QCOMPARE(timeoutSpy.count(), 0); - QTest::qWait(50); - QCOMPARE(timeoutSpy.count(), 0); - - int remainingTime = timer.remainingTime(); - QVERIFY2(remainingTime >= 50 && remainingTime <= 200, qPrintable(QString::number(remainingTime))); - - QVERIFY(timeoutSpy.wait()); - QCOMPARE(timeoutSpy.count(), 1); - - // the timer is still active, so it should have a non-zero remaining time - remainingTime = timer.remainingTime(); - QVERIFY2(remainingTime >= 50, qPrintable(QString::number(remainingTime))); + QTimer tested; + tested.setTimerType(Qt::PreciseTimer); + + QTimer tester; + tester.setTimerType(Qt::PreciseTimer); + tester.setSingleShot(true); + + const int testedInterval = 200; + const int testerInterval = 50; + const int expectedRemainingTime = testedInterval - testerInterval; + + int testIteration = 0; + const int desiredTestCount = 2; + + auto connection = QObject::connect(&tested, &QTimer::timeout, [&tester]() { + // We let tested (which isn't a single-shot) run repeatedly, to verify + // it *does* repeat, and check that the single-shot tester, starting + // at the same time, does finish first each time, by about the right duration. + tester.start(); // Start tester again. + }); + + QObject::connect(&tester, &QTimer::timeout, [&]() { + const int remainingTime = tested.remainingTime(); + // We expect that remainingTime is at most 150 and not overdue. + const bool remainingTimeInRange = remainingTime > 0 + && remainingTime <= expectedRemainingTime; + if (remainingTimeInRange) + ++testIteration; + else + testIteration = desiredTestCount; // We are going to fail on QVERIFY2() + // below, so we don't want to iterate + // anymore and quickly exit the QTRY_...() + // with this failure. + if (testIteration == desiredTestCount) + QObject::disconnect(connection); // Last iteration, don't start tester again. + QVERIFY2(remainingTimeInRange, qPrintable("Remaining time " + + QByteArray::number(remainingTime) + "ms outside expected range (0ms, " + + QByteArray::number(expectedRemainingTime) + "ms]")); + }); + + tested.start(testedInterval); + tester.start(testerInterval); // Start tester for the 1st time. + + // Test it desiredTestCount times, give it reasonable amount of time + // (twice as much as needed). + QTRY_COMPARE_WITH_TIMEOUT(testIteration, desiredTestCount, + testedInterval * desiredTestCount * 2); } void tst_QTimer::remainingTimeInitial_data() 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 9fde7da816..9f4e1773c8 100644 --- a/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp +++ b/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp @@ -29,6 +29,7 @@ #include <QtTest/QtTest> #include <qtranslator.h> #include <qfile.h> +#include <qtemporarydir.h> class tst_QTranslator : public QObject { @@ -40,9 +41,11 @@ protected: bool eventFilter(QObject *obj, QEvent *event); private slots: void initTestCase(); + void init(); void load_data(); void load(); + void loadLocale(); void threadLoad(); void testLanguageChange(); void plural(); @@ -64,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) @@ -155,6 +134,73 @@ void tst_QTranslator::load() } } +void tst_QTranslator::loadLocale() +{ + QLocale locale; + auto localeName = locale.uiLanguages().value(0).replace('-', '_'); + if (localeName.isEmpty()) + QSKIP("This test requires at least one available UI language."); + + QByteArray ba; + { + QFile file(":/tst_qtranslator/hellotr_la.qm"); + QVERIFY2(file.open(QFile::ReadOnly), qPrintable(file.errorString())); + ba = file.readAll(); + QVERIFY(!ba.isEmpty()); + } + + QTemporaryDir dir; + QVERIFY(dir.isValid()); + + auto path = dir.path(); + QFile file(path + "/dummy"); + QVERIFY2(file.open(QFile::WriteOnly), qPrintable(file.errorString())); + QCOMPARE(file.write(ba), ba.size()); + file.close(); + + /* + Test the following order: + + /tmp/tmpDir/foo-en_US.qm + /tmp/tmpDir/foo-en_US + /tmp/tmpDir/foo-en.qm + /tmp/tmpDir/foo-en + /tmp/tmpDir/foo.qm + /tmp/tmpDir/foo- + /tmp/tmpDir/foo + */ + + QStringList files; + while (true) { + files.append(path + "/foo-" + localeName + ".qm"); + QVERIFY2(file.copy(files.last()), qPrintable(file.errorString())); + + files.append(path + "/foo-" + localeName); + QVERIFY2(file.copy(files.last()), qPrintable(file.errorString())); + + int rightmost = localeName.lastIndexOf(QLatin1Char('_')); + if (rightmost <= 0) + break; + localeName.truncate(rightmost); + } + + files.append(path + "/foo.qm"); + QVERIFY2(file.copy(files.last()), qPrintable(file.errorString())); + + files.append(path + "/foo-"); + QVERIFY2(file.copy(files.last()), qPrintable(file.errorString())); + + files.append(path + "/foo"); + QVERIFY2(file.rename(files.last()), qPrintable(file.errorString())); + + QTranslator tor; + for (const auto &filePath : files) { + QVERIFY(tor.load(locale, "foo", "-", path, ".qm")); + QCOMPARE(tor.filePath(), filePath); + QVERIFY2(file.remove(filePath), qPrintable(file.errorString())); + } +} + class TranslatorThread : public QThread { void run() { @@ -307,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 @@ -346,9 +401,9 @@ void tst_QTranslator::translationInThreadWhileInstallingTranslator() thread.runningCondition.wait(&thread.startupLock); - QTranslator *tor = new QTranslator; - tor->load("hellotr_la"); - QCoreApplication::installTranslator(tor); + QTranslator tor; + tor.load("hellotr_la"); + QCoreApplication::installTranslator(&tor); ++thread.terminate; |