]> cloud.milkyroute.net Git - dolphin.git/blob - src/tests/kfileitemmodeltest.cpp
Renamed some signals for consistency with KItemViews classes
[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 testRemoveItems();
45 void testModelConsistencyWhenInsertingItems();
46 void testItemRangeConsistencyWhenInsertingItems();
47 void testExpandItems();
48
49 void testExpansionLevelsCompare_data();
50 void testExpansionLevelsCompare();
51
52 private:
53 bool isModelConsistent() const;
54
55 private:
56 KFileItemModel* m_model;
57 KDirLister* m_dirLister;
58 TestDir* m_testDir;
59 };
60
61 void KFileItemModelTest::init()
62 {
63 qRegisterMetaType<KItemRangeList>("KItemRangeList");
64 qRegisterMetaType<KFileItemList>("KFileItemList");
65
66 m_testDir = new TestDir();
67 m_dirLister = new KDirLister();
68 m_model = new KFileItemModel(m_dirLister);
69 }
70
71 void KFileItemModelTest::cleanup()
72 {
73 delete m_model;
74 m_model = 0;
75
76 delete m_dirLister;
77 m_dirLister = 0;
78
79 delete m_testDir;
80 m_testDir = 0;
81 }
82
83 void KFileItemModelTest::testDefaultRoles()
84 {
85 const QSet<QByteArray> roles = m_model->roles();
86 QCOMPARE(roles.count(), 2);
87 QVERIFY(roles.contains("name"));
88 QVERIFY(roles.contains("isDir"));
89 }
90
91 void KFileItemModelTest::testDefaultSortRole()
92 {
93 QCOMPARE(m_model->sortRole(), QByteArray("name"));
94
95 QStringList files;
96 files << "c.txt" << "a.txt" << "b.txt";
97
98 m_testDir->createFiles(files);
99
100 m_dirLister->openUrl(m_testDir->url());
101 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
102
103 QCOMPARE(m_model->count(), 3);
104 QCOMPARE(m_model->data(0)["name"].toString(), QString("a.txt"));
105 QCOMPARE(m_model->data(1)["name"].toString(), QString("b.txt"));
106 QCOMPARE(m_model->data(2)["name"].toString(), QString("c.txt"));
107 }
108
109 void KFileItemModelTest::testDefaultGroupRole()
110 {
111 QVERIFY(m_model->groupRole().isEmpty());
112 }
113
114 void KFileItemModelTest::testNewItems()
115 {
116 QStringList files;
117 files << "a.txt" << "b.txt" << "c.txt";
118 m_testDir->createFiles(files);
119
120 m_dirLister->openUrl(m_testDir->url());
121 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
122
123 QCOMPARE(m_model->count(), 3);
124
125 QVERIFY(isModelConsistent());
126 }
127
128 void KFileItemModelTest::testRemoveItems()
129 {
130 m_testDir->createFile("a.txt");
131 m_dirLister->openUrl(m_testDir->url());
132 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
133 QCOMPARE(m_model->count(), 1);
134
135 m_testDir->removeFile("a.txt");
136 m_dirLister->updateDirectory(m_testDir->url());
137 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsRemoved(KItemRangeList)), DefaultTimeout));
138 QCOMPARE(m_model->count(), 0);
139 }
140
141 void KFileItemModelTest::testModelConsistencyWhenInsertingItems()
142 {
143 QSKIP("Temporary disabled", SkipSingle);
144
145 // KFileItemModel prevents that inserting a punch of items sequentially
146 // results in an itemsInserted()-signal for each item. Instead internally
147 // a timeout is given that collects such operations and results in only
148 // one itemsInserted()-signal. However in this test we want to stress
149 // KFileItemModel to do a lot of insert operation and hence decrease
150 // the timeout to 1 millisecond.
151 m_model->m_minimumUpdateIntervalTimer->setInterval(1);
152
153 m_testDir->createFile("1");
154 m_dirLister->openUrl(m_testDir->url());
155 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
156 QCOMPARE(m_model->count(), 1);
157
158 // Insert 10 items for 20 times. After each insert operation the model consistency
159 // is checked.
160 QSet<int> insertedItems;
161 for (int i = 0; i < 20; ++i) {
162 QSignalSpy spy(m_model, SIGNAL(itemsInserted(KItemRangeList)));
163
164 for (int j = 0; j < 10; ++j) {
165 int itemName = qrand();
166 while (insertedItems.contains(itemName)) {
167 itemName = qrand();
168 }
169 insertedItems.insert(itemName);
170
171 m_testDir->createFile(QString::number(itemName));
172 }
173
174 m_dirLister->updateDirectory(m_testDir->url());
175 if (spy.count() == 0) {
176 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
177 }
178
179 QVERIFY(isModelConsistent());
180 }
181
182 QCOMPARE(m_model->count(), 201);
183 }
184
185 void KFileItemModelTest::testItemRangeConsistencyWhenInsertingItems()
186 {
187 QStringList files;
188 files << "B" << "E" << "G";
189 m_testDir->createFiles(files);
190
191 // Due to inserting the 3 items one item-range with index == 0 and
192 // count == 3 must be given
193 QSignalSpy spy1(m_model, SIGNAL(itemsInserted(KItemRangeList)));
194 m_dirLister->openUrl(m_testDir->url());
195 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
196
197 QCOMPARE(spy1.count(), 1);
198 QList<QVariant> arguments = spy1.takeFirst();
199 KItemRangeList itemRangeList = arguments.at(0).value<KItemRangeList>();
200 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(0, 3));
201
202 // The indexes of the item-ranges must always be related to the model before
203 // the items have been inserted. Having:
204 // 0 1 2
205 // B E G
206 // and inserting A, C, D, F the resulting model will be:
207 // 0 1 2 3 4 5 6
208 // A B C D E F G
209 // and the item-ranges must be:
210 // index: 0, count: 1 for A
211 // index: 1, count: 2 for B, C
212 // index: 2, count: 1 for G
213
214 files.clear();
215 files << "A" << "C" << "D" << "F";
216 m_testDir->createFiles(files);
217
218 QSignalSpy spy2(m_model, SIGNAL(itemsInserted(KItemRangeList)));
219 m_dirLister->updateDirectory(m_testDir->url());
220 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
221
222 QCOMPARE(spy2.count(), 1);
223 arguments = spy2.takeFirst();
224 itemRangeList = arguments.at(0).value<KItemRangeList>();
225 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(0, 1) << KItemRange(1, 2) << KItemRange(2, 1));
226 }
227
228 void KFileItemModelTest::testExpandItems()
229 {
230 // Test expanding subfolders in a folder with the items "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1".
231 // Besides testing the basic item expansion functionality, the test makes sure that
232 // KFileItemModel::expansionLevelsCompare(const KFileItem& a, const KFileItem& b)
233 // yields the correct result for "a/a/1" and "a/a-1/", whis is non-trivial because they share the
234 // first three characters.
235 QSet<QByteArray> modelRoles = m_model->roles();
236 modelRoles << "isExpanded" << "expansionLevel";
237 m_model->setRoles(modelRoles);
238
239 QStringList files;
240 files << "a/a/1" << "a/a-1/1"; // missing folders are created automatically
241 m_testDir->createFiles(files);
242
243 m_dirLister->openUrl(m_testDir->url());
244 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
245
246 // So far, the model contains only "a/"
247 QCOMPARE(m_model->count(), 1);
248 QVERIFY(m_model->isExpandable(0));
249 QVERIFY(!m_model->isExpanded(0));
250
251 QSignalSpy spyInserted(m_model, SIGNAL(itemsInserted(KItemRangeList)));
252
253 // Expand the folder "a/" -> "a/a/" and "a/a-1/" become visible
254 m_model->setExpanded(0, true);
255 QVERIFY(m_model->isExpanded(0));
256 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
257 QCOMPARE(m_model->count(), 3); // 3 items: "a/", "a/a/", "a/a-1/"
258
259 QCOMPARE(spyInserted.count(), 1);
260 KItemRangeList itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
261 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 2)); // 2 new items "a/a/" and "a/a-1/" with indices 1 and 2
262
263 QVERIFY(m_model->isExpandable(1));
264 QVERIFY(!m_model->isExpanded(1));
265 QVERIFY(m_model->isExpandable(2));
266 QVERIFY(!m_model->isExpanded(2));
267
268 // Expand the folder "a/a/" -> "a/a/1" becomes visible
269 m_model->setExpanded(1, true);
270 QVERIFY(m_model->isExpanded(1));
271 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
272 QCOMPARE(m_model->count(), 4); // 4 items: "a/", "a/a/", "a/a/1", "a/a-1/"
273
274 QCOMPARE(spyInserted.count(), 1);
275 itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
276 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(2, 1)); // 1 new item "a/a/1" with index 2
277
278 QVERIFY(!m_model->isExpandable(2));
279 QVERIFY(!m_model->isExpanded(2));
280
281 // Expand the folder "a/a-1/" -> "a/a-1/1" becomes visible
282 m_model->setExpanded(3, true);
283 QVERIFY(m_model->isExpanded(3));
284 QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
285 QCOMPARE(m_model->count(), 5); // 4 items: "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1"
286
287 QCOMPARE(spyInserted.count(), 1);
288 itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
289 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(4, 1)); // 1 new item "a/a-1/1" with index 4
290
291 QVERIFY(!m_model->isExpandable(4));
292 QVERIFY(!m_model->isExpanded(4));
293
294 QSignalSpy spyRemoved(m_model, SIGNAL(itemsRemoved(KItemRangeList)));
295
296 // Collapse the top-level folder -> all other items should disappear
297 m_model->setExpanded(0, false);
298 QVERIFY(!m_model->isExpanded(0));
299 QCOMPARE(spyRemoved.count(), 1);
300 itemRangeList = spyRemoved.takeFirst().at(0).value<KItemRangeList>();
301 QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 4)); // 4 items removed
302 }
303
304 void KFileItemModelTest::testExpansionLevelsCompare_data()
305 {
306 QTest::addColumn<QString>("urlA");
307 QTest::addColumn<QString>("urlB");
308 QTest::addColumn<int>("result");
309
310 QTest::newRow("Equal") << "/a/b" << "/a/b" << 0;
311 QTest::newRow("Sub path: A < B") << "/a/b" << "/a/b/c" << -1;
312 QTest::newRow("Sub path: A > B") << "/a/b/c" << "/a/b" << +1;
313 QTest::newRow("Same level: /a/1 < /a-1/1") << "/a/1" << "/a-1/1" << -1;
314 QTest::newRow("Same level: /a-/1 > /a/1") << "/a-1/1" << "/a/1" << +1;
315 QTest::newRow("Different levels: /a/a/1 < /a/a-1") << "/a/a/1" << "/a/a-1" << -1;
316 QTest::newRow("Different levels: /a/a-1 > /a/a/1") << "/a/a-1" << "/a/a/1" << +1;
317 }
318
319 void KFileItemModelTest::testExpansionLevelsCompare()
320 {
321 QFETCH(QString, urlA);
322 QFETCH(QString, urlB);
323 QFETCH(int, result);
324
325 const KFileItem a(KUrl(urlA), QString(), mode_t(-1));
326 const KFileItem b(KUrl(urlB), QString(), mode_t(-1));
327 QCOMPARE(m_model->expansionLevelsCompare(a, b), result);
328 }
329
330 bool KFileItemModelTest::isModelConsistent() const
331 {
332 for (int i = 0; i < m_model->count(); ++i) {
333 const KFileItem item = m_model->fileItem(i);
334 if (item.isNull()) {
335 qWarning() << "Item" << i << "is null";
336 return false;
337 }
338
339 const int itemIndex = m_model->index(item);
340 if (itemIndex != i) {
341 qWarning() << "Item" << i << "has a wrong index:" << itemIndex;
342 return false;
343 }
344 }
345
346 return true;
347 }
348
349 QTEST_KDEMAIN(KFileItemModelTest, NoGUI)
350
351 #include "kfileitemmodeltest.moc"