~ubuntu-branches/ubuntu/wily/zanshin/wily-proposed

« back to all changes in this revision

Viewing changes to src/tests/todocategoriesmodeltest.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2009-08-13 23:19:32 UTC
  • Revision ID: james.westby@ubuntu.com-20090813231932-lewqphiry1qs7w80
Tags: upstream-0.1+svn1006410
ImportĀ upstreamĀ versionĀ 0.1+svn1006410

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of Zanshin Todo.
 
2
 
 
3
   Copyright 2008 Kevin Ottens <ervin@kde.org>
 
4
   Copyright 2008, 2009 Mario Bensi <nef@ipsquad.net>
 
5
 
 
6
   This program is free software; you can redistribute it and/or
 
7
   modify it under the terms of the GNU General Public License as
 
8
   published by the Free Software Foundation; either version 2 of
 
9
   the License or (at your option) version 3 or any later version
 
10
   accepted by the membership of KDE e.V. (or its successor approved
 
11
   by the membership of KDE e.V.), which shall act as a proxy
 
12
   defined in Section 14 of version 3 of the license.
 
13
 
 
14
   This program is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
17
   GNU General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with this program; if not, write to the Free Software
 
21
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 
22
   USA.
 
23
*/
 
24
 
 
25
#include "modeltestbase.h"
 
26
 
 
27
#include <akonadi/collection.h>
 
28
#include <akonadi/item.h>
 
29
#include <akonadi/itemdeletejob.h>
 
30
#include <akonadi/qtest_akonadi.h>
 
31
 
 
32
#include <QtGui/QSortFilterProxyModel>
 
33
 
 
34
#include "todoflatmodel.h"
 
35
#include "todocategoriesmodel.h"
 
36
 
 
37
class TodoCategoriesModelTest : public ModelTestBase
 
38
{
 
39
    Q_OBJECT
 
40
 
 
41
private slots:
 
42
    void initTestCase();
 
43
    void testInitialState();
 
44
    void testSingleModification();
 
45
    void testReparentModification();
 
46
    void testSeveralReparentModification();
 
47
    void testSingleRemoved();
 
48
    void testMultipleRemoved();
 
49
    void testDragAndDrop();
 
50
    void testAddCategory_data();
 
51
    void testAddCategory();
 
52
    void testCategoryRename_data();
 
53
    void testCategoryRename();
 
54
    void testRemoveCategory_data();
 
55
    void testRemoveCategory();
 
56
    void testDnDCategory_data();
 
57
    void testDnDCategory();
 
58
 
 
59
private:
 
60
    TodoFlatModel m_flatModel;
 
61
    QSortFilterProxyModel m_flatSortedModel;
 
62
    TodoCategoriesModel m_model;
 
63
    QSortFilterProxyModel m_sortedModel;
 
64
};
 
65
 
 
66
QTEST_AKONADIMAIN(TodoCategoriesModelTest, GUI)
 
67
 
 
68
void TodoCategoriesModelTest::initTestCase()
 
69
{
 
70
    ModelTestBase::initTestCase();
 
71
    m_model.setSourceModel(&m_flatModel);
 
72
    m_model.setCollection(m_collection);
 
73
    flushNotifications();
 
74
 
 
75
    m_flatSortedModel.setSourceModel(&m_flatModel);
 
76
    m_flatSortedModel.sort(TodoFlatModel::RemoteId);
 
77
 
 
78
    m_sortedModel.setSourceModel(&m_model);
 
79
    m_sortedModel.sort(TodoFlatModel::Summary);
 
80
}
 
81
 
 
82
class TreeNode
 
83
{
 
84
public:
 
85
    TreeNode(const QString &i, const QString &s)
 
86
        : id(i), summary(s) { }
 
87
 
 
88
    TreeNode &operator<<(const TreeNode &child)
 
89
    {
 
90
        const_cast<TreeNode&>(child).parent = summary;
 
91
        children << child;
 
92
        return *this;
 
93
    }
 
94
 
 
95
    QString id;
 
96
    QString parent;
 
97
    QString summary;
 
98
    QList<TreeNode> children;
 
99
};
 
100
 
 
101
#if 0
 
102
static void dumpTree(const QList<TreeNode> &tree, int indent = 0)
 
