1 /* This file is part of KDE
2 SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #undef QT_NO_CAST_FROM_ASCII
8
9 #include "konqpopupmenutest.h"
10
11 #include <kconfiggroup.h>
12 #include <kbookmarkmanager.h>
13 #include <KSharedConfig>
14 #include <knewfilemenu.h>
15 #include <kfileitemlistproperties.h>
16
17 #include <QTest>
18 #include <QDebug>
19 #include <QDir>
20 #include <QUrl>
21 #include <QStandardPaths>
22
QTEST_MAIN(KonqPopupMenuTest)23 QTEST_MAIN(KonqPopupMenuTest)
24
25 KonqPopupMenuTest::KonqPopupMenuTest()
26 : m_actionCollection(this)
27 {
28 m_appFlags = KonqPopupMenu::NoPlugins;
29 }
30
extractActionNames(QMenu & menu)31 static QStringList extractActionNames(QMenu &menu)
32 {
33 menu.aboutToShow(); // signals are now public in Qt5, how convenient :-)
34
35 QString lastObjectName;
36 QStringList ret;
37 bool lastIsSeparator = false;
38 foreach (const QAction *action, menu.actions()) {
39 if (action->isSeparator()) {
40 if (!lastIsSeparator) { // Qt gets rid of duplicate separators, so we should too
41 ret.append(QStringLiteral("separator"));
42 }
43 lastIsSeparator = true;
44 } else {
45 lastIsSeparator = false;
46 //qDebug() << action->objectName() << action->metaObject()->className() << action->text();
47 const QString objectName = action->objectName();
48 if (objectName.isEmpty()) {
49 if (action->menu()) { // if this fails, then we have an unnamed action somewhere...
50 ret.append(QStringLiteral("submenu"));
51 } else {
52 ret.append("UNNAMED " + action->text());
53 }
54 } else {
55 if (objectName == QLatin1String("menuaction") // a single service-menu action, or a service-menu submenu: skip; too variable.
56 || objectName == QLatin1String("actions_submenu")) {
57 } else if (objectName == QLatin1String("openWith_submenu")) {
58 ret.append(QStringLiteral("openwith"));
59 } else if (objectName == QLatin1String("openwith_browse") && lastObjectName == QLatin1String("openwith")) {
60 // We had "open with foo" followed by openwith_browse, all is well.
61 // The expected lists only say "openwith" so that they work in both cases
62 // -> skip the browse action.
63 } else {
64 ret.append(objectName);
65 }
66 }
67 }
68 lastObjectName = action->objectName();
69 }
70 return ret;
71
72 }
73
initTestCase()74 void KonqPopupMenuTest::initTestCase()
75 {
76 QStandardPaths::setTestModeEnabled(true);
77
78 KSharedConfig::Ptr dolphin = KSharedConfig::openConfig(QStringLiteral("dolphinrc"));
79 KConfigGroup(dolphin, "General").writeEntry("ShowCopyMoveMenu", true);
80
81 m_thisDirectoryItem = KFileItem(QUrl::fromLocalFile(QDir::currentPath()), QStringLiteral("inode/directory"), S_IFDIR + 0777);
82 const QString makefile = QCoreApplication::applicationDirPath() + "/../Makefile";
83 QVERIFY2(QFile::exists(makefile), qPrintable(makefile));
84 m_fileItem = KFileItem(QUrl::fromLocalFile(makefile), QStringLiteral("text/x-makefile"), S_IFREG + 0660);
85 m_linkItem = KFileItem(QUrl::fromLocalFile(QStringLiteral("http://www.kde.org/foo")), QStringLiteral("text/html"), S_IFREG + 0660);
86 m_subDirItem = KFileItem(QUrl::fromLocalFile(QDir::currentPath() + "/CMakeFiles"), QStringLiteral("inode/directory"), S_IFDIR + 0755);
87 m_cut = KStandardAction::cut(nullptr, nullptr, this);
88 m_actionCollection.addAction(QStringLiteral("cut"), m_cut);
89 m_copy = KStandardAction::copy(nullptr, nullptr, this);
90 m_actionCollection.addAction(QStringLiteral("copy"), m_copy);
91 m_paste = KStandardAction::paste(nullptr, nullptr, this);
92 m_actionCollection.addAction(QStringLiteral("paste"), m_paste);
93 m_pasteTo = KStandardAction::paste(nullptr, nullptr, this);
94 m_actionCollection.addAction(QStringLiteral("pasteto"), m_pasteTo);
95 m_properties = new QAction(this);
96 m_actionCollection.addAction(QStringLiteral("properties"), m_properties);
97
98 m_tabHandlingActions = new QActionGroup(this);
99 m_newWindow = new QAction(m_tabHandlingActions);
100 m_actionCollection.addAction(QStringLiteral("openInNewWindow"), m_newWindow);
101 m_newTab = new QAction(m_tabHandlingActions);
102 m_actionCollection.addAction(QStringLiteral("openInNewTab"), m_newTab);
103 QAction *separator = new QAction(m_tabHandlingActions);
104 separator->setSeparator(true);
105 QCOMPARE(m_tabHandlingActions->actions().count(), 3);
106
107 m_previewActions = new QActionGroup(this);
108 m_preview1 = new QAction(m_previewActions);
109 m_actionCollection.addAction(QStringLiteral("preview1"), m_preview1);
110 m_preview2 = new QAction(m_previewActions);
111 m_actionCollection.addAction(QStringLiteral("preview2"), m_preview2);
112
113 m_fileEditActions = new QActionGroup(this);
114 m_rename = new QAction(m_fileEditActions);
115 m_actionCollection.addAction(QStringLiteral("rename"), m_rename);
116 m_trash = new QAction(m_fileEditActions);
117 m_actionCollection.addAction(QStringLiteral("trash"), m_trash);
118
119 m_htmlEditActions = new QActionGroup(this);
120 // TODO use m_htmlEditActions like in khtml (see khtml_popupmenu.rc)
121
122 m_linkActions = new QActionGroup(this);
123 QAction *saveLinkAs = new QAction(m_linkActions);
124 m_actionCollection.addAction(QStringLiteral("savelinkas"), saveLinkAs);
125 QAction *copyLinkLocation = new QAction(m_linkActions);
126 m_actionCollection.addAction(QStringLiteral("copylinklocation"), copyLinkLocation);
127 // TODO there's a whole bunch of things for frames, and for images, see khtml_popupmenu.rc
128
129 m_partActions = new QActionGroup(this);
130 separator = new QAction(m_partActions);
131 separator->setSeparator(true);
132 m_partActions->addAction(separator); // we better start with a separator
133 QAction *viewDocumentSource = new QAction(m_partActions);
134 m_actionCollection.addAction(QStringLiteral("viewDocumentSource"), viewDocumentSource);
135
136 m_newMenu = new KNewFileMenu(&m_actionCollection, QStringLiteral("newmenu"), nullptr);
137
138 // Check if extractActionNames works
139 QMenu popup;
140 popup.addAction(m_rename);
141 QMenu *subMenu = new QMenu(&popup);
142 popup.addMenu(subMenu);
143 subMenu->addAction(m_trash);
144 QStringList actions = extractActionNames(popup);
145 qDebug() << actions;
146 QCOMPARE(actions, QStringList() << "rename" << "submenu");
147 }
148
testFile()149 void KonqPopupMenuTest::testFile()
150 {
151 KFileItemList itemList;
152 itemList << m_fileItem;
153 QUrl viewUrl = QUrl::fromLocalFile(QDir::currentPath());
154 const KonqPopupMenu::Flags flags = m_appFlags
155 | KonqPopupMenu::ShowProperties
156 | KonqPopupMenu::ShowUrlOperations;
157 KonqPopupMenu::ActionGroupMap actionGroups;
158 actionGroups.insert(KonqPopupMenu::TabHandlingActions, m_tabHandlingActions->actions());
159 actionGroups.insert(KonqPopupMenu::EditActions, m_fileEditActions->actions());
160 actionGroups.insert(KonqPopupMenu::PreviewActions, QList<QAction *>() << m_preview1);
161
162 KonqPopupMenu popup(itemList, viewUrl, m_actionCollection, flags,
163 nullptr /*parent*/);
164 popup.setNewFileMenu(m_newMenu);
165 popup.setActionGroups(actionGroups);
166
167 QStringList actions = extractActionNames(popup);
168 actions.removeAll(QStringLiteral("services_submenu"));
169
170 // Be tolerant with openwith, it could be there once or twice
171 if (actions.count(QStringLiteral("openwith")) == 2) {
172 actions.removeOne(QStringLiteral("openwith"));
173 }
174 qDebug() << actions;
175 QStringList expectedActions;
176 expectedActions << QStringLiteral("openInNewWindow") << QStringLiteral("openInNewTab") << QStringLiteral("separator")
177 << QStringLiteral("cut") << QStringLiteral("copy") << QStringLiteral("rename") << QStringLiteral("trash")
178 << QStringLiteral("openwith")
179 << QStringLiteral("separator")
180 << QStringLiteral("preview1");
181 expectedActions << QStringLiteral("separator");
182 expectedActions << QStringLiteral("copyTo_submenu") << QStringLiteral("moveTo_submenu") << QStringLiteral("separator");
183 // (came from arkplugin) << "compress"
184 expectedActions << QStringLiteral("properties");
185 qDebug() << "Expected:" << expectedActions;
186 QCOMPARE(actions, expectedActions);
187 }
188
testFileInReadOnlyDirectory()189 void KonqPopupMenuTest::testFileInReadOnlyDirectory()
190 {
191 const KFileItem item(QUrl::fromLocalFile(QStringLiteral("/etc/passwd")));
192 KFileItemList itemList;
193 itemList << item;
194
195 KFileItemListProperties capabilities(itemList);
196 QVERIFY(!capabilities.supportsMoving());
197
198 QUrl viewUrl = QUrl::fromLocalFile(QStringLiteral("/etc"));
199 const KonqPopupMenu::Flags flags = m_appFlags
200 | KonqPopupMenu::ShowProperties
201 | KonqPopupMenu::ShowUrlOperations;
202 KonqPopupMenu::ActionGroupMap actionGroups;
203 actionGroups.insert(KonqPopupMenu::TabHandlingActions, m_tabHandlingActions->actions());
204 // DolphinPart doesn't add rename/trash when supportsMoving is false
205 // Maybe we should test dolphinpart directly :)
206 //actionGroups.insert(KonqPopupMenu::EditActions, m_fileEditActions->actions());
207 actionGroups.insert(KonqPopupMenu::PreviewActions, QList<QAction *>() << m_preview1);
208
209 KonqPopupMenu popup(itemList, viewUrl, m_actionCollection, flags);
210 popup.setNewFileMenu(m_newMenu);
211 popup.setActionGroups(actionGroups);
212
213 QStringList actions = extractActionNames(popup);
214 actions.removeAll(QStringLiteral("services_submenu"));
215 // Be tolerant with openwith, it could be there once or twice
216 if (actions.count(QStringLiteral("openwith")) == 2) {
217 actions.removeOne(QStringLiteral("openwith"));
218 }
219 qDebug() << actions;
220 QStringList expectedActions;
221 expectedActions << QStringLiteral("openInNewWindow") << QStringLiteral("openInNewTab") << QStringLiteral("separator")
222 << QStringLiteral("copy")
223 << QStringLiteral("openwith")
224 << QStringLiteral("separator")
225 << QStringLiteral("preview1");
226 expectedActions << QStringLiteral("separator");
227 expectedActions << QStringLiteral("copyTo_submenu") << QStringLiteral("separator");
228 expectedActions << QStringLiteral("properties");
229 qDebug() << "Expected:" << expectedActions;
230 QCOMPARE(actions, expectedActions);
231 }
232
testFilePreviewSubMenu()233 void KonqPopupMenuTest::testFilePreviewSubMenu()
234 {
235 // Same as testFile, but this time the "preview" action group has more than one action
236 KFileItemList itemList;
237 itemList << m_fileItem;
238 QUrl viewUrl = QUrl::fromLocalFile(QDir::currentPath());
239 const KonqPopupMenu::Flags flags = m_appFlags
240 | KonqPopupMenu::ShowProperties
241 | KonqPopupMenu::ShowUrlOperations;
242 KonqPopupMenu::ActionGroupMap actionGroups;
243 actionGroups.insert(KonqPopupMenu::TabHandlingActions, m_tabHandlingActions->actions());
244 actionGroups.insert(KonqPopupMenu::EditActions, m_fileEditActions->actions());
245 actionGroups.insert(KonqPopupMenu::PreviewActions, m_previewActions->actions());
246
247 KonqPopupMenu popup(itemList, viewUrl, m_actionCollection, flags);
248 popup.setNewFileMenu(m_newMenu);
249 popup.setActionGroups(actionGroups);
250
251 QStringList actions = extractActionNames(popup);
252 actions.removeAll(QStringLiteral("services_submenu"));
253 // Be tolerant with openwith, it could be there once or twice
254 if (actions.count(QStringLiteral("openwith")) == 2) {
255 actions.removeOne(QStringLiteral("openwith"));
256 }
257 qDebug() << actions;
258 QStringList expectedActions;
259 expectedActions << QStringLiteral("openInNewWindow") << QStringLiteral("openInNewTab") << QStringLiteral("separator")
260 << QStringLiteral("cut") << QStringLiteral("copy") << QStringLiteral("rename") << QStringLiteral("trash")
261 << QStringLiteral("openwith")
262 << QStringLiteral("separator")
263 << QStringLiteral("preview_submenu");
264 expectedActions << QStringLiteral("separator");
265 expectedActions << QStringLiteral("copyTo_submenu") << QStringLiteral("moveTo_submenu") << QStringLiteral("separator");
266 expectedActions << QStringLiteral("properties");
267 qDebug() << "Expected:" << expectedActions;
268 QCOMPARE(actions, expectedActions);
269 }
270
testSubDirectory()271 void KonqPopupMenuTest::testSubDirectory()
272 {
273 KFileItemList itemList;
274 itemList << m_subDirItem;
275 QUrl viewUrl = QUrl::fromLocalFile(QDir::currentPath());
276
277 const KonqPopupMenu::Flags flags = m_appFlags
278 | KonqPopupMenu::ShowProperties
279 | KonqPopupMenu::ShowUrlOperations;
280 KonqPopupMenu::ActionGroupMap actionGroups;
281 actionGroups.insert(KonqPopupMenu::TabHandlingActions, m_tabHandlingActions->actions());
282 actionGroups.insert(KonqPopupMenu::EditActions, m_fileEditActions->actions());
283 actionGroups.insert(KonqPopupMenu::PreviewActions, m_previewActions->actions());
284
285 KonqPopupMenu popup(itemList, viewUrl, m_actionCollection, flags);
286 popup.setNewFileMenu(m_newMenu);
287 popup.setActionGroups(actionGroups);
288 QStringList actions = extractActionNames(popup);
289 actions.removeAll(QStringLiteral("services_submenu"));
290 qDebug() << actions;
291 QStringList expectedActions;
292 expectedActions << QStringLiteral("openInNewWindow") << QStringLiteral("openInNewTab") << QStringLiteral("separator")
293 << QStringLiteral("cut") << QStringLiteral("copy") << QStringLiteral("pasteto") << QStringLiteral("rename") << QStringLiteral("trash")
294 << QStringLiteral("openwith")
295 << QStringLiteral("separator")
296 << QStringLiteral("preview_submenu");
297 expectedActions << QStringLiteral("separator");
298 expectedActions << QStringLiteral("copyTo_submenu") << QStringLiteral("moveTo_submenu") << QStringLiteral("separator");
299 expectedActions << QStringLiteral("properties");
300 qDebug() << "Expected:" << expectedActions;
301 QCOMPARE(actions, expectedActions);
302 }
303
testViewDirectory()304 void KonqPopupMenuTest::testViewDirectory()
305 {
306 KFileItemList itemList;
307 itemList << m_thisDirectoryItem;
308 QUrl viewUrl = m_thisDirectoryItem.url();
309 const KonqPopupMenu::Flags flags = m_appFlags |
310 KonqPopupMenu::ShowCreateDirectory |
311 KonqPopupMenu::ShowUrlOperations |
312 KonqPopupMenu::ShowProperties;
313 // KonqMainWindow says: doTabHandling = !openedForViewURL && ... So we don't add tabhandling here
314 KonqPopupMenu::ActionGroupMap actionGroups;
315 actionGroups.insert(KonqPopupMenu::PreviewActions, m_previewActions->actions());
316
317 KonqPopupMenu popup(itemList, viewUrl, m_actionCollection, flags);
318 popup.setNewFileMenu(m_newMenu);
319 popup.setActionGroups(actionGroups);
320
321 QStringList actions = extractActionNames(popup);
322 actions.removeAll(QStringLiteral("services_submenu"));
323 qDebug() << actions;
324 QStringList expectedActions;
325 expectedActions << QStringLiteral("newmenu") << QStringLiteral("separator")
326 << QStringLiteral("paste")
327 << QStringLiteral("openwith")
328 << QStringLiteral("separator")
329 << QStringLiteral("preview_submenu");
330 expectedActions << QStringLiteral("separator");
331 expectedActions << QStringLiteral("copyTo_submenu") << QStringLiteral("moveTo_submenu") << QStringLiteral("separator");
332 expectedActions << QStringLiteral("properties");
333 qDebug() << "Expected:" << expectedActions;
334 QCOMPARE(actions, expectedActions);
335 }
336
testViewReadOnlyDirectory()337 void KonqPopupMenuTest::testViewReadOnlyDirectory()
338 {
339 KFileItem rootItem(QUrl::fromLocalFile(QDir::rootPath()), QStringLiteral("inode/directory"), KFileItem::Unknown);
340 KFileItemList itemList;
341 itemList << rootItem;
342 QUrl viewUrl = rootItem.url();
343 const KonqPopupMenu::Flags flags = m_appFlags |
344 KonqPopupMenu::ShowCreateDirectory |
345 KonqPopupMenu::ShowUrlOperations |
346 KonqPopupMenu::ShowProperties;
347 // KonqMainWindow says: doTabHandling = !openedForViewURL && ... So we don't add tabhandling here
348 KonqPopupMenu::ActionGroupMap actionGroups;
349 actionGroups.insert(KonqPopupMenu::PreviewActions, m_previewActions->actions());
350
351 KonqPopupMenu popup(itemList, viewUrl, m_actionCollection, flags);
352 popup.setNewFileMenu(m_newMenu);
353 popup.setActionGroups(actionGroups);
354
355 QStringList actions = extractActionNames(popup);
356 actions.removeAll(QStringLiteral("services_submenu"));
357 qDebug() << actions;
358 QStringList expectedActions;
359 expectedActions // << "paste" // no paste since readonly
360 << QStringLiteral("openwith")
361 << QStringLiteral("separator")
362 << QStringLiteral("preview_submenu");
363 expectedActions << QStringLiteral("separator");
364 expectedActions << QStringLiteral("copyTo_submenu") << QStringLiteral("separator"); // no moveTo_submenu, since readonly
365 expectedActions << QStringLiteral("properties");
366 qDebug() << "Expected:" << expectedActions;
367 QCOMPARE(actions, expectedActions);
368 }
369
testHtmlLink()370 void KonqPopupMenuTest::testHtmlLink()
371 {
372 KFileItemList itemList;
373 itemList << m_linkItem;
374 QUrl viewUrl(QStringLiteral("http://www.kde.org"));
375 const KonqPopupMenu::Flags flags = m_appFlags
376 | KonqPopupMenu::ShowBookmark
377 | KonqPopupMenu::IsLink;
378 KonqPopupMenu::ActionGroupMap actionGroups;
379 actionGroups.insert(KonqPopupMenu::TabHandlingActions, m_tabHandlingActions->actions());
380 actionGroups.insert(KonqPopupMenu::EditActions, m_htmlEditActions->actions());
381 actionGroups.insert(KonqPopupMenu::PreviewActions, m_previewActions->actions());
382 actionGroups.insert(KonqPopupMenu::LinkActions, m_linkActions->actions());
383 actionGroups.insert(KonqPopupMenu::CustomActions, m_partActions->actions());
384 KonqPopupMenu popup(itemList, viewUrl, m_actionCollection, flags);
385 popup.setNewFileMenu(m_newMenu);
386 popup.setActionGroups(actionGroups);
387 popup.setBookmarkManager(KBookmarkManager::userBookmarksManager());
388
389 QStringList actions = extractActionNames(popup);
390 qDebug() << actions;
391 QStringList expectedActions;
392 expectedActions << QStringLiteral("openInNewWindow") << QStringLiteral("openInNewTab") << QStringLiteral("separator")
393 << QStringLiteral("bookmark_add") << QStringLiteral("savelinkas") << QStringLiteral("copylinklocation")
394 << QStringLiteral("openwith")
395 << QStringLiteral("separator")
396 << QStringLiteral("preview_submenu")
397 << QStringLiteral("separator")
398 << QStringLiteral("viewDocumentSource");
399 qDebug() << "Expected:" << expectedActions;
400 QCOMPARE(actions, expectedActions);
401 }
402
testHtmlPage()403 void KonqPopupMenuTest::testHtmlPage()
404 {
405 KFileItemList itemList;
406 itemList << m_linkItem;
407 QUrl viewUrl = m_linkItem.url();
408
409 const KonqPopupMenu::Flags flags = m_appFlags
410 | KonqPopupMenu::ShowBookmark;
411 KonqPopupMenu::ActionGroupMap actionGroups;
412 // KonqMainWindow says: doTabHandling = !openedForViewURL && ... So we don't add tabhandling here
413 // TODO we could just move that logic to KonqPopupMenu...
414 //actionGroups.insert(KonqPopupMenu::TabHandlingActions, m_tabHandlingActions->actions());
415 actionGroups.insert(KonqPopupMenu::EditActions, m_htmlEditActions->actions());
416 actionGroups.insert(KonqPopupMenu::PreviewActions, m_previewActions->actions());
417 //actionGroups.insert(KonqPopupMenu::LinkActions, m_linkActions->actions());
418 QAction *security = new QAction(m_partActions);
419 m_actionCollection.addAction(QStringLiteral("security"), security);
420 QAction *setEncoding = new QAction(m_partActions);
421 m_actionCollection.addAction(QStringLiteral("setEncoding"), setEncoding);
422 actionGroups.insert(KonqPopupMenu::CustomActions, m_partActions->actions());
423
424 KonqPopupMenu popup(itemList, viewUrl, m_actionCollection, flags);
425 popup.setNewFileMenu(m_newMenu);
426 popup.setActionGroups(actionGroups);
427 popup.setBookmarkManager(KBookmarkManager::userBookmarksManager());
428
429 QStringList actions = extractActionNames(popup);
430 qDebug() << actions;
431 QStringList expectedActions;
432 expectedActions << QStringLiteral("bookmark_add")
433 << QStringLiteral("openwith")
434 << QStringLiteral("separator")
435 << QStringLiteral("preview_submenu")
436 << QStringLiteral("separator")
437 // << TODO "stopanimations"
438 << QStringLiteral("viewDocumentSource") << QStringLiteral("security") << QStringLiteral("setEncoding");
439 qDebug() << "Expected:" << expectedActions;
440 QCOMPARE(actions, expectedActions);
441 }
442
443 // TODO test ShowBookmark. Probably the same logic?
444 // TODO separate filemanager and webbrowser bookmark managers, too (share file bookmarks with file dialog)
445
446 // TODO test text selection actions in khtml
447
448 // TODO trash:/ tests
449
450 // TODO test NoDeletion part flag
451