File indexing completed on 2021-12-21 13:19:39

0001 /* This file is part of the dbusmenu-qt library
0002    Copyright 2010 Canonical
0003    Author: Aurelien Gateau <aurelien.gateau@canonical.com>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License (LGPL) as published by the Free Software Foundation;
0008    either version 2 of the License, or (at your option) any later
0009    version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019    Boston, MA 02110-1301, USA.
0020 */
0021 // Self
0022 #include "dbusmenuimportertest.h"
0023 
0024 // Qt
0025 #include <QDBusConnection>
0026 #include <QDBusInterface>
0027 #include <QDBusReply>
0028 #include <QIcon>
0029 #include <QMenu>
0030 #include <QtTest>
0031 
0032 // DBusMenuQt
0033 #include <dbusmenuexporter.h>
0034 #include <dbusmenuimporter.h>
0035 #include <debug_p.h>
0036 
0037 // Local
0038 #include "testutils.h"
0039 
0040 QTEST_MAIN(DBusMenuImporterTest)
0041 
0042 static const char *TEST_SERVICE = "com.canonical.dbusmenu-qt-test";
0043 static const char *TEST_OBJECT_PATH = "/TestMenuBar";
0044 
0045 Q_DECLARE_METATYPE(QAction*)
0046 
0047 void DBusMenuImporterTest::initTestCase()
0048 {
0049     qRegisterMetaType<QAction*>("QAction*");
0050     QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
0051 }
0052 
0053 void DBusMenuImporterTest::cleanup()
0054 {
0055     waitForDeferredDeletes();
0056 }
0057 
0058 void DBusMenuImporterTest::testStandardItem()
0059 {
0060     QMenu inputMenu;
0061     QAction *action = inputMenu.addAction("Test");
0062     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
0063 
0064     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
0065     QTest::qWait(500);
0066 
0067     QMenu *outputMenu = importer.menu();
0068     QCOMPARE(outputMenu->actions().count(), 1);
0069     QAction *outputAction = outputMenu->actions().first();
0070     QCOMPARE(outputAction->text(), QString("Test"));
0071 }
0072 
0073 void DBusMenuImporterTest::testAddingNewItem()
0074 {
0075     QMenu inputMenu;
0076     QAction *action = inputMenu.addAction("Test");
0077     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
0078 
0079     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
0080     QTest::qWait(500);
0081     QMenu *outputMenu = importer.menu();
0082     QCOMPARE(outputMenu->actions().count(), inputMenu.actions().count());
0083 
0084     inputMenu.addAction("Test2");
0085     QTest::qWait(500);
0086     QCOMPARE(outputMenu->actions().count(), inputMenu.actions().count());
0087 }
0088 
0089 void DBusMenuImporterTest::testShortcut()
0090 {
0091     QMenu inputMenu;
0092     QAction *action = inputMenu.addAction("Test");
0093     action->setShortcut(Qt::CTRL | Qt::Key_S);
0094     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
0095 
0096     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
0097     QTest::qWait(500);
0098     QMenu *outputMenu = importer.menu();
0099 
0100     QAction *outputAction = outputMenu->actions().at(0);
0101     QCOMPARE(outputAction->shortcut(), action->shortcut());
0102 }
0103 
0104 void DBusMenuImporterTest::testDeletingImporterWhileWaitingForAboutToShow()
0105 {
0106     // Start test program and wait for it to be ready
0107     QProcess slowMenuProcess;
0108     slowMenuProcess.start("./slowmenu");
0109     QTest::qWait(500);
0110 
0111     // Create importer and wait for the menu
0112     DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
0113     QTest::qWait(500);
0114 
0115     QMenu *outputMenu = importer->menu();
0116     QTimer::singleShot(100, importer, SLOT(deleteLater()));
0117     outputMenu->popup(QPoint(0, 0));
0118 
0119     // If it crashes, it will crash while waiting there
0120     QTest::qWait(500);
0121 
0122     // Done, stop our test program
0123     slowMenuProcess.close();
0124     slowMenuProcess.waitForFinished();
0125 }
0126 
0127 void DBusMenuImporterTest::testDynamicMenu()
0128 {
0129     QMenu rootMenu;
0130     QAction* a1 = new QAction("a1", &rootMenu);
0131     QAction* a2 = new QAction("a2", &rootMenu);
0132     MenuFiller rootMenuFiller(&rootMenu);
0133     rootMenuFiller.addAction(a1);
0134     rootMenuFiller.addAction(a2);
0135 
0136     QMenu subMenu;
0137     MenuFiller subMenuFiller(&subMenu);
0138     subMenuFiller.addAction(new QAction("a3", &subMenu));
0139 
0140     a1->setMenu(&subMenu);
0141 
0142     DBusMenuExporter exporter(TEST_OBJECT_PATH, &rootMenu);
0143 
0144     // Import this menu
0145     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
0146     QTest::qWait(500);
0147     QMenu *outputMenu = importer.menu();
0148 
0149     // There should be no children for now
0150     QCOMPARE(outputMenu->actions().count(), 0);
0151 
0152     // Update menu, a1 and a2 should get added
0153     QSignalSpy spy(&importer, SIGNAL(menuUpdated()));
0154     QSignalSpy spyOld(&importer, SIGNAL(menuReadyToBeShown()));
0155     importer.updateMenu();
0156     while (spy.isEmpty()) {
0157         QTest::qWait(500);
0158     }
0159 
0160     QCOMPARE(outputMenu->actions().count(), 2);
0161     QTest::qWait(500);
0162     QAction* a1Output = outputMenu->actions().first();
0163 
0164     // a1Output should have an empty menu
0165     QMenu* a1OutputMenu = a1Output->menu();
0166     QVERIFY(a1OutputMenu);
0167     QCOMPARE(a1OutputMenu->actions().count(), 0);
0168 
0169     // Show a1OutputMenu, a3 should get added
0170     QMetaObject::invokeMethod(a1OutputMenu, "aboutToShow");
0171     QTest::qWait(500);
0172 
0173     QCOMPARE(a1OutputMenu->actions().count(), 1);
0174 
0175     // menuUpdated() and menuReadyToBeShown() should only have been emitted
0176     // once
0177     QCOMPARE(spy.count(), 1);
0178     QCOMPARE(spyOld.count(), 1);
0179 }
0180 
0181 void DBusMenuImporterTest::testActionActivationRequested()
0182 {
0183     // Export a menu
0184     QMenu inputMenu;
0185     QAction *inputA1 = inputMenu.addAction("a1");
0186     QAction *inputA2 = inputMenu.addAction("a2");
0187     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
0188 
0189     // Import the menu
0190     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
0191     QSignalSpy spy(&importer, SIGNAL(actionActivationRequested(QAction*)));
0192 
0193     QTest::qWait(500);
0194     QMenu *outputMenu = importer.menu();
0195 
0196     // Get matching output actions
0197     QCOMPARE(outputMenu->actions().count(), 2);
0198     QAction *outputA1 = outputMenu->actions().at(0);
0199     QAction *outputA2 = outputMenu->actions().at(1);
0200 
0201     // Request activation
0202     exporter.activateAction(inputA1);
0203     exporter.activateAction(inputA2);
0204 
0205     // Check we received the signal in the right order
0206     QTest::qWait(500);
0207     QCOMPARE(spy.count(), 2);
0208     QCOMPARE(spy.takeFirst().at(0).value<QAction*>(), outputA1);
0209     QCOMPARE(spy.takeFirst().at(0).value<QAction*>(), outputA2);
0210 }
0211 
0212 void DBusMenuImporterTest::testActionsAreDeletedWhenImporterIs()
0213 {
0214     // Export a menu
0215     QMenu inputMenu;
0216     inputMenu.addAction("a1");
0217     QMenu *inputSubMenu = inputMenu.addMenu("subMenu");
0218     inputSubMenu->addAction("a2");
0219     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
0220 
0221     // Import the menu
0222     DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
0223     QTest::qWait(500);
0224 
0225     // Put all items of the menu in a list of QPointers
0226     QList< QPointer<QObject> > children;
0227 
0228     QMenu *outputMenu = importer->menu();
0229     QCOMPARE(outputMenu->actions().count(), 2);
0230     QMenu *outputSubMenu = outputMenu->actions().at(1)->menu();
0231     QVERIFY(outputSubMenu);
0232     // Fake aboutToShow so that outputSubMenu is populated
0233     QMetaObject::invokeMethod(outputSubMenu, "aboutToShow");
0234     QCOMPARE(outputSubMenu->actions().count(), 1);
0235 
0236     children << outputMenu->actions().at(0);
0237     children << outputMenu->actions().at(1);
0238     children << outputSubMenu;
0239     children << outputSubMenu->actions().at(0);
0240 
0241     delete importer;
0242     waitForDeferredDeletes();
0243 
0244     // There should be only invalid pointers in children
0245     Q_FOREACH(QPointer<QObject> child, children) {
0246         //qDebug() << child;
0247         QVERIFY(child.isNull());
0248     }
0249 }
0250 
0251 void DBusMenuImporterTest::testIconData()
0252 {
0253     // Create an icon
0254     QImage img(16, 16, QImage::Format_ARGB32);
0255     {
0256         QPainter painter(&img);
0257         painter.setCompositionMode(QPainter::CompositionMode_Source);
0258         QRect rect = img.rect();
0259         painter.fillRect(rect, Qt::transparent);
0260         rect.adjust(2, 2, -2, -2);
0261         painter.fillRect(rect, Qt::red);
0262         rect.adjust(2, 2, -2, -2);
0263         painter.fillRect(rect, Qt::green);
0264     }
0265     QIcon inputIcon(QPixmap::fromImage(img));
0266 
0267     // Export a menu
0268     QMenu inputMenu;
0269     QAction *a1 = inputMenu.addAction("a1");
0270     a1->setIcon(inputIcon);
0271     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
0272 
0273     // Import the menu
0274     DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
0275     QTest::qWait(500);
0276 
0277     // Check icon of action
0278     QMenu *outputMenu = importer->menu();
0279     QCOMPARE(outputMenu->actions().count(), 1);
0280 
0281     QIcon outputIcon = outputMenu->actions().first()->icon();
0282     QVERIFY(!outputIcon.isNull());
0283 
0284     QImage result = outputIcon.pixmap(16).toImage();
0285     QByteArray origBytes, resultBytes;
0286     img.save(origBytes);
0287     result.save(resultBytes);
0288     QCOMPARE(origBytes,resultBytes);
0289 }
0290 
0291 void DBusMenuImporterTest::testInvisibleItem()
0292 {
0293     QMenu inputMenu;
0294     QAction *action = inputMenu.addAction("Test");
0295     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
0296 
0297     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
0298     QTest::qWait(500);
0299 
0300     QMenu *outputMenu = importer.menu();
0301     QCOMPARE(outputMenu->actions().count(), 1);
0302     QAction *outputAction = outputMenu->actions().first();
0303 
0304     QVERIFY(outputAction->isVisible());
0305 
0306     // Hide the action
0307     action->setVisible(false);
0308     QTest::qWait(500);
0309     QVERIFY(!outputAction->isVisible());
0310 
0311     // Show the action
0312     action->setVisible(true);
0313     QTest::qWait(500);
0314     QVERIFY(outputAction->isVisible());
0315 }
0316 
0317 void DBusMenuImporterTest::testDisabledItem()
0318 {
0319     QMenu inputMenu;
0320     QAction *action = inputMenu.addAction("Test");
0321     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
0322 
0323     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
0324     QTest::qWait(500);
0325 
0326     QMenu *outputMenu = importer.menu();
0327     QCOMPARE(outputMenu->actions().count(), 1);
0328     QAction *outputAction = outputMenu->actions().first();
0329     QVERIFY(outputAction->isEnabled());
0330 
0331     // Disable the action
0332     DMDEBUG << "Disabling";
0333     action->setEnabled(false);
0334     QTest::qWait(500);
0335     QVERIFY(!outputAction->isEnabled());
0336 
0337     // Enable the action
0338     action->setEnabled(true);
0339     QTest::qWait(500);
0340     QVERIFY(outputAction->isEnabled());
0341 }
0342 
0343 #include "dbusmenuimportertest.moc"