103
{
 
104
    QString prefix;
 
105
    for (int i=0; i<indent; ++i) {
 
106
        prefix+="    ";
 
107
    }
 
108
 
 
109
    foreach (const TreeNode &node, tree) {
 
110
        qDebug() << prefix << "[" << node.parent << node.id << node.summary;
 
111
        dumpTree(node.children, indent+1);
 
112
        qDebug() << prefix << "]";
 
113
    }
 
114
}
 
115
#endif
 
116
 
 
117
static void compareTrees(QAbstractItemModel *model, const QList<TreeNode> &tree,
 
118
                         const QModelIndex &root = QModelIndex())
 
119
{
 
120
    int row = 0;
 
121
    foreach (const TreeNode &node, tree) {
 
122
        QCOMPARE(model->data(model->index(row, TodoFlatModel::RemoteId, root)).toString(), node.id);
 
123
        QCOMPARE(model->data(model->index(row, TodoFlatModel::Summary, root)).toString(), node.summary);
 
124
        if (node.parent.isEmpty()) {
 
125
            QVERIFY(model->data(model->index(row, TodoFlatModel::Categories, root)).toStringList().isEmpty());
 
126
        } else {
 
127
            QVERIFY(model->data(model->index(row, TodoFlatModel::Categories, root)).toStringList().contains(node.parent));
 
128
        }
 
129
 
 
130
        QCOMPARE(model->rowCount(model->index(row, 0, root)), node.children.size());
 
131
        compareTrees(model, node.children, model->index(row, 0, root));
 
132
        row++;
 
133
    }
 
134
}
 
135
 
 
136
void TodoCategoriesModelTest::testInitialState()
 
137
{
 
138
    QList<TreeNode> tree;
 
139
 
 
140
    tree << (TreeNode(QString(), "Computer")
 
141
             << TreeNode(QString(), "Online")
 
142
             << TreeNode("fake-06", "Read magazine")
 
143
            )
 
144
 
 
145
         << (TreeNode(QString(), "Errands")
 
146
             << TreeNode("fake-03", "Walk around with the dog")
 
147
            )
 
148
 
 
149
         << (TreeNode(QString(), "Home")
 
150
             << TreeNode("fake-05", "Feed the dog")
 
151
            )
 
152
 
 
153
         << (TreeNode(QString(), "Office")
 
154
             << TreeNode("fake-06", "Read magazine")
 
155
            )
 
156
 
 
157
         << TreeNode(QString(), "Phone");
 
158
 
 
159
    compareTrees(&m_sortedModel, tree);
 
160
}
 
161
 
 
162
void TodoCategoriesModelTest::testSingleModification()
 
163
{
 
164
    Akonadi::Item item = m_flatModel.itemForIndex(m_flatSortedModel.mapToSource(m_flatSortedModel.index(5, 0)));
 
165
    QModelIndexList indexes = m_model.indexesForItem(item, TodoFlatModel::Summary);
 
166
 
 
167
    QSignalSpy spy(&m_model, SIGNAL(dataChanged(QModelIndex, QModelIndex)));
 
168
 
 
169
    QVERIFY(m_model.setData(indexes.first(), "Feed the cat"));
 
170
 
 
171
    flushNotifications();
 
172
 
 
173
    foreach (const QModelIndex &index, indexes) {
 
174
        QCOMPARE(m_model.data(index).toString(), QString("Feed the cat"));
 
175
    }
 
176
 
 
177
    indexes = m_model.indexesForItem(item, 0);
 
178
    QCOMPARE(spy.count(), indexes.size());
 
179
 
 
180
    while (!spy.isEmpty()) {
 
181
        QVariantList signal = spy.takeFirst();
 
182
 
 
183
        QCOMPARE(signal.count(), 2);
 
184
        QModelIndex begin = signal.at(0).value<QModelIndex>();
 
185
        QModelIndex end = signal.at(1).value<QModelIndex>();
 
186
 
 
187
        QVERIFY(begin.row()==end.row());
 
188
        QVERIFY(begin.parent()==end.parent());
 
189
        QCOMPARE(begin.column(), 0);
 
190
        QCOMPARE(end.column(), (int)TodoFlatModel::LastColumn);
 
191
 
 
192
        QVERIFY(indexes.contains(begin));
 
193
    }
 
194
}
 
