]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/tests/kfileitemmodeltest.cpp
Merge remote-tracking branch 'origin/KDE/4.10'
[dolphin.git] / src / tests / kfileitemmodeltest.cpp
index e636bcd9170c5559a9bb2b9d7e27449f4ab77e1d..383575a97a8bb7bb91756770f0391ea6a61335ff 100644 (file)
@@ -21,6 +21,8 @@
 #include <qtest_kde.h>
 
 #include <KDirLister>
+#include <kio/job.h>
+
 #include "kitemviews/kfileitemmodel.h"
 #include "kitemviews/private/kfileitemmodeldirlister.h"
 #include "testdir.h"
@@ -71,6 +73,7 @@ private slots:
     void testItemRangeConsistencyWhenInsertingItems();
     void testExpandItems();
     void testExpandParentItems();
+    void testMakeExpandedItemHidden();
     void testSorting();
     void testIndexForKeyboardSearch();
     void testNameFilter();
@@ -79,9 +82,9 @@ private slots:
     void testRemoveHiddenItems();
     void collapseParentOfHiddenItems();
     void removeParentOfHiddenItems();
+    void testGeneralParentChildRelationships();
 
 private:
-    bool isModelConsistent() const;
     QStringList itemsInModel() const;
 
 private:
@@ -156,7 +159,7 @@ void KFileItemModelTest::testNewItems()
 
     QCOMPARE(m_model->count(), 3);
 
-    QVERIFY(isModelConsistent());
+    QVERIFY(m_model->isConsistent());
 }
 
 void KFileItemModelTest::testRemoveItems()
@@ -166,13 +169,13 @@ void KFileItemModelTest::testRemoveItems()
     m_model->loadDirectory(m_testDir->url());
     QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
     QCOMPARE(m_model->count(), 2);
-    QVERIFY(isModelConsistent());
+    QVERIFY(m_model->isConsistent());
 
     m_testDir->removeFile("a.txt");
     m_model->m_dirLister->updateDirectory(m_testDir->url());
     QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsRemoved(KItemRangeList)), DefaultTimeout));
     QCOMPARE(m_model->count(), 1);
-    QVERIFY(isModelConsistent());
+    QVERIFY(m_model->isConsistent());
 }
 
 void KFileItemModelTest::testDirLoadingCompleted()
@@ -215,7 +218,7 @@ void KFileItemModelTest::testDirLoadingCompleted()
     QCOMPARE(itemsRemovedSpy.count(), 2);
     QCOMPARE(m_model->count(), 4);
 
-    QVERIFY(isModelConsistent());
+    QVERIFY(m_model->isConsistent());
 }
 
 void KFileItemModelTest::testSetData()
@@ -236,7 +239,7 @@ void KFileItemModelTest::testSetData()
     values = m_model->data(0);
     QCOMPARE(values.value("customRole1").toString(), QString("Test1"));
     QCOMPARE(values.value("customRole2").toString(), QString("Test2"));
-    QVERIFY(isModelConsistent());
+    QVERIFY(m_model->isConsistent());
 }
 
 void KFileItemModelTest::testSetDataWithModifiedSortRole_data()
@@ -317,7 +320,7 @@ void KFileItemModelTest::testSetDataWithModifiedSortRole()
     QCOMPARE(m_model->data(0).value("rating").toInt(), ratingIndex0);
     QCOMPARE(m_model->data(1).value("rating").toInt(), ratingIndex1);
     QCOMPARE(m_model->data(2).value("rating").toInt(), ratingIndex2);
-    QVERIFY(isModelConsistent());
+    QVERIFY(m_model->isConsistent());
 }
 
 void KFileItemModelTest::testModelConsistencyWhenInsertingItems()
@@ -356,7 +359,7 @@ void KFileItemModelTest::testModelConsistencyWhenInsertingItems()
             QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
         }
 
-        QVERIFY(isModelConsistent());
+        QVERIFY(m_model->isConsistent());
     }
 
     QCOMPARE(m_model->count(), 201);
@@ -490,6 +493,7 @@ void KFileItemModelTest::testExpandItems()
     QCOMPARE(spyRemoved.count(), 1);
     itemRangeList = spyRemoved.takeFirst().at(0).value<KItemRangeList>();
     QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 4)); // 4 items removed
