]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/tests/dolphinmainwindowtest.cpp
Add a sort by duration option for videos
[dolphin.git] / src / tests / dolphinmainwindowtest.cpp
index 2d90ae52f9bda448a3e442c728025d1fd7559f9f..61a72ad51b055d92e2f00ceb9b520031d196c02f 100644 (file)
@@ -20,6 +20,7 @@
 #include <KConfigGui>
 
 #include <QAccessible>
+#include <QDomDocument>
 #include <QFileSystemWatcher>
 #include <QScopedPointer>
 #include <QSignalSpy>
@@ -27,6 +28,7 @@
 #include <QTest>
 
 #include <set>
+#include <unordered_set>
 
 class DolphinMainWindowTest : public QObject
 {
@@ -35,6 +37,7 @@ class DolphinMainWindowTest : public QObject
 private Q_SLOTS:
     void initTestCase();
     void init();
+    void testSyncDesktopAndPhoneUi();
     void testClosingTabsWithSearchBoxVisible();
     void testActiveViewAfterClosingSplitView_data();
     void testActiveViewAfterClosingSplitView();
@@ -45,6 +48,7 @@ private Q_SLOTS:
     void testNewFileMenuEnabled();
     void testWindowTitle_data();
     void testWindowTitle();
+    void testFocusPlacesPanel();
     void testPlacesPanelWidthResistance();
     void testGoActions();
     void testOpenFiles();
@@ -66,6 +70,109 @@ void DolphinMainWindowTest::init()
     m_mainWindow.reset(new DolphinMainWindow());
 }
 
+/**
+ * It is too easy to forget that most changes in dolphinui.rc should be mirrored in dolphinuiforphones.rc. This test makes sure that these two files stay
+ * mostly identical. Differences between those files need to be explicitly added as exceptions to this test. So if you land here after changing either
+ * dolphinui.rc or dolphinuiforphones.rc, then resolve this test failure either by making the exact same change to the other ui.rc file, or by adding the
+ * changed object to the `exceptions` variable below.
+ */
+void DolphinMainWindowTest::testSyncDesktopAndPhoneUi()
+{
+    std::unordered_set<QString> exceptions{{QStringLiteral("version"), QStringLiteral("ToolBar")}};
+
+    QDomDocument desktopUi;
+    QFile desktopUiXmlFile(":/kxmlgui5/dolphin/dolphinui.rc");
+    desktopUiXmlFile.open(QIODevice::ReadOnly);
+    desktopUi.setContent(&desktopUiXmlFile);
+    desktopUiXmlFile.close();
+
+    QDomDocument phoneUi;
+    QFile phoneUiXmlFile(":/kxmlgui5/dolphin/dolphinuiforphones.rc");
+    phoneUiXmlFile.open(QIODevice::ReadOnly);
+    phoneUi.setContent(&phoneUiXmlFile);
+    phoneUiXmlFile.close();
+
+    QDomElement desktopUiElement = desktopUi.documentElement();
+    QDomElement phoneUiElement = phoneUi.documentElement();
+
+    auto nextUiElement = [&exceptions](QDomElement uiElement) -> QDomElement {
+        QDomNode nextUiNode{uiElement};
+        do {
+            // If the current node is an exception, we skip its children as well.
+            if (exceptions.count(nextUiNode.nodeName()) == 0) {
+                auto firstChild{nextUiNode.firstChild()};
+                if (!firstChild.isNull()) {
+                    nextUiNode = firstChild;
+                    continue;
+                }
+            }
+            auto nextSibling{nextUiNode.nextSibling()};
+            if (!nextSibling.isNull()) {
+                nextUiNode = nextSibling;
+                continue;
+            }
+            auto parent{nextUiNode.parentNode()};
+            while (true) {
+                if (parent.isNull()) {
+                    return QDomElement();
+                }
+                auto nextParentSibling{parent.nextSibling()};
+                if (!nextParentSibling.isNull()) {
+                    nextUiNode = nextParentSibling;
+                    break;
+                }
+                parent = parent.parentNode();
+            }
+        } while (
+            !nextUiNode.isNull()
+            && (nextUiNode.toElement().isNull() || exceptions.count(nextUiNode.nodeName()))); // We loop until we either give up finding an element or find one.
+        if (nextUiNode.isNull()) {
+            return QDomElement();
+        }
+        return nextUiNode.toElement();
+    };
+
+    int totalComparisonsCount{0};
+    do {
+        QVERIFY2(desktopUiElement.tagName() == phoneUiElement.tagName(),
+                 qPrintable(QStringLiteral("Node mismatch: dolphinui.rc/%1::%2 and dolphinuiforphones.rc/%3::%4")
+                                .arg(desktopUiElement.parentNode().toElement().tagName())
+                                .arg(desktopUiElement.tagName())
+                                .arg(phoneUiElement.parentNode().toElement().tagName())
+                                .arg(phoneUiElement.tagName())));
+        QCOMPARE(desktopUiElement.text(), phoneUiElement.text());
+        const auto desktopUiElementAttributes = desktopUiElement.attributes();
+        const auto phoneUiElementAttributes = phoneUiElement.attributes();
+        for (int i = 0; i < desktopUiElementAttributes.count(); i++) {
+            QVERIFY2(phoneUiElementAttributes.count() >= i,
+                     qPrintable(QStringLiteral("Attribute mismatch: dolphinui.rc/%1::%2 has more attributes than dolphinuiforphones.rc/%3::%4")
+                                    .arg(desktopUiElement.parentNode().toElement().tagName())
+                                    .arg(desktopUiElement.tagName())
+                                    .arg(phoneUiElement.parentNode().toElement().tagName())
+                                    .arg(phoneUiElement.tagName())));
+            if (exceptions.count(desktopUiElementAttributes.item(i).nodeName())) {
+                continue;
+            }
+            QCOMPARE(desktopUiElementAttributes.item(i).nodeName(), phoneUiElementAttributes.item(i).nodeName());
+            QCOMPARE(desktopUiElementAttributes.item(i).nodeValue(), phoneUiElementAttributes.item(i).nodeValue());
+            totalComparisonsCount++;
+        }
+        QVERIFY2(desktopUiElementAttributes.count() == phoneUiElementAttributes.count(),
+                 qPrintable(QStringLiteral("Attribute mismatch: dolphinui.rc/%1::%2 has fewer attributes than dolphinuiforphones.rc/%3::%4. %5 < %6")
+                                .arg(desktopUiElement.parentNode().toElement().tagName())
+                                .arg(desktopUiElement.tagName())
+                                .arg(phoneUiElement.parentNode().toElement().tagName())
+                                .arg(phoneUiElement.tagName())
+                                .arg(phoneUiElementAttributes.count())
+                                .arg(desktopUiElementAttributes.count())));
+
+        desktopUiElement = nextUiElement(desktopUiElement);
+        phoneUiElement = nextUiElement(phoneUiElement);
+        totalComparisonsCount++;
+    } while (!desktopUiElement.isNull() || !phoneUiElement.isNull());
+    QVERIFY2(totalComparisonsCount > 200, qPrintable(QStringLiteral("There were only %1 comparisons. Did the test run correctly?").arg(totalComparisonsCount)));
+}
+
 // See https://bugs.kde.org/show_bug.cgi?id=379135
 void DolphinMainWindowTest::testClosingTabsWithSearchBoxVisible()
 {
@@ -282,6 +389,44 @@ void DolphinMainWindowTest::testWindowTitle()
     QCOMPARE(m_mainWindow->windowTitle(), expectedWindowTitle);
 }
 
