File indexing completed on 2025-01-26 05:06:20
0001 /* 0002 SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.com> 0003 SPDX-FileCopyrightText: Andras Mantia <andras.mantia@kdab.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "positionertest.h" 0009 0010 #include <QSignalSpy> 0011 #include <QTemporaryDir> 0012 #include <QTest> 0013 0014 #include "foldermodel.h" 0015 #include "positioner.h" 0016 #include "screenmapper.h" 0017 0018 QTEST_MAIN(PositionerTest) 0019 0020 static const QLatin1String desktop(QLatin1String("Desktop")); 0021 0022 void PositionerTest::initTestCase() 0023 { 0024 m_currentActivity = QStringLiteral("00000000-0000-0000-0000-000000000000"); 0025 m_folderDir = new QTemporaryDir(); 0026 0027 QDir dir(m_folderDir->path()); 0028 dir.mkdir(desktop); 0029 dir.cd(desktop); 0030 dir.mkdir(QStringLiteral("firstDir")); 0031 QFile f; 0032 for (int i = 1; i < 10; i++) { 0033 f.setFileName(QStringLiteral("%1/file%2.txt").arg(dir.path(), QString::number(i))); 0034 f.open(QFile::WriteOnly); 0035 f.close(); 0036 } 0037 } 0038 0039 void PositionerTest::cleanupTestCase() 0040 { 0041 delete m_folderDir; 0042 } 0043 0044 void PositionerTest::init() 0045 { 0046 m_folderModel = new FolderModel(this); 0047 m_folderModel->classBegin(); 0048 m_folderModel->setScreen(0); 0049 m_folderModel->setUsedByContainment(true); 0050 m_folderModel->componentComplete(); 0051 m_positioner = new Positioner(this); 0052 m_positioner->setEnabled(true); 0053 m_positioner->setFolderModel(m_folderModel); 0054 m_positioner->setPerStripe(3); 0055 0056 m_folderModel->setUrl(m_folderDir->path() + QDir::separator() + desktop); 0057 QSignalSpy s(m_folderModel, &FolderModel::listingCompleted); 0058 s.wait(1000); 0059 } 0060 0061 void PositionerTest::cleanup() 0062 { 0063 delete m_folderModel; 0064 m_folderModel = nullptr; 0065 delete m_positioner; 0066 m_positioner = nullptr; 0067 } 0068 0069 void PositionerTest::tst_positions_data() 0070 { 0071 QTest::addColumn<int>("perStripe"); 0072 QTest::newRow("3 per column") << 3; 0073 QTest::newRow("5 per column") << 5; 0074 } 0075 0076 void PositionerTest::tst_positions() 0077 { 0078 QFETCH(int, perStripe); 0079 m_positioner->setPerStripe(perStripe); 0080 checkPositions(perStripe); 0081 } 0082 0083 void PositionerTest::tst_map() 0084 { 0085 // by default the mapping is 1-1 0086 for (int i = 0; i < m_positioner->rowCount(); i++) { 0087 QCOMPARE(m_positioner->map(i), i); 0088 } 0089 } 0090 0091 void PositionerTest::tst_move_data() 0092 { 0093 QTest::addColumn<QVariantList>("moves"); 0094 QTest::addColumn<QList<int>>("result"); 0095 QTest::newRow("First to last") << QVariantList({0, 10}) << QList<int>({-1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}); 0096 QTest::newRow("First to after last") << QVariantList({0, 11}) << QList<int>({-1, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, 0}); 0097 QTest::newRow("Switch 2nd with 3rd ") << QVariantList({1, 2, 2, 1}) << QList<int>({0, 2, 1, 3, 4, 5, 6, 7, 8, 9}); 0098 QTest::newRow("Switch 2nd with 2nd ") << QVariantList({1, 1, 1, 1}) << QList<int>({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); 0099 QTest::newRow("2nd to last") << QVariantList({2, 10}) << QList<int>({0, 1, -1, 3, 4, 5, 6, 7, 8, 9, 2}); 0100 } 0101 0102 void PositionerTest::tst_move() 0103 { 0104 QFETCH(QVariantList, moves); 0105 QFETCH(QList<int>, result); 0106 0107 ensureFolderModelReady(); 0108 m_positioner->move(moves); 0109 for (int i = 0; i < m_positioner->rowCount(); i++) { 0110 QCOMPARE(m_positioner->map(i), result[i]); 0111 } 0112 } 0113 0114 void PositionerTest::tst_nearestitem_data() 0115 { 0116 QTest::addColumn<int>("index"); 0117 QTest::addColumn<QList<int>>("result"); 0118 QTest::newRow("Around first") << 0 << QList<int>{-1, -1, 3, -1, 1}; 0119 QTest::newRow("Around second") << 1 << QList<int>{-1, -1, 4, 0, 2}; 0120 QTest::newRow("Around 5th") << 4 << QList<int>{-1, 1, 7, 3, 5}; 0121 QTest::newRow("Around last") << 9 << QList<int>{-1, 6, -1, -1, 7}; 0122 QTest::newRow("Around invalid") << 11 << QList<int>{-1, -1, -1, -1, -1}; 0123 } 0124 0125 void PositionerTest::tst_nearestitem() 0126 { 0127 QFETCH(int, index); 0128 QFETCH(QList<int>, result); 0129 for (int i = Qt::NoArrow; i <= Qt::RightArrow; i++) { 0130 QCOMPARE(m_positioner->nearestItem(index, (Qt::ArrowType)i), result[i]); 0131 } 0132 } 0133 0134 void PositionerTest::tst_isBlank() 0135 { 0136 QCOMPARE(m_positioner->isBlank(0), false); 0137 QCOMPARE(m_positioner->isBlank(11), true); 0138 m_positioner->move({0, 10}); 0139 QCOMPARE(m_positioner->isBlank(0), true); 0140 } 0141 0142 void PositionerTest::tst_reset() 0143 { 0144 ensureFolderModelReady(); 0145 m_positioner->move({0, 10}); 0146 m_positioner->reset(); 0147 QSignalSpy s(m_positioner, &Positioner::positionsChanged); 0148 s.wait(500); 0149 QCOMPARE(s.count(), 1); 0150 checkPositions(3); 0151 0152 for (int i = 0; i < m_positioner->rowCount(); i++) { 0153 QCOMPARE(m_positioner->map(i), i); 0154 } 0155 } 0156 0157 void PositionerTest::tst_defaultValues() 0158 { 0159 Positioner positioner; 0160 QVERIFY(!positioner.enabled()); 0161 QVERIFY(!positioner.folderModel()); 0162 QCOMPARE(positioner.perStripe(), 0); 0163 QVERIFY(positioner.positions().isEmpty()); 0164 } 0165 0166 void PositionerTest::tst_changeEnabledStatus() 0167 { 0168 Positioner positioner; 0169 QVERIFY(!positioner.enabled()); 0170 QSignalSpy s(&positioner, &Positioner::enabledChanged); 0171 positioner.setEnabled(true); 0172 QCOMPARE(s.count(), 1); 0173 0174 positioner.setEnabled(false); 0175 QCOMPARE(s.count(), 2); 0176 0177 // No change 0178 positioner.setEnabled(false); 0179 QCOMPARE(s.count(), 2); 0180 } 0181 0182 void PositionerTest::tst_changePerStripe() 0183 { 0184 Positioner positioner; 0185 QCOMPARE(positioner.perStripe(), 0); 0186 QSignalSpy s(&positioner, &Positioner::perStripeChanged); 0187 positioner.setPerStripe(1); 0188 QCOMPARE(s.count(), 1); 0189 0190 // No change 0191 positioner.setPerStripe(1); 0192 QCOMPARE(s.count(), 1); 0193 0194 positioner.setPerStripe(4); 0195 QCOMPARE(s.count(), 2); 0196 } 0197 0198 void PositionerTest::tst_proxyMapping() 0199 { 0200 auto *screenMapper = ScreenMapper::instance(); 0201 FolderModel secondFolderModel; 0202 secondFolderModel.classBegin(); 0203 secondFolderModel.setUrl(m_folderDir->path() + QDir::separator() + desktop); 0204 secondFolderModel.setUsedByContainment(true); 0205 secondFolderModel.setScreen(1); 0206 secondFolderModel.componentComplete(); 0207 Positioner secondPositioner; 0208 secondPositioner.setEnabled(true); 0209 secondPositioner.setFolderModel(&secondFolderModel); 0210 secondPositioner.setPerStripe(3); 0211 0212 QSignalSpy s2(&secondFolderModel, &FolderModel::listingCompleted); 0213 QVERIFY(s2.wait(1000)); 0214 0215 QHash<int, int> expectedSource2ProxyScreen0; 0216 QHash<int, int> expectedProxy2SourceScreen0; 0217 QHash<int, int> expectedProxy2SourceScreen1; 0218 QHash<int, int> expectedSource2ProxyScreen1; 0219 0220 for (int i = 0; i < m_folderModel->rowCount(); i++) { 0221 expectedSource2ProxyScreen0[i] = i; 0222 expectedProxy2SourceScreen0[i] = i; 0223 } 0224 0225 // swap items 1 and 2 in the positioner 0226 m_positioner->move({1, 2, 2, 1}); 0227 expectedSource2ProxyScreen0[1] = 2; 0228 expectedSource2ProxyScreen0[2] = 1; 0229 expectedProxy2SourceScreen0[1] = 2; 0230 expectedProxy2SourceScreen0[2] = 1; 0231 0232 auto savedSource2ProxyScreen0 = expectedSource2ProxyScreen0; 0233 auto savedProxy2SourceScreen0 = expectedProxy2SourceScreen0; 0234 0235 auto verifyMapping = [](const QHash<int, int> &actual, const QHash<int, int> &expected) { 0236 auto ensureUnique = [](const QHash<int, int> mapping) { 0237 auto values = mapping.values(); 0238 std::sort(values.begin(), values.end()); 0239 auto uniqueValues = values; 0240 uniqueValues.erase(std::unique(uniqueValues.begin(), uniqueValues.end()), uniqueValues.end()); 0241 std::sort(uniqueValues.begin(), uniqueValues.end()); 0242 QVERIFY(uniqueValues == values); 0243 }; 0244 0245 ensureUnique(actual); 0246 QCOMPARE(actual, expected); 0247 }; 0248 0249 verifyMapping(m_positioner->proxyToSourceMapping(), expectedProxy2SourceScreen0); 0250 verifyMapping(m_positioner->sourceToProxyMapping(), expectedSource2ProxyScreen0); 0251 verifyMapping(secondPositioner.proxyToSourceMapping(), expectedProxy2SourceScreen1); 0252 verifyMapping(secondPositioner.sourceToProxyMapping(), expectedSource2ProxyScreen1); 0253 0254 const auto movedItem = m_folderModel->index(1, 0).data(FolderModel::UrlRole).toUrl(); 0255 0256 // move the item 1 from source (now in position 2) to the second screen 0257 screenMapper->addMapping(movedItem, 1, m_currentActivity); 0258 0259 expectedProxy2SourceScreen1[0] = 0; 0260 expectedSource2ProxyScreen1[0] = 0; 0261 expectedSource2ProxyScreen0.clear(); 0262 expectedProxy2SourceScreen0.clear(); 0263 for (int i = 0; i < m_folderModel->rowCount(); i++) { 0264 // as item 1 disappeared, the mapping of all items after that are shifted 0265 auto proxyIndex = (i <= 1) ? i : i + 1; 0266 expectedProxy2SourceScreen0[proxyIndex] = i; 0267 expectedSource2ProxyScreen0[i] = proxyIndex; 0268 } 0269 0270 verifyMapping(m_positioner->proxyToSourceMapping(), expectedProxy2SourceScreen0); 0271 verifyMapping(m_positioner->sourceToProxyMapping(), expectedSource2ProxyScreen0); 0272 verifyMapping(secondPositioner.proxyToSourceMapping(), expectedProxy2SourceScreen1); 0273 verifyMapping(secondPositioner.sourceToProxyMapping(), expectedSource2ProxyScreen1); 0274 0275 // move back the same item to the first screen 0276 screenMapper->addMapping(movedItem, 0, m_currentActivity); 0277 0278 // nothing on the second screen 0279 expectedSource2ProxyScreen1.clear(); 0280 expectedProxy2SourceScreen1.clear(); 0281 // first screen should look like in the beginning 0282 expectedSource2ProxyScreen0 = savedSource2ProxyScreen0; 0283 expectedProxy2SourceScreen0 = savedProxy2SourceScreen0; 0284 0285 verifyMapping(m_positioner->proxyToSourceMapping(), expectedProxy2SourceScreen0); 0286 verifyMapping(m_positioner->sourceToProxyMapping(), expectedSource2ProxyScreen0); 0287 verifyMapping(secondPositioner.proxyToSourceMapping(), expectedProxy2SourceScreen1); 0288 verifyMapping(secondPositioner.sourceToProxyMapping(), expectedSource2ProxyScreen1); 0289 } 0290 0291 void PositionerTest::checkPositions(int perStripe) 0292 { 0293 ensureFolderModelReady(); 0294 0295 QSignalSpy s(m_positioner, &Positioner::positionsChanged); 0296 s.wait(); 0297 0298 const auto positions = m_positioner->positions(); 0299 struct Pos { 0300 int x; 0301 int y; 0302 }; 0303 const auto fileCount = m_folderModel->rowCount(); 0304 QHash<QString, Pos> posHash; 0305 QCOMPARE(positions[0].toInt(), 1 + ((fileCount - 1) / perStripe)); // rows 0306 QCOMPARE(positions[1].toInt(), perStripe); // columns 0307 for (int i = 2; i < positions.length() - 2; i += 3) { 0308 posHash[positions[i]] = {positions[i + 1].toInt(), positions[i + 2].toInt()}; 0309 } 0310 0311 int row = 0; 0312 int col = 0; 0313 for (int i = 0; i < fileCount; i++) { 0314 const auto index = m_folderModel->index(i, 0); 0315 const auto url = index.data(FolderModel::UrlRole).toString(); 0316 const Pos pos = posHash[url]; 0317 QCOMPARE(pos.x, row); 0318 QCOMPARE(pos.y, col); 0319 col++; 0320 if (col == perStripe) { 0321 row++; 0322 col = 0; 0323 } 0324 } 0325 } 0326 0327 void PositionerTest::ensureFolderModelReady() 0328 { 0329 if (m_folderModel->status() == FolderModel::Listing) { 0330 QSignalSpy folderModelReadySpy(m_folderModel, &FolderModel::statusChanged); 0331 QVERIFY(folderModelReadySpy.wait()); 0332 } 0333 }