@@ -24,6 +24,7 @@
24#include "launcheritem.h"
24#include "launcheritem.h"
25#include "launchermodel.h"
25#include "launchermodel.h"
26#include "dbusinterface.h"
26#include "dbusinterface.h"
27+#include "gsettings.h"
28#include <QtTest>
29#include <QtTest>
29#include <QDBusInterface>
30#include <QDBusInterface>
@@ -81,7 +82,15 @@ public:
81 return nullptr;
82 return nullptr;
83 unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
84 unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
84− bool stopApplication(const QString &) { return false; }
85+ bool stopApplication(const QString &appId) {
86+ Q_FOREACH(MockApp* app, m_list) {
87+ if (app->appId() == appId) {
88+ removeApplication(m_list.indexOf(app));
85 bool focusApplication(const QString &appId) {
94 bool focusApplication(const QString &appId) {
86 Q_FOREACH(MockApp* app, m_list) {
95 Q_FOREACH(MockApp* app, m_list) {
87 app->setFocused(app->appId() == appId);
96 app->setFocused(app->appId() == appId);
@@ -137,6 +146,8 @@ private Q_SLOTS:
138 appManager->addApplication(new MockApp("no-icon"));
147 appManager->addApplication(new MockApp("no-icon"));
139 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
148 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
150+ launcherModel->m_settings->setStoredApplications(QStringList());
142 // Removing apps from appmanager and launcher as pinned ones would stick
153 // Removing apps from appmanager and launcher as pinned ones would stick
@@ -172,14 +183,15 @@ private Q_SLOTS:
172 launcherModel->pin(launcherModel->get(0)->appId());
183 launcherModel->pin(launcherModel->get(0)->appId());
173 QCOMPARE(launcherModel->get(0)->pinned(), true);
184 QCOMPARE(launcherModel->get(0)->pinned(), true);
174 QCOMPARE(launcherModel->get(1)->pinned(), false);
185 QCOMPARE(launcherModel->get(1)->pinned(), false);
175− QCOMPARE(spy.count(), 1);
186+ QCOMPARE(spy.count() > 0, true);
176 QCOMPARE(spy.at(0).at(2).value<QVector<int>>().first(), (int)LauncherModelInterface::RolePinned);
187 QCOMPARE(spy.at(0).at(2).value<QVector<int>>().first(), (int)LauncherModelInterface::RolePinned);
178 launcherModel->requestRemove(launcherModel->get(0)->appId());
190 launcherModel->requestRemove(launcherModel->get(0)->appId());
179 QCOMPARE(launcherModel->get(0)->pinned(), false);
191 QCOMPARE(launcherModel->get(0)->pinned(), false);
180 QCOMPARE(launcherModel->get(1)->pinned(), false);
192 QCOMPARE(launcherModel->get(1)->pinned(), false);
181− QCOMPARE(spy.count(), 2);
193+ QCOMPARE(spy.count(), 1);
182− QCOMPARE(spy.at(1).at(2).value<QVector<int>>().first(), (int)LauncherModelInterface::RolePinned);
194+ QCOMPARE(spy.at(0).at(2).value<QVector<int>>().first(), (int)LauncherModelInterface::RolePinned);
185 void testRemove_data() {
197 void testRemove_data() {
@@ -188,7 +200,7 @@ private Q_SLOTS:
188 QTest::addColumn<bool>("running");
200 QTest::addColumn<bool>("running");
190 QTest::newRow("non-pinned, running") << false << true;
202 QTest::newRow("non-pinned, running") << false << true;
191− QTest::newRow("pinned, running") << true << false;
203+ QTest::newRow("pinned, running") << true << true;
192 QTest::newRow("pinned, non-running") << true << false;
204 QTest::newRow("pinned, non-running") << true << false;
@@ -201,23 +213,24 @@ private Q_SLOTS:
202 // pin one if required
214 // pin one if required
203 if (pinned) {
215 if (pinned) {
204− launcherModel->pin(launcherModel->get(1)->appId());
216+ launcherModel->pin("abs-icon");
207 // stop it if required
219 // stop it if required
208 if (!running) {
220 if (!running) {
209− appManager->removeApplication(1);
221+ appManager->stopApplication("abs-icon");
212 // Now remove it
224 // Now remove it
213− launcherModel->requestRemove(launcherModel->get(1)->appId());
225+ launcherModel->requestRemove("abs-icon");
215 if (running) {
227 if (running) {
216 // both apps are running, both apps must still be here
228 // both apps are running, both apps must still be here
217 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
229 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
219 // Item must be unpinned now
231 // Item must be unpinned now
232+ int index = launcherModel->findApplication("abs-icon");
220− QCOMPARE(launcherModel->get(1)->pinned(), false);
233+ QCOMPARE(launcherModel->get(index)->pinned(), false);
222 } else if (pinned) {
235 } else if (pinned) {
223 // Item 1 must go away, item 0 is here to stay
236 // Item 1 must go away, item 0 is here to stay
@@ -226,7 +239,7 @@ private Q_SLOTS:
227 // done our checks. now stop the app if was still running
240 // done our checks. now stop the app if was still running
228 if (running) {
241 if (running) {
229− appManager->removeApplication(1);
242+ appManager->stopApplication("abs-icon");
232 // It needs to go away in any case now
245 // It needs to go away in any case now
@@ -371,12 +384,75 @@ private Q_SLOTS:
371 QCOMPARE(launcherModel->get(index)->count(), 55);
384 QCOMPARE(launcherModel->get(index)->count(), 55);
374− void testRefresh() {
387+ void testRefreshAfterDeletedDesktopFiles_data() {
388+ QTest::addColumn<bool>("deleted");
389+ QTest::newRow("have .desktop files") << false;
390+ QTest::newRow("deleted .desktop files") << true;
393+ void testRefreshAfterDeletedDesktopFiles() {
394+ QFETCH(bool, deleted);
397+ launcherModel->pin("abs-icon");
398+ launcherModel->pin("no-icon");
400+ appManager->removeApplication(0);
401+ appManager->removeApplication(0);
403+ // "delete" the .desktop files
404+ QString oldCurrent = QDir::currentPath();
406+ // In testing mode, the launcher searches the current dir for the sample .desktop file
407+ // We can make that fail by changing the current dir
408+ QDir::setCurrent("..");
375 QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher", "com.canonical.Unity.Launcher");
412 QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher", "com.canonical.Unity.Launcher");
376 QDBusReply<void> reply = interface.call("Refresh");
413 QDBusReply<void> reply = interface.call("Refresh");
378 // Make sure the call to Refresh returned without error.
415 // Make sure the call to Refresh returned without error.
379 QCOMPARE(reply.isValid(), true);
416 QCOMPARE(reply.isValid(), true);
418+ QCOMPARE(launcherModel->rowCount(), deleted ? 0 : 2);
420+ // Restoring current dir
421+ QDir::setCurrent(oldCurrent);
424+ void testSettings() {
425+ GSettings *settings = launcherModel->m_settings;
427+ // Nothing pinned at startup
428+ QCOMPARE(settings->storedApplications().count(), 0);
431+ launcherModel->pin("abs-icon");
432+ launcherModel->pin("no-icon");
434+ // Now settings should have 2 apps
435+ QCOMPARE(settings->storedApplications().count(), 2);
438+ appManager->removeApplication(0);
439+ appManager->removeApplication(0);
441+ // Now settings should have 2 apps
442+ QCOMPARE(settings->storedApplications().count(), 2);
444+ // Now remove 1 app through the backend, make sure one is still there
445+ settings->simulateDConfChanged(QStringList() << "abs-icon");
446+ QCOMPARE(settings->storedApplications().count(), 1);
448+ // Check if it disappeared from the frontend too
449+ QCOMPARE(launcherModel->rowCount(), 1);
451+ // Add them back but in reverse order
452+ settings->simulateDConfChanged(QStringList() << "no-icon" << "abs-icon");
453+ QCOMPARE(launcherModel->rowCount(), 2);
454+ QCOMPARE(launcherModel->get(0)->appId(), QString("no-icon"));
455+ QCOMPARE(launcherModel->get(1)->appId(), QString("abs-icon"));