195
 
 
196
void TodoCategoriesModelTest::testReparentModification()
 
197
{
 
198
    Akonadi::Item item = m_flatModel.itemForIndex(m_flatSortedModel.mapToSource(m_flatSortedModel.index(5, 0)));
 
199
    QModelIndexList indexes = m_model.indexesForItem(item, TodoFlatModel::Categories);
 
200
 
 
201
    QModelIndexList oldParents;
 
202
    QList<int> oldParentsRow;
 
203
    foreach (const QModelIndex &index, indexes) {
 
204
        oldParents << index.parent();
 
205
        oldParentsRow << index.row();
 
206
    }
 
207
 
 
208
    QModelIndexList newParents;
 
209
    QList<int> newParentsRow;
 
210
    newParents << m_model.indexForCategory("Errands")
 
211
               << m_model.indexForCategory("Home");
 
212
    foreach (const QModelIndex &newParent, newParents) {
 
213
        newParentsRow << m_model.rowCount(newParent);
 
214
    }
 
215
 
 
216
    QSignalSpy rowsInserted(&m_model, SIGNAL(rowsInserted(QModelIndex, int, int)));
 
217
    QSignalSpy rowsRemoved(&m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)));
 
218
 
 
219
    // Note: It includes a category "Foo" which wasn't in the model previously,
 
220
    // we should get an insert event for it too!
 
221
    QVERIFY(m_model.setData(indexes.first(), "Home, Errands, Foo"));
 
222
 
 
223
    flushNotifications();
 
224
 
 
225
    QCOMPARE(rowsRemoved.count(), 2);
 
226
    while (!rowsRemoved.isEmpty()) {
 
227
        QVariantList signal = rowsRemoved.takeFirst();
 
228
        QCOMPARE(signal.count(), 3);
 
229
 
 
230
        QModelIndex parent = signal.at(0).value<QModelIndex>();
 
231
        QVERIFY(oldParents.contains(parent));
 
232
 
 
233
        int expectedRow = oldParentsRow[oldParents.indexOf(parent)];
 
234
        QCOMPARE(signal.at(1).toInt(), expectedRow);
 
235
        QCOMPARE(signal.at(2).toInt(), expectedRow);
 
236
    }
 
237
 
 
238
    QCOMPARE(rowsInserted.count(), 4);
 
239
 
 
240
    // first insert event should be for "Foo":
 
241
    {
 
242
        QVariantList signal = rowsInserted.takeFirst();
 
243
        QCOMPARE(signal.count(), 3);
 
244
 
 
245
        QModelIndex parent = signal.at(0).value<QModelIndex>();
 
246
        QVERIFY(!parent.isValid());
 
247
 
 
248
        int expectedRow = m_model.rowCount()-1;
 
249
        QCOMPARE(signal.at(1).toInt(), expectedRow);
 
250
        QCOMPARE(signal.at(2).toInt(), expectedRow);
 
251
    }
 
252
 
 
253
    // Adjust newParents and newParentsRow to include the new "Foo" category
 
254
    newParents << m_model.index(m_model.rowCount()-1, 0);
 
255
    newParentsRow << 0;
 
256
 
 
257
    // now check the other events for the item itself
 
258
    while (!rowsInserted.isEmpty()) {
 
259
        QVariantList signal = rowsInserted.takeFirst();
 
260
        QCOMPARE(signal.count(), 3);
 
261
 
 
262
        QModelIndex parent = signal.at(0).value<QModelIndex>();
 
263
        QVERIFY(newParents.contains(parent));
 
264
 
 
265
        int expectedRow = newParentsRow[newParents.indexOf(parent)];
 
266
        QCOMPARE(signal.at(1).toInt(), expectedRow);
 
267
        QCOMPARE(signal.at(2).toInt(), expectedRow);
 
268
    }
 
269
}
 
270
 
 
271
void TodoCategoriesModelTest::testSeveralReparentModification()
 
