OSDN Git Service

e81faec9ad787e43b1082b1ee53c850b4b21701e
[kde/libdbusmenu-qt.git] / tests / dbusmenuimportertest.cpp
1 /* This file is part of the dbusmenu-qt library
2    Copyright 2010 Canonical
3    Author: Aurelien Gateau <aurelien.gateau@canonical.com>
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License (LGPL) as published by the Free Software Foundation;
8    either version 2 of the License, or (at your option) any later
9    version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public License
17    along with this library; see the file COPYING.LIB.  If not, write to
18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1301, USA.
20 */
21 // Self
22 #include "dbusmenuimportertest.h"
23
24 // Qt
25 #include <QTimer>
26 #include <QProcess>
27 #include <QDBusConnection>
28 #include <QDBusInterface>
29 #include <QDBusReply>
30 #include <QIcon>
31 #include <QMenu>
32 #include <QtTest>
33
34 // DBusMenuQt
35 #include <dbusmenuexporter.h>
36 #include <dbusmenuimporter.h>
37 #include <debug_p.h>
38
39 // Local
40 #include "testutils.h"
41
42 QTEST_MAIN(DBusMenuImporterTest)
43
44 static const char *TEST_SERVICE = "com.canonical.dbusmenu-qt-test";
45 static const char *TEST_OBJECT_PATH = "/TestMenuBar";
46
47 Q_DECLARE_METATYPE(QAction*)
48
49 void DBusMenuImporterTest::initTestCase()
50 {
51     qRegisterMetaType<QAction*>("QAction*");
52     QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
53 }
54
55 void DBusMenuImporterTest::cleanup()
56 {
57     waitForDeferredDeletes();
58 }
59
60 void DBusMenuImporterTest::testStandardItem()
61 {
62     QMenu inputMenu;
63     QAction *action = inputMenu.addAction("Test");
64     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
65
66     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
67     QTest::qWait(500);
68
69     QMenu *outputMenu = importer.menu();
70     QCOMPARE(outputMenu->actions().count(), 1);
71     QAction *outputAction = outputMenu->actions().first();
72     QCOMPARE(outputAction->text(), QString("Test"));
73 }
74
75 void DBusMenuImporterTest::testAddingNewItem()
76 {
77     QMenu inputMenu;
78     QAction *action = inputMenu.addAction("Test");
79     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
80
81     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
82     QTest::qWait(500);
83     QMenu *outputMenu = importer.menu();
84     QCOMPARE(outputMenu->actions().count(), inputMenu.actions().count());
85
86     inputMenu.addAction("Test2");
87     QTest::qWait(500);
88     QCOMPARE(outputMenu->actions().count(), inputMenu.actions().count());
89 }
90
91 void DBusMenuImporterTest::testShortcut()
92 {
93     QMenu inputMenu;
94     QAction *action = inputMenu.addAction("Test");
95     action->setShortcut(Qt::CTRL | Qt::Key_S);
96     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
97
98     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
99     QTest::qWait(500);
100     QMenu *outputMenu = importer.menu();
101
102     QAction *outputAction = outputMenu->actions().at(0);
103     QCOMPARE(outputAction->shortcut(), action->shortcut());
104 }
105
106 void DBusMenuImporterTest::testDeletingImporterWhileWaitingForAboutToShow()
107 {
108     // Start test program and wait for it to be ready
109     QProcess slowMenuProcess;
110     slowMenuProcess.start("./slowmenu");
111     QTest::qWait(500);
112
113     // Create importer and wait for the menu
114     DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
115     QTest::qWait(500);
116
117     QMenu *outputMenu = importer->menu();
118     QTimer::singleShot(100, importer, SLOT(deleteLater()));
119     outputMenu->popup(QPoint(0, 0));
120
121     // If it crashes, it will crash while waiting there
122     QTest::qWait(500);
123
124     // Done, stop our test program
125     slowMenuProcess.close();
126     slowMenuProcess.waitForFinished();
127 }
128
129 void DBusMenuImporterTest::testDynamicMenu()
130 {
131     QMenu rootMenu;
132     QAction* a1 = new QAction("a1", &rootMenu);
133     QAction* a2 = new QAction("a2", &rootMenu);
134     MenuFiller rootMenuFiller(&rootMenu);
135     rootMenuFiller.addAction(a1);
136     rootMenuFiller.addAction(a2);
137
138     QMenu subMenu;
139     MenuFiller subMenuFiller(&subMenu);
140     subMenuFiller.addAction(new QAction("a3", &subMenu));
141
142     a1->setMenu(&subMenu);
143
144     DBusMenuExporter exporter(TEST_OBJECT_PATH, &rootMenu);
145
146     // Import this menu
147     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
148     QTest::qWait(500);
149     QMenu *outputMenu = importer.menu();
150
151     // There should be no children for now
152     QCOMPARE(outputMenu->actions().count(), 0);
153
154     // Update menu, a1 and a2 should get added
155     QSignalSpy spy(&importer, SIGNAL(menuUpdated()));
156     QSignalSpy spyOld(&importer, SIGNAL(menuReadyToBeShown()));
157     importer.updateMenu();
158     while (spy.isEmpty()) {
159         QTest::qWait(500);
160     }
161
162     QCOMPARE(outputMenu->actions().count(), 2);
163     QTest::qWait(500);
164     QAction* a1Output = outputMenu->actions().first();
165
166     // a1Output should have an empty menu
167     QMenu* a1OutputMenu = a1Output->menu();
168     QVERIFY(a1OutputMenu);
169     QCOMPARE(a1OutputMenu->actions().count(), 0);
170
171     // Show a1OutputMenu, a3 should get added
172     QMetaObject::invokeMethod(a1OutputMenu, "aboutToShow");
173     QTest::qWait(500);
174
175     QCOMPARE(a1OutputMenu->actions().count(), 1);
176
177     // menuUpdated() and menuReadyToBeShown() should only have been emitted
178     // once
179     QCOMPARE(spy.count(), 1);
180     QCOMPARE(spyOld.count(), 1);
181 }
182
183 void DBusMenuImporterTest::testActionActivationRequested()
184 {
185     // Export a menu
186     QMenu inputMenu;
187     QAction *inputA1 = inputMenu.addAction("a1");
188     QAction *inputA2 = inputMenu.addAction("a2");
189     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
190
191     // Import the menu
192     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
193     QSignalSpy spy(&importer, SIGNAL(actionActivationRequested(QAction*)));
194
195     QTest::qWait(500);
196     QMenu *outputMenu = importer.menu();
197
198     // Get matching output actions
199     QCOMPARE(outputMenu->actions().count(), 2);
200     QAction *outputA1 = outputMenu->actions().at(0);
201     QAction *outputA2 = outputMenu->actions().at(1);
202
203     // Request activation
204     exporter.activateAction(inputA1);
205     exporter.activateAction(inputA2);
206
207     // Check we received the signal in the right order
208     QTest::qWait(500);
209     QCOMPARE(spy.count(), 2);
210     QCOMPARE(spy.takeFirst().at(0).value<QAction*>(), outputA1);
211     QCOMPARE(spy.takeFirst().at(0).value<QAction*>(), outputA2);
212 }
213
214 void DBusMenuImporterTest::testActionsAreDeletedWhenImporterIs()
215 {
216     // Export a menu
217     QMenu inputMenu;
218     inputMenu.addAction("a1");
219     QMenu *inputSubMenu = inputMenu.addMenu("subMenu");
220     inputSubMenu->addAction("a2");
221     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
222
223     // Import the menu
224     DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
225     QTest::qWait(500);
226
227     // Put all items of the menu in a list of QPointers
228     QList< QPointer<QObject> > children;
229
230     QMenu *outputMenu = importer->menu();
231     QCOMPARE(outputMenu->actions().count(), 2);
232     QMenu *outputSubMenu = outputMenu->actions().at(1)->menu();
233     QVERIFY(outputSubMenu);
234     // Fake aboutToShow so that outputSubMenu is populated
235     QMetaObject::invokeMethod(outputSubMenu, "aboutToShow");
236     QCOMPARE(outputSubMenu->actions().count(), 1);
237
238     children << outputMenu->actions().at(0);
239     children << outputMenu->actions().at(1);
240     children << outputSubMenu;
241     children << outputSubMenu->actions().at(0);
242
243     delete importer;
244     waitForDeferredDeletes();
245
246     // There should be only invalid pointers in children
247     Q_FOREACH(QPointer<QObject> child, children) {
248         //qDebug() << child;
249         QVERIFY(child.isNull());
250     }
251 }
252
253 void DBusMenuImporterTest::testIconData()
254 {
255     // Create an icon
256     QImage img(16, 16, QImage::Format_ARGB32);
257     {
258         QPainter painter(&img);
259         painter.setCompositionMode(QPainter::CompositionMode_Source);
260         QRect rect = img.rect();
261         painter.fillRect(rect, Qt::transparent);
262         rect.adjust(2, 2, -2, -2);
263         painter.fillRect(rect, Qt::red);
264         rect.adjust(2, 2, -2, -2);
265         painter.fillRect(rect, Qt::green);
266     }
267     QIcon inputIcon(QPixmap::fromImage(img));
268
269     // Export a menu
270     QMenu inputMenu;
271     QAction *a1 = inputMenu.addAction("a1");
272     a1->setIcon(inputIcon);
273     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
274
275     // Import the menu
276     DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
277     QTest::qWait(500);
278
279     // Check icon of action
280     QMenu *outputMenu = importer->menu();
281     QCOMPARE(outputMenu->actions().count(), 1);
282
283     QIcon outputIcon = outputMenu->actions().first()->icon();
284     QVERIFY(!outputIcon.isNull());
285
286     QImage result = outputIcon.pixmap(16).toImage();
287     QByteArray origBytes, resultBytes;
288     img.save(origBytes);
289     result.save(resultBytes);
290     QCOMPARE(origBytes,resultBytes);
291 }
292
293 void DBusMenuImporterTest::testInvisibleItem()
294 {
295     QMenu inputMenu;
296     QAction *action = inputMenu.addAction("Test");
297     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
298
299     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
300     QTest::qWait(500);
301
302     QMenu *outputMenu = importer.menu();
303     QCOMPARE(outputMenu->actions().count(), 1);
304     QAction *outputAction = outputMenu->actions().first();
305
306     QVERIFY(outputAction->isVisible());
307
308     // Hide the action
309     action->setVisible(false);
310     QTest::qWait(500);
311     QVERIFY(!outputAction->isVisible());
312
313     // Show the action
314     action->setVisible(true);
315     QTest::qWait(500);
316     QVERIFY(outputAction->isVisible());
317 }
318
319 void DBusMenuImporterTest::testDisabledItem()
320 {
321     QMenu inputMenu;
322     QAction *action = inputMenu.addAction("Test");
323     DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
324
325     DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
326     QTest::qWait(500);
327
328     QMenu *outputMenu = importer.menu();
329     QCOMPARE(outputMenu->actions().count(), 1);
330     QAction *outputAction = outputMenu->actions().first();
331     QVERIFY(outputAction->isEnabled());
332
333     // Disable the action
334     DMDEBUG << "Disabling";
335     action->setEnabled(false);
336     QTest::qWait(500);
337     QVERIFY(!outputAction->isEnabled());
338
339     // Enable the action
340     action->setEnabled(true);
341     QTest::qWait(500);
342     QVERIFY(outputAction->isEnabled());
343 }
344
345 #include "moc_dbusmenuimportertest.cpp"