#include "kitemviews/kfileitemmodel.h"
#include "testdir.h"
+void myMessageOutput(QtMsgType type, const char* msg)
+{
+ switch (type) {
+ case QtDebugMsg:
+ break;
+ case QtWarningMsg:
+ break;
+ case QtCriticalMsg:
+ fprintf(stderr, "Critical: %s\n", msg);
+ break;
+ case QtFatalMsg:
+ fprintf(stderr, "Fatal: %s\n", msg);
+ abort();
+ default:
+ break;
+ }
+ }
+
namespace {
const int DefaultTimeout = 5000;
};
void testDefaultRoles();
void testDefaultSortRole();
- void testDefaultGroupRole();
+ void testDefaultGroupedSorting();
void testNewItems();
void testRemoveItems();
+ void testSetData();
+ void testSetDataWithModifiedSortRole_data();
+ void testSetDataWithModifiedSortRole();
void testModelConsistencyWhenInsertingItems();
void testItemRangeConsistencyWhenInsertingItems();
void testExpandItems();
void testIndexForKeyboardSearch();
+ void testNameFilter();
+
private:
bool isModelConsistent() const;
QStringList itemsInModel() const;
void KFileItemModelTest::init()
{
+ // The item-model tests result in a huge number of debugging
+ // output from kdelibs. Only show critical and fatal messages.
+ qInstallMsgHandler(myMessageOutput);
+
qRegisterMetaType<KItemRange>("KItemRange");
qRegisterMetaType<KItemRangeList>("KItemRangeList");
qRegisterMetaType<KFileItemList>("KFileItemList");
QCOMPARE(m_model->data(2)["name"].toString(), QString("c.txt"));
}
-void KFileItemModelTest::testDefaultGroupRole()
+void KFileItemModelTest::testDefaultGroupedSorting()
{
- QVERIFY(m_model->groupRole().isEmpty());
+ QCOMPARE(m_model->groupedSorting(), false);
}
void KFileItemModelTest::testNewItems()
void KFileItemModelTest::testRemoveItems()
{
m_testDir->createFile("a.txt");
+ m_testDir->createFile("b.txt");
m_dirLister->openUrl(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
- QCOMPARE(m_model->count(), 1);
+ QCOMPARE(m_model->count(), 2);
+ QVERIFY(isModelConsistent());
m_testDir->removeFile("a.txt");
m_dirLister->updateDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsRemoved(KItemRangeList)), DefaultTimeout));
- QCOMPARE(m_model->count(), 0);
+ QCOMPARE(m_model->count(), 1);
+ QVERIFY(isModelConsistent());
+}
+
+void KFileItemModelTest::testSetData()
+{
+ m_testDir->createFile("a.txt");
+
+ m_dirLister->openUrl(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ QHash<QByteArray, QVariant> values;
+ values.insert("customRole1", "Test1");
+ values.insert("customRole2", "Test2");
+
+ QSignalSpy itemsChangedSpy(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)));
+ m_model->setData(0, values);
+ QCOMPARE(itemsChangedSpy.count(), 1);
+
+ values = m_model->data(0);
+ QCOMPARE(values.value("customRole1").toString(), QString("Test1"));
+ QCOMPARE(values.value("customRole2").toString(), QString("Test2"));
+ QVERIFY(isModelConsistent());
+}
+
+void KFileItemModelTest::testSetDataWithModifiedSortRole_data()
+{
+ QTest::addColumn<int>("changedIndex");
+ QTest::addColumn<int>("changedRating");
+ QTest::addColumn<bool>("expectMoveSignal");
+ QTest::addColumn<int>("ratingIndex0");
+ QTest::addColumn<int>("ratingIndex1");
+ QTest::addColumn<int>("ratingIndex2");
+
+ // Default setup:
+ // Index 0 = rating 2
+ // Index 1 = rating 4
+ // Index 2 = rating 6
+
+ QTest::newRow("Index 0: Rating 3") << 0 << 3 << false << 3 << 4 << 6;
+ QTest::newRow("Index 0: Rating 5") << 0 << 5 << true << 4 << 5 << 6;
+ QTest::newRow("Index 0: Rating 8") << 0 << 8 << true << 4 << 6 << 8;
+
+ QTest::newRow("Index 2: Rating 1") << 2 << 1 << true << 1 << 2 << 4;
+ QTest::newRow("Index 2: Rating 3") << 2 << 3 << true << 2 << 3 << 4;
+ QTest::newRow("Index 2: Rating 5") << 2 << 5 << false << 2 << 4 << 5;
+}
+
+void KFileItemModelTest::testSetDataWithModifiedSortRole()
+{
+ QFETCH(int, changedIndex);
+ QFETCH(int, changedRating);
+ QFETCH(bool, expectMoveSignal);
+ QFETCH(int, ratingIndex0);
+ QFETCH(int, ratingIndex1);
+ QFETCH(int, ratingIndex2);
+
+ // Changing the value of a sort-role must result in
+ // a reordering of the items.
+ QCOMPARE(m_model->sortRole(), QByteArray("name"));
+
+ QStringList files;
+ files << "a.txt" << "b.txt" << "c.txt";
+ m_testDir->createFiles(files);
+
+ m_dirLister->openUrl(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ // Fill the "rating" role of each file:
+ // a.txt -> 2
+ // b.txt -> 4
+ // c.txt -> 6
+
+ QHash<QByteArray, QVariant> ratingA;
+ ratingA.insert("rating", 2);
+ m_model->setData(0, ratingA);
+
+ QHash<QByteArray, QVariant> ratingB;
+ ratingB.insert("rating", 4);
+ m_model->setData(1, ratingB);
+
+ QHash<QByteArray, QVariant> ratingC;
+ ratingC.insert("rating", 6);
+ m_model->setData(2, ratingC);
+
+ m_model->setSortRole("rating");
+ QCOMPARE(m_model->data(0).value("rating").toInt(), 2);
+ QCOMPARE(m_model->data(1).value("rating").toInt(), 4);
+ QCOMPARE(m_model->data(2).value("rating").toInt(), 6);
+
+ // Now change the rating from a.txt. This usually results
+ // in reordering of the items.
+ QHash<QByteArray, QVariant> rating;
+ rating.insert("rating", changedRating);
+ m_model->setData(changedIndex, rating);
+
+ if (expectMoveSignal) {
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)), DefaultTimeout));
+ }
+
+ 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());
}
void KFileItemModelTest::testModelConsistencyWhenInsertingItems()
{
- QSKIP("Temporary disabled", SkipSingle);
+ //QSKIP("Temporary disabled", SkipSingle);
// KFileItemModel prevents that inserting a punch of items sequentially
// results in an itemsInserted()-signal for each item. Instead internally
// yields the correct result for "a/a/1" and "a/a-1/", whis is non-trivial because they share the
// first three characters.
QSet<QByteArray> modelRoles = m_model->roles();
- modelRoles << "isExpanded" << "expansionLevel";
+ modelRoles << "isExpanded" << "isExpandable" << "expansionLevel";
m_model->setRoles(modelRoles);
QStringList files;
QVERIFY(m_model->isExpanded(3));
QVERIFY(!m_model->isExpanded(4));
QCOMPARE(m_model->expandedUrls(), allFolders);
+
+ // Move to a sub folder, then call restoreExpandedFolders() *before* going back.
+ // This is how DolphinView restores the expanded folders when navigating in history.
+ m_dirLister->openUrl(KUrl(m_testDir->name() + "a/a/"));
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout));
+ QCOMPARE(m_model->count(), 1); // 1 item: "1"
+ m_model->restoreExpandedUrls(allFolders);
+ m_dirLister->openUrl(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout));
+ QCOMPARE(m_model->count(), 5); // 5 items: "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1"
+ QCOMPARE(m_model->expandedUrls(), allFolders);
}
void KFileItemModelTest::testSorting()
QTest::newRow("Sub path: A < B") << "/a/b" << "/a/b/c" << -1;
QTest::newRow("Sub path: A > B") << "/a/b/c" << "/a/b" << +1;
QTest::newRow("Same level: /a/1 < /a-1/1") << "/a/1" << "/a-1/1" << -1;
- QTest::newRow("Same level: /a-/1 > /a/1") << "/a-1/1" << "/a/1" << +1;
+ QTest::newRow("Same level: /a-1/1 > /a/1") << "/a-1/1" << "/a/1" << +1;
QTest::newRow("Different levels: /a/a/1 < /a/a-1") << "/a/a/1" << "/a/a-1" << -1;
QTest::newRow("Different levels: /a/a-1 > /a/a/1") << "/a/a-1" << "/a/a/1" << +1;
}
void KFileItemModelTest::testExpansionLevelsCompare()
{
+ QSKIP("Temporary deactivated as KFileItemModel::ItemData has been extended "
+ "by a 'parent' member that is required for a correct comparison. For a "
+ "successful test the item-data of all parents must be available.", SkipAll);
+
QFETCH(QString, urlA);
QFETCH(QString, urlB);
QFETCH(int, result);
- const KFileItem a(KUrl(urlA), QString(), mode_t(-1));
- const KFileItem b(KUrl(urlB), QString(), mode_t(-1));
- QCOMPARE(m_model->expansionLevelsCompare(a, b), result);
+ const KFileItem itemA(KUrl(urlA), QString(), mode_t(-1));
+ const KFileItem itemB(KUrl(urlB), QString(), mode_t(-1));
+
+ KFileItemModel::ItemData a;
+ a.item = itemA;
+ a.parent = 0;
+
+ KFileItemModel::ItemData b;
+ b.item = itemB;
+ b.parent = 0;
+
+ QCOMPARE(m_model->expansionLevelsCompare(&a, &b), result);
}
void KFileItemModelTest::testIndexForKeyboardSearch()
// TODO: Maybe we should also test keyboard searches in directories which are not sorted by Name?
}
+void KFileItemModelTest::testNameFilter()
+{
+ QStringList files;
+ files << "A1" << "A2" << "Abc" << "Bcd" << "Cde";
+ m_testDir->createFiles(files);
+
+ m_dirLister->openUrl(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ m_model->setNameFilter("A"); // Shows A1, A2 and Abc
+ QCOMPARE(m_model->count(), 3);
+
+ m_model->setNameFilter("A2"); // Shows only A2
+ QCOMPARE(m_model->count(), 1);
+
+ m_model->setNameFilter("A2"); // Shows only A1
+ QCOMPARE(m_model->count(), 1);
+
+ m_model->setNameFilter("Bc"); // Shows "Abc" and "Bcd"
+ QCOMPARE(m_model->count(), 2);
+
+ m_model->setNameFilter("bC"); // Shows "Abc" and "Bcd"
+ QCOMPARE(m_model->count(), 2);
+
+ m_model->setNameFilter(QString()); // Shows again all items
+ QCOMPARE(m_model->count(), 5);
+}
+
bool KFileItemModelTest::isModelConsistent() const
{
+ if (m_model->m_items.count() != m_model->m_itemData.count()) {
+ return false;
+ }
+
for (int i = 0; i < m_model->count(); ++i) {
const KFileItem item = m_model->fileItem(i);
if (item.isNull()) {