]> cloud.milkyroute.net Git - dolphin.git/blob - src/tests/kfileitemmodeltest.cpp
Fix issues with the anchor selection
[dolphin.git] / src / tests / kfileitemmodeltest.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include <qtest_kde.h>
21
22 #include <KDirLister>
23 #include "kitemviews/kfileitemmodel.h"
24 #include "testdir.h"
25
26 namespace {
27 const int DefaultTimeout = 5000;
28 };
29
30 Q_DECLARE_METATYPE(KItemRangeList)
31
32 class KFileItemModelTest : public QObject
33 {
34 Q_OBJECT
35
36 private slots:
37 void init();
38 void cleanup();
39
40 void testDefaultRoles();
41 void testDefaultSortRole();
42 void testDefaultGroupRole();
43 void testNewItems();
44 void testModelConsistencyWhenInsertingItems();
45 void testItemRangeConsistencyWhenInsertingItems();
46 void testExpandItems();
47
48 void testExpansionLevelsCompare_data();
49 void testExpansionLevelsCompare();
50
51 private:
52 bool isModelConsistent() const;
53
54 private:
55 KFileItemModel* m_model;
56 KDirLister* m_dirLister;
57 TestDir* m_testDir;
58 };
59
60 void KFileItemModelTest::init()
61 {
62 qRegisterMetaType<KItemRangeList>("KItemRangeList");
63 qRegisterMetaType<KFileItemList>("KFileItemList");
64
65 m_testDir = new TestDir();
66 m_dirLister = new KDirLister();
67 m_model = new KFileItemModel(m_dirLister);
68 }
69
70 void KFileItemModelTest::cleanup()
71 {
72 delete m_model;
73 m_model = 0;
74
75 delete m_dirLister;
76 m_dirLister = 0;
77
78 delete m_testDir;
79 m_testDir = 0;
80 }
81
82 void KFileItemModelTest::testDefaultRoles()
83 {
84 const QSet<QByteArray> roles = m_model->roles();
85 QCOMPARE(roles.count(), 2);
86 QVERIFY(roles.contains("name"));
87 QVERIFY(roles.contains("isDir"));
88 }
89
90 void KFileItemModelTest::testDefaultSortRole()
91 {
92 QCOMPARE(m_model->sortRole(), QByteArray("name"));
93
94 QStringList files;
95 files << "c.txt" << "a.txt" << "b.txt";
96
97 m_testDir->createFiles(files);
98
99 m_dirLister->openUrl(m_testDir->url());
100 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
101
102 QCOMPARE(m_model->count(), 3);
103 QCOMPARE(m_model->data(0)["name"].toString(), QString("a.txt"));
104 QCOMPARE(m_model->data(1)["name"].toString(), QString("b.txt"));
105 QCOMPARE(m_model->data(2)["name"].toString(), QString("c.txt"));
106 }
107
108 void KFileItemModelTest::testDefaultGroupRole()
109 {
110 QVERIFY(m_model->groupRole().isEmpty());
111 }
112
113 void KFileItemModelTest::testNewItems()
114 {
115 QStringList files;
116 files << "a.txt" << "b.txt" << "c.txt";
117 m_testDir->createFiles(files);
118
119 m_dirLister->openUrl(m_testDir->url());
120 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
121
122 QCOMPARE(m_model->count(), 3);
123
124 QVERIFY(isModelConsistent());
125 }
126
127 void KFileItemModelTest::testModelConsistencyWhenInsertingItems()
128 {
129 QSKIP("Temporary disabled", SkipSingle);
130
131 // KFileItemModel prevents that inserting a punch of items sequentially
132 // results in an itemsInserted()-signal for each item. Instead internally
133 // a timeout is given that collects such operations and results in only
134 // one itemsInserted()-signal. However in this test we want to stress
135 // KFileItemModel to do a lot of insert operation and hence decrease
136 // the timeout to 1 millisecond.
137 m_model->m_minimumUpdateIntervalTimer->setInterval(1);
138
139 m_testDir->createFile("1");
140 m_dirLister->openUrl(m_testDir->url());
141 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
142 QCOMPARE(m_model->count(), 1);
143
144 // Insert 10 items for 20 times. After each insert operation the model consistency
145 // is checked.
146 QSet<int> insertedItems;
147 for (int i = 0; i < 20; ++i) {
148 QSignalSpy spy(m_model, SIGNAL(itemsInserted(KItemRangeList)));
149
150 for (int j = 0; j < 10; ++j) {
151 int itemName = qrand();
152 while (insertedItems.contains(itemName)) {
153 itemName = qrand();
154 }
155 insertedItems.insert(itemName);
156
157 m_testDir->createFile(QString::number(itemName));
158 }
159
160 m_dirLister->updateDirectory(m_testDir->url());
161 if (spy.count() == 0) {
162 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
163 }
164
165 QVERIFY(isModelConsistent());
166 }
167
168 QCOMPARE(m_model->count(), 201);
169 }
170
171 void KFileItemModelTest::testItemRangeConsistencyWhenInsertingItems()
172 {
173 QStringList files;
174 files << "B" << "E" << "G";
175 m_testDir->createFiles(files);
176
177 // Due to inserting the 3 items one item-range with index == 0 and
178 // count == 3 must be given
179 QSignalSpy spy1(m_model, SIGNAL(itemsInserted(KItemRangeList)));
180 m_dirLister->openUrl(m_testDir->url());
181 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
182
183 QCOMPARE(spy1.count(), 1);
184 QList<QVariant> arguments = spy1.takeFirst();
185 KItemRangeList itemRangeList = arguments.at(0).value<KItemRangeList>();
186 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(0, 3));
187
188 // The indexes of the item-ranges must always be related to the model before
189 // the items have been inserted. Having:
190 // 0 1 2
191 // B E G
192 // and inserting A, C, D, F the resulting model will be:
193 // 0 1 2 3 4 5 6
194 // A B C D E F G
195 // and the item-ranges must be:
196 // index: 0, count: 1 for A
197 // index: 1, count: 2 for B, C
198 // index: 2, count: 1 for G
199
200 files.clear();
201 files << "A" << "C" << "D" << "F";
202 m_testDir->createFiles(files);
203
204 QSignalSpy spy2(m_model, SIGNAL(itemsInserted(KItemRangeList)));
205 m_dirLister->updateDirectory(m_testDir->url());
206 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
207
208 QCOMPARE(spy2.count(), 1);
209 arguments = spy2.takeFirst();
210 itemRangeList = arguments.at(0).value<KItemRangeList>();
211 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(0, 1) << KItemRange(1, 2) << KItemRange(2, 1));
212 }
213
214 void KFileItemModelTest::testExpandItems()
215 {
216 // Test expanding subfolders in a folder with the items "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1".
217 // Besides testing the basic item expansion functionality, the test makes sure that
218 // KFileItemModel::expansionLevelsCompare(const KFileItem& a, const KFileItem& b)
219 // yields the correct result for "a/a/1" and "a/a-1/", whis is non-trivial because they share the
220 // first three characters.
221 QSet<QByteArray> modelRoles = m_model->roles();
222 modelRoles << "isExpanded" << "expansionLevel";
223 m_model->setRoles(modelRoles);
224
225 QStringList files;
226 files << "a/a/1" << "a/a-1/1"; // missing folders are created automatically
227 m_testDir->createFiles(files);
228
229 m_dirLister->openUrl(m_testDir->url());
230 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
231
232 // So far, the model contains only "a/"
233 QCOMPARE(m_model->count(), 1);
234 QVERIFY(m_model->isExpandable(0));
235 QVERIFY(!m_model->isExpanded(0));
236
237 QSignalSpy spyInserted(m_model, SIGNAL(itemsInserted(KItemRangeList)));
238
239 // Expand the folder "a/" -> "a/a/" and "a/a-1/" become visible
240 m_model->setExpanded(0, true);
241 QVERIFY(m_model->isExpanded(0));
242 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
243 QCOMPARE(m_model->count(), 3); // 3 items: "a/", "a/a/", "a/a-1/"
244
245 QCOMPARE(spyInserted.count(), 1);
246 KItemRangeList itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
247 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 2)); // 2 new items "a/a/" and "a/a-1/" with indices 1 and 2
248
249 QVERIFY(m_model->isExpandable(1));
250 QVERIFY(!m_model->isExpanded(1));
251 QVERIFY(m_model->isExpandable(2));
252 QVERIFY(!m_model->isExpanded(2));
253
254 // Expand the folder "a/a/" -> "a/a/1" becomes visible
255 m_model->setExpanded(1, true);
256 QVERIFY(m_model->isExpanded(1));
257 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
258 QCOMPARE(m_model->count(), 4); // 4 items: "a/", "a/a/", "a/a/1", "a/a-1/"
259
260 QCOMPARE(spyInserted.count(), 1);
261 itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
262 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(2, 1)); // 1 new item "a/a/1" with index 2
263
264 QVERIFY(!m_model->isExpandable(2));
265 QVERIFY(!m_model->isExpanded(2));
266
267 // Expand the folder "a/a-1/" -> "a/a-1/1" becomes visible
268 m_model->setExpanded(3, true);
269 QVERIFY(m_model->isExpanded(3));
270 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
271 QCOMPARE(m_model->count(), 5); // 4 items: "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1"
272
273 QCOMPARE(spyInserted.count(), 1);
274 itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
275 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(4, 1)); // 1 new item "a/a-1/1" with index 4
276
277 QVERIFY(!m_model->isExpandable(4));
278 QVERIFY(!m_model->isExpanded(4));
279
280 QSignalSpy spyRemoved(m_model, SIGNAL(itemsRemoved(KItemRangeList)));
281
282 // Collapse the top-level folder -> all other items should disappear
283 m_model->setExpanded(0, false);
284 QVERIFY(!m_model->isExpanded(0));
285 QCOMPARE(spyRemoved.count(), 1);
286 itemRangeList = spyRemoved.takeFirst().at(0).value<KItemRangeList>();
287 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 4)); // 4 items removed
288 }
289
290 void KFileItemModelTest::testExpansionLevelsCompare_data()
291 {
292 QTest::addColumn<QString>("urlA");
293 QTest::addColumn<QString>("urlB");
294 QTest::addColumn<int>("result");
295
296 QTest::newRow("Equal") << "/a/b" << "/a/b" << 0;
297 QTest::newRow("Sub path: A < B") << "/a/b" << "/a/b/c" << -1;
298 QTest::newRow("Sub path: A > B") << "/a/b/c" << "/a/b" << +1;
299 QTest::newRow("Same level: /a/1 < /a-1/1") << "/a/1" << "/a-1/1" << -1;
300 QTest::newRow("Same level: /a-/1 > /a/1") << "/a-1/1" << "/a/1" << +1;
301 QTest::newRow("Different levels: /a/a/1 < /a/a-1") << "/a/a/1" << "/a/a-1" << -1;
302 QTest::newRow("Different levels: /a/a-1 > /a/a/1") << "/a/a-1" << "/a/a/1" << +1;
303 }
304
305 void KFileItemModelTest::testExpansionLevelsCompare()
306 {
307 QFETCH(QString, urlA);
308 QFETCH(QString, urlB);
309 QFETCH(int, result);
310
311 const KFileItem a(KUrl(urlA), QString(), mode_t(-1));
312 const KFileItem b(KUrl(urlB), QString(), mode_t(-1));
313 QCOMPARE(m_model->expansionLevelsCompare(a, b), result);
314 }
315
316 bool KFileItemModelTest::isModelConsistent() const
317 {
318 for (int i = 0; i < m_model->count(); ++i) {
319 const KFileItem item = m_model->fileItem(i);
320 if (item.isNull()) {
321 qWarning() << "Item" << i << "is null";
322 return false;
323 }
324
325 const int itemIndex = m_model->index(item);
326 if (itemIndex != i) {
327 qWarning() << "Item" << i << "has a wrong index:" << itemIndex;
328 return false;
329 }
330 }
331
332 return true;
333 }
334
335 QTEST_KDEMAIN(KFileItemModelTest, NoGUI)
336
337 #include "kfileitemmodeltest.moc"