+    QVERIFY(m_model->isConsistent());
 
     // Clear the model, reload the folder and try to restore the expanded folders.
     m_model->clear();
@@ -506,6 +510,7 @@ void KFileItemModelTest::testExpandItems()
     QVERIFY(m_model->isExpanded(3));
     QVERIFY(!m_model->isExpanded(4));
     QCOMPARE(m_model->expandedDirectories(), allFolders);
+    QVERIFY(m_model->isConsistent());
 
     // Move to a sub folder, then call restoreExpandedFolders() *before* going back.
     // This is how DolphinView restores the expanded folders when navigating in history.
@@ -568,6 +573,56 @@ void KFileItemModelTest::testExpandParentItems()
     QVERIFY(m_model->isExpanded(2));
     QVERIFY(m_model->isExpanded(3));
     QVERIFY(!m_model->isExpanded(4));
+    QVERIFY(m_model->isConsistent());
+}
+
+/**
+ * Renaming an expanded folder by prepending its name with a dot makes it
+ * hidden. Verify that this does not cause an inconsistent model state and
+ * a crash later on, see https://bugs.kde.org/show_bug.cgi?id=311947
+ */
+void KFileItemModelTest::testMakeExpandedItemHidden()
+{
+    QSet<QByteArray> modelRoles = m_model->roles();
+    modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
+    m_model->setRoles(modelRoles);
+
+    QStringList files;
+    m_testDir->createFile("1a/2a/3a");
+    m_testDir->createFile("1a/2a/3b");
+    m_testDir->createFile("1a/2b");
+    m_testDir->createFile("1b");
+
+    m_model->loadDirectory(m_testDir->url());
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+    // So far, the model contains only "1a/" and "1b".
+    QCOMPARE(m_model->count(), 2);
+    m_model->setExpanded(0, true);
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+    // Now "1a/2a" and "1a/2b" have appeared.
+    QCOMPARE(m_model->count(), 4);
+    m_model->setExpanded(1, true);
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+    QCOMPARE(m_model->count(), 6);
+
+    // Rename "1a/2" and make it hidden.
+    const QString oldPath = m_model->fileItem(0).url().path() + "/2a";
+    const QString newPath = m_model->fileItem(0).url().path() + "/.2a";
+
+    KIO::SimpleJob* job = KIO::rename(oldPath, newPath, KIO::HideProgressInfo);
+    bool ok = job->exec();
+    QVERIFY(ok);
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsRemoved(KItemRangeList)), DefaultTimeout));
+
+    // "1a/2" and its subfolders have disappeared now.
+    QVERIFY(m_model->isConsistent());
+    QCOMPARE(m_model->count(), 3);
+
+    m_model->setExpanded(0, false);
+    QCOMPARE(m_model->count(), 2);
+
 }
 
 void KFileItemModelTest::testSorting()
@@ -798,7 +853,7 @@ void KFileItemModelTest::testEmptyPath()
     
     KFileItemList items;
     items << KFileItem(emptyUrl, QString(), KFileItem::Unknown) << KFileItem(url, QString(), KFileItem::Unknown);
-    m_model->slotNewItems(items);
+    m_model->slotItemsAdded(emptyUrl, items);
     m_model->slotCompleted();
 }
 
@@ -984,27 +1039,96 @@ void KFileItemModelTest::removeParentOfHiddenItems()
     QCOMPARE(itemsInModel(), QStringList() << "a" << "1");
 }
 
