diff options
Diffstat (limited to 'tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp')
-rw-r--r-- | tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp | 200 |
1 files changed, 106 insertions, 94 deletions
diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp index 721901ffe7..a5b0087f9c 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp +++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp @@ -1,30 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + #include <QTest> #include <QCoreApplication> @@ -33,18 +9,33 @@ #include <QFileSystemWatcher> #include <QElapsedTimer> #include <QTextStream> +#include <QMap> +#include <QString> #include <QDir> #include <QSignalSpy> #include <QTimer> #include <QTemporaryFile> #if defined(Q_OS_WIN) -#include <windows.h> +#include <qt_windows.h> #endif -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) +#ifdef Q_OS_ANDROID #include <QStandardPaths> #endif +using namespace std::chrono_literals; + +#if defined(Q_OS_QNX) +// Longer polling times on QNX, otherwise the tests fail on the CI +constexpr auto nativeEngineTimeout = 1s; +constexpr auto pollingEngineTimeout = 1s; +constexpr bool isQNX = true; +#else +constexpr auto nativeEngineTimeout = 0ms; +constexpr auto pollingEngineTimeout = 20ms; +constexpr bool isQNX = false; +#endif + /* All tests need to run in temporary directories not used * by the application to avoid non-deterministic failures on Windows * due to locked directories and left-overs from previous tests. */ @@ -104,7 +95,7 @@ tst_QFileSystemWatcher::tst_QFileSystemWatcher() m_tempDirPattern += QLatin1Char('/'); m_tempDirPattern += QStringLiteral("tst_qfilesystemwatcherXXXXXX"); -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) +#ifdef Q_OS_ANDROID QDir::setCurrent(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); #endif } @@ -124,7 +115,7 @@ void tst_QFileSystemWatcher::basicTest_data() + QChar(ushort(0x00DC)) // LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS + QStringLiteral(".txt"); -#if !defined(Q_OS_QNX) || !defined(QT_NO_INOTIFY) +#if !defined(QT_NO_INOTIFY) QTest::newRow("native backend-testfile") << "native" << testFile; QTest::newRow("native backend-specialchars") << "native" << specialCharacterFile; #endif @@ -152,26 +143,27 @@ void tst_QFileSystemWatcher::basicTest() watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); QVERIFY(watcher.addPath(testFile.fileName())); + const bool isPollerBackend = backend == u"poller"; + QSignalSpy changedSpy(&watcher, &QFileSystemWatcher::fileChanged); QVERIFY(changedSpy.isValid()); QEventLoop eventLoop; QTimer timer; + timer.setInterval(isPollerBackend ? pollingEngineTimeout : nativeEngineTimeout); connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); // modify the file, should get a signal from the watcher - // resolution of the modification time is system dependent, but it's at most 1 second when using - // the polling engine. I've heard rumors that FAT32 has a 2 second resolution. So, we have to - // wait a bit before we can modify the file (hrmph)... - QTest::qWait(2000); + if (isPollerBackend || isQNX) + QTest::qWait(pollingEngineTimeout); - testFile.open(QIODevice::WriteOnly | QIODevice::Append); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Append)); testFile.write(QByteArray("world")); testFile.close(); // waiting max 5 seconds for notification for file modification to trigger - QTRY_COMPARE(changedSpy.count(), 1); - QCOMPARE(changedSpy.at(0).count(), 1); + QTRY_COMPARE(changedSpy.size(), 1); + QCOMPARE(changedSpy.at(0).size(), 1); QString fileName = changedSpy.at(0).at(0).toString(); QCOMPARE(fileName, testFile.fileName()); @@ -180,25 +172,25 @@ void tst_QFileSystemWatcher::basicTest() // remove the watch and modify the file, should not get a signal from the watcher QVERIFY(watcher.removePath(testFile.fileName())); - testFile.open(QIODevice::WriteOnly | QIODevice::Truncate); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); testFile.write(QByteArray("hello universe!")); testFile.close(); - // waiting max 5 seconds for notification for file modification to trigger - timer.start(5000); + // waiting for notification for file modification to trigger + timer.start(); eventLoop.exec(); - QCOMPARE(changedSpy.count(), 0); + QCOMPARE(changedSpy.size(), 0); // readd the file watch with a relative path const QString relativeTestFileName = QDir::current().relativeFilePath(testFile.fileName()); QVERIFY(!relativeTestFileName.isEmpty()); QVERIFY(watcher.addPath(relativeTestFileName)); - testFile.open(QIODevice::WriteOnly | QIODevice::Truncate); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); testFile.write(QByteArray("hello multiverse!")); testFile.close(); - QTRY_VERIFY(changedSpy.count() > 0); + QTRY_VERIFY(changedSpy.size() > 0); QVERIFY(watcher.removePath(relativeTestFileName)); @@ -214,8 +206,8 @@ void tst_QFileSystemWatcher::basicTest() #if !defined(Q_OS_QNX) // waiting max 5 seconds for notification for file permission modification to trigger - QTRY_COMPARE(changedSpy.count(), 1); - QCOMPARE(changedSpy.at(0).count(), 1); + QTRY_COMPARE(changedSpy.size(), 1); + QCOMPARE(changedSpy.at(0).size(), 1); fileName = changedSpy.at(0).at(0).toString(); QCOMPARE(fileName, testFile.fileName()); @@ -228,11 +220,11 @@ void tst_QFileSystemWatcher::basicTest() QVERIFY(watcher.removePath(testFile.fileName())); testFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOther); - // waiting max 5 seconds for notification for file modification to trigger - timer.start(5000); + // waiting for notification for file modification to trigger + timer.start(); eventLoop.exec(); - QCOMPARE(changedSpy.count(), 0); + QCOMPARE(changedSpy.size(), 0); // readd the file watch QVERIFY(watcher.addPath(testFile.fileName())); @@ -243,8 +235,8 @@ void tst_QFileSystemWatcher::basicTest() // waiting max 5 seconds for notification for file removal to trigger // > 0 && < 3 because some platforms may emit two changes // XXX: which platforms? (QTBUG-23370) - QTRY_VERIFY(changedSpy.count() > 0 && changedSpy.count() < 3); - QCOMPARE(changedSpy.at(0).count(), 1); + QTRY_VERIFY(changedSpy.size() > 0 && changedSpy.size() < 3); + QCOMPARE(changedSpy.at(0).size(), 1); fileName = changedSpy.at(0).at(0).toString(); QCOMPARE(fileName, testFile.fileName()); @@ -256,11 +248,11 @@ void tst_QFileSystemWatcher::basicTest() testFile.write(QByteArray("hello")); testFile.close(); - // waiting max 5 seconds for notification for file recreation to trigger - timer.start(5000); + // waiting for notification for file recreation to trigger + timer.start(); eventLoop.exec(); - QCOMPARE(changedSpy.count(), 0); + QCOMPARE(changedSpy.size(), 0); QVERIFY(testFile.remove()); } @@ -271,7 +263,9 @@ void tst_QFileSystemWatcher::watchDirectory_data() QTest::addColumn<QStringList>("testDirNames"); const QStringList testDirNames = {QStringLiteral("testdir"), QStringLiteral("testdir2")}; +#if !defined(QT_NO_INOTIFY) QTest::newRow("native backend") << "native" << testDirNames; +#endif QTest::newRow("poller backend") << "poller" << testDirNames; } @@ -302,16 +296,18 @@ void tst_QFileSystemWatcher::watchDirectory() watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); QVERIFY(watcher.addPaths(testDirs).isEmpty()); + const bool isPollerBackend = backend == u"poller"; + QSignalSpy changedSpy(&watcher, &QFileSystemWatcher::directoryChanged); QVERIFY(changedSpy.isValid()); QEventLoop eventLoop; QTimer timer; + timer.setInterval(isPollerBackend ? pollingEngineTimeout : nativeEngineTimeout); connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); - // resolution of the modification time is system dependent, but it's at most 1 second when using - // the polling engine. From what I know, FAT32 has a 2 second resolution. So we have to - // wait before modifying the directory... - QTest::qWait(2000); + if (isPollerBackend || isQNX) + QTest::qWait(pollingEngineTimeout); + // remove the watch, should not get notification of a new file QVERIFY(watcher.removePaths(testDirs).isEmpty()); for (const auto &testFileName : testFiles) { @@ -320,11 +316,11 @@ void tst_QFileSystemWatcher::watchDirectory() testFile.close(); } - // waiting max 5 seconds for notification for file recreationg to trigger - timer.start(5000); + // waiting for notification for file recreation to trigger + timer.start(); eventLoop.exec(); - QCOMPARE(changedSpy.count(), 0); + QCOMPARE(changedSpy.size(), 0); QVERIFY(watcher.addPaths(testDirs).isEmpty()); @@ -332,7 +328,7 @@ void tst_QFileSystemWatcher::watchDirectory() for (const auto &testFileName : testFiles) QVERIFY(QFile::remove(testFileName)); - timer.start(5000); + timer.start(); eventLoop.exec(); // remove the directory, should get a signal from the watcher @@ -344,10 +340,10 @@ void tst_QFileSystemWatcher::watchDirectory() signalCounter[testDirName] = 0; // waiting max 5 seconds for notification for directory removal to trigger - QTRY_COMPARE(changedSpy.count(), testDirs.size() * 2); - for (int i = 0; i < changedSpy.count(); i++) { + QTRY_COMPARE(changedSpy.size(), testDirs.size() * 2); + for (int i = 0; i < changedSpy.size(); i++) { const auto &signal = changedSpy.at(i); - QCOMPARE(signal.count(), 1); + QCOMPARE(signal.size(), 1); auto it = signalCounter.find(signal.at(0).toString()); QVERIFY(it != signalCounter.end()); @@ -359,7 +355,7 @@ void tst_QFileSystemWatcher::watchDirectory() QCOMPARE(count, 2); // flush pending signals (like the one from the rmdir above) - timer.start(5000); + timer.start(); eventLoop.exec(); changedSpy.clear(); @@ -371,11 +367,11 @@ void tst_QFileSystemWatcher::watchDirectory() } } - // waiting max 5 seconds for notification for dir recreation to trigger - timer.start(5000); + // waiting for notification for dir recreation to trigger + timer.start(); eventLoop.exec(); - QCOMPARE(changedSpy.count(), 0); + QCOMPARE(changedSpy.size(), 0); for (const auto &testDirName : testDirs) QVERIFY(temporaryDir.rmdir(testDirName)); @@ -387,12 +383,12 @@ void tst_QFileSystemWatcher::addPath() QFileSystemWatcher watcher; QString home = QDir::homePath(); QVERIFY(watcher.addPath(home)); - QCOMPARE(watcher.directories().count(), 1); + QCOMPARE(watcher.directories().size(), 1); QCOMPARE(watcher.directories().first(), home); // second watch on an already-watched path should fail QVERIFY(!watcher.addPath(home)); - QCOMPARE(watcher.directories().count(), 1); + QCOMPARE(watcher.directories().size(), 1); // With empty string QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::addPath: path is empty"); @@ -405,9 +401,9 @@ void tst_QFileSystemWatcher::removePath() QString home = QDir::homePath(); QVERIFY(watcher.addPath(home)); QVERIFY(watcher.removePath(home)); - QCOMPARE(watcher.directories().count(), 0); + QCOMPARE(watcher.directories().size(), 0); QVERIFY(!watcher.removePath(home)); - QCOMPARE(watcher.directories().count(), 0); + QCOMPARE(watcher.directories().size(), 0); // With empty string QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::removePath: path is empty"); @@ -418,9 +414,15 @@ void tst_QFileSystemWatcher::addPaths() { QFileSystemWatcher watcher; QStringList paths; - paths << QDir::homePath() << QDir::currentPath(); + paths << QDir::homePath() << QDir::tempPath(); +#ifndef Q_OS_QNX + // Adding this makes QNX fail and we haven't investigated why + for (const QFileInfo &fi : QDir::drives()) + paths << fi.absoluteFilePath(); // on Unix, this will be just "/" +#endif + QCOMPARE(watcher.addPaths(paths), QStringList()); - QCOMPARE(watcher.directories().count(), 2); + QCOMPARE(watcher.directories().size(), paths.size()); // With empty list paths.clear(); @@ -486,11 +488,17 @@ void tst_QFileSystemWatcher::removePaths() { QFileSystemWatcher watcher; QStringList paths; - paths << QDir::homePath() << QDir::currentPath(); + paths << QDir::homePath() << QDir::tempPath(); +#ifndef Q_OS_QNX + // Adding this makes QNX fail and we haven't investigated why + for (const QFileInfo &fi : QDir::drives()) + paths << fi.absoluteFilePath(); // on Unix, this will be just "/" +#endif + QCOMPARE(watcher.addPaths(paths), QStringList()); - QCOMPARE(watcher.directories().count(), 2); + QCOMPARE(watcher.directories().size(), paths.size()); QCOMPARE(watcher.removePaths(paths), QStringList()); - QCOMPARE(watcher.directories().count(), 0); + QCOMPARE(watcher.directories().size(), 0); //With empty list paths.clear(); @@ -558,28 +566,29 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QVERIFY(watcher.addPath(testDir.absolutePath())); QVERIFY(watcher.addPath(testFileName)); + const bool isPollerBackend = backend == u"poller"; + QSignalSpy fileChangedSpy(&watcher, &QFileSystemWatcher::fileChanged); FileSystemWatcherSpy dirChangedSpy(&watcher, FileSystemWatcherSpy::SpyOnDirectoryChanged); QVERIFY(fileChangedSpy.isValid()); QEventLoop eventLoop; QTimer timer; + timer.setInterval(isPollerBackend ? pollingEngineTimeout : nativeEngineTimeout); connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); - // resolution of the modification time is system dependent, but it's at most 1 second when using - // the polling engine. From what I know, FAT32 has a 2 second resolution. So we have to - // wait before modifying the directory... - QTest::qWait(2000); + if (isPollerBackend || isQNX) + QTest::qWait(pollingEngineTimeout); QVERIFY2(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate), msgFileOperationFailed("open", testFile)); QVERIFY2(testFile.write(QByteArrayLiteral("hello again")), msgFileOperationFailed("write", testFile)); testFile.close(); -#ifdef Q_OS_MAC +#ifdef Q_OS_DARWIN // wait again for the file's atime to be updated QTest::qWait(2000); #endif - QTRY_VERIFY(fileChangedSpy.count() > 0); + QTRY_VERIFY(fileChangedSpy.size() > 0); QVERIFY2(dirChangedSpy.count() == 0, dirChangedSpy.receivedFilesMessage()); fileChangedSpy.clear(); @@ -588,9 +597,9 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QVERIFY2(secondFile.write(QByteArrayLiteral("Foo")) > 0, msgFileOperationFailed("write", secondFile)); secondFile.close(); - timer.start(3000); + timer.start(); eventLoop.exec(); - int fileChangedSpyCount = fileChangedSpy.count(); + int fileChangedSpyCount = fileChangedSpy.size(); #ifdef Q_OS_WIN if (fileChangedSpyCount != 0) QEXPECT_FAIL("", "See QTBUG-30943", Continue); @@ -602,7 +611,7 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QVERIFY(QFile::remove(testFileName)); - QTRY_VERIFY(fileChangedSpy.count() > 0); + QTRY_VERIFY(fileChangedSpy.size() > 0); QTRY_COMPARE(dirChangedSpy.count(), 1); fileChangedSpy.clear(); @@ -612,9 +621,9 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QVERIFY(!watcher.removePath(testFileName)); QVERIFY(QFile::remove(secondFileName)); - timer.start(3000); + timer.start(); eventLoop.exec(); - QCOMPARE(fileChangedSpy.count(), 0); + QCOMPARE(fileChangedSpy.size(), 0); QCOMPARE(dirChangedSpy.count(), 1); // QTBUG-61792, removal should succeed (bug on Windows which uses one change @@ -636,9 +645,11 @@ void tst_QFileSystemWatcher::nonExistingFile() QStringList() << "../..//./does-not-exist"); // empty path is not actually a failure + QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::addPaths: list is empty"); QCOMPARE(watcher.addPaths(QStringList() << QString()), QStringList()); // empty path is not actually a failure + QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::removePaths: list is empty"); QCOMPARE(watcher.removePaths(QStringList() << QString()), QStringList()); } @@ -717,7 +728,7 @@ void tst_QFileSystemWatcher::QTBUG2331() // remove directory, we should get one change signal, and we should no longer // be watching the directory. QVERIFY(temporaryDirectory.remove()); - QTRY_COMPARE(changedSpy.count(), 1); + QTRY_COMPARE(changedSpy.size(), 1); QCOMPARE(watcher.directories(), QStringList()); } #endif // QT_BUILD_INTERNAL @@ -745,7 +756,8 @@ public slots: QCOMPARE(finfo.absolutePath(), moveSrcDir.absolutePath()); if (!added) { - foreach (const QFileInfo &fi, moveDestination.entryInfoList(QDir::Files | QDir::NoSymLinks)) + const auto entries = moveDestination.entryInfoList(QDir::Files | QDir::NoSymLinks); + for (const QFileInfo &fi : entries) watcher->addPath(fi.absoluteFilePath()); added = true; } @@ -785,9 +797,9 @@ void tst_QFileSystemWatcher::signalsEmittedAfterFileMoved() QVERIFY(watcher.addPath(movePath)); // add files to watcher - QFileInfoList files = testDir.entryInfoList(QDir::Files | QDir::NoSymLinks); + const QFileInfoList files = testDir.entryInfoList(QDir::Files | QDir::NoSymLinks); QCOMPARE(files.size(), fileCount); - foreach (const QFileInfo &finfo, files) + for (const QFileInfo &finfo : files) QVERIFY(watcher.addPath(finfo.absoluteFilePath())); // create the signal receiver @@ -799,7 +811,7 @@ void tst_QFileSystemWatcher::signalsEmittedAfterFileMoved() QCOMPARE(changedSpy.count(), 0); // move files to second directory - foreach (const QFileInfo &finfo, files) + for (const QFileInfo &finfo : files) QVERIFY(testDir.rename(finfo.fileName(), QString("movehere/%2").arg(finfo.fileName()))); QCoreApplication::processEvents(); |