File indexing completed on 2024-11-10 04:40:11

0001 /*
0002     SPDX-FileCopyrightText: 2013 Christian Mollekopf <mollekopf@kolabsys.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "changerecorder_p.h"
0008 #include "collectioncreatejob.h"
0009 #include "control.h"
0010 #include "entitytreemodel.h"
0011 #include "entitytreemodel_p.h"
0012 #include "favoritecollectionsmodel.h"
0013 #include "itemcreatejob.h"
0014 #include "monitor_p.h"
0015 #include "qtest_akonadi.h"
0016 
0017 #include <KConfigGroup>
0018 #include <KSharedConfig>
0019 
0020 #include <QObject>
0021 #include <QSortFilterProxyModel>
0022 
0023 using namespace Akonadi;
0024 
0025 class InspectableETM : public EntityTreeModel
0026 {
0027 public:
0028     explicit InspectableETM(ChangeRecorder *monitor, QObject *parent = nullptr)
0029         : EntityTreeModel(monitor, parent)
0030     {
0031     }
0032     EntityTreeModelPrivate *etmPrivate()
0033     {
0034         return d_ptr.get();
0035     }
0036     void reset()
0037     {
0038         beginResetModel();
0039         endResetModel();
0040     }
0041 };
0042 
0043 class FavoriteProxyTest : public QObject
0044 {
0045     Q_OBJECT
0046 
0047 private Q_SLOTS:
0048     void initTestCase();
0049     void testItemAdded();
0050     void testLoadConfig();
0051     void testInsertAfterModelCreation();
0052 
0053 private:
0054     InspectableETM *createETM();
0055 };
0056 
0057 void FavoriteProxyTest::initTestCase()
0058 {
0059     AkonadiTest::checkTestIsIsolated();
0060     Akonadi::Control::start();
0061     AkonadiTest::setAllResourcesOffline();
0062 }
0063 
0064 QModelIndex getIndex(const QString &string, EntityTreeModel *model)
0065 {
0066     QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, string, 1, Qt::MatchRecursive);
0067     if (list.isEmpty()) {
0068         return QModelIndex();
0069     }
0070     return list.first();
0071 }
0072 
0073 /**
0074  * Since we have no sensible way to figure out if the model is fully populated,
0075  * we use the brute force approach.
0076  */
0077 bool waitForPopulation(const QModelIndex &idx, EntityTreeModel *model, int count)
0078 {
0079     for (int i = 0; i < 500; i++) {
0080         if (model->rowCount(idx) >= count) {
0081             return true;
0082         }
0083         QTest::qWait(10);
0084     }
0085     return false;
0086 }
0087 
0088 InspectableETM *FavoriteProxyTest::createETM()
0089 {
0090     auto changeRecorder = new ChangeRecorder(this);
0091     changeRecorder->setCollectionMonitored(Collection::root());
0092     AkonadiTest::akWaitForSignal(changeRecorder, &Monitor::monitorReady);
0093     auto model = new InspectableETM(changeRecorder, this);
0094     model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation);
0095     return model;
0096 }
0097 
0098 /**
0099  * Tests that the item is being referenced when added to the favorite proxy, and dereferenced when removed.
0100  */
0101 void FavoriteProxyTest::testItemAdded()
0102 {
0103     Collection res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3")));
0104 
0105     InspectableETM *model = createETM();
0106 
0107     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("favoritecollectionsmodeltest"));
0108 
0109     auto favoriteModel = new FavoriteCollectionsModel(model, configGroup, this);
0110 
0111     const int numberOfRootCollections = 4;
0112     // Wait for initial listing to complete
0113     QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections));
0114 
0115     const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model);
0116     QVERIFY(res3Index.isValid());
0117 
0118     const auto favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0119     QVERIFY(favoriteCollection.isValid());
0120 
0121     QVERIFY(!model->etmPrivate()->isMonitored(favoriteCollection.id()));
0122 
0123     // Ensure the collection is reference counted after being added to the favorite model
0124     {
0125         favoriteModel->addCollection(favoriteCollection);
0126         // the collection is in the favorites model
0127         QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1);
0128         QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value<Akonadi::Collection::Id>(),
0129                      favoriteCollection.id());
0130         // the collection got referenced
0131         QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id()));
0132         // the collection is not yet buffered though
0133         QTRY_VERIFY(!model->etmPrivate()->isBuffered(favoriteCollection.id()));
0134     }
0135 
0136     // Survive a reset
0137     {
0138         QSignalSpy resetSpy(model, &QAbstractItemModel::modelReset);
0139         model->reset();
0140         QTRY_COMPARE(resetSpy.count(), 1);
0141         // the collection is in the favorites model
0142         QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1);
0143         QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value<Akonadi::Collection::Id>(),
0144                      favoriteCollection.id());
0145         // the collection got referenced
0146         QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id()));
0147         // the collection is not yet buffered though
0148         QTRY_VERIFY(!model->etmPrivate()->isBuffered(favoriteCollection.id()));
0149     }
0150 
0151     // Ensure the collection is no longer reference counted after being added to the favorite model, and moved to the buffer
0152     {
0153         favoriteModel->removeCollection(favoriteCollection);
0154         // moved from being reference counted to being buffered
0155         QTRY_VERIFY(model->etmPrivate()->isBuffered(favoriteCollection.id()));
0156         QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 0);
0157     }
0158 }
0159 
0160 void FavoriteProxyTest::testLoadConfig()
0161 {
0162     InspectableETM *model = createETM();
0163 
0164     const int numberOfRootCollections = 4;
0165     // Wait for initial listing to complete
0166     QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections));
0167     const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model);
0168     QVERIFY(res3Index.isValid());
0169     const auto favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0170     QVERIFY(favoriteCollection.isValid());
0171 
0172     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("favoritecollectionsmodeltest"));
0173     configGroup.writeEntry("FavoriteCollectionIds", QList<Akonadi::Collection::Id>() << favoriteCollection.id());
0174     configGroup.writeEntry("FavoriteCollectionLabels", QStringList() << QStringLiteral("label1"));
0175 
0176     auto favoriteModel = new FavoriteCollectionsModel(model, configGroup, this);
0177 
0178     {
0179         QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1);
0180         QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value<Akonadi::Collection::Id>(),
0181                      favoriteCollection.id());
0182         // the collection got referenced
0183         QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id()));
0184     }
0185 }
0186 
0187 class Filter : public QSortFilterProxyModel
0188 {
0189 public:
0190     bool filterAcceptsRow(int /*source_row*/, const QModelIndex & /*source_parent*/) const override
0191     {
0192         return accepts;
0193     }
0194     bool accepts;
0195 };
0196 
0197 void FavoriteProxyTest::testInsertAfterModelCreation()
0198 {
0199     InspectableETM *model = createETM();
0200     Filter filter;
0201     filter.accepts = false;
0202     filter.setSourceModel(model);
0203 
0204     const int numberOfRootCollections = 4;
0205     // Wait for initial listing to complete
0206     QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections));
0207     const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model);
0208     QVERIFY(res3Index.isValid());
0209     const auto favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0210     QVERIFY(favoriteCollection.isValid());
0211 
0212     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("favoritecollectionsmodeltest2"));
0213 
0214     auto favoriteModel = new FavoriteCollectionsModel(&filter, configGroup, this);
0215 
0216     // Make sure the filter is not letting anything through
0217     QTest::qWait(0);
0218     QCOMPARE(filter.rowCount(QModelIndex()), 0);
0219 
0220     // The collection is not in the model yet
0221     favoriteModel->addCollection(favoriteCollection);
0222     filter.accepts = true;
0223     filter.invalidate();
0224 
0225     {
0226         QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1);
0227         QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value<Akonadi::Collection::Id>(),
0228                      favoriteCollection.id());
0229         // the collection got referenced
0230         QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id()));
0231     }
0232 }
0233 
0234 #include "favoriteproxytest.moc"
0235 
0236 QTEST_AKONADIMAIN(FavoriteProxyTest)