+void DolphinMainWindowTest::testFocusPlacesPanel()
+{
+    m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false);
+    m_mainWindow->show();
+    QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data()));
+    QVERIFY(m_mainWindow->isVisible());
+
+    QWidget *placesPanel = reinterpret_cast<QWidget *>(m_mainWindow->m_placesPanel);
+    QVERIFY2(QTest::qWaitFor(
+                 [&]() {
+                     return placesPanel && placesPanel->isVisible() && placesPanel->width() > 0 && placesPanel->height() > 0;
+                 },
+                 5000),
+             "The test couldn't be initialised properly. The places panel should be visible.");
+
+    QAction *focusPlacesPanelAction = m_mainWindow->actionCollection()->action(QStringLiteral("focus_places_panel"));
+    QAction *showPlacesPanelAction = m_mainWindow->actionCollection()->action(QStringLiteral("show_places_panel"));
+
+    focusPlacesPanelAction->trigger();
+    QVERIFY(placesPanel->hasFocus());
+
+    focusPlacesPanelAction->trigger();
+    QVERIFY2(m_mainWindow->activeViewContainer()->isAncestorOf(QApplication::focusWidget()),
+             "Triggering focus_places_panel while the panel already has focus should return the focus to the view.");
+
+    focusPlacesPanelAction->trigger();
+    QVERIFY(placesPanel->hasFocus());
+
+    showPlacesPanelAction->trigger();
+    QVERIFY(!placesPanel->isVisible());
+    QVERIFY2(m_mainWindow->activeViewContainer()->isAncestorOf(QApplication::focusWidget()),
+             "Hiding the Places panel while it has focus should return the focus to the view.");
+
+    showPlacesPanelAction->trigger();
+    QVERIFY(placesPanel->isVisible());
+    QVERIFY2(placesPanel->hasFocus(), "Enabling the Places panel should move keyboard focus there.");
+}
+
 /**
  * The places panel will resize itself if any of the other widgets requires too much horizontal space
  * but a user never wants the size of the places panel to change unless they resized it themselves explicitly.