272
{
 
273
    Akonadi::Item item = m_flatModel.itemForIndex(m_flatSortedModel.mapToSource(m_flatSortedModel.index(4, 0)));
 
274
    QModelIndexList indexes = m_model.indexesForItem(item, TodoFlatModel::Categories);
 
275
    QCOMPARE(indexes.size(), 1);
 
276
    QModelIndex index = indexes.takeFirst();
 
277
 
 
278
    QModelIndex oldParent = index.parent();
 
279
    QCOMPARE(oldParent, m_model.indexForCategory("Home"));
 
280
 
 
281
    QModelIndex newParent = m_model.indexForCategory("Errands");
 
282
 
 
283
    QSignalSpy rowsInserted(&m_model, SIGNAL(rowsInserted(QModelIndex, int, int)));
 
284
    QSignalSpy rowsRemoved(&m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)));
 
285
 
 
286
 
 
287
    QVERIFY(m_model.setData(index, "Errands"));
 
288
 
 
289
    flushNotifications();
 
290
 
 
291
    QCOMPARE(rowsRemoved.count(), 1);
 
292
    QVariantList signal = rowsRemoved.takeFirst();
 
293
    QCOMPARE(signal.count(), 3);
 
294
    QCOMPARE(signal.at(0).value<QModelIndex>(), oldParent);
 
295
    QCOMPARE(signal.at(1).toInt(), 0);
 
296
    QCOMPARE(signal.at(2).toInt(), 0);
 
297
 
 
298
    QCOMPARE(rowsInserted.count(), 1);
 
299
    signal = rowsInserted.takeFirst();
 
300
    QCOMPARE(signal.count(), 3);
 
301
    QCOMPARE(signal.at(0).value<QModelIndex>(), newParent);
 
302
    QCOMPARE(signal.at(1).toInt(), 2);
 
303
    QCOMPARE(signal.at(2).toInt(), 2);
 
304
 
 
305
 
 
306
    indexes = m_model.indexesForItem(item, TodoFlatModel::Categories);
 
307
    QCOMPARE(indexes.size(), 1);
 
308
    index = indexes.takeFirst();
 
309
 
 
310
    QVERIFY(m_model.setData(index, "Home"));
 
311
 
 
312
    flushNotifications();
 
313
 
 
314
    QCOMPARE(rowsRemoved.count(), 1);
 
315
    signal = rowsRemoved.takeFirst();
 
316
    QCOMPARE(signal.count(), 3);
 
317
    qDebug() << signal.at(0).value<QModelIndex>() << newParent;
 
318
    QCOMPARE(signal.at(0).value<QModelIndex>(), newParent);
 
319
    QCOMPARE(signal.at(1).toInt(), 2);
 
320
    QCOMPARE(signal.at(2).toInt(), 2);
 
321
 
 
322
    QCOMPARE(rowsInserted.count(), 1);
 
323
    signal = rowsInserted.takeFirst();
 
324
    QCOMPARE(signal.count(), 3);
 
325
    QCOMPARE(signal.at(0).value<QModelIndex>(), oldParent);
 
326
    QCOMPARE(signal.at(1).toInt(), 1);
 
327
    QCOMPARE(signal.at(2).toInt(), 1);
 
328
}
 
329
 
 
330
void TodoCategoriesModelTest::testSingleRemoved()
 
331
{
 
332
    Akonadi::Item item = m_flatModel.itemForIndex(m_flatSortedModel.mapToSource(m_flatSortedModel.index(4, 0)));
 
333
    QModelIndexList indexes = m_model.indexesForItem(item, TodoFlatModel::Categories);
 
334
 
 
335
    QCOMPARE(indexes.size(), 1);
 
336
    QModelIndex index = indexes.takeFirst();
 
337
    QModelIndex parent = index.parent();
 
338
    int count = m_model.rowCount(parent);
 
339
 
 
340
    QSignalSpy spy(&m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)));
 
341
 
 
342
    Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob(item);
 
343
    QVERIFY(job->exec());
 
344
 
 
345
    flushNotifications();
 
346
 
 
347
    QCOMPARE(m_model.rowCount(parent), count - 1);
 
348
 
 
349
    QCOMPARE(spy.count(), 1);
 
350
    QVariantList signal = spy.takeFirst();
 
351
    QCOMPARE(signal.count(), 3);
 
352
    QCOMPARE(signal.at(0).value<QModelIndex>(), parent);
 
353
    QCOMPARE(signal.at(1).toInt(), 1);
 
354
    QCOMPARE(signal.at(1).toInt(), 1);
 
