Merge lp:~mardy/online-accounts-api/providers-1627001 into lp:online-accounts-api

Proposed by Alberto Mardegan
Status: Merged
Approved by: Alberto Mardegan
Approved revision: 52
Merged at revision: 38
Proposed branch: lp:~mardy/online-accounts-api/providers-1627001
Merge into: lp:online-accounts-api
Diff against target: 1839 lines (+826/-80)
34 files modified
debian/control (+1/-1)
src/lib/OnlineAccounts/CMakeLists.txt (+2/-0)
src/lib/OnlineAccounts/Service (+1/-0)
src/lib/OnlineAccounts/account.cpp (+11/-0)
src/lib/OnlineAccounts/account.h (+3/-0)
src/lib/OnlineAccounts/account_p.h (+2/-0)
src/lib/OnlineAccounts/dbus_interface.cpp (+2/-0)
src/lib/OnlineAccounts/manager.cpp (+14/-1)
src/lib/OnlineAccounts/manager.h (+6/-1)
src/lib/OnlineAccounts/manager_p.h (+6/-0)
src/lib/OnlineAccounts/service.cpp (+54/-0)
src/lib/OnlineAccounts/service.h (+83/-0)
src/lib/OnlineAccountsDaemon/CMakeLists.txt (+1/-0)
src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xml (+14/-0)
src/lib/OnlineAccountsDaemon/dbus_constants.h (+3/-0)
src/lib/OnlineAccountsDaemon/i18n.cpp (+34/-0)
src/lib/OnlineAccountsDaemon/i18n.h (+32/-0)
src/lib/OnlineAccountsDaemon/manager.cpp (+86/-10)
src/lib/OnlineAccountsDaemon/manager.h (+2/-1)
src/lib/OnlineAccountsDaemon/manager_adaptor.cpp (+7/-3)
src/lib/OnlineAccountsDaemon/manager_adaptor.h (+4/-1)
src/lib/Ubuntu/OnlineAccounts.2/account.cpp (+34/-4)
src/lib/Ubuntu/OnlineAccounts.2/account.h (+10/-1)
src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp (+28/-1)
src/lib/Ubuntu/OnlineAccounts.2/account_model.h (+9/-0)
src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp (+5/-0)
tests/daemon/functional_tests/data/com.ubuntu.tests_application.application (+4/-1)
tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.service (+1/-1)
tests/daemon/functional_tests/data/coolmail.service (+0/-1)
tests/daemon/functional_tests/data/missing-provider.service (+14/-0)
tests/daemon/functional_tests/functional_tests.cpp (+133/-10)
tests/daemon/functional_tests/test_process.py (+5/-2)
tests/lib/OnlineAccounts/functional_tests/functional_tests.cpp (+108/-22)
tests/lib/qml_module/tst_qml_module.cpp (+107/-19)
To merge this branch: bzr merge lp:~mardy/online-accounts-api/providers-1627001
Reviewer Review Type Date Requested Status
Alexandre Abreu (community) Approve
Review via email: mp+310060@code.launchpad.net

Commit message

Add provider information to public API

Allow clients to retrieve the list of available service providers, consisting of translated display name and icon URL.
Also, add a service() method to the Account class, to get the data associated with each account.

Description of the change

Add provider information to public API

Allow clients to retrieve the list of available service providers, consisting of translated display name and icon URL.
Also, add a service() method to the Account class, to get the data associated with each account.

To post a comment you must log in.
Revision history for this message
Michi Henning (michihenning) wrote :

I may be missing something here, but (not being familiar with the code), it looks like the translated service name is not present? We need the translated name of the service too (such as "Google" or "Dropbox", or their equivalents in Arabic script, or whatever).

35. By Alberto Mardegan

Bump dependency on libaccounts-qt

36. By Alberto Mardegan

Add missing files

37. By Alberto Mardegan

DOn't use qjsEngine() it doesn't exist in QT 5.4

Revision history for this message
Alberto Mardegan (mardy) wrote :

> I may be missing something here, but (not being familiar with the code), it
> looks like the translated service name is not present? We need the translated
> name of the service too (such as "Google" or "Dropbox", or their equivalents
> in Arabic script, or whatever).

It's there, line 549 of the diff. I'll soon prepare a test app to verify that everything is place, in case unit tests are not catching everything.

38. By Alberto Mardegan

more of the same

39. By Alberto Mardegan

Cast QList<QString> to QStringList

40. By Alberto Mardegan

Don't use Q_GADGET functionality in Qt < 5.5

41. By Alberto Mardegan

Fix typo

42. By Alberto Mardegan

type conv for qt 5.4

43. By Alberto Mardegan

fix

44. By Alberto Mardegan

skip test

45. By Alberto Mardegan

fix

46. By Alberto Mardegan

Fallback to provider's icon and display name

47. By Alberto Mardegan

test debugging

48. By Alberto Mardegan

fix test

49. By Alberto Mardegan

remove debugging

50. By Alberto Mardegan

Don't crash if serviceList property is retrieved when the model is not ready

With this fix, we also need a signal to inform the QML engine of when the
property becomes available

51. By Alberto Mardegan

Skip missing providers

52. By Alberto Mardegan

Expose enums to QML

Revision history for this message
Alberto Mardegan (mardy) wrote :

This is implemented and available for testing here: https://bileto.ubuntu.com/#/ticket/2016

See the "Test plan" in that silo for a quick way to test it.

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

LGTM

one inlined question

review: Approve
53. By Alberto Mardegan

