File indexing completed on 2024-05-05 05:53:01
0001 /* 0002 * Copyright 2010 David Faure <faure@kde.org> 0003 * 0004 * This program is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU General Public License as 0006 * published by the Free Software Foundation; either version 2 of 0007 * the License or (at your option) version 3 or any later version 0008 * accepted by the membership of KDE e.V. (or its successor approved 0009 * by the membership of KDE e.V.), which shall act as a proxy 0010 * defined in Section 14 of version 3 of the license. 0011 * 0012 * This program is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 * GNU General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU General Public License 0018 * along with this program. If not, see <https://www.gnu.org/licenses/> 0019 */ 0020 0021 #include <KActionCollection> 0022 #include <QAction> 0023 0024 #include <KBookmarkManager> 0025 #include <QMimeData> 0026 #include <QStandardPaths> 0027 #include <QTemporaryFile> 0028 #include <QTest> 0029 0030 #include "../../kbookmarkmodel/commandhistory.h" 0031 #include "../../kbookmarkmodel/commands.h" // TODO provide public API in the model instead? 0032 #include "../../kbookmarkmodel/model.h" 0033 0034 // Return a list of all bookmark addresses or urls in a KBookmarkManager. 0035 class BookmarkLister : public KBookmarkGroupTraverser 0036 { 0037 public: 0038 BookmarkLister(const KBookmarkGroup &root) 0039 { 0040 traverse(root); 0041 } 0042 static QStringList addressList(KBookmarkManager *mgr) 0043 { 0044 BookmarkLister lister(mgr->root()); 0045 return lister.m_addressList; 0046 } 0047 static QStringList urlList(KBookmarkManager *mgr) 0048 { 0049 BookmarkLister lister(mgr->root()); 0050 return lister.m_urlList; 0051 } 0052 static QStringList titleList(KBookmarkManager *mgr) 0053 { 0054 BookmarkLister lister(mgr->root()); 0055 return lister.m_titleList; 0056 } 0057 void visit(const KBookmark &bk) override 0058 { 0059 m_addressList.append(bk.address()); 0060 m_urlList.append(bk.url().url()); 0061 m_titleList.append(bk.text()); 0062 } 0063 void visitEnter(const KBookmarkGroup &group) override 0064 { 0065 m_addressList.append(group.address() + QLatin1Char('/')); 0066 m_titleList.append(group.text()); 0067 } 0068 0069 private: 0070 QStringList m_addressList; 0071 QStringList m_urlList; 0072 QStringList m_titleList; 0073 }; 0074 0075 class KBookmarkModelTest : public QObject 0076 { 0077 Q_OBJECT 0078 public: 0079 KBookmarkModelTest() 0080 : m_collection(this) 0081 { 0082 } 0083 0084 private: 0085 private Q_SLOTS: 0086 void initTestCase() 0087 { 0088 const QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/konqueror/bookmarks.xml"); 0089 QFile::remove(filename); 0090 m_bookmarkManager = std::make_unique<KBookmarkManager>(filename); 0091 m_cmdHistory = new CommandHistory(this); 0092 m_cmdHistory->setBookmarkManager(m_bookmarkManager.get()); 0093 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList()); 0094 m_model = new KBookmarkModel(m_bookmarkManager->root(), m_cmdHistory, this); 0095 QCOMPARE(m_model->rowCount(), 1); // the toplevel "Bookmarks" toplevel item 0096 m_rootIndex = m_model->index(0, 0); 0097 QVERIFY(m_rootIndex.isValid()); 0098 QCOMPARE(m_model->rowCount(m_rootIndex), 0); 0099 m_cmdHistory->createActions(&m_collection); 0100 } 0101 0102 // The commands modify the model, so the test code uses the commands 0103 void testAddBookmark() 0104 { 0105 CreateCommand *cmd = 0106 new CreateCommand(m_model, QStringLiteral("/0"), QStringLiteral("test_bk"), QStringLiteral("www"), QUrl(QStringLiteral("https://www.kde.org"))); 0107 cmd->redo(); 0108 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList() << QStringLiteral("/0")); 0109 QCOMPARE(BookmarkLister::urlList(m_bookmarkManager.get()), QStringList() << QStringLiteral("https://www.kde.org")); 0110 QCOMPARE(m_model->rowCount(m_rootIndex), 1); 0111 cmd->undo(); 0112 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList()); 0113 QCOMPARE(m_model->rowCount(m_rootIndex), 0); 0114 delete cmd; 0115 } 0116 0117 void testDeleteBookmark() 0118 { 0119 CreateCommand *cmd = 0120 new CreateCommand(m_model, QStringLiteral("/0"), QStringLiteral("test_bk"), QStringLiteral("www"), QUrl(QStringLiteral("https://www.kde.org"))); 0121 cmd->redo(); 0122 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList() << QStringLiteral("/0")); 0123 DeleteCommand *deleteCmd = new DeleteCommand(m_model, QStringLiteral("/0")); 0124 deleteCmd->redo(); 0125 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList()); 0126 deleteCmd->undo(); 0127 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList() << QStringLiteral("/0")); 0128 deleteCmd->redo(); 0129 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList()); 0130 0131 delete cmd; 0132 delete deleteCmd; 0133 } 0134 0135 void testCreateFolder() // and test moving stuff around 0136 { 0137 CreateCommand *folderCmd = new CreateCommand(m_model, QStringLiteral("/0"), QStringLiteral("folder"), QStringLiteral("folder"), true /*open*/); 0138 m_cmdHistory->addCommand(folderCmd); // calls redo 0139 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList() << QStringLiteral("/0/")); 0140 QCOMPARE(m_model->rowCount(m_rootIndex), 1); 0141 0142 const QString kde = QStringLiteral("https://www.kde.org"); 0143 CreateCommand *cmd = new CreateCommand(m_model, QStringLiteral("/0/0"), QStringLiteral("test_bk"), QStringLiteral("www"), QUrl(kde)); 0144 m_cmdHistory->addCommand(cmd); // calls redo 0145 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList() << QStringLiteral("/0/") << QStringLiteral("/0/0")); 0146 0147 // Insert before this bookmark 0148 const QString first = QStringLiteral("https://first.example.com"); 0149 m_cmdHistory->addCommand(new CreateCommand(m_model, QStringLiteral("/0/0"), QStringLiteral("first_bk"), QStringLiteral("www"), QUrl(first))); 0150 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), 0151 QStringList() << QStringLiteral("/0/") << QStringLiteral("/0/0") << QStringLiteral("/0/1")); 0152 QCOMPARE(BookmarkLister::urlList(m_bookmarkManager.get()), QStringList() << first << kde); 0153 0154 // Move the kde bookmark before the first bookmark 0155 KBookmark kdeBookmark = m_bookmarkManager->findByAddress(QStringLiteral("/0/1")); 0156 QCOMPARE(kdeBookmark.url().url(), kde); 0157 QModelIndex kdeIndex = m_model->indexForBookmark(kdeBookmark); 0158 QCOMPARE(kdeIndex.row(), 1); 0159 QCOMPARE(m_model->rowCount(kdeIndex.parent()), 2); 0160 0161 QMimeData *mimeData = m_model->mimeData(QModelIndexList() << kdeIndex); 0162 bool ok = m_model->dropMimeData(mimeData, Qt::MoveAction, 0, 0, kdeIndex.parent()); 0163 QVERIFY(ok); 0164 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), 0165 QStringList() << QStringLiteral("/0/") << QStringLiteral("/0/0") << QStringLiteral("/0/1")); 0166 QCOMPARE(BookmarkLister::urlList(m_bookmarkManager.get()), QStringList() << kde << first); 0167 delete mimeData; 0168 0169 // Move the kde bookmark after the bookmark called 'first' 0170 kdeBookmark = m_bookmarkManager->findByAddress(QStringLiteral("/0/0")); 0171 kdeIndex = m_model->indexForBookmark(kdeBookmark); 0172 QCOMPARE(kdeIndex.row(), 0); 0173 mimeData = m_model->mimeData(QModelIndexList() << kdeIndex); 0174 ok = m_model->dropMimeData(mimeData, Qt::MoveAction, 2, 0, kdeIndex.parent()); 0175 QVERIFY(ok); 0176 QCOMPARE(BookmarkLister::urlList(m_bookmarkManager.get()), QStringList() << first << kde); 0177 delete mimeData; 0178 0179 // Create new folder, then move both bookmarks into it (#287038) 0180 m_cmdHistory->addCommand(new CreateCommand(m_model, QStringLiteral("/1"), QStringLiteral("folder2"), QStringLiteral("folder2"), true)); 0181 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), 0182 QStringList() << QStringLiteral("/0/") << QStringLiteral("/0/0") << QStringLiteral("/0/1") << QStringLiteral("/1/")); 0183 QCOMPARE(m_model->rowCount(m_rootIndex), 2); 0184 0185 moveTwoBookmarks(QStringLiteral("/0/0"), QStringLiteral("/0/1"), QStringLiteral("/1")); 0186 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), 0187 QStringList() << QStringLiteral("/0/") << QStringLiteral("/1/") << QStringLiteral("/1/0") << QStringLiteral("/1/1")); 0188 QCOMPARE(BookmarkLister::urlList(m_bookmarkManager.get()), QStringList() << kde << first); 0189 0190 // Move bookmarks from /1 into subfolder /1/2 (which will become /1/0) 0191 m_cmdHistory->addCommand(new CreateCommand(m_model, QStringLiteral("/1/2"), QStringLiteral("subfolder"), QStringLiteral("subfolder"), true)); 0192 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), 0193 QStringList() << QStringLiteral("/0/") << QStringLiteral("/1/") << QStringLiteral("/1/0") << QStringLiteral("/1/1") 0194 << QStringLiteral("/1/2/")); 0195 moveTwoBookmarks(QStringLiteral("/1/0"), QStringLiteral("/1/1"), QStringLiteral("/1/2")); 0196 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), 0197 QStringList() << QStringLiteral("/0/") << QStringLiteral("/1/") << QStringLiteral("/1/0/") << QStringLiteral("/1/0/0") 0198 << QStringLiteral("/1/0/1")); 0199 0200 // Move them up again 0201 moveTwoBookmarks(QStringLiteral("/1/0/0"), QStringLiteral("/1/0/1"), QStringLiteral("/1")); 0202 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), 0203 QStringList() << QStringLiteral("/0/") << QStringLiteral("/1/") << QStringLiteral("/1/0") << QStringLiteral("/1/1") 0204 << QStringLiteral("/1/2/")); 0205 0206 undoAll(); 0207 } 0208 0209 void testSort() 0210 { 0211 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList()); 0212 CreateCommand *folderCmd = new CreateCommand(m_model, QStringLiteral("/0"), QStringLiteral("folder"), QStringLiteral("folder"), true /*open*/); 0213 m_cmdHistory->addCommand(folderCmd); // calls redo 0214 const QString kde = QStringLiteral("https://www.kde.org"); 0215 QStringList bookmarks; 0216 bookmarks << QStringLiteral("Faure") << QStringLiteral("Web") << QStringLiteral("Kde") << QStringLiteral("Avatar") << QStringLiteral("David"); 0217 for (int i = 0; i < bookmarks.count(); ++i) { 0218 m_cmdHistory->addCommand(new CreateCommand(m_model, QStringLiteral("/0/") + QString::number(i), bookmarks[i], QStringLiteral("www"), QUrl(kde))); 0219 } 0220 const QStringList addresses = BookmarkLister::addressList(m_bookmarkManager.get()); 0221 // qCDebug(KEDITBOOKMARKS_LOG) << addresses; 0222 const QStringList origTitleList = BookmarkLister::titleList(m_bookmarkManager.get()); 0223 QCOMPARE(addresses.count(), bookmarks.count() + 1 /* parent folder */); 0224 SortCommand *sortCmd = new SortCommand(m_model, QStringLiteral("Sort"), QStringLiteral("/0")); 0225 m_cmdHistory->addCommand(sortCmd); 0226 QStringList expectedTitleList = bookmarks; 0227 expectedTitleList.sort(); 0228 expectedTitleList.prepend(QStringLiteral("folder")); 0229 const QStringList sortedTitles = BookmarkLister::titleList(m_bookmarkManager.get()); 0230 // qCDebug(KEDITBOOKMARKS_LOG) << sortedTitles; 0231 QCOMPARE(sortedTitles, expectedTitleList); 0232 0233 sortCmd->undo(); 0234 QCOMPARE(BookmarkLister::titleList(m_bookmarkManager.get()), origTitleList); 0235 sortCmd->redo(); 0236 undoAll(); 0237 } 0238 0239 void testSortBug258505() 0240 { 0241 // Given a specific set of bookmarks from XML 0242 const QString testFile(QFINDTESTDATA("kde-bug-258505-bookmarks.xml")); 0243 QVERIFY(!testFile.isEmpty()); 0244 // (copied to a temp file to avoid saving the sorted bookmarks) 0245 QFile xmlFile(testFile); 0246 QVERIFY(xmlFile.open(QIODevice::ReadOnly)); 0247 const QByteArray data = xmlFile.readAll(); 0248 QTemporaryFile tempFile; 0249 QVERIFY(tempFile.open()); 0250 const QString fileName = tempFile.fileName(); 0251 tempFile.write(data); 0252 tempFile.close(); 0253 KBookmarkManager bookmarkManager(fileName); 0254 0255 const QStringList addresses = BookmarkLister::addressList(&bookmarkManager); 0256 const QStringList origTitleList = BookmarkLister::titleList(&bookmarkManager); 0257 // qCDebug(KEDITBOOKMARKS_LOG) << addresses << origTitleList; 0258 QCOMPARE(addresses.count(), 53); 0259 0260 CommandHistory cmdHistory; 0261 cmdHistory.setBookmarkManager(&bookmarkManager); 0262 KBookmarkModel *model = new KBookmarkModel(bookmarkManager.root(), &cmdHistory, this); 0263 QCOMPARE(model->rowCount(), 1); // the toplevel "Bookmarks" toplevel item 0264 0265 // When sorting 0266 SortCommand *sortCmd = new SortCommand(model, QStringLiteral("Sort"), QStringLiteral("/0")); 0267 cmdHistory.addCommand(sortCmd); 0268 0269 // Then the contents should be correctly sorted 0270 const QStringList sortedTitles = BookmarkLister::titleList(&bookmarkManager); 0271 QCOMPARE(sortedTitles.at(0), QStringLiteral("Cyclone V")); 0272 QCOMPARE(sortedTitles.at(1), QStringLiteral("Altera SoC design courses")); 0273 QCOMPARE(sortedTitles.at(2), QStringLiteral("Hardware Design Fl...r an ARM-based SoC")); 0274 // ... 0275 0276 // And when undoing 0277 sortCmd->undo(); 0278 0279 // Then the contents should revert to the orig order 0280 QCOMPARE(BookmarkLister::titleList(&bookmarkManager), origTitleList); 0281 0282 QFile::remove(fileName + QLatin1String(".bak")); 0283 } 0284 0285 private: 0286 void moveTwoBookmarks(const QString &src1, const QString &src2, const QString &dest) 0287 { 0288 const QModelIndex firstIndex = m_model->indexForBookmark(m_bookmarkManager->findByAddress(src1)); 0289 const QModelIndex secondIndex = m_model->indexForBookmark(m_bookmarkManager->findByAddress(src2)); 0290 QMimeData *mimeData = m_model->mimeData(QModelIndexList() << firstIndex << secondIndex); 0291 QModelIndex folder2Index = m_model->indexForBookmark(m_bookmarkManager->findByAddress(dest)); 0292 QVERIFY(m_model->dropMimeData(mimeData, Qt::MoveAction, -1, 0, folder2Index)); 0293 delete mimeData; 0294 } 0295 0296 void undoAll() 0297 { 0298 QAction *undoAction = m_collection.action(KStandardAction::name(KStandardAction::Undo)); 0299 QVERIFY(undoAction); 0300 while (undoAction->isEnabled()) { 0301 undoAction->trigger(); 0302 } 0303 QCOMPARE(BookmarkLister::addressList(m_bookmarkManager.get()), QStringList()); 0304 } 0305 0306 std::unique_ptr<KBookmarkManager> m_bookmarkManager; 0307 KBookmarkModel *m_model; 0308 CommandHistory *m_cmdHistory; 0309 KActionCollection m_collection; 0310 QModelIndex m_rootIndex; // the index of the "Bookmarks" root 0311 }; 0312 0313 QTEST_MAIN(KBookmarkModelTest) 0314 0315 #include "kbookmarkmodeltest.moc"