355
}
 
356
 
 
357
void TodoCategoriesModelTest::testMultipleRemoved()
 
358
{
 
359
    Akonadi::Item item = m_flatModel.itemForIndex(m_flatSortedModel.mapToSource(m_flatSortedModel.index(4, 0)));
 
360
    QModelIndexList indexes = m_model.indexesForItem(item, TodoFlatModel::Categories);
 
361
 
 
362
    QCOMPARE(indexes.size(), 3);
 
363
    QModelIndex index = indexes.takeFirst();
 
364
    QModelIndex index2 = indexes.takeFirst();
 
365
    QModelIndex index3 = indexes.takeFirst();
 
366
 
 
367
    QModelIndex parent = index.parent();
 
368
    QModelIndex parent2 = index2.parent();
 
369
    QModelIndex parent3 = index3.parent();
 
370
    int count = m_model.rowCount(parent);
 
371
 
 
372
    QSignalSpy spy(&m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)));
 
373
 
 
374
    Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob(item);
 
375
    QVERIFY(job->exec());
 
376
 
 
377
    flushNotifications();
 
378
 
 
379
    QCOMPARE(m_model.rowCount(parent), count - 1);
 
380
 
 
381
    QCOMPARE(spy.count(), 3);
 
382
    QVariantList signal = spy.takeFirst();
 
383
    QCOMPARE(signal.count(), 3);
 
384
    QCOMPARE(signal.at(0).value<QModelIndex>(), parent);
 
385
    QCOMPARE(signal.at(1).toInt(), 0);
 
386
    QCOMPARE(signal.at(1).toInt(), 0);
 
387
 
 
388
    QCOMPARE(spy.count(), 2);
 
389
    signal = spy.takeFirst();
 
390
    QCOMPARE(signal.count(), 3);
 
391
    QCOMPARE(signal.at(0).value<QModelIndex>(), parent2);
 
392
    QCOMPARE(signal.at(1).toInt(), 1);
 
393
    QCOMPARE(signal.at(1).toInt(), 1);
 
394
 
 
395
    QCOMPARE(spy.count(), 1);
 
396
    signal = spy.takeFirst();
 
397
    QCOMPARE(signal.count(), 3);
 
398
    QCOMPARE(signal.at(0).value<QModelIndex>(), parent3);
 
399
    QCOMPARE(signal.at(1).toInt(), 0);
 
400
    QCOMPARE(signal.at(1).toInt(), 0);
 
401
}
 
402
 
 
403
void TodoCategoriesModelTest::testDragAndDrop()
 
404
{
 
405
    // move 1 item
 
406
    Akonadi::Item item = m_flatModel.itemForIndex(m_flatSortedModel.mapToSource(m_flatSortedModel.index(2, 0)));
 
407
    QModelIndexList indexes = m_model.indexesForItem(item);
 
408
    QModelIndexList catIndexes = m_model.indexesForItem(item, TodoFlatModel::Categories);
 
409
 
 
410
    QCOMPARE(indexes.size(), 1);
 
411
    QModelIndex index = indexes.first();
 
412
    QModelIndex catIndex = catIndexes.first();
 
413
    QCOMPARE(m_model.data(catIndex).toString(), QString("Errands"));
 
414
    QModelIndex parent = m_model.indexForCategory("Phone");
 
415
 
 
416
    QMimeData *mimeData = m_model.mimeData(indexes);
 
417
    QVERIFY(m_model.dropMimeData(mimeData, Qt::MoveAction, 0, 0, parent));
 
418
 
 
419
    catIndexes = m_model.indexesForItem(item, TodoFlatModel::Categories);
 
420
    QCOMPARE(m_model.data(catIndexes.first()).toString(), QString("Phone"));
 
421
 
 
422
 
 
423
    //move 2 new items
 
424
    item = m_flatModel.itemForIndex(m_flatSortedModel.mapToSource(m_flatSortedModel.index(4, 0)));
 
425
    index = m_flatModel.indexForItem(item, 0);
 
426
    catIndex = m_flatModel.indexForItem(item, TodoFlatModel::Categories);
 
427
    QCOMPARE(m_flatModel.data(catIndex).toString(), QString(""));
 
428
 
 
429
    Akonadi::Item item2 = m_flatModel.itemForIndex(m_flatSortedModel.mapToSource(m_flatSortedModel.index(5, 0)));
 
430
    QModelIndex index2 = m_flatModel.indexForItem(item2, 0);
 
431
    QModelIndex catIndex2 = m_flatModel.indexForItem(item2, TodoFlatModel::Categories);
 
432
    QCOMPARE(m_flatModel.data(catIndex2).toString(), QString(""));
 
433
 
 
434
    indexes.clear();
 
435
 
 
436
    indexes << index;
 
437
    indexes << index2;
 
438
 
 
439
    parent = m_model.indexForCategory("Office");
 
440
 
 
441
    mimeData = m_flatModel.mimeData(indexes);
 
442
    QVERIFY(m_model.dropMimeData(mimeData, Qt::MoveAction, 0, 0, parent));
 
443
 
 
444
    flushNotifications();
 
445
 
 
446
    catIndexes = m_model.indexesForItem(item, TodoFlatModel::Categories);
 
447
    QCOMPARE(m_model.data(catIndexes.first()).toString(), QString("Office"));
 
448
 
 
449
    catIndexes = m_model.indexesForItem(item2, TodoFlatModel::Categories);
 
450
    QCOMPARE(m_model.data(catIndexes.first()).toString(), QString("Office"));
 
451
}
 
