File indexing completed on 2024-11-10 04:40:15
0001 /* 0002 SPDX-FileCopyrightText: 2016 David Faure <faure@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "statisticsproxymodel.h" 0008 #include "collection.h" 0009 #include "collectionstatistics.h" 0010 #include "entitytreemodel.h" 0011 #include "test_model_helpers.h" 0012 0013 #include <QStandardItemModel> 0014 #include <QTest> 0015 0016 using namespace TestModelHelpers; 0017 0018 using Akonadi::StatisticsProxyModel; 0019 0020 #ifndef Q_OS_WIN 0021 void initLocale() 0022 { 0023 setenv("LC_ALL", "en_US.utf-8", 1); 0024 } 0025 Q_CONSTRUCTOR_FUNCTION(initLocale) 0026 #endif 0027 0028 class StatisticsProxyModelTest : public QObject 0029 { 0030 Q_OBJECT 0031 0032 private Q_SLOTS: 0033 void initTestCase(); 0034 0035 void init(); 0036 void shouldDoNothingIfNoExtraColumns(); 0037 void shouldShowExtraColumns(); 0038 void shouldShowToolTip(); 0039 void shouldHandleDataChanged(); 0040 void shouldHandleDataChangedInExtraColumn(); 0041 0042 private: 0043 QStandardItemModel m_model; 0044 }; 0045 0046 // Helper functions 0047 0048 static QString indexToText(const QModelIndex &index) 0049 { 0050 if (!index.isValid()) { 0051 return QStringLiteral("invalid"); 0052 } 0053 return QString::number(index.row()) + QLatin1Char(',') + QString::number(index.column()) + QLatin1Char(',') 0054 + QString::number(reinterpret_cast<qulonglong>(index.internalPointer()), 16) + QLatin1StringView(" in ") 0055 + QString::number(reinterpret_cast<qulonglong>(index.model()), 16); 0056 } 0057 0058 static QString indexRowCol(const QModelIndex &index) 0059 { 0060 if (!index.isValid()) { 0061 return QStringLiteral("invalid"); 0062 } 0063 return QString::number(index.row()) + QLatin1Char(',') + QString::number(index.column()); 0064 } 0065 0066 static Akonadi::CollectionStatistics makeStats(qint64 unread, qint64 count, qint64 size) 0067 { 0068 Akonadi::CollectionStatistics stats; 0069 stats.setUnreadCount(unread); 0070 stats.setCount(count); 0071 stats.setSize(size); 0072 return stats; 0073 } 0074 0075 void StatisticsProxyModelTest::initTestCase() 0076 { 0077 } 0078 0079 void StatisticsProxyModelTest::init() 0080 { 0081 // Prepare the source model to use later on 0082 m_model.clear(); 0083 m_model.appendRow(makeStandardItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C") << QStringLiteral("D"))); 0084 m_model.item(0, 0)->appendRow(makeStandardItems(QStringList() << QStringLiteral("m") << QStringLiteral("n") << QStringLiteral("o") << QStringLiteral("p"))); 0085 m_model.item(0, 0)->appendRow(makeStandardItems(QStringList() << QStringLiteral("q") << QStringLiteral("r") << QStringLiteral("s") << QStringLiteral("t"))); 0086 m_model.appendRow(makeStandardItems(QStringList() << QStringLiteral("E") << QStringLiteral("F") << QStringLiteral("G") << QStringLiteral("H"))); 0087 m_model.item(1, 0)->appendRow(makeStandardItems(QStringList() << QStringLiteral("x") << QStringLiteral("y") << QStringLiteral("z") << QStringLiteral("."))); 0088 m_model.setHorizontalHeaderLabels(QStringList() << QStringLiteral("H1") << QStringLiteral("H2") << QStringLiteral("H3") << QStringLiteral("H4")); 0089 0090 // Set Collection c1 for row A 0091 Akonadi::Collection c1(1); 0092 c1.setName(QStringLiteral("c1")); 0093 c1.setStatistics(makeStats(2, 6, 9)); // unread, count, size in bytes 0094 m_model.item(0, 0)->setData(QVariant::fromValue(c1), Akonadi::EntityTreeModel::CollectionRole); 0095 0096 // Set Collection c2 for first child (row m) 0097 Akonadi::Collection c2(2); 0098 c2.setName(QStringLiteral("c2")); 0099 c2.setStatistics(makeStats(1, 3, 4)); // unread, count, size in bytes 0100 m_model.item(0, 0)->child(0)->setData(QVariant::fromValue(c2), Akonadi::EntityTreeModel::CollectionRole); 0101 0102 // Set Collection c2 for first child (row m) 0103 Akonadi::Collection c3(3); 0104 c3.setName(QStringLiteral("c3")); 0105 c3.setStatistics(makeStats(0, 1, 1)); // unread, count, size in bytes 0106 m_model.item(0, 0)->child(1)->setData(QVariant::fromValue(c3), Akonadi::EntityTreeModel::CollectionRole); 0107 0108 QCOMPARE(extractRowTexts(&m_model, 0), QStringLiteral("ABCD")); 0109 QCOMPARE(extractRowTexts(&m_model, 0, m_model.index(0, 0)), QStringLiteral("mnop")); 0110 QCOMPARE(extractRowTexts(&m_model, 1, m_model.index(0, 0)), QStringLiteral("qrst")); 0111 QCOMPARE(extractRowTexts(&m_model, 1), QStringLiteral("EFGH")); 0112 QCOMPARE(extractRowTexts(&m_model, 0, m_model.index(1, 0)), QStringLiteral("xyz.")); 0113 QCOMPARE(extractHorizontalHeaderTexts(&m_model), QStringLiteral("H1H2H3H4")); 0114 } 0115 0116 void StatisticsProxyModelTest::shouldDoNothingIfNoExtraColumns() 0117 { 0118 // Given a statistics proxy with no extra columns 0119 StatisticsProxyModel pm; 0120 pm.setExtraColumnsEnabled(false); 0121 0122 // When setting it to a source model 0123 pm.setSourceModel(&m_model); 0124 0125 // Then the proxy should show the same as the model 0126 QCOMPARE(pm.rowCount(), m_model.rowCount()); 0127 QCOMPARE(pm.columnCount(), m_model.columnCount()); 0128 0129 QCOMPARE(pm.rowCount(pm.index(0, 0)), 2); 0130 QCOMPARE(pm.index(0, 0).parent(), QModelIndex()); 0131 0132 // (verify that the mapFromSource(mapToSource(x)) == x roundtrip works) 0133 for (int row = 0; row < pm.rowCount(); ++row) { 0134 for (int col = 0; col < pm.columnCount(); ++col) { 0135 QCOMPARE(pm.mapFromSource(pm.mapToSource(pm.index(row, col))), pm.index(row, col)); 0136 } 0137 } 0138 0139 QCOMPARE(extractRowTexts(&pm, 0), QStringLiteral("ABCD")); 0140 QCOMPARE(extractRowTexts(&pm, 0, pm.index(0, 0)), QStringLiteral("mnop")); 0141 QCOMPARE(extractRowTexts(&pm, 1, pm.index(0, 0)), QStringLiteral("qrst")); 0142 QCOMPARE(extractRowTexts(&pm, 1), QStringLiteral("EFGH")); 0143 QCOMPARE(extractRowTexts(&pm, 0, pm.index(1, 0)), QStringLiteral("xyz.")); 0144 QCOMPARE(extractHorizontalHeaderTexts(&pm), QStringLiteral("H1H2H3H4")); 0145 } 0146 0147 void StatisticsProxyModelTest::shouldShowExtraColumns() 0148 { 0149 // Given a extra-columns proxy with three extra columns 0150 StatisticsProxyModel pm; 0151 0152 // When setting it to a source model 0153 pm.setSourceModel(&m_model); 0154 0155 // Then the proxy should show the extra column 0156 QCOMPARE(extractRowTexts(&pm, 0), QStringLiteral("ABCD269 B")); 0157 QCOMPARE(extractRowTexts(&pm, 0, pm.index(0, 0)), QStringLiteral("mnop134 B")); 0158 QCOMPARE(extractRowTexts(&pm, 1, pm.index(0, 0)), QStringLiteral("qrst 11 B")); 0159 QCOMPARE(extractRowTexts(&pm, 1), QStringLiteral("EFGH ")); 0160 QCOMPARE(extractRowTexts(&pm, 0, pm.index(1, 0)), QStringLiteral("xyz. ")); 0161 QCOMPARE(extractHorizontalHeaderTexts(&pm), QStringLiteral("H1H2H3H4UnreadTotalSize")); 0162 0163 // Verify tree structure of proxy 0164 const QModelIndex secondParent = pm.index(1, 0); 0165 QVERIFY(!secondParent.parent().isValid()); 0166 QCOMPARE(indexToText(pm.index(0, 0, secondParent).parent()), indexToText(secondParent)); 0167 QCOMPARE(indexToText(pm.index(0, 3, secondParent).parent()), indexToText(secondParent)); 0168 QVERIFY(indexToText(pm.index(0, 4)).startsWith(QLatin1StringView("0,4,"))); 0169 QCOMPARE(indexToText(pm.index(0, 4, secondParent).parent()), indexToText(secondParent)); 0170 QVERIFY(indexToText(pm.index(0, 5)).startsWith(QLatin1StringView("0,5,"))); 0171 QCOMPARE(indexToText(pm.index(0, 5, secondParent).parent()), indexToText(secondParent)); 0172 0173 QCOMPARE(pm.index(0, 0).sibling(0, 4).column(), 4); 0174 QCOMPARE(pm.index(0, 4).sibling(0, 1).column(), 1); 0175 0176 QVERIFY(!pm.canFetchMore(QModelIndex())); 0177 } 0178 0179 void StatisticsProxyModelTest::shouldShowToolTip() 0180 { 0181 // Given a extra-columns proxy with three extra columns 0182 StatisticsProxyModel pm; 0183 pm.setSourceModel(&m_model); 0184 0185 // When enabling tooltips and getting the tooltip for the first folder 0186 pm.setToolTipEnabled(true); 0187 QString toolTip = pm.index(0, 0).data(Qt::ToolTipRole).toString(); 0188 0189 // Then the tooltip should contain the expected information 0190 toolTip.remove(QStringLiteral("<strong>")); 0191 toolTip.remove(QStringLiteral("</strong>")); 0192 QVERIFY2(toolTip.contains(QLatin1StringView("Total Messages: 6")), qPrintable(toolTip)); 0193 QVERIFY2(toolTip.contains(QLatin1StringView("Unread Messages: 2")), qPrintable(toolTip)); 0194 QVERIFY2(toolTip.contains(QLatin1StringView("Storage Size: 9 B")), qPrintable(toolTip)); 0195 QVERIFY2(toolTip.contains(QLatin1StringView("Subfolder Storage Size: 5 B")), qPrintable(toolTip)); 0196 } 0197 0198 void StatisticsProxyModelTest::shouldHandleDataChanged() 0199 { 0200 // Given a extra-columns proxy with three extra columns 0201 StatisticsProxyModel pm; 0202 pm.setSourceModel(&m_model); 0203 QSignalSpy dataChangedSpy(&pm, &QAbstractItemModel::dataChanged); 0204 0205 // When ETM says the collection changed 0206 m_model.item(0, 0)->setData(QStringLiteral("a"), Qt::EditRole); 0207 0208 // Then the change should be notified to the proxy -- including the extra columns 0209 QCOMPARE(dataChangedSpy.count(), 1); 0210 QCOMPARE(indexRowCol(dataChangedSpy.at(0).at(0).toModelIndex()), QStringLiteral("0,0")); 0211 QCOMPARE(indexRowCol(dataChangedSpy.at(0).at(1).toModelIndex()), QStringLiteral("0,6")); 0212 QCOMPARE(extractRowTexts(&pm, 0), QStringLiteral("aBCD269 B")); 0213 } 0214 0215 void StatisticsProxyModelTest::shouldHandleDataChangedInExtraColumn() 0216 { 0217 // Given a extra-columns proxy with three extra columns 0218 StatisticsProxyModel pm; 0219 pm.setSourceModel(&m_model); 0220 QSignalSpy dataChangedSpy(&pm, &QAbstractItemModel::dataChanged); 0221 0222 // When the proxy wants to signal a change in an extra column 0223 Akonadi::Collection c1(1); 0224 c1.setName(QStringLiteral("c1")); 0225 c1.setStatistics(makeStats(3, 5, 8)); // changed: unread, count, size in bytes 0226 0227 // trick QStandardItemModel into noticing something changed here 0228 m_model.item(0, 0)->setData(QVariant::fromValue(Akonadi::Collection()), Akonadi::EntityTreeModel::CollectionRole); 0229 dataChangedSpy.clear(); 0230 m_model.item(0, 0)->setData(QVariant::fromValue(c1), Akonadi::EntityTreeModel::CollectionRole); 0231 0232 // Then the change should be available and notified 0233 QCOMPARE(extractRowTexts(&pm, 0), QStringLiteral("ABCD358 B")); 0234 QCOMPARE(dataChangedSpy.count(), 1); 0235 QCOMPARE(indexRowCol(dataChangedSpy.at(0).at(0).toModelIndex()), QStringLiteral("0,0")); 0236 QCOMPARE(indexRowCol(dataChangedSpy.at(0).at(1).toModelIndex()), QStringLiteral("0,6")); 0237 } 0238 0239 #include "statisticsproxymodeltest.moc" 0240 0241 QTEST_MAIN(StatisticsProxyModelTest)