Remove commented line

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2016-10-03 07:46:50 +0000
3+++ debian/control 2016-11-10 09:12:06 +0000
4@@ -6,7 +6,7 @@
5 debhelper (>= 9),
6 pkg-config,
7 python3:any,
8- libaccounts-qt5-dev,
9+ libaccounts-qt5-dev (>= 1.15),
10 libapparmor-dev,
11 libonline-accounts-client-dev (>= 0.7),
12 libqtdbusmock1-dev,
13
14=== modified file 'src/lib/OnlineAccounts/CMakeLists.txt'
15--- src/lib/OnlineAccounts/CMakeLists.txt 2016-11-01 09:48:22 +0000
16+++ src/lib/OnlineAccounts/CMakeLists.txt 2016-11-10 09:12:06 +0000
17@@ -22,6 +22,7 @@
18 manager.cpp
19 pending_call.cpp
20 request_access_reply.cpp
21+ service.cpp
22 )
23 set_target_properties(${CLIENT_LIB} PROPERTIES
24 VERSION 1.0.0
25@@ -52,5 +53,6 @@
26 PasswordData
27 PendingCall pending_call.h
28 PendingCallWatcher
29+ Service service.h
30 DESTINATION include/${CLIENT_LIB}/OnlineAccounts
31 )
32
33=== added file 'src/lib/OnlineAccounts/Service'
34--- src/lib/OnlineAccounts/Service 1970-01-01 00:00:00 +0000
35+++ src/lib/OnlineAccounts/Service 2016-11-10 09:12:06 +0000
36@@ -0,0 +1,1 @@
37+#include "service.h"
38
39=== modified file 'src/lib/OnlineAccounts/account.cpp'
40--- src/lib/OnlineAccounts/account.cpp 2015-08-26 13:32:38 +0000
41+++ src/lib/OnlineAccounts/account.cpp 2016-11-10 09:12:06 +0000
42@@ -53,6 +53,11 @@
43 }
44 }
45
46+Service AccountPrivate::service() const
47+{
48+ return m_manager->d_ptr->service(m_info.service());
49+}
50+
51 Account::Account(AccountPrivate *priv, QObject *parent):
52 QObject(parent),
53 d_ptr(priv)
54@@ -72,6 +77,12 @@
55 return d->m_isValid;
56 }
57
58+Service Account::service() const
59+{
60+ Q_D(const Account);
61+ return d->service();
62+}
63+
64 AccountId Account::id() const
65 {
66 Q_D(const Account);
67
68=== modified file 'src/lib/OnlineAccounts/account.h'
69--- src/lib/OnlineAccounts/account.h 2015-08-26 13:32:38 +0000
70+++ src/lib/OnlineAccounts/account.h 2016-11-10 09:12:06 +0000
71@@ -26,6 +26,7 @@
72
73 #include "global.h"
74 #include "pending_call.h"
75+#include "service.h"
76
77 namespace OnlineAccounts {
78
79@@ -43,6 +44,8 @@
80 /* Returns false if account deleted or disabled */
81 bool isValid() const;
82
83+ Service service() const;
84+
85 AccountId id() const;
86 QString displayName() const;
87 QString serviceId() const;
88
89=== modified file 'src/lib/OnlineAccounts/account_p.h'
90--- src/lib/OnlineAccounts/account_p.h 2015-03-04 10:01:32 +0000
91+++ src/lib/OnlineAccounts/account_p.h 2016-11-10 09:12:06 +0000
92@@ -37,6 +37,8 @@
93 void setInvalid();
94 void update(const AccountInfo &info);
95
96+ Service service() const;
97+
98 private:
99 Manager *m_manager;
100 AccountInfo m_info;
101
102=== modified file 'src/lib/OnlineAccounts/dbus_interface.cpp'
103--- src/lib/OnlineAccounts/dbus_interface.cpp 2015-03-03 07:09:50 +0000
104+++ src/lib/OnlineAccounts/dbus_interface.cpp 2016-11-10 09:12:06 +0000
105@@ -22,6 +22,7 @@
106
107 #include <QDBusMetaType>
108 #include <QDebug>
109+#include <QVariantMap>
110 #include <climits>
111
112 using namespace OnlineAccounts;
113@@ -37,6 +38,7 @@
114
115 qDBusRegisterMetaType<AccountInfo>();
116 qDBusRegisterMetaType<QList<AccountInfo>>();
117+ qDBusRegisterMetaType<QList<QVariantMap>>();
118
119 bool ok = connect("AccountChanged", "s(ua{sv})",
120 this, SLOT(onAccountChanged(const QString&,const OnlineAccounts::AccountInfo&)));
121
122=== modified file 'src/lib/OnlineAccounts/manager.cpp'
123--- src/lib/OnlineAccounts/manager.cpp 2016-11-01 09:48:22 +0000
124+++ src/lib/OnlineAccounts/manager.cpp 2016-11-10 09:12:06 +0000
125@@ -45,6 +45,7 @@
126 q_ptr(q)
127 {
128 qRegisterMetaType<Account*>();
129+ qRegisterMetaType<Service>("OnlineAccounts::Service");
130
131 QObject::connect(&m_daemon,
132 SIGNAL(accountChanged(const QString&, const OnlineAccounts::AccountInfo&)),
133@@ -125,7 +126,7 @@
134
135 Q_ASSERT(m_getAccountsCall);
136
137- QDBusPendingReply<QList<AccountInfo> > reply = *m_getAccountsCall;
138+ QDBusPendingReply<QList<AccountInfo>,QList<QVariantMap>> reply = *m_getAccountsCall;
139 if (Q_UNLIKELY(reply.isError())) {
140 qCWarning(DBG_ONLINE_ACCOUNTS) << "GetAccounts call failed:" <<
141 reply.error();
142@@ -136,6 +137,12 @@
143 Q_FOREACH(const AccountInfo &info, accountInfos) {
144 m_accounts.insert({info.id(), info.service()}, AccountData(info));
145 }
146+
147+ QList<QVariantMap> services = reply.argumentAt<1>();
148+ for (const QVariantMap &data: services) {
149+ Service service(new Service::ServiceData(data));
150+ m_services.insert(service.id(), service);
151+ }
152 }
153 m_getAccountsCall->deleteLater();
154 m_getAccountsCall = 0;
155@@ -197,6 +204,12 @@
156 }
157 }
158
159+QList<Service> Manager::availableServices() const
160+{
161+ Q_D(const Manager);
162+ return d->m_services.values();
163+}
164+
165 QList<Account*> Manager::availableAccounts(const QString &service)
166 {
167 Q_D(Manager);
168
169=== modified file 'src/lib/OnlineAccounts/manager.h'
170--- src/lib/OnlineAccounts/manager.h 2016-07-22 05:08:06 +0000
171+++ src/lib/OnlineAccounts/manager.h 2016-11-10 09:12:06 +0000
172@@ -27,12 +27,14 @@
173 #include "error.h"
174 #include "global.h"
175 #include "pending_call.h"
176+#include "service.h"
177
178 class QDBusConnection;
179
180 namespace OnlineAccounts {
181
182 class Account;
183+class AccountPrivate;
184 class AuthenticationData;
185 class RequestAccessReplyPrivate;
186
187@@ -44,12 +46,14 @@
188 public:
189 explicit Manager(const QString &applicationId, QObject *parent = 0);
190 Manager(const QString &applicationId, const QDBusConnection &bus,
191- QObject *parent = 0);
192+ QObject *parent = 0);
193 ~Manager();
194
195 bool isReady() const;
196 void waitForReady();
197
198+ QList<Service> availableServices() const;
199+
200 QList<Account*> availableAccounts(const QString &service = QString());
201 Account *account(AccountId accountId);
202 Account *account(AccountId accountId, const QString &service);
203@@ -63,6 +67,7 @@
204
205 private:
206 friend class Account;
207+ friend class AccountPrivate;
208 friend class RequestAccessReplyPrivate;
209 Q_DECLARE_PRIVATE(Manager)
210 Q_DISABLE_COPY(Manager)
211
212=== modified file 'src/lib/OnlineAccounts/manager_p.h'
213--- src/lib/OnlineAccounts/manager_p.h 2016-07-22 05:08:06 +0000
214+++ src/lib/OnlineAccounts/manager_p.h 2016-11-10 09:12:06 +0000
215@@ -58,6 +58,11 @@
216
217 Account *ensureAccount(const AccountInfo &info);
218
219+ static Service serviceFromMap(const QVariantMap &map);
220+ Service service(const QString &serviceId) {
221+ return m_services.value(serviceId);
222+ }
223+
224 private:
225 void retrieveAccounts();
226
227@@ -71,6 +76,7 @@
228 DBusInterface m_daemon;
229 QDBusPendingCallWatcher *m_getAccountsCall;
230 QMap<QPair<AccountId,QString>,AccountData> m_accounts;
231+ QMap<QString,Service> m_services;
232 mutable Manager *q_ptr;
233 };
234
235
236=== added file 'src/lib/OnlineAccounts/service.cpp'
237--- src/lib/OnlineAccounts/service.cpp 1970-01-01 00:00:00 +0000
238+++ src/lib/OnlineAccounts/service.cpp 2016-11-10 09:12:06 +0000
239@@ -0,0 +1,54 @@
240+/*
241+ * This file is part of libOnlineAccounts
242+ *
243+ * Copyright (C) 2016 Canonical Ltd.
244+ *
245+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
246+ *
247+ * This program is free software: you can redistribute it and/or modify it
248+ * under the terms of the GNU Lesser General Public License version 3, as
249+ * published by the Free Software Foundation.
250+ *
251+ * This program is distributed in the hope that it will be useful, but
252+ * WITHOUT ANY WARRANTY; without even the implied warranties of
253+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
254+ * PURPOSE. See the GNU Lesser General Public License for more details.
255+ *
256+ * You should have received a copy of the GNU Lesser General Public License
257+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
258+ */
259+
260+#include "service.h"
261+
262+#include <QVariantMap>
263+#include "OnlineAccountsDaemon/dbus_constants.h"
264+
265+using namespace OnlineAccounts;
266+
267+Service::ServiceData::ServiceData(const QVariantMap &map):
268+ m_id(map.value(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID).toString()),
269+ m_displayName(map.value(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME).toString()),
270+ m_iconSource(map.value(ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE).toString())
271+{
272+}
273+
274+Service::Service():
275+ d(new ServiceData(QVariantMap()))
276+{
277+}
278+
279+Service::Service(const QVariantMap &map):
280+ d(new ServiceData(map))
281+{
282+}
283+
284+#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
285+QVariantMap Service::toMap() const
286+{
287+ return QVariantMap {
288+ { "serviceId", id() },
289+ { "displayName", displayName() },
290+ { "iconSource", iconSource() },
291+ };
292+}
293+#endif
294
295=== added file 'src/lib/OnlineAccounts/service.h'
296--- src/lib/OnlineAccounts/service.h 1970-01-01 00:00:00 +0000
297+++ src/lib/OnlineAccounts/service.h 2016-11-10 09:12:06 +0000
298@@ -0,0 +1,83 @@
299+/*
300+ * This file is part of libOnlineAccounts
301+ *
302+ * Copyright (C) 2016 Canonical Ltd.
303+ *
304+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
305+ *
306+ * This program is free software: you can redistribute it and/or modify it
307+ * under the terms of the GNU Lesser General Public License version 3, as
308+ * published by the Free Software Foundation.
309+ *
310+ * This program is distributed in the hope that it will be useful, but
311+ * WITHOUT ANY WARRANTY; without even the implied warranties of
312+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
313+ * PURPOSE. See the GNU Lesser General Public License for more details.
314+ *
315+ * You should have received a copy of the GNU Lesser General Public License
316+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
317+ */
318+
319+#ifndef ONLINE_ACCOUNTS_SERVICE_H
320+#define ONLINE_ACCOUNTS_SERVICE_H
321+
322+#include <QObject>
323+#include <QSharedData>
324+#include <QSharedDataPointer>
325+#include <QUrl>
326+#include <QVariantMap>
327+
328+#include "global.h"
329+
330+namespace OnlineAccounts {
331+
332+class Manager;
333+class ManagerPrivate;
334+
335+class ONLINE_ACCOUNTS_EXPORT Service
336+{
337+ Q_GADGET
338+ Q_PROPERTY(QString serviceId READ id CONSTANT)
339+ Q_PROPERTY(QString displayName READ displayName CONSTANT)
340+ Q_PROPERTY(QUrl iconSource READ iconSource CONSTANT)
341+
342+private:
343+ class ServiceData: public QSharedData {
344+ ServiceData(const QVariantMap &map);
345+ friend class ManagerPrivate;
346+ friend class Service;
347+ QString m_id;
348+ QString m_displayName;
349+ QUrl m_iconSource;
350+ };
351+
352+public:
353+ Service();
354+ ~Service() {}
355+
356+ Service(const Service &other): d(other.d) {}
357+
358+ bool isValid() const { return !d->m_id.isEmpty(); }
359+ QString id() const { return d->m_id; }
360+ QString displayName() const { return d->m_displayName; }
361+ QUrl iconSource() const { return d->m_iconSource; }
362+
363+#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
364+ QVariantMap toMap() const;
365+#endif
366+
367+protected:
368+ Service(const QVariantMap &map);
369+
370+private:
371+ friend class Manager;
372+ friend class ManagerPrivate;
373+ Service(ServiceData *d): d(d) {};
374+ QSharedDataPointer<ServiceData> d;
375+};
376+
377+} // namespace
378+
379+Q_DECLARE_METATYPE(OnlineAccounts::Service)
380+
381+#endif // ONLINE_ACCOUNTS_SERVICE_H
382
383=== modified file 'src/lib/OnlineAccountsDaemon/CMakeLists.txt'
384--- src/lib/OnlineAccountsDaemon/CMakeLists.txt 2015-09-04 08:32:00 +0000
385+++ src/lib/OnlineAccountsDaemon/CMakeLists.txt 2016-11-10 09:12:06 +0000
386@@ -23,6 +23,7 @@
387 authentication_request.cpp
388 authenticator.cpp
389 client_registry.cpp
390+ i18n.cpp
391 manager.cpp
392 manager_adaptor.cpp
393 state_saver.cpp
394
395=== modified file 'src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xml'
396--- src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xml 2015-08-28 14:25:23 +0000
397+++ src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xml 2016-11-10 09:12:06 +0000
398@@ -49,6 +49,7 @@
399 -->
400 <method name="GetAccounts">
401 <arg name="filters" type="a{sv}" direction="in" />
402+
403 <!--
404 The return value is a list of account IDs paired with a dictionary of account data.
405 This will always include:
406@@ -61,9 +62,22 @@
407 the framework level.
408 -->
409 <arg name="accounts" type="a(ua{sv})" direction="out" />
410+
411+ <!--
412+ The returned "services" is a list of dictionaries of the services' data.
413+ This will always include:
414+ - "serviceId" (s)
415+ - "displayName" (s): the translated display name
416+ - "iconSource" (s): URL to the service icon; if the URL starts with
417+ "image://theme/", then what follows is the symbolic icon name
418+ -->
419+ <arg name="services" type="aa{sv}" direction="out" />
420+
421 <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
422 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0"
423 value="QList&lt;AccountInfo&gt;"/>
424+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out1"
425+ value="QList&lt;QVariantMap&gt;"/>
426 </method>
427
428 <!--
429
430=== modified file 'src/lib/OnlineAccountsDaemon/dbus_constants.h'
431--- src/lib/OnlineAccountsDaemon/dbus_constants.h 2016-02-11 09:00:13 +0000
432+++ src/lib/OnlineAccountsDaemon/dbus_constants.h 2016-11-10 09:12:06 +0000
433@@ -42,6 +42,9 @@
434 # define ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED 1
435 # define ONLINE_ACCOUNTS_INFO_CHANGE_UPDATED 2
436
437+/* Keys for the service info dictionary */
438+#define ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE "iconSource"
439+
440 /* Error codes */
441 #define ONLINE_ACCOUNTS_ERROR_PREFIX "com.ubuntu.OnlineAccounts.Error."
442 #define ONLINE_ACCOUNTS_ERROR_NO_ACCOUNT \
443
444=== added file 'src/lib/OnlineAccountsDaemon/i18n.cpp'
445--- src/lib/OnlineAccountsDaemon/i18n.cpp 1970-01-01 00:00:00 +0000
446+++ src/lib/OnlineAccountsDaemon/i18n.cpp 2016-11-10 09:12:06 +0000
447@@ -0,0 +1,34 @@
448+/*
449+ * This file is part of OnlineAccountsDaemon
450+ *
451+ * Copyright (C) 2016 Canonical Ltd.
452+ *
453+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
454+ *
455+ * This program is free software: you can redistribute it and/or modify it
456+ * under the terms of the GNU Lesser General Public License version 3, as
457+ * published by the Free Software Foundation.
458+ *
459+ * This program is distributed in the hope that it will be useful, but
460+ * WITHOUT ANY WARRANTY; without even the implied warranties of
461+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
462+ * PURPOSE. See the GNU Lesser General Public License for more details.
463+ *
464+ * You should have received a copy of the GNU Lesser General Public License
465+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
466+ */
467+
468+#define NO_TR_OVERRIDE
469+#include "i18n.h"
470+
471+#include <libintl.h>
472+
473+namespace OnlineAccountsDaemon {
474+
475+QString translate(const QString &text, const QString &domain)
476+{
477+ return QString::fromUtf8(dgettext(domain.toUtf8().constData(),
478+ text.toUtf8().constData()));
479+}
480+
481+}; // namespace
482
483=== added file 'src/lib/OnlineAccountsDaemon/i18n.h'
484--- src/lib/OnlineAccountsDaemon/i18n.h 1970-01-01 00:00:00 +0000
485+++ src/lib/OnlineAccountsDaemon/i18n.h 2016-11-10 09:12:06 +0000
486@@ -0,0 +1,32 @@
487+/*
488+ * This file is part of OnlineAccountsDaemon
489+ *
490+ * Copyright (C) 2016 Canonical Ltd.
491+ *
492+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
493+ *
494+ * This program is free software: you can redistribute it and/or modify it
495+ * under the terms of the GNU Lesser General Public License version 3, as
496+ * published by the Free Software Foundation.
497+ *
498+ * This program is distributed in the hope that it will be useful, but
499+ * WITHOUT ANY WARRANTY; without even the implied warranties of
500+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
501+ * PURPOSE. See the GNU Lesser General Public License for more details.
502+ *
503+ * You should have received a copy of the GNU Lesser General Public License
504+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
505+ */
506+
507+#ifndef ONLINE_ACCOUNTS_DAEMON_I18N_H
508+#define ONLINE_ACCOUNTS_DAEMON_I18N_H
509+
510+#include <QString>
511+
512+namespace OnlineAccountsDaemon {
513+
514+QString translate(const QString &text, const QString &domain);
515+
516+} // namespace
517+
518+#endif // ONLINE_ACCOUNTS_DAEMON_I18N_H
519
520=== modified file 'src/lib/OnlineAccountsDaemon/manager.cpp'
521--- src/lib/OnlineAccountsDaemon/manager.cpp 2016-09-28 13:09:06 +0000
522+++ src/lib/OnlineAccountsDaemon/manager.cpp 2016-11-10 09:12:06 +0000
523@@ -36,6 +36,7 @@
524 #include "authenticator.h"
525 #include "client_registry.h"
526 #include "dbus_constants.h"
527+#include "i18n.h"
528 #include "manager_adaptor.h"
529 #include "state_saver.h"
530
531@@ -78,8 +79,10 @@
532 const QStringList &clients);
533
534 AccountInfo readAccountInfo(const Accounts::AccountService *as);
535+ QList<QVariantMap> buildServiceList(const Accounts::Application &app) const;
536 QList<AccountInfo> getAccounts(const QVariantMap &filters,
537- const CallContext &context);
538+ const CallContext &context,
539+ QList<QVariantMap> &services);
540 void authenticate(uint accountId, const QString &serviceId,
541 bool interactive, bool invalidate,
542 const QVariantMap &parameters,
543@@ -89,6 +92,8 @@
544 const CallContext &context);
545 bool canAccess(const QString &context, const QString &serviceId);
546
547+ static QString applicationIdFromLabel(const QString &label);
548+
549 void notifyAccountChange(const ActiveAccount &account, uint change);
550
551 private Q_SLOTS:
552@@ -344,22 +349,82 @@
553 return AccountInfo(as->account()->id(), info);
554 }
555
556+QList<QVariantMap>
557+ManagerPrivate::buildServiceList(const Accounts::Application &app) const
558+{
559+ QList<QVariantMap> services;
560+
561+ const auto serviceList = m_manager.serviceList(app);
562+ for (const Accounts::Service &service: serviceList) {
563+ QString displayName = translate(service.displayName(),
564+ service.trCatalog());
565+ QString icon = service.iconName();
566+
567+ /* Applications might declare support for a service while the provider
568+ * (and account plugin) for that account is not installed. We probably
569+ * don't want to include these services in the list, as it would lead
570+ * to empty/invalid UI elements. */
571+ Accounts::Provider provider = m_manager.provider(service.provider());
572+ if (!provider.isValid()) continue;
573+
574+ /* Now check the service data; if either display name or icon are
575+ * empty, fetch this information from the provider file, as a fallback
576+ */
577+ if (displayName.isEmpty() ||
578+ // sometimes we use a '.' as display name placeholder
579+ displayName == ".") {
580+ displayName = translate(provider.displayName(),
581+ provider.trCatalog());
582+ }
583+ if (icon.isEmpty()) {
584+ icon = provider.iconName();
585+ }
586+
587+ QString iconSource;
588+ if (icon.startsWith('/')) {
589+ iconSource = QStringLiteral("file:/") + icon;
590+ } else {
591+ iconSource = QStringLiteral("image://theme/") + icon;
592+ }
593+
594+ services.append({
595+ { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, service.name() },
596+ { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, displayName },
597+ { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, iconSource },
598+ });
599+ }
600+
601+ return services;
602+}
603+
604 QList<AccountInfo> ManagerPrivate::getAccounts(const QVariantMap &filters,
605- const CallContext &context)
606+ const CallContext &context,
607+ QList<QVariantMap> &services)
608 {
609 QString desiredApplicationId = filters.value("applicationId").toString();
610 QString desiredServiceId = filters.value("serviceId").toString();
611 Accounts::AccountId desiredAccountId = filters.value("accountId").toUInt();
612
613- Accounts::Application application = desiredApplicationId.isEmpty() ?
614- Accounts::Application() : m_manager.application(desiredApplicationId);
615-
616- if (application.isValid() &&
617- canAccess(context.securityContext(), desiredApplicationId)) {
618+ QString applicationId = desiredApplicationId.isEmpty() ?
619+ applicationIdFromLabel(context.securityContext()) : desiredApplicationId;
620+
621+ Accounts::Application application = m_manager.application(applicationId);
622+
623+ QList<AccountInfo> accounts;
624+
625+ if (!application.isValid() ||
626+ !canAccess(context.securityContext(), applicationId)) {
627+ if (!desiredApplicationId.isEmpty()) {
628+ context.sendError(ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED,
629+ QString("App '%1' cannot act as '%2'").
630+ arg(applicationId).arg(desiredApplicationId));
631+ return accounts;
632+ }
633+ } else {
634 m_clients.insert(context.clientName(), application);
635 }
636
637- QList<AccountInfo> accounts;
638+ services = buildServiceList(application);
639
640 Q_FOREACH(Accounts::AccountId accountId, m_manager.accountListEnabled()) {
641 if (desiredAccountId != 0 && accountId != desiredAccountId) {
642@@ -473,6 +538,16 @@
643 return serviceId.left(pos) == pkgname;
644 }
645
646+QString ManagerPrivate::applicationIdFromLabel(const QString &label)
647+{
648+ QStringList parts = label.split('_');
649+ if (parts.count() == 3) {
650+ return QStringList(parts.mid(0, 2)).join('_');
651+ } else {
652+ return QString();
653+ }
654+}
655+
656 void ManagerPrivate::onAccountServiceEnabled(bool enabled)
657 {
658 auto as = qobject_cast<Accounts::AccountService*>(sender());
659@@ -553,10 +628,11 @@
660 }
661
662 QList<AccountInfo> Manager::getAccounts(const QVariantMap &filters,
663- const CallContext &context)
664+ const CallContext &context,
665+ QList<QVariantMap> &services)
666 {
667 Q_D(Manager);
668- return d->getAccounts(filters, context);
669+ return d->getAccounts(filters, context, services);
670 }
671
672 void Manager::authenticate(uint accountId, const QString &serviceId,
673
674=== modified file 'src/lib/OnlineAccountsDaemon/manager.h'
675--- src/lib/OnlineAccountsDaemon/manager.h 2015-09-03 13:28:30 +0000
676+++ src/lib/OnlineAccountsDaemon/manager.h 2016-11-10 09:12:06 +0000
677@@ -52,7 +52,8 @@
678 bool isIdle() const;
679
680 QList<AccountInfo> getAccounts(const QVariantMap &filters,
681- const CallContext &context);
682+ const CallContext &context,
683+ QList<QVariantMap> &services);
684 void authenticate(uint accountId, const QString &serviceId,
685 bool interactive, bool invalidate,
686 const QVariantMap &parameters,
687
688=== modified file 'src/lib/OnlineAccountsDaemon/manager_adaptor.cpp'
689--- src/lib/OnlineAccountsDaemon/manager_adaptor.cpp 2015-08-28 14:25:23 +0000
690+++ src/lib/OnlineAccountsDaemon/manager_adaptor.cpp 2016-11-10 09:12:06 +0000
691@@ -147,6 +147,7 @@
692 qRegisterMetaType<QList<AccountInfo> >("QList<AccountInfo>");
693 qDBusRegisterMetaType<AccountInfo>();
694 qDBusRegisterMetaType<QList<AccountInfo>>();
695+ qDBusRegisterMetaType<QList<QVariantMap>>();
696
697 setAutoRelaySignals(false);
698 }
699@@ -175,10 +176,13 @@
700 return QVariantMap();
701 }
702
703-QList<AccountInfo> ManagerAdaptor::GetAccounts(const QVariantMap &filters)
704+void ManagerAdaptor::GetAccounts(const QVariantMap &filters,
705+ QList<AccountInfo> &accounts,
706+ QList<QVariantMap> &services)
707 {
708- return parent()->getAccounts(filters,
709- CallContext(dbusContext()));
710+ accounts = parent()->getAccounts(filters,
711+ CallContext(dbusContext()),
712+ services);
713 }
714
715 AccountInfo ManagerAdaptor::RequestAccess(const QString &serviceId,
716
717=== modified file 'src/lib/OnlineAccountsDaemon/manager_adaptor.h'
718--- src/lib/OnlineAccountsDaemon/manager_adaptor.h 2015-09-02 11:42:04 +0000
719+++ src/lib/OnlineAccountsDaemon/manager_adaptor.h 2016-11-10 09:12:06 +0000
720@@ -85,6 +85,7 @@
721 " <method name=\"GetAccounts\">\n"
722 " <arg direction=\"in\" type=\"a{sv}\" name=\"filters\"/>\n"
723 " <arg direction=\"out\" type=\"a(ua{sv})\" name=\"accounts\"/>\n"
724+" <arg direction=\"out\" type=\"aa{sv}\" name=\"services\"/>\n"
725 " </method>\n"
726 " <method name=\"Authenticate\">\n"
727 " <arg direction=\"in\" type=\"u\" name=\"accountId\"/>\n"
728@@ -123,7 +124,9 @@
729 QVariantMap Authenticate(uint accountId, const QString &serviceId,
730 bool interactive, bool invalidate,
731 const QVariantMap &parameters);
732- QList<AccountInfo> GetAccounts(const QVariantMap &filters);
733+ void GetAccounts(const QVariantMap &filters,
734+ QList<AccountInfo> &accounts,
735+ QList<QVariantMap> &services);
736 AccountInfo RequestAccess(const QString &serviceId,
737 const QVariantMap &parameters,
738 QVariantMap &credentials);
739
740=== modified file 'src/lib/Ubuntu/OnlineAccounts.2/account.cpp'
741--- src/lib/Ubuntu/OnlineAccounts.2/account.cpp 2016-01-13 14:23:12 +0000
742+++ src/lib/Ubuntu/OnlineAccounts.2/account.cpp 2016-11-10 09:12:06 +0000
743@@ -26,6 +26,9 @@
744 #include "OnlineAccounts/AuthenticationReply"
745 #include "OnlineAccounts/PendingCall"
746
747+#include <QDebug>
748+#include <QJSEngine>
749+
750 using namespace OnlineAccountsModule;
751
752 namespace OnlineAccountsModule {
753@@ -36,20 +39,25 @@
754 Q_DECLARE_PUBLIC(Account)
755
756 public:
757- AccountPrivate(OnlineAccounts::Account *account, Account *q);
758+ AccountPrivate(OnlineAccounts::Account *account, QJSEngine *engine,
759+ Account *q);
760
761 private Q_SLOTS:
762 void onAuthenticationFinished();
763
764 private:
765 OnlineAccounts::Account *m_account;
766+ QJSEngine *m_engine;
767 mutable Account *q_ptr;
768 };
769
770 } // namespace
771
772-AccountPrivate::AccountPrivate(OnlineAccounts::Account *account, Account *q):
773+AccountPrivate::AccountPrivate(OnlineAccounts::Account *account,
774+ QJSEngine *engine,
775+ Account *q):
776 m_account(account),
777+ m_engine(engine),
778 q_ptr(q)
779 {
780 QObject::connect(account, SIGNAL(changed()),
781@@ -122,9 +130,10 @@
782 * \endlist
783 */
784
785-Account::Account(OnlineAccounts::Account *account, QObject *parent):
786+Account::Account(OnlineAccounts::Account *account, QJSEngine *engine,
787+ QObject *parent):
788 QObject(parent),
789- d_ptr(new AccountPrivate(account, this))
790+ d_ptr(new AccountPrivate(account, engine, this))
791 {
792 }
793
794@@ -187,6 +196,27 @@
795 }
796
797 /*!
798+ * \qmlproperty int Account::service
799+ *
800+ * Service data associated with this account. This is an object containing the
801+ * following properties:
802+ * \list
803+ * \li \c serviceId - same service ID returned by Account::serviceId
804+ * \li \c displayName - the localized display name for the service
805+ * \li \c iconSource - URL for the icon; can be a "file://" URL to a local
806+ * file, or an icon from the theme if the URL starts with "image://theme/"
807+ */
808+QJSValue Account::service() const
809+{
810+ Q_D(const Account);
811+#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
812+ return d->m_engine->toScriptValue(d->m_account->service());
813+#else
814+ return d->m_engine->toScriptValue(d->m_account->service().toMap());
815+#endif
816+}
817+
818+/*!
819 * \qmlproperty enumeration Account::authenticationMethod
820 *
821 * The authentication method used when authenticating with the account.
822
823=== modified file 'src/lib/Ubuntu/OnlineAccounts.2/account.h'
824--- src/lib/Ubuntu/OnlineAccounts.2/account.h 2016-01-13 14:23:12 +0000
825+++ src/lib/Ubuntu/OnlineAccounts.2/account.h 2016-11-10 09:12:06 +0000
826@@ -21,10 +21,13 @@
827 #ifndef ONLINE_ACCOUNTS_MODULE_ACCOUNT_H
828 #define ONLINE_ACCOUNTS_MODULE_ACCOUNT_H
829
830+#include <QJSValue>
831 #include <QObject>
832 #include <QString>
833 #include <QVariantMap>
834
835+class QJSEngine;
836+
837 namespace OnlineAccounts {
838 class Account;
839 }
840@@ -40,6 +43,7 @@
841 Q_PROPERTY(QString displayName READ displayName NOTIFY accountChanged)
842 Q_PROPERTY(int accountId READ accountId CONSTANT)
843 Q_PROPERTY(QString serviceId READ serviceId CONSTANT)
844+ Q_PROPERTY(QJSValue service READ service CONSTANT)
845 Q_PROPERTY(AuthenticationMethod authenticationMethod \
846 READ authenticationMethod CONSTANT)
847 Q_PROPERTY(QVariantMap settings READ settings NOTIFY accountChanged)
848@@ -64,13 +68,15 @@
849 ErrorCodeInteractionRequired,
850 };
851
852- explicit Account(OnlineAccounts::Account *account, QObject *parent = 0);
853+ explicit Account(OnlineAccounts::Account *account, QJSEngine *engine,
854+ QObject *parent = 0);
855 ~Account();
856
857 bool isValid() const;
858 QString displayName() const;
859 int accountId() const;
860 QString serviceId() const;
861+ QJSValue service() const;
862 AuthenticationMethod authenticationMethod() const;
863 QVariantMap settings() const;
864
865@@ -90,4 +96,7 @@
866
867 } // namespace
868
869+Q_DECLARE_METATYPE(OnlineAccountsModule::Account::AuthenticationMethod)
870+Q_DECLARE_METATYPE(OnlineAccountsModule::Account::ErrorCode)
871+
872 #endif // ONLINE_ACCOUNTS_MODULE_ACCOUNT_H
873
874=== modified file 'src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp'
875--- src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp 2016-01-18 12:23:07 +0000
876+++ src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp 2016-11-10 09:12:06 +0000
877@@ -30,6 +30,7 @@
878 #include <QDebug>
879 #include <QQmlEngine>
880 #include <QVariantMap>
881+#include <QtQml>
882
883 using namespace OnlineAccountsModule;
884
885@@ -85,6 +86,7 @@
886 roleNames[AccountModel::AuthenticationMethodRole] = "authenticationMethod";
887 roleNames[AccountModel::SettingsRole] = "settings";
888 roleNames[AccountModel::AccountRole] = "account";
889+ roleNames[AccountModel::ServiceRole] = "service";
890 }
891
892 void AccountModelPrivate::queueUpdate()
893@@ -122,13 +124,17 @@
894
895 Account *AccountModelPrivate::handleAccount(OnlineAccounts::Account *account)
896 {
897+ Q_Q(AccountModel);
898+
899 /* First, check if the account is already handled */
900 Q_FOREACH(Account *a, m_accounts) {
901 if (account == a->internalObject()) {
902 return a;
903 }
904 }
905- Account *a = new Account(account, this);
906+
907+ QQmlEngine *engine = qmlEngine(q);
908+ Account *a = new Account(account, engine, this);
909 QQmlEngine::setObjectOwnership(a, QQmlEngine::CppOwnership);
910 QObject::connect(a, SIGNAL(validChanged()),
911 this, SLOT(onAccountValidChanged()));
912@@ -386,6 +392,24 @@
913 return objects;
914 }
915
916+QJSValue AccountModel::serviceList() const
917+{
918+ Q_D(const AccountModel);
919+ QJSEngine *engine = qmlEngine(this);
920+ QJSValue ret = engine->newArray();
921+ if (!d->m_manager) return ret;
922+ int i = 0;
923+ Q_FOREACH(const auto &service, d->m_manager->availableServices()) {
924+#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
925+ QJSValue v = engine->toScriptValue(service);
926+#else
927+ QJSValue v = engine->toScriptValue(service.toMap());
928+#endif
929+ ret.setProperty(i++, v);
930+ }
931+ return ret;
932+}
933+
934 /*!
935 * \qmlsignal AccountModel::accessReply(jsobject reply, jsobject authenticationData)
936 *
937@@ -495,6 +519,9 @@
938 case AccountRole:
939 ret = QVariant::fromValue<QObject*>(account);
940 break;
941+ case ServiceRole:
942+ ret = QVariant::fromValue(account->service());
943+ break;
944 }
945
946 return ret;
947
948=== modified file 'src/lib/Ubuntu/OnlineAccounts.2/account_model.h'
949--- src/lib/Ubuntu/OnlineAccounts.2/account_model.h 2016-01-18 12:23:07 +0000
950+++ src/lib/Ubuntu/OnlineAccounts.2/account_model.h 2016-11-10 09:12:06 +0000
951@@ -21,8 +21,12 @@
952 #ifndef ONLINE_ACCOUNTS_MODULE_ACCOUNT_MODEL_H
953 #define ONLINE_ACCOUNTS_MODULE_ACCOUNT_MODEL_H
954
955+#include "OnlineAccounts/Service"
956+
957 #include <QAbstractListModel>
958 #include <QQmlParserStatus>
959+#include <QQmlListProperty>
960+#include <QJSValue>
961 #include <QString>
962 #include <QVariant>
963
964@@ -43,6 +47,8 @@
965 WRITE setServiceId NOTIFY serviceIdChanged)
966 Q_PROPERTY(QList<QObject*> accountList READ accountList \
967 NOTIFY accountListChanged)
968+ Q_PROPERTY(QJSValue serviceList READ serviceList \
969+ NOTIFY isReadyChanged)
970
971 public:
972 enum Roles {
973@@ -53,6 +59,7 @@
974 AuthenticationMethodRole,
975 SettingsRole,
976 AccountRole,
977+ ServiceRole,
978 };
979
980 explicit AccountModel(QObject *parent = 0);
981@@ -68,6 +75,8 @@
982
983 QList<QObject*> accountList() const;
984
985+ QJSValue serviceList() const;
986+
987 Q_INVOKABLE void requestAccess(const QString &service,
988 const QVariantMap &params);
989
990
991=== modified file 'src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp'
992--- src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp 2015-07-31 12:44:30 +0000
993+++ src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp 2016-11-10 09:12:06 +0000
994@@ -20,6 +20,7 @@
995
996 #include "plugin.h"
997
998+#include "account.h"
999 #include "account_model.h"
1000
1001 #include <QDebug>
1002@@ -32,4 +33,8 @@
1003 qDebug() << Q_FUNC_INFO << uri;
1004
1005 qmlRegisterType<AccountModel>(uri, 2, 0, "AccountModel");
1006+ qmlRegisterUncreatableType<Account>(uri, 2, 0, "Account",
1007+ "Cannot be created from QML");
1008+ qmlRegisterUncreatableType<OnlineAccounts::Service>(uri, 2, 0, "Service",
1009+ "Cannot be created from QML");
1010 }
1011
1012=== modified file 'tests/daemon/functional_tests/data/com.ubuntu.tests_application.application'
1013--- tests/daemon/functional_tests/data/com.ubuntu.tests_application.application 2015-07-07 12:58:49 +0000
1014+++ tests/daemon/functional_tests/data/com.ubuntu.tests_application.application 2016-11-10 09:12:06 +0000
1015@@ -5,9 +5,12 @@
1016 <desktop-entry>mailer.desktop</desktop-entry>
1017
1018 <services>
1019- <service id="coolshare">
1020+ <service id="com.ubuntu.tests_coolshare">
1021 <description>Mailer can even share stuff on CoolShare</description>
1022 </service>
1023+ <service id="missing-provider">
1024+ <description>service exists, provider does not</description>
1025+ </service>
1026 </services>
1027 <profile>com.ubuntu.tests_application_0.3</profile>
1028 </application>
1029
1030=== modified file 'tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.service'
1031--- tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.service 2016-09-28 13:09:06 +0000
1032+++ tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.service 2016-11-10 09:12:06 +0000
1033@@ -1,5 +1,5 @@
1034 <?xml version="1.0" encoding="UTF-8" ?>
1035-<service id="coolshare">
1036+<service id="com.ubuntu.tests_coolshare">
1037 <type>sharing</type>
1038 <name>Cool Share</name>
1039 <icon>general_otherservice</icon>
1040
1041=== modified file 'tests/daemon/functional_tests/data/coolmail.service'
1042--- tests/daemon/functional_tests/data/coolmail.service 2015-07-02 08:29:48 +0000
1043+++ tests/daemon/functional_tests/data/coolmail.service 2016-11-10 09:12:06 +0000
1044@@ -2,7 +2,6 @@
1045 <service id="coolmail">
1046 <type>e-mail</type>
1047 <name>Cool Mail</name>
1048- <icon>general_myservice</icon>
1049 <provider>cool</provider>
1050
1051 <template>
1052
1053=== added file 'tests/daemon/functional_tests/data/missing-provider.service'
1054--- tests/daemon/functional_tests/data/missing-provider.service 1970-01-01 00:00:00 +0000
1055+++ tests/daemon/functional_tests/data/missing-provider.service 2016-11-10 09:12:06 +0000
1056@@ -0,0 +1,14 @@
1057+<?xml version="1.0" encoding="UTF-8" ?>
1058+<service id="missing-provider">
1059+ <type>sharing</type>
1060+ <name>Orphan</name>
1061+ <icon>icon_missing_provider</icon>
1062+ <provider>missing</provider>
1063+
1064+ <template>
1065+ <group name="auth">
1066+ <setting name="method">password</setting>
1067+ <setting name="mechanism">password</setting>
1068+ </group>
1069+ </template>
1070+</service>
1071
1072=== modified file 'tests/daemon/functional_tests/functional_tests.cpp'
1073--- tests/daemon/functional_tests/functional_tests.cpp 2016-10-13 13:42:12 +0000
1074+++ tests/daemon/functional_tests/functional_tests.cpp 2016-11-10 09:12:06 +0000
1075@@ -60,8 +60,28 @@
1076 return qstrdup(doc.toJson(QJsonDocument::Compact).data());
1077 }
1078
1079+template<>
1080+char *toString(const QSet<QVariantMap> &set)
1081+{
1082+ QByteArray ba = "QSet<QVariantMap>(";
1083+ QStringList list;
1084+ Q_FOREACH(const QVariantMap &map, set) {
1085+ list.append(QJsonDocument::fromVariant(map).toJson(QJsonDocument::Compact));
1086+ }
1087+ ba += list.join(", ");
1088+ ba += ")";
1089+ return qstrdup(ba.data());
1090+}
1091+
1092 } // QTest namespace
1093
1094+static inline uint qHash(const QVariantMap &m, uint seed = 0)
1095+{
1096+ QString signature = QStringList(m.keys()).join(' ') +
1097+ m.value(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID).toString();
1098+ return ::qHash(signature, seed);
1099+}
1100+
1101 class TestProcess: public QProcess
1102 {
1103 Q_OBJECT
1104@@ -90,6 +110,12 @@
1105 void quit() { write("\n"); waitForFinished(); }
1106
1107 QList<AccountInfo> getAccounts(const QVariantMap &filters) {
1108+ QList<QVariantMap> services;
1109+ return getAccounts(filters, services);
1110+ }
1111+
1112+ QList<AccountInfo> getAccounts(const QVariantMap &filters,
1113+ QList<QVariantMap> &services) {
1114 QJsonDocument doc(QJsonObject::fromVariantMap(filters));
1115 m_replyExpected = true;
1116 write("GetAccounts -f ");
1117@@ -97,16 +123,31 @@
1118
1119 waitForReadyRead();
1120 doc = QJsonDocument::fromJson(readLine());
1121+ qDebug() << "Got Json:" << doc;
1122 m_replyExpected = false;
1123 QList<AccountInfo> accountInfos;
1124- Q_FOREACH(const QJsonValue &v, doc.array()) {
1125+ if (checkError(doc)) return accountInfos;
1126+ const QJsonArray accountsJson = doc.array().at(0).toArray();
1127+ const QJsonArray servicesJson = doc.array().at(1).toArray();
1128+ Q_FOREACH(const QJsonValue &v, accountsJson) {
1129 QJsonArray a = v.toArray();
1130 accountInfos.append(AccountInfo(a.at(0).toInt(),
1131 a.at(1).toObject().toVariantMap()));
1132 }
1133+ Q_FOREACH(const QJsonValue &v, servicesJson) {
1134+ services.append(v.toObject().toVariantMap());
1135+ }
1136 return accountInfos;
1137 }
1138
1139+ QString errorName() const { return m_errorName; }
1140+
1141+protected:
1142+ bool checkError(const QJsonDocument &doc) {
1143+ m_errorName = doc.object().value("error").toString();
1144+ return !m_errorName.isEmpty();
1145+ }
1146+
1147 private Q_SLOTS:
1148 void onReadyRead() {
1149 if (m_replyExpected) return;
1150@@ -128,6 +169,7 @@
1151
1152 private:
1153 QString m_uniqueName;
1154+ QString m_errorName;
1155 bool m_replyExpected;
1156 };
1157
1158@@ -275,35 +317,113 @@
1159 delete m_dbus;
1160 }
1161
1162+
1163 void FunctionalTests::testGetAccountsFiltering_data()
1164 {
1165 QTest::addColumn<QVariantMap>("filters");
1166 QTest::addColumn<QString>("securityContext");
1167+ QTest::addColumn<QString>("expectedError");
1168 QTest::addColumn<QList<int> >("expectedAccountIds");
1169+ QTest::addColumn<QList<QVariantMap> >("expectedServices");
1170
1171 QVariantMap filters;
1172 QTest::newRow("empty filters") <<
1173 filters <<
1174 "unconfined" <<
1175- (QList<int>() << 1 << 2 << 3);
1176+ QString() <<
1177+ (QList<int>() << 1 << 2 << 3) <<
1178+ QList<QVariantMap> {};
1179
1180 QTest::newRow("empty filters, confined") <<
1181 filters <<
1182 "com.ubuntu.tests_application_0.2" <<
1183- (QList<int>() << 2);
1184-
1185- filters[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = "coolmail";
1186- QTest::newRow("by service ID") <<
1187- filters <<
1188- "unconfined" <<
1189- (QList<int>() << 1 << 3);
1190+ QString() <<
1191+ (QList<int>() << 2) <<
1192+ QList<QVariantMap> {
1193+ {
1194+ { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Cool Share" },
1195+ { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "com.ubuntu.tests_coolshare" },
1196+ { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_otherservice" },
1197+ },
1198+ };
1199+
1200+ filters[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = "coolmail";
1201+ QTest::newRow("unconfined, by service ID") <<
1202+ filters <<
1203+ "unconfined" <<
1204+ QString() <<
1205+ (QList<int>() << 1 << 3) <<
1206+ QList<QVariantMap> {};
1207+ filters.clear();
1208+
1209+ filters[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = "coolmail";
1210+ QTest::newRow("confined, by service ID") <<
1211+ filters <<
1212+ "com.ubuntu.tests_application_0.2" <<
1213+ QString() <<
1214+ (QList<int>()) <<
1215+ QList<QVariantMap> {
1216+ {
1217+ { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Cool Share" },
1218+ { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "com.ubuntu.tests_coolshare" },
1219+ { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_otherservice" },
1220+ },
1221+ };
1222+ filters.clear();
1223+
1224+ filters["applicationId"] = "com.ubuntu.tests_application";
1225+ QTest::newRow("by app ID") <<
1226+ filters <<
1227+ "unconfined" <<
1228+ QString() <<
1229+ (QList<int>() << 2) <<
1230+ QList<QVariantMap> {
1231+ {
1232+ { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Cool Share" },
1233+ { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "com.ubuntu.tests_coolshare" },
1234+ { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_otherservice" },
1235+ },
1236+ };
1237+ filters.clear();
1238+
1239+ filters["applicationId"] = "mailer";
1240+ QTest::newRow("confined app requesting other app ID") <<
1241+ filters <<
1242+ "com.ubuntu.tests_application_0.2" <<
1243+ ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED <<
1244+ (QList<int>()) <<
1245+ QList<QVariantMap> {};
1246+ filters.clear();
1247+
1248+ filters["applicationId"] = "mailer";
1249+ QTest::newRow("by app ID, with service fallback") <<
1250+ filters <<
1251+ "unconfined" <<
1252+ QString() <<
1253+ QList<int>{ 3, 1 } <<
1254+ QList<QVariantMap> {
1255+ {
1256+ { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "OAuth 1 test" },
1257+ { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "oauth1auth" },
1258+ { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_myservice" },
1259+ },
1260+ {
1261+ { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Cool Mail" },
1262+ { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "coolmail" },
1263+ { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_myprovider" },
1264+ },
1265+ };
1266+ filters.clear();
1267+
1268 }
1269
1270 void FunctionalTests::testGetAccountsFiltering()
1271 {
1272 QFETCH(QVariantMap, filters);
1273 QFETCH(QString, securityContext);
1274+ QFETCH(QString, expectedError);
1275 QFETCH(QList<int>, expectedAccountIds);
1276+ QFETCH(QList<QVariantMap>, expectedServices);
1277
1278 DaemonInterface *daemon = new DaemonInterface(m_dbus->sessionConnection());
1279
1280@@ -313,7 +433,10 @@
1281 };
1282 m_dbus->dbusApparmor().setCredentials(testProcess.uniqueName(), credentials);
1283
1284- QList<AccountInfo> accountInfos = testProcess.getAccounts(filters);
1285+ QList<QVariantMap> services;
1286+ QList<AccountInfo> accountInfos = testProcess.getAccounts(filters, services);
1287+ QCOMPARE(testProcess.errorName(), expectedError);
1288+ QCOMPARE(services.toSet(), expectedServices.toSet());
1289 QList<int> accountIds;
1290 Q_FOREACH(const AccountInfo &info, accountInfos) {
1291 accountIds.append(info.id() + m_firstAccountId);
1292
1293=== modified file 'tests/daemon/functional_tests/test_process.py'
1294--- tests/daemon/functional_tests/test_process.py 2016-07-19 11:55:45 +0000
1295+++ tests/daemon/functional_tests/test_process.py 2016-11-10 09:12:06 +0000
1296@@ -30,8 +30,11 @@
1297 filters = dbus.Dictionary(signature='sv')
1298 if args.filters:
1299 filters.update(json.loads(args.filters))
1300- print('%s' % json.dumps(self.manager.GetAccounts(filters), sort_keys=True),
1301- flush=True)
1302+ try:
1303+ print('%s' % json.dumps(self.manager.GetAccounts(filters), sort_keys=True),
1304+ flush=True)
1305+ except dbus.exceptions.DBusException as err:
1306+ print('{ "error": "%s" }' % err.get_dbus_name(), flush=True)
1307
1308 def on_account_changed(self, serviceId, accountInfo):
1309 info = json.dumps(accountInfo, sort_keys=True)
1310
1311=== modified file 'tests/lib/OnlineAccounts/functional_tests/functional_tests.cpp'
1312--- tests/lib/OnlineAccounts/functional_tests/functional_tests.cpp 2016-07-22 05:08:06 +0000
1313+++ tests/lib/OnlineAccounts/functional_tests/functional_tests.cpp 2016-11-10 09:12:06 +0000
1314@@ -26,18 +26,22 @@
1315 #include "OnlineAccounts/account_info.h"
1316 #include "OnlineAccountsDaemon/dbus_constants.h"
1317 #include <QDBusConnection>
1318+#include <QJsonDocument>
1319+#include <QJsonObject>
1320 #include <QObject>
1321 #include <QSignalSpy>
1322 #include <QTest>
1323 #include <libqtdbusmock/DBusMock.h>
1324
1325 namespace QTest {
1326+
1327 template<>
1328 char *toString(const QVariantMap &map)
1329 {
1330 QJsonDocument doc(QJsonObject::fromVariantMap(map));
1331 return qstrdup(doc.toJson(QJsonDocument::Compact).data());
1332 }
1333+
1334 } // QTest namespace
1335
1336 class FunctionalTests: public QObject
1337@@ -82,6 +86,8 @@
1338 void testManagerReady();
1339 void testManagerAvailableAccounts_data();
1340 void testManagerAvailableAccounts();
1341+ void testManagerAvailableServices_data();
1342+ void testManagerAvailableServices();
1343 void testManagerAccount();
1344 void testManagerRequestAccess_data();
1345 void testManagerRequestAccess();
1346@@ -132,7 +138,7 @@
1347 QFETCH(bool, haveGetAccountsMethod);
1348
1349 if (haveGetAccountsMethod) {
1350- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []");
1351+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", "ret = ([], [])");
1352 }
1353 OnlineAccounts::Manager manager("my-app");
1354
1355@@ -150,12 +156,12 @@
1356 QTest::addColumn<QStringList>("expectedDisplayNames");
1357
1358 QTest::newRow("no accounts") <<
1359- "ret = []" <<
1360+ "ret = ([], [])" <<
1361 QList<int>() <<
1362 QStringList();
1363
1364 QTest::newRow("one account, no data") <<
1365- "ret = [(1, {'displayName': 'Tom'})]" <<
1366+ "ret = ([(1, {'displayName': 'Tom'})], [])" <<
1367 (QList<int>() << 1) <<
1368 (QStringList() << "Tom");
1369 }
1370@@ -166,7 +172,7 @@
1371 QFETCH(QList<int>, expectedIds);
1372 QFETCH(QStringList, expectedDisplayNames);
1373
1374- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply);
1375+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", reply);
1376 OnlineAccounts::Manager manager("my-app");
1377
1378 manager.waitForReady();
1379@@ -181,10 +187,77 @@
1380 QCOMPARE(displayNames, expectedDisplayNames);
1381 }
1382
1383+void FunctionalTests::testManagerAvailableServices_data()
1384+{
1385+ QTest::addColumn<QString>("reply");
1386+ QTest::addColumn<QList<QVariantMap>>("expectedServices");
1387+
1388+ QTest::newRow("no services") <<
1389+ "ret = ([], [])" <<
1390+ QList<QVariantMap> {};
1391+
1392+ QTest::newRow("one service") <<
1393+ "ret = ([], [{"
1394+ "'" ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID "': 'app_coolshare',"
1395+ "'" ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME "': 'Cool Share',"
1396+ "'" ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE "': 'image://theme/coolshare',"
1397+ "}])" <<
1398+ QList<QVariantMap> {
1399+ {
1400+ { "serviceId", "app_coolshare" },
1401+ { "displayName", "Cool Share" },
1402+ { "iconSource", "image://theme/coolshare"},
1403+ },
1404+ };
1405+}
1406+
1407+void FunctionalTests::testManagerAvailableServices()
1408+{
1409+ QFETCH(QString, reply);
1410+ QFETCH(QList<QVariantMap>, expectedServices);
1411+
1412+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", reply);
1413+ OnlineAccounts::Manager manager("my-app");
1414+
1415+ manager.waitForReady();
1416+ const auto availableServices = manager.availableServices();
1417+#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
1418+ QList<QVariantMap> services;
1419+ for (const OnlineAccounts::Service &service: availableServices) {
1420+ QVariantMap data;
1421+
1422+ const QMetaObject &mo = service.staticMetaObject;
1423+ for (int i = mo.propertyOffset(); i < mo.propertyCount(); i++) {
1424+ const QMetaProperty prop = mo.property(i);
1425+ data.insert(prop.name(), prop.readOnGadget(&service));
1426+ }
1427+
1428+ services.append(data);
1429+ }
1430+
1431+ QCOMPARE(services, expectedServices);
1432+#else
1433+ QCOMPARE(availableServices.count(), expectedServices.count());
1434+#endif
1435+}
1436+
1437 void FunctionalTests::testManagerAccount()
1438 {
1439- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})",
1440- "ret = [(1, {'displayName': 'John'})]");
1441+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}",
1442+ "ret = (["
1443+ " (1, {"
1444+ " 'displayName': 'John',"
1445+ " 'serviceId': 'app_coolshare',"
1446+ " }),"
1447+ " (2, {"
1448+ " 'displayName': 'Bob',"
1449+ " 'serviceId': 'a missing one',"
1450+ " }),"
1451+ "], [{"
1452+ " 'serviceId': 'app_coolshare',"
1453+ " 'displayName': 'Cool Share',"
1454+ " 'iconSource': 'image://theme/coolshare',"
1455+ "}])");
1456 OnlineAccounts::Manager manager("my-app");
1457
1458 manager.waitForReady();
1459@@ -193,10 +266,22 @@
1460 OnlineAccounts::Account *account = manager.account(4);
1461 QVERIFY(!account);
1462
1463+ // valid account linking to invalid service
1464+ account = manager.account(2);
1465+ QVERIFY(account);
1466+ QCOMPARE(account->displayName(), QString("Bob"));
1467+ QCOMPARE(account->serviceId(), QString("a missing one"));
1468+ QVERIFY(!account->service().isValid());
1469+
1470 // valid account
1471 account = manager.account(1);
1472 QVERIFY(account);
1473 QCOMPARE(account->displayName(), QString("John"));
1474+ QCOMPARE(account->serviceId(), QString("app_coolshare"));
1475+ QVERIFY(account->service().isValid());
1476+ QCOMPARE(account->service().displayName(), QString("Cool Share"));
1477+ QCOMPARE(account->service().iconSource(),
1478+ QUrl("image://theme/coolshare"));
1479 }
1480
1481 void FunctionalTests::testManagerRequestAccess_data()
1482@@ -236,7 +321,7 @@
1483 QFETCH(QString, displayName);
1484 QFETCH(QString, accessToken);
1485
1486- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []");
1487+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", "ret = ([], [])");
1488 addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}", reply);
1489 OnlineAccounts::Manager manager("my-app");
1490
1491@@ -277,12 +362,12 @@
1492 QTest::addColumn<QVariantMap>("settings");
1493
1494 QTest::newRow("empty account") <<
1495- "ret = [(1, {})]" <<
1496+ "[(1, {})]" <<
1497 1 <<
1498 "" << "" << 0 << QVariantMap();
1499
1500 QTest::newRow("no settings") <<
1501- "ret = [(3, {"
1502+ "[(3, {"
1503 " 'displayName': 'Bob',"
1504 " 'serviceId': 'MyService',"
1505 " 'authMethod': 1,"
1506@@ -297,7 +382,7 @@
1507 settings.insert("Host", "example.com");
1508 settings.insert("Port", int(7000));
1509 QTest::newRow("with settings") <<
1510- "ret = [(4, {"
1511+ "[(4, {"
1512 " 'displayName': 'Tom',"
1513 " 'serviceId': 'MyService',"
1514 " 'authMethod': 2,"
1515@@ -320,7 +405,8 @@
1516 QFETCH(int, authenticationMethod);
1517 QFETCH(QVariantMap, settings);
1518
1519- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply);
1520+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}",
1521+ QString("ret = (%1, [])").arg(reply));
1522 OnlineAccounts::Manager manager("my-app");
1523
1524 manager.waitForReady();
1525@@ -347,7 +433,7 @@
1526
1527 void FunctionalTests::testPendingCallWatcher()
1528 {
1529- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []");
1530+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", "ret = ([], [])");
1531 addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}",
1532 "ret = ((1, {'displayName': 'Bob'}),{})");
1533 OnlineAccounts::Manager manager("my-app");
1534@@ -378,7 +464,7 @@
1535
1536 void FunctionalTests::testAccountChanges()
1537 {
1538- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []");
1539+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", "ret = ([], [])");
1540 OnlineAccounts::Manager manager("my-app");
1541 QSignalSpy accountAvailable(&manager,
1542 SIGNAL(accountAvailable(OnlineAccounts::Account*)));
1543@@ -442,8 +528,8 @@
1544
1545 void FunctionalTests::testMultipleServices()
1546 {
1547- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})",
1548- "ret = ["
1549+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}",
1550+ "ret = (["
1551 "(1, {"
1552 " 'displayName': 'One',"
1553 " 'serviceId': 'service2',"
1554@@ -464,7 +550,7 @@
1555 " 'serviceId': 'service1',"
1556 " 'authMethod': 1,"
1557 "}),"
1558- "]");
1559+ "], [])");
1560 OnlineAccounts::Manager manager("my-app");
1561 manager.waitForReady();
1562
1563@@ -494,8 +580,8 @@
1564
1565 void FunctionalTests::testAuthentication()
1566 {
1567- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})",
1568- "ret = ["
1569+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}",
1570+ "ret = (["
1571 "(1, {"
1572 " 'displayName': 'Bob',"
1573 " 'serviceId': 'MyService0',"
1574@@ -516,7 +602,7 @@
1575 " 'serviceId': 'MyService3',"
1576 " 'authMethod': 4,"
1577 "}),"
1578- "]");
1579+ "], [])");
1580 addMockedMethod("Authenticate", "usbba{sv}", "a{sv}",
1581 "if args[0] == 1:\n"
1582 " ret = {"
1583@@ -671,12 +757,12 @@
1584 QFETCH(int, errorCode);
1585 QFETCH(QString, errorMessage);
1586
1587- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})",
1588- "ret = [(1, {"
1589+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}",
1590+ "ret = ([(1, {"
1591 " 'displayName': 'Bob',"
1592 " 'serviceId': 'MyService0',"
1593 " 'authMethod': 2,"
1594- "})]");
1595+ "})], [])");
1596 addMockedMethod("Authenticate", "usbba{sv}", "a{sv}", reply);
1597 OnlineAccounts::Manager manager("my-app");
1598 manager.waitForReady();
1599
1600=== modified file 'tests/lib/qml_module/tst_qml_module.cpp'
1601--- tests/lib/qml_module/tst_qml_module.cpp 2016-10-06 08:20:10 +0000
1602+++ tests/lib/qml_module/tst_qml_module.cpp 2016-11-10 09:12:06 +0000
1603@@ -55,14 +55,18 @@
1604 }
1605
1606 void addMockedMethod(const QString &name,
1607- const QString &in_sig,
1608- const QString &out_sig,
1609- const QString &code)
1610+ const QString &in_sig,
1611+ const QString &out_sig,
1612+ const QString &code)
1613 {
1614 return mocked().AddMethod(ONLINE_ACCOUNTS_MANAGER_INTERFACE,
1615 name, in_sig, out_sig, code).waitForFinished();
1616 }
1617
1618+ void addGetAccountsMethod(const QString &code) {
1619+ addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", code);
1620+ }
1621+
1622 void emitAccountChanged(const QString &service,
1623 uint accountId,
1624 const QVariantMap &changes)
1625@@ -90,6 +94,8 @@
1626 void initTestCase();
1627 void testModuleImport();
1628 void testModelProperties();
1629+ void testServices_data();
1630+ void testServices();
1631 void testModelRoles_data();
1632 void testModelRoles();
1633 void testModelFilters_data();
1634@@ -156,9 +162,85 @@
1635 delete object;
1636 }
1637
1638+void ModuleTest::testServices_data()
1639+{
1640+ QTest::addColumn<QString>("reply");
1641+ QTest::addColumn<QList<QVariantMap>>("expectedServices");
1642+
1643+ QTest::newRow("no services") <<
1644+ "[]" <<
1645+ QList<QVariantMap> {};
1646+
1647+ QTest::newRow("one service") <<
1648+ "[{"
1649+ "'" ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID "': 'app_coolshare',"
1650+ "'" ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME "': 'Cool Share',"
1651+ "'" ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE "': 'image://theme/coolshare',"
1652+ "}]" <<
1653+ QList<QVariantMap> {
1654+ {
1655+ { "serviceId", "app_coolshare" },
1656+ { "displayName", "Cool Share" },
1657+ { "iconSource", "image://theme/coolshare"},
1658+ },
1659+ };
1660+}
1661+
1662+void ModuleTest::testServices()
1663+{
1664+ QFETCH(QString, reply);
1665+ QFETCH(QList<QVariantMap>, expectedServices);
1666+
1667+ addGetAccountsMethod(QString("ret = ([], %1)").arg(reply));
1668+
1669+ QQmlEngine engine;
1670+ QQmlComponent component(&engine);
1671+ /* We could return the serviceList property directly, but that would be
1672+ * passing a OnlineAccounts::Service as QJSValue, which might not be a
1673+ * proof that every property is properly accessible from QML. Therefore, we
1674+ * explicitly run through the list and copy it as a new object. */
1675+ component.setData("import Ubuntu.OnlineAccounts 2.0\n"
1676+ "AccountModel {\n"
1677+ " applicationId: \"foo\"\n"
1678+ " function getServices() {\n"
1679+ " var ret = [];\n"
1680+ " for (var i = 0; i < serviceList.length; i++) {\n"
1681+ " var s = serviceList[i];\n"
1682+ " var service = {};\n"
1683+ " for (var key in s) { service[key] = s[key]; }\n"
1684+ " ret.push(service);\n"
1685+ " }\n"
1686+ " return ret;\n"
1687+ " }\n"
1688+ "}",
1689+ QUrl());
1690+ QObject *object = component.create();
1691+ QVERIFY(object != 0);
1692+ QAbstractListModel *model = qobject_cast<QAbstractListModel*>(object);
1693+ QVERIFY(model != 0);
1694+
1695+ QSignalSpy ready(object, SIGNAL(isReadyChanged()));
1696+ ready.wait();
1697+
1698+ QVariant serviceList;
1699+ bool ok = QMetaObject::invokeMethod(object, "getServices",
1700+ Q_RETURN_ARG(QVariant, serviceList));
1701+ QVERIFY(ok);
1702+
1703+ QVariantList serviceVariantList = serviceList.toList();
1704+ QList<QVariantMap> services;
1705+ for (const QVariant &v: serviceVariantList) {
1706+ services.append(v.toMap());
1707+ }
1708+
1709+ QCOMPARE(services, expectedServices);
1710+ delete object;
1711+}
1712+
1713 void ModuleTest::testModelRoles_data()
1714 {
1715 QTest::addColumn<QString>("accountData");
1716+ QTest::addColumn<QString>("serviceData");
1717 QTest::addColumn<QString>("displayName");
1718 QTest::addColumn<QString>("serviceId");
1719 QTest::addColumn<int>("authenticationMethod");
1720@@ -167,6 +249,7 @@
1721 QVariantMap settings;
1722 QTest::newRow("empty") <<
1723 "{}" <<
1724+ "" <<
1725 "" << "" << 0 << settings;
1726
1727 settings.insert("Server", "www.example.com");
1728@@ -179,19 +262,23 @@
1729 " '" ONLINE_ACCOUNTS_INFO_KEY_SETTINGS "Server': 'www.example.com',"
1730 " '" ONLINE_ACCOUNTS_INFO_KEY_SETTINGS "Port': 9900,"
1731 "}" <<
1732+ "{"
1733+ " '" ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID "': 'cool',"
1734+ "}" <<
1735 "Tom" << "cool" << 2 << settings;
1736 }
1737
1738 void ModuleTest::testModelRoles()
1739 {
1740 QFETCH(QString, accountData);
1741+ QFETCH(QString, serviceData);
1742 QFETCH(QString, displayName);
1743 QFETCH(QString, serviceId);
1744 QFETCH(int, authenticationMethod);
1745 QFETCH(QVariantMap, settings);
1746
1747- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})",
1748- QString("ret = [(1, %1)]").arg(accountData));
1749+ addGetAccountsMethod(QString("ret = ([(1, %1)], [%2])").
1750+ arg(accountData).arg(serviceData));
1751
1752 QQmlEngine engine;
1753 QQmlComponent component(&engine);
1754@@ -218,7 +305,6 @@
1755 QCOMPARE(get(model, 0, "serviceId").toString(), serviceId);
1756 QCOMPARE(get(model, 0, "authenticationMethod").toInt(),
1757 authenticationMethod);
1758- // until https://bugs.launchpad.net/bugs/1479768 is fixed
1759 QCOMPARE(get(model, 0, "settings").toMap(), settings);
1760 QObject *account = get(model, 0, "account").value<QObject*>();
1761 QVERIFY(account != 0);
1762@@ -226,6 +312,10 @@
1763 QCOMPARE(account,
1764 model->property("accountList").value<QList<QObject*> >().first());
1765
1766+ QJSValue service = get(model, 0, "service").value<QJSValue>();
1767+ QVERIFY(service.isObject());
1768+ QCOMPARE(service.property("serviceId").toString(), serviceId);
1769+
1770 delete object;
1771 }
1772
1773@@ -237,17 +327,17 @@
1774 QTest::addColumn<QStringList>("expectedDisplayNames");
1775
1776 QTest::newRow("no accounts") <<
1777- "ret = []" <<
1778+ "[]" <<
1779 "" <<
1780 QList<int>();
1781
1782 QTest::newRow("one account, no service filter") <<
1783- "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" <<
1784+ "[(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" <<
1785 "" <<
1786 (QList<int>() << 1);
1787
1788 QTest::newRow("one account, with service filter") <<
1789- "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" <<
1790+ "[(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" <<
1791 "serviceId: \"bar\"" <<
1792 QList<int>();
1793 }
1794@@ -258,7 +348,7 @@
1795 QFETCH(QString, filters);
1796 QFETCH(QList<int>, expectedIds);
1797
1798- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply);
1799+ addGetAccountsMethod(QString("ret = (%1, [])").arg(reply));
1800
1801 QQmlEngine engine;
1802 QQmlComponent component(&engine);
1803@@ -287,7 +377,7 @@
1804
1805 void ModuleTest::testModelChanges()
1806 {
1807- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []");
1808+ addGetAccountsMethod("ret = ([], [])");
1809 QQmlEngine engine;
1810 QQmlComponent component(&engine);
1811 component.setData("import Ubuntu.OnlineAccounts 2.0\n"
1812@@ -397,8 +487,7 @@
1813 QFETCH(QVariantMap, expectedAccessReply);
1814 QFETCH(QVariantMap, expectedAuthenticationData);
1815
1816- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})",
1817- "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]");
1818+ addGetAccountsMethod("ret = ([(1, {'displayName': 'Tom', 'serviceId': 'Foo' })], [])");
1819 addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}", reply);
1820
1821 QQmlEngine engine;
1822@@ -536,12 +625,11 @@
1823 QFETCH(QVariantMap, params);
1824 QFETCH(QVariantMap, expectedAuthenticationData);
1825
1826- addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})",
1827- QString("ret = [(1, {"
1828- " 'displayName': 'Bob',"
1829- " 'serviceId': 'MyService0',"
1830- " 'authMethod': %1,"
1831- "})]").arg(authMethod));
1832+ addGetAccountsMethod(QString("ret = ([(1, {"
1833+ " 'displayName': 'Bob',"
1834+ " 'serviceId': 'MyService0',"
1835+ " 'authMethod': %1,"
1836+ "})], [])").arg(authMethod));
1837 addMockedMethod("Authenticate", "usbba{sv}", "a{sv}", reply);
1838
1839 QQmlEngine engine;

Subscribers

People subscribed via source and target branches