452
 
 
453
void TodoCategoriesModelTest::testAddCategory_data()
 
454
{
 
455
    QTest::addColumn<QString>("name");
 
456
    QTest::addColumn<QString>("parentName");
 
457
    QTest::addColumn<bool>("expected");
 
458
 
 
459
    QTest::newRow("Adding root category") <<  "Baz" << QString() << true;
 
460
    QTest::newRow("Adding sub-category") <<  "FooBar" << "Baz" << true;
 
461
    QTest::newRow("Adding existing root category") <<  "Foo" << QString() << false;
 
462
    QTest::newRow("Adding existing category, deeper") <<  "Foo" << "Baz" << false;
 
463
}
 
464
 
 
465
void TodoCategoriesModelTest::testAddCategory()
 
466
{
 
467
    QFETCH(QString, name);
 
468
    QFETCH(QString, parentName);
 
469
    QFETCH(bool, expected);
 
470
 
 
471
    QModelIndex parent = m_model.indexForCategory(parentName);
 
472
 
 
473
    int row = m_model.rowCount(parent);
 
474
    QSignalSpy spy(&m_model, SIGNAL(rowsInserted(QModelIndex, int, int)));
 
475
 
 
476
    bool result = m_model.addCategory(name, parent);
 
477
    QCOMPARE(result, expected);
 
478
 
 
479
    flushNotifications();
 
480
 
 
481
    if (!expected) {
 
482
        QCOMPARE(spy.count(), 0);
 
483
        return;
 
484
    }
 
485
 
 
486
    QCOMPARE(spy.count(), 1);
 
487
    QVariantList signal = spy.takeFirst();
 
488
    QCOMPARE(signal.count(), 3);
 
489
    QCOMPARE(signal.at(0).value<QModelIndex>(), parent);
 
490
    QCOMPARE(signal.at(1).toInt(), row);
 
491
    QCOMPARE(signal.at(2).toInt(), row);
 
492
 
 
493
    QCOMPARE(m_model.rowCount(parent), row+1);
 
494
 
 
495
    QModelIndex index = m_model.index(row, 0, parent);
 
496
    QCOMPARE(m_model.data(index).toString(), name);
 
497
    QCOMPARE(m_model.rowCount(index), 0);
 
498
}
 
499
 
 
500
void TodoCategoriesModelTest::testCategoryRename_data()
 
501
{
 
502
    QTest::addColumn<QString>("oldName");
 
503
    QTest::addColumn<QString>("newName");
 
504
    QTest::addColumn<bool>("expected");
 
505
 
 
506
    QTest::newRow("Nominal case") <<  "Office" << "Office renamed" << true;
 
507
    QTest::newRow("Go back to original name") <<  "Office renamed" << "Office" << true;
 
508
    QTest::newRow("Invalid name") <<  "Office" << "   " << false;
 
509
    QTest::newRow("Already exists") <<  "Office" << "Home" << false;
 
510
}
 
