diff --git a/autotests/kdirlistertest.h b/autotests/kdirlistertest.h --- a/autotests/kdirlistertest.h +++ b/autotests/kdirlistertest.h @@ -88,12 +88,14 @@ void cleanup(); void testOpenUrl(); void testOpenUrlFromCache(); + void testNewItem(); void testNewItems(); void testNewItemByCopy(); void testNewItemsInSymlink(); void testRefreshItems(); void testRefreshRootItem(); void testDeleteItem(); + void testDeleteItems(); void testRenameItem(); void testRenameAndOverwrite(); void testConcurrentListing(); @@ -132,7 +134,6 @@ { return m_tempDir.path() + '/'; } - bool waitForRefreshedItems(); void createSimpleFile(const QString &fileName); void fillDirLister2(MyDirLister &lister, const QString &path); void waitUntilMTimeChange(const QString &path); diff --git a/autotests/kdirlistertest.cpp b/autotests/kdirlistertest.cpp --- a/autotests/kdirlistertest.cpp +++ b/autotests/kdirlistertest.cpp @@ -25,6 +25,7 @@ QTEST_MAIN(KDirListerTest) #include +#include #include "kiotesthelper.h" #include #include @@ -179,27 +180,19 @@ } // This test assumes testOpenUrl was run before. So m_dirLister is holding the items already. -void KDirListerTest::testNewItems() +// This test creates 1 file in the temporary directory +void KDirListerTest::testNewItem() { QCOMPARE(m_items.count(), 4); const QString path = m_tempDir.path() + '/'; - connect(&m_dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewItems(KFileItemList))); - - QTest::qWait(1000); // We need a 1s timestamp difference on the dir, otherwise FAM won't notice anything. + connect(&m_dirLister, &KCoreDirLister::newItems, this, &KDirListerTest::slotNewItems); - qDebug() << "Creating new file"; + qDebug() << "Creating a new file"; const QString fileName = QStringLiteral("toplevelfile_new"); - createSimpleFile(path + fileName); - int numTries = 0; - // Give time for KDirWatch to notify us - while (m_items.count() == 4) { - QVERIFY(++numTries < 20); - QTest::qWait(100); - } - //qDebug() << "numTries=" << numTries; - QCOMPARE(m_items.count(), 5); + createSimpleFile(path + fileName); + QTRY_COMPARE(m_items.count(), 5); QCOMPARE(m_dirLister.spyStarted.count(), 1); // Updates call started QCOMPARE(m_dirLister.spyCompleted.count(), 1); // and completed QCOMPARE(m_dirLister.spyCompletedQUrl.count(), 1); @@ -208,6 +201,46 @@ QCOMPARE(m_dirLister.spyClear.count(), 0); QCOMPARE(m_dirLister.spyClearQUrl.count(), 0); + const QUrl itemUrl = QUrl::fromLocalFile(path + fileName); + KFileItem itemForUrl = KDirLister::cachedItemForUrl(itemUrl); + QVERIFY(!itemForUrl.isNull()); + QCOMPARE(itemForUrl.url().toString(), itemUrl.toString()); + QCOMPARE(itemForUrl.entry().stringValue(KIO::UDSEntry::UDS_NAME), fileName); + disconnect(&m_dirLister, nullptr, this, nullptr); +} + + +// This test assumes testNewItem was run before. So m_dirLister is holding the items already. +// This test creates 100 more files in the temporary directory in reverse order +void KDirListerTest::testNewItems() +{ + QCOMPARE(m_items.count(), 5); + connect(&m_dirLister, &KCoreDirLister::newItems, this, &KDirListerTest::slotNewItems); + + const QString path = m_tempDir.path() + '/'; + + qDebug() << "Creating new 100 files"; + for (int i = 50; i > 0; i--) { + createSimpleFile(path + QString("toplevelfile_new_%1").arg(i)); + } + QTest::qWait(1000); // Create them with 1s difference + for (int i = 100; i > 50; i--) { + createSimpleFile(path + QString("toplevelfile_new_%1").arg(i)); + } + + // choose one of the new created files + const QString fileName = QStringLiteral("toplevelfile_new_50"); + + QTRY_COMPARE(m_items.count(), 105); + + QVERIFY(m_dirLister.spyStarted.count() < 3); // Updates call started, probably twice + QVERIFY(m_dirLister.spyCompleted.count() < 3); // and completed, probably twice + QVERIFY(m_dirLister.spyCompletedQUrl.count() < 3); + QCOMPARE(m_dirLister.spyCanceled.count(), 0); + QCOMPARE(m_dirLister.spyCanceledQUrl.count(), 0); + QCOMPARE(m_dirLister.spyClear.count(), 0); + QCOMPARE(m_dirLister.spyClearQUrl.count(), 0); + const QUrl itemUrl = QUrl::fromLocalFile(path + fileName); KFileItem itemForUrl = KDirLister::cachedItemForUrl(itemUrl); QVERIFY(!itemForUrl.isNull()); @@ -231,14 +264,8 @@ KIO::CopyJob *job = KIO::copyAs(QUrl::fromLocalFile(path + "toplevelfile_3"), itemUrl, KIO::HideProgressInfo); job->exec(); - int numTries = 0; // Give time for KDirWatch/KDirNotify to notify us - while (m_items.count() == origItemCount) { - QVERIFY(++numTries < 10); - QTest::qWait(200); - } - //qDebug() << "numTries=" << numTries; - QCOMPARE(m_items.count(), origItemCount + 1); + QTRY_COMPARE(m_items.count(), origItemCount + 1); QCOMPARE(m_dirLister.spyStarted.count(), 1); // Updates call started QCOMPARE(m_dirLister.spyCompleted.count(), 1); // and completed @@ -282,9 +309,8 @@ connect(&dirLister2, SIGNAL(completed()), this, SLOT(exitLoop())); enterLoop(); QCOMPARE(m_items2.count(), origItemCount); - QVERIFY(dirLister2.isFinished()); - QTest::qWait(1000); // We need a 1s timestamp difference on the dir, otherwise FAM won't notice anything. + QTRY_VERIFY(dirLister2.isFinished()); qDebug() << "Creating new file"; const QString fileName = QStringLiteral("toplevelfile_newinlink"); @@ -302,14 +328,9 @@ { createSimpleFile(path + fileName2); - int numTries = 0; // Give time for KDirWatch to notify us - while (m_items2.count() == origItemCount + 1) { - QVERIFY(++numTries < 10); - QTest::qWait(200); - } - QCOMPARE(m_items2.count(), origItemCount + 2); - QCOMPARE(m_items.count(), origItemCount + 2); + QTRY_COMPARE(m_items2.count(), origItemCount + 2); + QTRY_COMPARE(m_items.count(), origItemCount + 2); } QCOMPARE(fileCount(), m_items.count()); @@ -318,12 +339,7 @@ qDebug() << "Deleting" << (path + fileName); QTest::qWait(1000); // for timestamp difference QFile::remove(path + fileName); - int numTries = 0; - while (dirLister2.spyItemsDeleted.count() == 0) { - QVERIFY(++numTries < 10); - QTest::qWait(200); - } - QCOMPARE(dirLister2.spyItemsDeleted.count(), 1); + QTRY_COMPARE(dirLister2.spyItemsDeleted.count(), 1); const KFileItem item = dirLister2.spyItemsDeleted[0][0].value().at(0); QCOMPARE(item.url().toLocalFile(), QString(symPath + '/' + fileName)); } @@ -335,6 +351,7 @@ } // This test assumes testOpenUrl was run before. So m_dirLister is holding the items already. +// Modifies one of the files to have html content void KDirListerTest::testRefreshItems() { m_refreshedItems.clear(); @@ -345,8 +362,8 @@ QVERIFY(!cachedItem.isNull()); QCOMPARE(cachedItem.mimetype(), QString("application/octet-stream")); - connect(&m_dirLister, SIGNAL(refreshItems(QList >)), - this, SLOT(slotRefreshItems(QList >))); + connect(&m_dirLister, &KCoreDirLister::refreshItems, + this, &KDirListerTest::slotRefreshItems); QFile file(fileName); QVERIFY(file.open(QIODevice::Append)); @@ -354,11 +371,11 @@ file.close(); QCOMPARE(QFileInfo(fileName).size(), 11LL /*Hello world*/ + 6 /**/); - QVERIFY(waitForRefreshedItems()); + QTRY_COMPARE(m_refreshedItems.isEmpty(), false); - QCOMPARE(m_dirLister.spyStarted.count(), 0); // fast path: no directory listing needed - QCOMPARE(m_dirLister.spyCompleted.count(), 0); - QCOMPARE(m_dirLister.spyCompletedQUrl.count(), 0); + QTRY_COMPARE(m_dirLister.spyStarted.count(), 0); // fast path: no directory listing needed + QTRY_VERIFY(m_dirLister.spyCompleted.count() < 2); + QTRY_VERIFY(m_dirLister.spyCompletedQUrl.count() < 2); QCOMPARE(m_dirLister.spyCanceled.count(), 0); QCOMPARE(m_dirLister.spyCanceledQUrl.count(), 0); QCOMPARE(m_dirLister.spyClear.count(), 0); @@ -403,7 +420,7 @@ // Arguably, the mtime change of "subdir" should lead to a refreshItem of subdir in the root dir. // So the next line shouldn't be necessary, if KDirLister did this correctly. This isn't what this test is about though. org::kde::KDirNotify::emitFilesChanged(QList() << QUrl::fromLocalFile(path)); - QVERIFY(waitForRefreshedItems()); + QTRY_COMPARE(m_refreshedItems.isEmpty(), false); QCOMPARE(m_dirLister.spyStarted.count(), 0); QCOMPARE(m_dirLister.spyCompleted.count(), 0); @@ -437,7 +454,8 @@ // The order of these two is not deterministic org::kde::KDirNotify::emitFilesChanged(QList() << QUrl::fromLocalFile(directoryFile)); org::kde::KDirNotify::emitFilesChanged(QList() << QUrl::fromLocalFile(path)); - QVERIFY(waitForRefreshedItems()); + QTRY_COMPARE(m_refreshedItems.isEmpty(), false); + QCOMPARE(m_refreshedItems.count(), 1); entry = m_refreshedItems.first(); QCOMPARE(entry.first.url().toLocalFile(), path); @@ -457,10 +475,11 @@ const int origItemCount = m_items.count(); QCOMPARE(fileCount(), origItemCount); const QString path = m_tempDir.path() + '/'; + connect(&m_dirLister, SIGNAL(itemsDeleted(KFileItemList)), this, SLOT(exitLoop())); - //qDebug() << "Removing " << path+"toplevelfile_1"; - QFile::remove(path + "toplevelfile_1"); + //qDebug() << "Removing " << path+"toplevelfile_new"; + QFile::remove(path + QString("toplevelfile_new")); // the remove() doesn't always trigger kdirwatch in stat mode, if this all happens in the same second KDirWatch::self()->setDirty(path); if (m_dirLister.spyItemsDeleted.count() == 0) { @@ -468,7 +487,8 @@ enterLoop(); } - QCOMPARE(m_dirLister.spyItemsDeleted.count(), 1); + // The signal could be emited 1 time with all the deleted files or more times + QVERIFY(m_dirLister.spyItemsDeleted.count() > 0); // OK now kdirlister told us the file was deleted, let's try a re-listing m_items.clear(); @@ -484,8 +504,52 @@ QCOMPARE(fileCount(), m_items.count()); } + +void KDirListerTest::testDeleteItems() +{ + testOpenUrl(); // ensure m_items is uptodate + + const int origItemCount = m_items.count(); + QCOMPARE(fileCount(), origItemCount); + const QString path = m_tempDir.path() + '/'; + + connect(&m_dirLister, SIGNAL(itemsDeleted(KFileItemList)), this, SLOT(exitLoop())); + + qDebug() << "Removing 100 files from " << path; + for (int i=0; i <= 100; ++i) { + QFile::remove(path + QString("toplevelfile_new_%1").arg(i)); + } + // the remove() doesn't always trigger kdirwatch in stat mode, if this all happens in the same second + KDirWatch::self()->setDirty(path); + if (m_dirLister.spyItemsDeleted.count() == 0) { + qDebug("waiting for itemsDeleted"); + enterLoop(); + } + + // The signal could be emited 1 time with all the deleted files or more times + QVERIFY(m_dirLister.spyItemsDeleted.count() > 0); + + // OK now kdirlister told us the file was deleted, let's try a re-listing + m_items.clear(); + connect(&m_dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewItems(KFileItemList))); + m_dirLister.openUrl(QUrl::fromLocalFile(path), KDirLister::NoFlags); + QVERIFY(!m_dirLister.isFinished()); + connect(&m_dirLister, SIGNAL(completed()), this, SLOT(exitLoop())); + enterLoop(); + QVERIFY(m_dirLister.isFinished()); + QCOMPARE(m_items.count(), origItemCount - 100); + + disconnect(&m_dirLister, nullptr, this, nullptr); + QCOMPARE(fileCount(), m_items.count()); +} + + void KDirListerTest::testRenameItem() { + QMimeDatabase db; + const QMimeType htmlType = db.mimeTypeForUrl(QUrl(QLatin1String("file:///index.html"))); + qDebug() << "html mimeType=" << htmlType; + m_refreshedItems2.clear(); const QString dirPath = m_tempDir.path() + '/'; connect(&m_dirLister, SIGNAL(refreshItems(QList >)), @@ -497,14 +561,13 @@ QVERIFY(job->exec()); QSignalSpy spyRefreshItems(&m_dirLister, SIGNAL(refreshItems(QList >))); - QVERIFY(spyRefreshItems.wait(2000)); - QCOMPARE(m_refreshedItems2.count(), 1); + QTRY_COMPARE(m_refreshedItems2.count(), 1); QPair entry = m_refreshedItems2.first(); QCOMPARE(entry.first.url().toLocalFile(), path); QCOMPARE(entry.first.mimetype(), QString("application/octet-stream")); QCOMPARE(entry.second.url().toLocalFile(), newPath); - QCOMPARE(entry.second.mimetype(), QString("text/html")); + QCOMPARE(entry.second.mimetype(), htmlType.name()); disconnect(&m_dirLister, nullptr, this, nullptr); // Let's see what KDirLister has in cache now @@ -542,7 +605,7 @@ QVERIFY(ok); if (m_refreshedItems.isEmpty()) { - QVERIFY(waitForRefreshedItems()); // refreshItems could come from KDirWatch or KDirNotify. + QTRY_COMPARE(m_refreshedItems.isEmpty(), false); // could come from KDirWatch or KDirNotify. } // Check that itemsDeleted was emitted -- preferably BEFORE refreshItems, @@ -1321,19 +1384,6 @@ return QDir(path()).entryList(QDir::AllEntries | QDir::NoDotAndDotDot).count(); } -bool KDirListerTest::waitForRefreshedItems() -{ - int numTries = 0; - // Give time for KDirWatch to notify us - while (m_refreshedItems.isEmpty()) { - if (++numTries == 20) { - return false; - } - QTest::qWait(100); - } - return true; -} - void KDirListerTest::createSimpleFile(const QString &fileName) { QFile file(fileName);