-bool KFileItemModelTest::isModelConsistent() const
+/**
+ * Create a tree structure where parent-child relationships can not be
+ * determined by parsing the URLs, and verify that KFileItemModel
+ * handles them correctly.
+ */
+void KFileItemModelTest::testGeneralParentChildRelationships()
 {
-    if (m_model->m_items.count() != m_model->m_itemData.count()) {
-        return false;
-    }
+    QSet<QByteArray> modelRoles = m_model->roles();
+    modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
+    m_model->setRoles(modelRoles);
 
-    for (int i = 0; i < m_model->count(); ++i) {
-        const KFileItem item = m_model->fileItem(i);
-        if (item.isNull()) {
-            qWarning() << "Item" << i << "is null";
-            return false;
-        }
+    QStringList files;
+    files << "parent1/realChild1/realGrandChild1" << "parent2/realChild2/realGrandChild2";
+    m_testDir->createFiles(files);
 
-        const int itemIndex = m_model->index(item);
-        if (itemIndex != i) {
-            qWarning() << "Item" << i << "has a wrong index:" << itemIndex;
-            return false;
-        }
-    }
+    m_model->loadDirectory(m_testDir->url());
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "parent2");
+
+    // Expand all folders.
+    m_model->setExpanded(0, true);
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "parent2");
+
+    m_model->setExpanded(1, true);
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "realGrandChild1" << "parent2");
+
+    m_model->setExpanded(3, true);
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "realGrandChild1" << "parent2" << "realChild2");
+
+    m_model->setExpanded(4, true);
+    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "realGrandChild1" << "parent2" << "realChild2" << "realGrandChild2");
+
+    // Add some more children and grand-children.
+    const KUrl parent1 = m_model->fileItem(0).url();
+    const KUrl parent2 = m_model->fileItem(3).url();
+    const KUrl realChild1 = m_model->fileItem(1).url();
+    const KUrl realChild2 = m_model->fileItem(4).url();
+
+    m_model->slotItemsAdded(parent1, KFileItemList() << KFileItem(KUrl("child1"), QString(), KFileItem::Unknown));
+    m_model->slotCompleted();
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "realGrandChild1" << "child1" << "parent2" << "realChild2" << "realGrandChild2");
+
+    m_model->slotItemsAdded(parent2, KFileItemList() << KFileItem(KUrl("child2"), QString(), KFileItem::Unknown));
+    m_model->slotCompleted();
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "realGrandChild1" << "child1" << "parent2" << "realChild2" << "realGrandChild2" << "child2");
 
-    return true;
+    m_model->slotItemsAdded(realChild1, KFileItemList() << KFileItem(KUrl("grandChild1"), QString(), KFileItem::Unknown));
+    m_model->slotCompleted();
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "grandChild1" << "realGrandChild1" << "child1" << "parent2" << "realChild2" << "realGrandChild2" << "child2");
+
+    m_model->slotItemsAdded(realChild1, KFileItemList() << KFileItem(KUrl("grandChild1"), QString(), KFileItem::Unknown));
+    m_model->slotCompleted();
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "grandChild1" << "realGrandChild1" << "child1" << "parent2" << "realChild2" << "realGrandChild2" << "child2");
+
+    m_model->slotItemsAdded(realChild2, KFileItemList() << KFileItem(KUrl("grandChild2"), QString(), KFileItem::Unknown));
+    m_model->slotCompleted();
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "grandChild1" << "realGrandChild1" << "child1" << "parent2" << "realChild2" << "grandChild2" << "realGrandChild2" << "child2");
+
+    // Set a name filter that matches nothing -> only expanded folders remain.
+    QSignalSpy itemsRemovedSpy(m_model, SIGNAL(itemsRemoved(KItemRangeList)));
+    m_model->setNameFilter("xyz");
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "realChild1" << "parent2" << "realChild2");
+    QCOMPARE(itemsRemovedSpy.count(), 1);
+    QList<QVariant> arguments = itemsRemovedSpy.takeFirst();
+    KItemRangeList itemRangeList = arguments.at(0).value<KItemRangeList>();
+    QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(2, 3) << KItemRange(7, 3));
+
+    // Collapse "parent1".
+    m_model->setExpanded(0, false);
+    QCOMPARE(itemsInModel(), QStringList() << "parent1" << "parent2" << "realChild2");
+    QCOMPARE(itemsRemovedSpy.count(), 1);
+    arguments = itemsRemovedSpy.takeFirst();
+    itemRangeList = arguments.at(0).value<KItemRangeList>();
+    QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 1));
+
+    // Remove "parent2".
+    m_model->slotItemsDeleted(KFileItemList() << m_model->fileItem(1));
+    QCOMPARE(itemsInModel(), QStringList() << "parent1");
+    QCOMPARE(itemsRemovedSpy.count(), 1);
+    arguments = itemsRemovedSpy.takeFirst();
+    itemRangeList = arguments.at(0).value<KItemRangeList>();
+    QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 2));
+
+    // Clear filter, verify that no items reappear.
+    m_model->setNameFilter(QString());
+    QCOMPARE(itemsInModel(), QStringList() << "parent1");
 }
 
 QStringList KFileItemModelTest::itemsInModel() const