511
 
 
512
void TodoCategoriesModelTest::testCategoryRename()
 
513
{
 
514
    QFETCH(QString, oldName);
 
515
    QFETCH(QString, newName);
 
516
    QFETCH(bool, expected);
 
517
 
 
518
    QModelIndex index = m_model.indexForCategory(oldName);
 
519
 
 
520
    QCOMPARE(m_model.data(index).toString(), oldName);
 
521
    int rowCount = m_model.rowCount(index);
 
522
    QSignalSpy spy(&m_model, SIGNAL(dataChanged(QModelIndex, QModelIndex)));
 
523
 
 
524
    bool result = m_model.setData(index, newName);
 
525
    QCOMPARE(result, expected);
 
526
    flushNotifications();
 
527
 
 
528
    if (!expected) {
 
529
        QCOMPARE(spy.count(), 0);
 
530
        return;
 
531
    }
 
532
 
 
533
    QCOMPARE(m_model.data(index).toString(), newName);
 
534
    QCOMPARE(m_model.rowCount(index), rowCount);
 
535
 
 
536
    for (int row = 0; row<rowCount; row++) {
 
537
        QModelIndex childCatIndex = index.child(row, TodoFlatModel::Categories);
 
538
        QStringList categories = m_model.data(childCatIndex).toStringList();
 
539
 
 
540
        QVERIFY(!categories.contains(oldName));
 
541
        QVERIFY(categories.contains(newName));
 
542
    }
 
543
 
 
544
    QCOMPARE(spy.count(), rowCount+1);
 
545
 
 
546
    QVariantList signal = spy.takeFirst();
 
547
    QCOMPARE(signal.size(), 2);
 
548
    QModelIndex begin = signal.first().value<QModelIndex>();
 
549
    QModelIndex end = signal.last().value<QModelIndex>();
 
550
    QCOMPARE(begin, index);
 
551
    QCOMPARE(begin.row(), end.row());
 
552
    QCOMPARE(begin.column(), 0);
 
553
    QCOMPARE(end.column(), (int)TodoFlatModel::LastColumn);
 
554
 
 
555
    for (int row = 0; row<rowCount; row++) {
 
556
        signal = spy.takeFirst();
 
557
        QCOMPARE(signal.size(), 2);
 
558
        begin = signal.first().value<QModelIndex>();
 
559
        end = signal.last().value<QModelIndex>();
 
560
        QCOMPARE(begin.parent(), index);
 
561
        QCOMPARE(begin.row(), row);
 
562
 
 
563
        QCOMPARE(begin.parent(), end.parent());
 
564
        QCOMPARE(begin.row(), end.row());
 
565
        QCOMPARE(begin.column(), 0);
 
566
        QCOMPARE(end.column(), (int)TodoFlatModel::LastColumn);
 
567
    }
 
568
}
 
569
 
 
570
void TodoCategoriesModelTest::testRemoveCategory_data()
 
571
{
 
572
    QTest::addColumn<QString>("name");
 
573
    QTest::addColumn<bool>("expected");
 
574
 
 
575
    QTest::newRow("Removing isolated category") <<  "Home" <<  true;
 
576
    QTest::newRow("Removing non existant category") <<  "Plop" <<  false;
 
577
    QTest::newRow("Removing category with sub-category") <<  "Computer" <<  true;
 
578
    QTest::newRow("Removing category with actions") <<  "Office" <<  true;
 
579
}
 
580
 
 
581
void TodoCategoriesModelTest::testRemoveCategory()
 
582
{
 
583
    QFETCH(QString, name);
 
584
    QFETCH(bool, expected);
 
585
 
 
586
    QModelIndex index = m_model.indexForCategory(name);
 
587
    QModelIndex parent = index.parent();
 
588
    int row = index.row();
 
589
 
 
590
    if (expected) {
 
591
        QCOMPARE(m_model.data(index).toString(), name);
 
592
    }
 
593
    int rowCount = m_model.rowCount(index);
 
594
    QSignalSpy spy(&m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)));
 
595
    QSignalSpy flatSpy(&m_flatModel, SIGNAL(rowsRemoved(QModelIndex, int, int)));
 
596
 
 
597
    bool result = m_model.removeCategory(name);
 
598
    QCOMPARE(result, expected);
 
599
    flushNotifications();
 
600
 
 
601
    QCOMPARE(flatSpy.count(), 0);
 
602
    if (!expected) {
 
603
        QCOMPARE(spy.count(), 0);
 
604
        return;
 
605
    }
 
606
 
 
607
    QVERIFY(!m_model.indexForCategory(name).isValid());
 
608
 
 
609
    QCOMPARE(spy.count(), rowCount+1);
 
610
 
 
611
    for (int i=0; i<rowCount; i++) {
 
612
        QVariantList signal = spy.takeFirst();
 
613
        QCOMPARE(signal.size(), 3);
 
614
        QCOMPARE(signal.at(0).value<QModelIndex>(), index);
 
615
        QCOMPARE(signal.at(1).toInt(), 0);
 
616
        QCOMPARE(signal.at(2).toInt(), 0);
 
617
    }
 
618
 
 
619
    QVariantList signal = spy.takeFirst();
 
620
    QCOMPARE(signal.size(), 3);
 
621
    QCOMPARE(signal.at(0).value<QModelIndex>(), parent);
 
622
    QCOMPARE(signal.at(1).toInt(), row);
 
623
    QCOMPARE(signal.at(2).toInt(), row);
 
624
 
 
625
}
 
626
 
 
627
void TodoCategoriesModelTest::testDnDCategory_data()
 
628
{
 
629
    QTest::addColumn<QString>("category");
 
630
    QTest::addColumn<QString>("oldParent");
 
631
    QTest::addColumn<QString>("newParent");
 
632
    QTest::addColumn<bool>("expected");
 
633
 
 
634
    QTest::newRow("Moving root category to sub-category") <<  "Phone" << QString() << "Errands" << true;
 
635
    QTest::newRow("Moving sub-category to root") <<  "Phone" << "Errands" << QString() << true;
 
636
}
 
637
void TodoCategoriesModelTest::testDnDCategory()
 
638
{
 
639
    QFETCH(QString, category);
 
640
    QFETCH(QString, oldParent);
 
641
    QFETCH(QString, newParent);
 
642
    QFETCH(bool, expected);
 
643
 
 
644
    QModelIndex index = m_model.indexForCategory(category);
 
645
    QModelIndex oldParentIndex = m_model.indexForCategory(oldParent);
 
646
    QModelIndex newParentIndex = m_model.indexForCategory(newParent);
 
647
 
 
648
    int oldRow = index.row();
 
649
    int newRow = m_model.rowCount(newParentIndex);
 
650
 
 
651
    QSignalSpy rowsInserted(&m_model, SIGNAL(rowsInserted(QModelIndex, int, int)));
 
652
    QSignalSpy rowsRemoved(&m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)));
 
653
 
 
654
    QMimeData *mimeData = m_model.mimeData(QModelIndexList() << index);
 
655
 
 
656
    bool result = m_model.dropMimeData(mimeData, Qt::MoveAction, 0, 0, newParentIndex);
 
657
    QCOMPARE(result, expected);
 
658
 
 
659
    flushNotifications();
 
660
 
 
661
    if (!expected) {
 
662
        QCOMPARE(rowsRemoved.count(), 0);
 
663
        QCOMPARE(rowsInserted.count(), 0);
 
664
        return;
 
665
    }
 
666
 
 
667
    QCOMPARE(rowsRemoved.count(), 1);
 
668
    QVariantList signal = rowsRemoved.takeFirst();
 
669
    QCOMPARE(signal.count(), 3);
 
670
    QCOMPARE(signal.at(0).value<QModelIndex>(), oldParentIndex);
 
671
    QCOMPARE(signal.at(1).toInt(), oldRow);
 
672
    QCOMPARE(signal.at(2).toInt(), oldRow);
 
673
 
 
674
 
 
675
    QCOMPARE(rowsInserted.count(), 1);
 
676
    signal = rowsInserted.takeFirst();
 
677
    QCOMPARE(signal.count(), 3);
 
678
    QCOMPARE(signal.at(0).value<QModelIndex>(), newParentIndex);
 
679
    QCOMPARE(signal.at(1).toInt(), newRow);
 
680
    QCOMPARE(signal.at(2).toInt(), newRow);
 
681
}
 
682
 
 
683
#include "todocategoriesmodeltest.moc"