Merge lp:~justinmcp/unity-chromium-extension/generic-extension into lp:unity-chromium-extension

Proposed by Justin McPherson
Status: Work in progress
Proposed branch: lp:~justinmcp/unity-chromium-extension/generic-extension
Merge into: lp:unity-chromium-extension
Diff against target: 4642 lines (+2399/-1482)
67 files modified
CMakeLists.txt (+32/-0)
chromium-extension/CMakeLists.txt (+69/-0)
chromium-extension/background-page.html (+2/-2)
chromium-extension/background-page.js (+64/-61)
chromium-extension/browser.js (+24/-24)
chromium-extension/build.sh (+0/-27)
chromium-extension/chromium-extension.pro (+0/-66)
chromium-extension/infobar.css (+0/-20)
chromium-extension/infobar.html (+0/-20)
chromium-extension/infobar.js (+0/-33)
chromium-extension/manifest.json.in (+41/-35)
chromium-extension/options.html (+4/-6)
chromium-extension/options.js (+3/-3)
chromium-extension/popup.css (+21/-0)
chromium-extension/popup.html (+20/-0)
chromium-extension/popup.js (+36/-0)
chromium-extension/unity-api-page-proxy.js (+1/-1)
chromium-extension/unity-webapps.json.in (+2/-2)
common-project-config.pri (+0/-41)
common-vars.pri (+0/-6)
coverage.pri (+0/-49)
debian/changelog (+7/-0)
debian/control (+13/-5)
debian/unity-chromium-extension.install (+2/-3)
debian/unity-webapps-extension-process.install (+1/-0)
messaging-host/CMakeLists.txt (+101/-0)
messaging-host/Makefile.am (+0/-2)
messaging-host/click-handler.cpp (+386/-0)
messaging-host/click-handler.h (+55/-0)
messaging-host/com.canonical.webapp.extension.json.in (+9/-0)
messaging-host/com.canonical.webapp.installer.json.in (+0/-9)
messaging-host/main.cpp (+28/-8)
messaging-host/messaging-host.pro (+0/-42)
messaging-host/service-handler.cpp (+75/-0)
messaging-host/service-handler.h (+54/-0)
messaging-host/service.cpp (+18/-11)
messaging-host/webapps-handler.cpp (+11/-17)
messaging-host/webapps-handler.h (+0/-1)
tests/CMakeLists.txt (+1/-0)
tests/tests.pro (+0/-3)
tests/unit/CMakeLists.txt (+1/-0)
tests/unit/messaging-host/CMakeLists.txt (+5/-0)
tests/unit/messaging-host/click-handler/CMakeLists.txt (+38/-0)
tests/unit/messaging-host/click-handler/tst_click-handler.cpp (+291/-0)
tests/unit/messaging-host/connection-host.cpp (+0/-71)
tests/unit/messaging-host/connection/CMakeLists.txt (+40/-0)
tests/unit/messaging-host/connection/connection-host.cpp (+71/-0)
tests/unit/messaging-host/connection/tst_connection.cpp (+112/-0)
tests/unit/messaging-host/inactivity-timer/CMakeLists.txt (+23/-0)
tests/unit/messaging-host/inactivity-timer/tst_inactivity_timer.cpp (+125/-0)
tests/unit/messaging-host/messaging-host.pri (+0/-9)
tests/unit/messaging-host/messaging-host.pro (+0/-12)
tests/unit/messaging-host/service/CMakeLists.txt (+23/-0)
tests/unit/messaging-host/service/tst_service.cpp (+189/-0)
tests/unit/messaging-host/tst_connection.cpp (+0/-112)
tests/unit/messaging-host/tst_connection.pro (+0/-14)
tests/unit/messaging-host/tst_connection_host.pro (+0/-14)
tests/unit/messaging-host/tst_inactivity_timer.cpp (+0/-125)
tests/unit/messaging-host/tst_inactivity_timer.pro (+0/-18)
tests/unit/messaging-host/tst_service.cpp (+0/-189)
tests/unit/messaging-host/tst_service.pro (+0/-18)
tests/unit/messaging-host/tst_webapps-handler.cpp (+0/-354)
tests/unit/messaging-host/tst_webapps-handler.pro (+0/-32)
tests/unit/messaging-host/webapps-handler/CMakeLists.txt (+47/-0)
tests/unit/messaging-host/webapps-handler/tst_webapps-handler.cpp (+354/-0)
tests/unit/unit.pro (+0/-3)
unity-chromium-extension.pro (+0/-14)
To merge this branch: bzr merge lp:~justinmcp/unity-chromium-extension/generic-extension
Reviewer Review Type Date Requested Status
WebApps Pending
Review via email: mp+272066@code.launchpad.net

Commit message

Signal available webapps while navigating with Chrome and Webbrowser-app.
Look for compatible webapps in the installed click packages.

Description of the change

Signal available webapps while navigating with Chrome and Webbrowser-app.
Look for compatible webapps in the installed click packages.

To post a comment you must log in.
251. By Justin McPherson

WIP

252. By Justin McPherson

WIP

253. By Justin McPherson

WIP

254. By Justin McPherson

WIP

255. By Justin McPherson

WIP

256. By Justin McPherson

WIP

257. By Justin McPherson

WIP

258. By Justin McPherson

Add tests

259. By Justin McPherson

Finish click related tests

260. By Justin McPherson

Make checking for maintainer configurable

261. By Justin McPherson

Fix leak

Unmerged revisions

261. By Justin McPherson

Fix leak

260. By Justin McPherson

Make checking for maintainer configurable

259. By Justin McPherson

Finish click related tests

258. By Justin McPherson

Add tests

257. By Justin McPherson

WIP

256. By Justin McPherson

WIP

255. By Justin McPherson

WIP

254. By Justin McPherson

WIP

253. By Justin McPherson

WIP

252. By Justin McPherson

WIP

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'CMakeLists.txt'
2--- CMakeLists.txt 1970-01-01 00:00:00 +0000
3+++ CMakeLists.txt 2015-10-07 04:25:10 +0000
4@@ -0,0 +1,32 @@
5+# vim:expandtab:shiftwidth=2:tabstop=2:
6+
7+# Copyright (C) 2015 Canonical Ltd.
8+
9+# This library is free software; you can redistribute it and/or
10+# modify it under the terms of the GNU Lesser General Public
11+# License as published by the Free Software Foundation; either
12+# version 2.1 of the License, or (at your option) any later version.
13+
14+# This library is distributed in the hope that it will be useful,
15+# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+# Lesser General Public License for more details.
18+
19+# You should have received a copy of the GNU Lesser GeneraGl Public
20+# License along with this library; if not, write to the Free Software
21+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22+
23+cmake_minimum_required(VERSION 2.8.11)
24+
25+project(unity-chromium-extension)
26+
27+set(PROJECT_NAME "unity_webapps_chromium")
28+set(PROJECT_VERSION "3.3")
29+
30+include(GNUInstallDirs)
31+
32+add_subdirectory(chromium-extension)
33+add_subdirectory(messaging-host)
34+
35+enable_testing()
36+add_subdirectory(tests)
37
38=== added file 'chromium-extension/CMakeLists.txt'
39--- chromium-extension/CMakeLists.txt 1970-01-01 00:00:00 +0000
40+++ chromium-extension/CMakeLists.txt 2015-10-07 04:25:10 +0000
41@@ -0,0 +1,69 @@
42+
43+set(PEMFILE unity-webapps.pem)
44+
45+set(EXTENSION_DIR ${CMAKE_INSTALL_FULL_LIBDIR}/libunity-chromium)
46+set(EXTENSION_NAME unity-webapps)
47+set(EXTENSION_FILE ${EXTENSION_NAME}.crx)
48+set(EXTENSION_WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_NAME})
49+set(EXTENSION_FILES)
50+
51+list(
52+ APPEND EXTENSION_FILES
53+ background-page.html
54+ background-page.js
55+ base-content-script.js
56+ browser.js
57+ popup.css
58+ popup.html
59+ popup.js
60+ _locales
61+ options.html
62+ options.js
63+ skin
64+ unity-api-page-proxy-builder-gen.js
65+ unity-api-page-proxy.js
66+)
67+
68+# Create a directory for archiving+signing extension and copy in necessary files
69+file(MAKE_DIRECTORY ${EXTENSION_WORKING_DIR})
70+file(COPY ${EXTENSION_FILES} DESTINATION ${EXTENSION_WORKING_DIR})
71+
72+# If we already have a signing key, copy it to the working directory
73+if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/${PEMFILE})
74+ file(COPY ${CMAKE_CURRENT_LIST_DIR}/${PEMFILE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
75+endif()
76+
77+# fill out config files
78+configure_file(manifest.json.in ${EXTENSION_WORKING_DIR}/manifest.json)
79+configure_file(unity-webapps.json.in ${CMAKE_CURRENT_BINARY_DIR}/unity-webapps.json)
80+
81+# If not using the included signing key, generate one TODO: use key id
82+add_custom_command(
83+ OUTPUT ${PEMFILE}
84+ COMMAND openssl genrsa 1024 > ${PEMFILE}
85+)
86+
87+# Prepare extension
88+add_custom_command(
89+ OUTPUT ${EXTENSION_FILE}
90+ COMMAND ${CMAKE_CURRENT_LIST_DIR}/crxmake.sh ${EXTENSION_NAME} ${PEMFILE}
91+ DEPENDS ${PEMFILE}
92+)
93+
94+add_custom_target(
95+ build-extension ALL
96+ DEPENDS ${EXTENSION_FILE}
97+)
98+
99+# Install extension description in chrome data dir
100+# The crxmake.sh script writes this file to ./res
101+install(
102+ DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/res/
103+ DESTINATION ${CMAKE_INSTALL_DATADIR}/chromium/extensions
104+ FILES_MATCHING PATTERN "*.json"
105+)
106+
107+install(
108+ FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_FILE}
109+ DESTINATION ${EXTENSION_DIR}
110+)
111
112=== modified file 'chromium-extension/background-page.html'
113--- chromium-extension/background-page.html 2014-05-20 13:40:09 +0000
114+++ chromium-extension/background-page.html 2015-10-07 04:25:10 +0000
115@@ -4,9 +4,9 @@
116
117 <title>Unity Webapps Extension Background Page</title>
118 <embed type="application/x-unity-webapps-npapi" id="unityChromiumExtensionId"/>
119-
120+
121 <script src="background-page.js"></script>
122-
123+
124 </head>
125
126 <body>
127
128=== modified file 'chromium-extension/background-page.js'
129--- chromium-extension/background-page.js 2014-06-20 06:16:48 +0000
130+++ chromium-extension/background-page.js 2015-10-07 04:25:10 +0000
131@@ -1,28 +1,28 @@
132 /* Chromium Unity integration extension
133- *
134+ *
135 * Copyright 2012 Canonical Ltd.
136 *
137- * This program is free software: you can redistribute it and/or modify it
138- * under the terms of the GNU General Public License version 3, as published
139+ * This program is free software: you can redistribute it and/or modify it
140+ * under the terms of the GNU General Public License version 3, as published
141 * by the Free Software Foundation.
142 *
143- * This program is distributed in the hope that it will be useful, but
144- * WITHOUT ANY WARRANTY; without even the implied warranties of
145- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
146+ * This program is distributed in the hope that it will be useful, but
147+ * WITHOUT ANY WARRANTY; without even the implied warranties of
148+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
149 * PURPOSE. See the GNU General Public License for more details.
150 *
151- * You should have received a copy of the GNU General Public License along
152+ * You should have received a copy of the GNU General Public License along
153 * with this program. If not, see <http://www.gnu.org/licenses/>.
154 **/
155
156 var background_page = (function () {
157 // Native messaging support
158- var HOST_ADDRESS = 'com.canonical.webapp.installer';
159+ var HOST_ADDRESS = 'com.canonical.webapp.extension';
160 var port = null;
161 var host_callbacks = [];
162
163 var portListener = function (msg) {
164- callback = host_callbacks.pop();
165+ callback = host_callbacks.pop();
166 if (callback === undefined) {
167 return;
168 }
169@@ -30,12 +30,10 @@
170 };
171
172 var portDisconnecter = function () {
173- console.log('UCX: port disconnected');
174- port = null
175+ port = null;
176 };
177
178 var sendNativeMessage = function (msg, callback) {
179- console.log("UCX: sendnativemessage: port=" + port);
180 if (port === null) {
181 port = chrome.runtime.connectNative(HOST_ADDRESS);
182 port.onMessage.addListener(portListener);
183@@ -50,46 +48,42 @@
184
185
186 /////////////////////////////////////////////////////////
187- //
188- // Scafolding to keep track of data associated w/ infobar requests
189+ //
190+ // Scafolding to keep track of data associated w/ pageaction requests
191 // (Chromium's structure imposes some kind of state being maintained
192- // in order to communicate data)
193- //
194+ // in order to communicate data)
195+ //
196 ////////////////////////////////////////////////////////
197- //
198+ //
199 // list of callback that are to be called asynchronously
200 // per tab. Used in the user integration/installation resquests context.
201- //
202- // One thing to keep in mind is that one constraint, that bring some amount of
203- // 'soundness' is that there is a hard limit (provided by the browser) of one infobar per tab.
204
205- var user_infobar_request_callbacks = {};
206- var addInfobarRequestCallbackFor = function (infobarRequestId, callback, message, details) {
207- user_infobar_request_callbacks[infobarRequestId] = {
208+ var user_popup_request_callbacks = {};
209+ var addPopupRequestCallbackFor = function (popupRequestId, callback, message, details) {
210+ user_popup_request_callbacks[popupRequestId] = {
211 callback: callback,
212 message: message,
213 details: details
214 };
215 };
216
217- var getDataIfAnyFor = function (infobarRequestId) {
218- if (user_infobar_request_callbacks[infobarRequestId] === undefined) {
219+ var getDataIfAnyFor = function (popupRequestId) {
220+ if (user_popup_request_callbacks[popupRequestId] === undefined) {
221 return "";
222 }
223 return {
224- message: user_infobar_request_callbacks[infobarRequestId].message,
225- details: user_infobar_request_callbacks[infobarRequestId].details
226+ message: user_popup_request_callbacks[popupRequestId].message,
227+ details: user_popup_request_callbacks[popupRequestId].details
228 };
229 };
230-
231- var invokeAndRemoveCallbackIfAnyFor = function (infobarRequestId, arguments) {
232- if (user_infobar_request_callbacks[infobarRequestId] === undefined) {
233+ var invokeAndRemoveCallbackIfAnyFor = function (popupRequestId, args) {
234+ if (user_popup_request_callbacks[popupRequestId] === undefined) {
235 return;
236 }
237- var callback = user_infobar_request_callbacks[infobarRequestId].callback;
238- user_infobar_request_callbacks[infobarRequestId] = undefined;
239+ var callback = user_popup_request_callbacks[popupRequestId].callback;
240+ user_popup_request_callbacks[popupRequestId] = undefined;
241 if (typeof(callback) === 'function') {
242- callback(arguments);
243+ callback(args);
244 }
245 };
246
247@@ -106,35 +100,37 @@
248 },
249 function (response) {
250 if (response.available) {
251- addInfobarRequestCallbackFor(
252+ addPopupRequestCallbackFor(
253 windowInfos.tabId,
254 function (result) {
255 if (result && result.integrate) {
256 sendNativeMessage({
257 "method" : "install",
258 "url" : url
259- })
260+ });
261 } else {
262 sendNativeMessage({
263 "method" : "dont_ask",
264 "url" : url
265- })
266+ });
267 }
268+
269+ chrome.pageAction.hide(windowInfos.tabId);
270 },
271 chrome.i18n.getMessage("integration_copy", [ response.appName, response.appDomain ]),
272 null);
273
274- chrome.infobars.show({ tabId: windowInfos.tabId, path: "infobar.html" });
275+ chrome.pageAction.show(windowInfos.tabId);
276 }
277 });
278- };
279-
280-
281+ };
282+
283+
284 // {{{ main request handler
285-
286+
287 /**
288 * Handles & responds to content script requests.
289- *
290+ *
291 */
292 var init_requested_stamps = {};
293 var contentScriptsRequestHandler = function (request, sender, callback) {
294@@ -144,10 +140,10 @@
295 logging: false,
296 incognito: sender.tab.incognito
297 };
298-
299+
300 try {
301 if (window.localStorage) {
302- settings.logging = localStorage['logging'];
303+ settings.logging = localStorage.logging;
304 }
305 }
306 catch (e) {
307@@ -156,8 +152,8 @@
308
309 callback (settings);
310 },
311- on_user_infobar_request_result: function (request, sender, callback) {
312- invokeAndRemoveCallbackIfAnyFor (request.tabId, request);
313+ on_user_popup_request_result: function (request, sender, callback) {
314+ invokeAndRemoveCallbackIfAnyFor(request.tabId, request);
315 },
316 init_requested: function (request, sender, callback) {
317 sendNativeMessage({
318@@ -166,30 +162,32 @@
319 },
320 function (response) {
321 if (response.available) {
322- addInfobarRequestCallbackFor(
323+ addPopupRequestCallbackFor(
324 sender.tab.id,
325 function (result) {
326 if (result && result.integrate) {
327 sendNativeMessage({
328 "method" : "install",
329 "url" : request.options.url
330- })
331+ });
332 } else {
333 sendNativeMessage({
334 "method" : "dont_ask",
335 "url" : request.options.url
336- })
337+ });
338 }
339+
340+ chrome.pageAction.hide(windowInfos.tabId);
341 },
342 chrome.i18n.getMessage("integration_copy", [ response.appName, response.appDomain ]),
343 null);
344
345- chrome.infobars.show({ tabId: windowInfos.tabId, path: "infobar.html" });
346+ chrome.pageAction.show(windowInfos.tabId);
347 }
348 });
349 }
350 };
351-
352+
353 // validate request
354 if (!request || !request.method) {
355 callback({ error: "Invalid request structure" });
356@@ -200,20 +198,18 @@
357 return true;
358 }
359
360- if (typeof(request.method) != 'string' || request.method.length == 0) {
361+ if (typeof(request.method) != 'string' || request.method.length === 0) {
362 callback({ error: "Invalid request method" });
363 return true;
364 }
365
366- console.log('Got request: ' + request.method);
367-
368 var handler = handlers [request.method];
369 if (handler !== undefined && typeof(handler) == 'function') {
370 handler(request, sender, callback);
371 return true;
372 }
373 return false;
374- }
375+ };
376
377 // Main event handler and communication link
378 // w/ content scripts
379@@ -221,18 +217,16 @@
380 // }}}
381
382 ///////////////////////////////////////////////////////////////////////
383- //
384+ //
385 // Window management related functions. In chromeless mode, we have specific
386 // rules for tab management to make webapps feel more "native" than plain
387 // web applications.
388- //
389+ //
390 ///////////////////////////////////////////////////////////////////////
391
392 var onTabChanged = function (tabId, windowId, url) {
393 var onInstalled = function (installed, packageName, appName, appDomain) { };
394
395- console.log("onTabChanged: " + url);
396-
397 matchesIntegrationScripts(
398 null, //plugin,
399 url,
400@@ -255,15 +249,24 @@
401
402 chrome.tabs.onUpdated.addListener(
403 function(tabId, changeInfo, tab) {
404- console.log("onUpdated " + changeInfo.url);
405 if (changeInfo && changeInfo.url) {
406 onTabChanged(tabId, tab.windowId, changeInfo.url);
407 }
408 }
409 );
410
411+ chrome.tabs.onReplaced.addListener(
412+ function(addedTabId, removedTabId) {
413+ chrome.tabs.get(addedTabId, function(tab) {
414+ if (tab && tab.url) {
415+ onTabChanged(addedTabId, tab.windowId, tab.url);
416+ }
417+ });
418+ }
419+ );
420+
421 /*
422- * Returns a potential message associated with a tab id (infobar)
423+ * Returns a potential message associated with a tab id (popup)
424 */
425 return {
426 getMessageForTabId: function (tabId) {
427
428=== modified file 'chromium-extension/browser.js'
429--- chromium-extension/browser.js 2014-05-20 13:40:09 +0000
430+++ chromium-extension/browser.js 2015-10-07 04:25:10 +0000
431@@ -10,20 +10,21 @@
432 var service = null;
433 var api = {
434 init: function (options) {
435- options.url = window.location.href;
436- options.hostname = window.location.hostname;
437- options.host = window.location.host;
438- options.protocol = window.location.protocol;
439- chrome.runtime.sendMessage (
440- {method: "init_requested", options: options}
441- , function (response) {});
442+ options.url = window.location.href;
443+ options.hostname = window.location.hostname;
444+ options.host = window.location.host;
445+ options.protocol = window.location.protocol;
446+ chrome.runtime.sendMessage(
447+ {method: "init_requested", options: options},
448+ function (response) {}
449+ );
450 }
451 };
452
453 /**
454 * Inserts a given script in the webpage.
455 * Needs chrome.extension functionality.
456- *
457+ *
458 * @param path of file to be injected (part of the extension)
459 */
460 var insertScriptIntoWebpage = function (path) {
461@@ -47,14 +48,14 @@
462 var e = document.createEvent ("Events");
463 d.style.cssText = "display:none;";
464 d.value = id;
465- d.addEventListener ("unity-webapps-chromium-api-com-link-callback-called-ack"
466- , function() { d.parentNode.removeChild (d); }
467- , true);
468+ d.addEventListener("unity-webapps-chromium-api-com-link-callback-called-ack",
469+ function() { d.parentNode.removeChild (d); },
470+ true);
471 document.body.appendChild (d);
472 e.initEvent ("unity-webapps-chromium-api-com-link-callback-called", false, true);
473 d.dispatchEvent (e);
474 };
475- };
476+ }
477
478 // TODO: should be shared / generated w/ web page code
479 var isIterableObject = function(obj) {
480@@ -75,9 +76,9 @@
481 if ( ! isIterableObject(obj)) {
482 return obj;
483 }
484- if (obj
485- && obj.hasOwnProperty('callbackid')
486- && obj.callbackid != null) {
487+ if (obj &&
488+ obj.hasOwnProperty('callbackid') &&
489+ obj.callbackid !== null) {
490 return makeWebpageCallback (obj.callbackid);
491 }
492
493@@ -87,7 +88,7 @@
494
495 if (isIterableObject (obj[key])) {
496
497- if (obj[key].callbackid != null) {
498+ if (obj[key].callbackid !== null) {
499 ret[key] = makeWebpageCallback (obj[key].callbackid);
500 }
501 else {
502@@ -100,7 +101,7 @@
503 }
504 }
505 return ret;
506- };
507+ }
508
509 // 2. open the communication mean between the two
510
511@@ -120,9 +121,9 @@
512 console.log ('Error while dispatching call to ' + funcnames.join('.') + ': ' + err);
513 }
514 };
515-
516- document.addEventListener("unity-webapps-chromium-api-com-link"
517- , function(event) {
518+
519+ document.addEventListener("unity-webapps-chromium-api-com-link",
520+ function(event) {
521 var from = event.target;
522 if (from) {
523 var type = from.getAttribute("data-eventType");
524@@ -133,7 +134,7 @@
525 // Actuall call, e.g. 'Notification.showNotification("a","b")
526 // being reduces to successive calls to associated objects:
527 // Notification, showNotification
528- //
529+ //
530 // TODO add proper error handling
531 dispatchActualFunctionCall(type, args);
532 }
533@@ -142,8 +143,8 @@
534 var ret = document.createEvent('Events');
535 ret.initEvent('unity-webapps-chromium-api-com-link-ack', true, false);
536 from.dispatchEvent(ret);
537- }
538- , true);
539+ },
540+ true);
541 };
542
543 // handle the proxy side of the api which is being injected on the
544@@ -151,4 +152,3 @@
545 injectApiProxy();
546 }
547 )(window);
548-
549
550=== removed file 'chromium-extension/build.sh'
551--- chromium-extension/build.sh 2012-04-27 19:34:47 +0000
552+++ chromium-extension/build.sh 1970-01-01 00:00:00 +0000
553@@ -1,27 +0,0 @@
554-#!/bin/bash -e
555-
556-
557-CRX_FILENAME=`pwd`/../chromium-extension.crx
558-PEM_FILENAME=`pwd`/../chromium-extension.pem
559-
560-if [ -e "$CRX_FILENAME" ]
561-then
562- rm -f "$CRX_FILENAME"
563-fi
564-
565-#if [ -e "$PEM_FILENAME" ]
566-#then
567-# rm -f "$PEM_FILENAME"
568-#fi
569-
570-if test -n "`which google-chrome`"; then
571- google-chrome --no-message-box --pack-extension=`pwd` --pack-extension-key=../chromium-extension.pem
572-else
573- chromium-browser --no-message-box --pack-extension=`pwd`
574-fi
575-
576-# not necessary
577-# mv `pwd`/../unity-chromium-extension.crx .
578-
579-
580-
581
582=== removed file 'chromium-extension/chromium-extension.pro'
583--- chromium-extension/chromium-extension.pro 2014-05-21 12:53:43 +0000
584+++ chromium-extension/chromium-extension.pro 1970-01-01 00:00:00 +0000
585@@ -1,66 +0,0 @@
586-include(../common-project-config.pri)
587-include($${TOP_SRC_DIR}/common-vars.pri)
588-
589-TEMPLATE = aux
590-
591-EXTENSION_DIR = $${INSTALL_LIBDIR}/libunity-chromium
592-EXTENSION_NAME = unity-webapps
593-EXTENSION_FILE = $${EXTENSION_NAME}.crx
594-
595-STATIC_EXTENSION_FILES = \
596- background-page.html \
597- background-page.js \
598- base-content-script.js \
599- browser.js \
600- infobar.css \
601- infobar.html \
602- infobar.js \
603- _locales \
604- options.html \
605- options.js \
606- skin \
607- unity-api-page-proxy-builder-gen.js \
608- unity-api-page-proxy.js \
609-
610-SCRIPT_FILES = \
611- $${STATIC_EXTENSION_FILES} \
612- manifest.json \
613- unity-webapps.json
614-
615-QMAKE_SUBSTITUTES += \
616- manifest.json.in \
617- unity-webapps.json.in
618-
619-pemfile.target = unity-webapps.pem
620-pemfile.commands = "openssl genrsa 1024 > $${pemfile.target}"
621-
622-static_files.depends = \
623- $${SCRIPT_FILES}
624-static_files.commands = mkdir -p $${OUT_PWD}/$${EXTENSION_NAME} && ${COPY_DIR} $${SCRIPT_FILES} $${OUT_PWD}/$${EXTENSION_NAME}
625-
626-static_files_stamp.target = buildstamp
627-static_files_stamp.depends = static_files
628-static_files_stamp.commands = touch $${static_files_stamp.target}
629-
630-extension.target = res/$${EXTENSION_NAME}.crx
631-extension.commands = $${TOP_SRC_DIR}/chromium-extension/crxmake.sh $${OUT_PWD}/$${EXTENSION_NAME} $${pemfile.target}
632-extension.depends = pemfile static_files_stamp
633-
634-QMAKE_EXTRA_TARGETS += \
635- extension \
636- pemfile \
637- static_files \
638- static_files_stamp
639-
640-PRE_TARGETDEPS = $${extension.target}
641-
642-manifest.files = \
643- $${OUT_PWD}/res/*.json
644-manifest.path = $${INSTALL_PREFIX}/share/chromium/extensions/
645-manifest.CONFIG = no_check_exist
646-INSTALLS += manifest
647-
648-crx.files = res/$${EXTENSION_NAME}.crx
649-crx.path = $${EXTENSION_DIR}
650-crx.CONFIG = no_check_exist
651-INSTALLS += crx
652
653=== removed file 'chromium-extension/infobar.css'
654--- chromium-extension/infobar.css 2012-05-16 18:19:03 +0000
655+++ chromium-extension/infobar.css 1970-01-01 00:00:00 +0000
656@@ -1,20 +0,0 @@
657-body {
658- background: -webkit-linear-gradient(#E9E9E9, #DADADA);
659- font-family: Tahoma, Geneva, sans-serif;
660- font-size: 13px;
661- height: 36px; /* Infobars are limited to 36-72px */
662- margin: 0;
663- overflow: hidden;
664- padding-left: 6px;
665- padding-right: 6px;
666- padding-top: 5px;
667-}
668-
669-img {
670- padding-right: 6px;
671-}
672-
673-button {
674- padding-right: 10px;
675-}
676-
677
678=== removed file 'chromium-extension/infobar.html'
679--- chromium-extension/infobar.html 2012-10-12 01:18:07 +0000
680+++ chromium-extension/infobar.html 1970-01-01 00:00:00 +0000
681@@ -1,20 +0,0 @@
682-<html>
683-
684-<head>
685-</head>
686-
687-<link rel="stylesheet" type="text/css" href="infobar.css"></link>
688-<script src="infobar.js"></script>
689-
690-<body>
691-
692-<div id="content" style="display:none">
693- <span id="message"></span>
694- <input type="button" id="notintegrate" value="Never for this site" />
695- <input type="button" id="integrate" value="Yes" onclick="doIntegrate(true)"/>
696-</div>
697-
698-</body>
699-
700-
701-</html>
702
703=== removed file 'chromium-extension/infobar.js'
704--- chromium-extension/infobar.js 2014-11-18 07:07:15 +0000
705+++ chromium-extension/infobar.js 1970-01-01 00:00:00 +0000
706@@ -1,33 +0,0 @@
707-var doIntegrate = function (integrate) {
708- chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
709- chrome.runtime.sendMessage({tabId: tabs[0].id, method: "on_user_infobar_request_result", integrate: integrate}
710- , function (response) {});
711- window.close();
712- });
713-};
714-
715-window.onload = function () {
716- chrome.runtime.getBackgroundPage(function (bg) {
717- document.getElementById('notintegrate').onclick = function () { doIntegrate(false); };
718- document.getElementById('integrate').onclick = function () { doIntegrate(true); };
719-
720- chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
721- if (tabs.length === 0) {
722- window.close();
723- return;
724- }
725- if (!bg || !bg.background_page) {
726- window.close();
727- return;
728- }
729- var msg = bg.background_page.getMessageForTabId(tabs[0].id);
730- if (msg == null) {
731- window.close();
732- return;
733- }
734- document.getElementById ('content').style.display = "block";
735- document.getElementById ('message').innerHTML = msg || "";
736- });
737- });
738-};
739-
740
741=== modified file 'chromium-extension/manifest.json.in'
742--- chromium-extension/manifest.json.in 2014-05-21 12:22:21 +0000
743+++ chromium-extension/manifest.json.in 2015-10-07 04:25:10 +0000
744@@ -1,42 +1,48 @@
745 {
746- '"name": "Unity WebApps Chromium extension"',
747- '"manifest_version"': 2,
748- '"minimum_chrome_version": "34.0"',
749- '"content_security_policy"': '"script-src \'self\' chrome-extension://infobar.js \'unsafe-eval\'; object-src \'self\'"',
750-
751- '"version": "$${PROJECT_VERSION}"',
752-
753- '"description": "Unity Webapps Chromium integration"',
754-
755- '"web_accessible_resources"': [
756- '"browser.js"',
757- '"unity-api-page-proxy-builder-gen.js"',
758- '"unity-api-page-proxy.js"',
759- '"infobar.js"',
760- '"options.js"'
761+ "name": "Unity WebApps Chromium extension",
762+ "manifest_version": 2,
763+ "minimum_chrome_version": "34.0",
764+ "content_security_policy": "script-src \'self\' chrome-extension://infobar.js \'unsafe-eval\'; object-src \'self\'",
765+
766+ "version": "${PROJECT_VERSION}",
767+
768+ "description": "Unity Webapps Chromium integration",
769+
770+ "web_accessible_resources": [
771+ "browser.js",
772+ "unity-api-page-proxy-builder-gen.js",
773+ "unity-api-page-proxy.js",
774+ "options.js"
775 ],
776
777- '"icons"': {
778- '"16": "skin/cof-16.png"',
779- '"48": "skin/cof-48.png"'
780- },
781-
782- '"default_locale": "en"',
783-
784- '"background"': {
785- '"page"': '"background-page.html"'
786- },
787-
788- '"permissions": ["tabs", "http://*/*", "infobars", "nativeMessaging"]',
789- '"options_page": "options.html"',
790-
791- '"content_scripts"': [
792+ "icons": {
793+ "16": "skin/cof-16.png",
794+ "48": "skin/cof-48.png"
795+ },
796+
797+ "default_locale": "en",
798+
799+ "background": {
800+ "page": "background-page.html"
801+ },
802+
803+ "permissions": ["tabs", "http://*/*", "nativeMessaging"],
804+ "page_action": {
805+ "default_icon": {
806+ "19": "skin/cof-16.png",
807+ "38": "skin/cof-48.png"
808+ },
809+ "default_title": "Unity Webapps",
810+ "default_popup": "popup.html"
811+ },
812+ "options_page": "options.html",
813+
814+ "content_scripts": [
815 {
816- '"all_frames"': true,
817- '"matches": [ "<all_urls>" ]',
818- '"js": ["base-content-script.js"]',
819- '"run_at": "document_end"'
820+ "all_frames": true,
821+ "matches": [ "<all_urls>" ],
822+ "js": ["base-content-script.js"],
823+ "run_at": "document_end"
824 }
825 ]
826 }
827-
828
829=== modified file 'chromium-extension/options.html'
830--- chromium-extension/options.html 2012-11-08 18:15:19 +0000
831+++ chromium-extension/options.html 2015-10-07 04:25:10 +0000
832@@ -8,23 +8,23 @@
833 width: 600px;
834 font-size: 13px;
835 }
836-
837+
838 body {
839 background-color: "#ebeff9";
840 font-family: Arial, sans-serif;
841 }
842-
843+
844 #logo {
845 font-size: 20px;
846 text-align: center;
847 }
848-
849+
850 #extensionName {
851 color: #444;
852 font-size: 16px;
853 font-weight: 500;
854 }
855-
856+
857 .setting {
858 pagging-left: 20px;
859 }
860@@ -48,5 +48,3 @@
861
862 </body>
863 </html>
864-
865-
866
867=== modified file 'chromium-extension/options.js'
868--- chromium-extension/options.js 2012-11-08 18:15:19 +0000
869+++ chromium-extension/options.js 2015-10-07 04:25:10 +0000
870@@ -1,6 +1,6 @@
871 function save_options() {
872 var logging = document.getElementById("logging");
873- localStorage["logging"] = logging.checked;
874+ localStorage.logging = logging.checked;
875 }
876
877 function restore_options() {
878@@ -9,8 +9,8 @@
879 document.getElementById('logging').disabled = true;
880 return;
881 }
882-
883- var logging = localStorage["logging"];
884+
885+ var logging = localStorage.logging;
886 var loggingElt = document.getElementById("logging");
887 if (loggingElt) {
888 loggingElt.checked = (logging == "true");
889
890=== added file 'chromium-extension/popup.css'
891--- chromium-extension/popup.css 1970-01-01 00:00:00 +0000
892+++ chromium-extension/popup.css 2015-10-07 04:25:10 +0000
893@@ -0,0 +1,21 @@
894+body {
895+ background: -webkit-linear-gradient(#E9E9E9, #DADADA);
896+ font-family: Tahoma, Geneva, sans-serif;
897+ font-size: 13px;
898+ height: 36px;
899+ width: 300px;
900+ margin: 0;
901+ overflow: hidden;
902+ padding-left: 6px;
903+ padding-right: 6px;
904+ padding-top: 5px;
905+}
906+
907+img {
908+ padding-right: 6px;
909+}
910+
911+button {
912+ padding-right: 10px;
913+}
914+
915
916=== added file 'chromium-extension/popup.html'
917--- chromium-extension/popup.html 1970-01-01 00:00:00 +0000
918+++ chromium-extension/popup.html 2015-10-07 04:25:10 +0000
919@@ -0,0 +1,20 @@
920+<html>
921+
922+<head>
923+</head>
924+
925+<link rel="stylesheet" type="text/css" href="popup.css"></link>
926+<script src="popup.js"></script>
927+
928+<body>
929+
930+<div id="content" style="display:none">
931+ <span id="message"></span>
932+ <input type="button" id="notintegrate" value="Never for this site" />
933+ <input type="button" id="integrate" value="Yes" onclick="doIntegrate(true)"/>
934+</div>
935+
936+</body>
937+
938+
939+</html>
940
941=== added file 'chromium-extension/popup.js'
942--- chromium-extension/popup.js 1970-01-01 00:00:00 +0000
943+++ chromium-extension/popup.js 2015-10-07 04:25:10 +0000
944@@ -0,0 +1,36 @@
945+var doIntegrate = function (integrate) {
946+ chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
947+ chrome.runtime.sendMessage({
948+ tabId: tabs[0].id,
949+ method: "on_user_popup_request_result",
950+ integrate: integrate
951+ },
952+ function (response) {});
953+ window.close();
954+ });
955+};
956+
957+window.onload = function () {
958+ chrome.runtime.getBackgroundPage(function (bg) {
959+ document.getElementById('notintegrate').onclick = function () { doIntegrate(false); };
960+ document.getElementById('integrate').onclick = function () { doIntegrate(true); };
961+
962+ chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
963+ if (tabs.length === 0) {
964+ window.close();
965+ return;
966+ }
967+ if (!bg || !bg.background_page) {
968+ window.close();
969+ return;
970+ }
971+ var msg = bg.background_page.getMessageForTabId(tabs[0].id);
972+ if (msg === null) {
973+ window.close();
974+ return;
975+ }
976+ document.getElementById ('content').style.display = "block";
977+ document.getElementById ('message').innerHTML = msg || "";
978+ });
979+ });
980+};
981
982=== modified file 'chromium-extension/unity-api-page-proxy.js'
983--- chromium-extension/unity-api-page-proxy.js 2014-05-20 13:40:09 +0000
984+++ chromium-extension/unity-api-page-proxy.js 2015-10-07 04:25:10 +0000
985@@ -1,5 +1,5 @@
986 /**
987- *
988+ *
989 *
990 */
991 setTimeout (
992
993=== modified file 'chromium-extension/unity-webapps.json.in'
994--- chromium-extension/unity-webapps.json.in 2014-05-21 09:03:42 +0000
995+++ chromium-extension/unity-webapps.json.in 2015-10-07 04:25:10 +0000
996@@ -1,4 +1,4 @@
997 {
998- '"external_crx": "$${EXTENSION_DIR}/$${EXTENSION_FILE}"',
999- '"external_version": "$${PROJECT_VERSION}"'
1000+ "external_crx": "${EXTENSION_DIR}/${EXTENSION_FILE}",
1001+ "external_version": "${PROJECT_VERSION}"
1002 }
1003
1004=== removed file 'common-project-config.pri'
1005--- common-project-config.pri 2014-05-19 14:04:19 +0000
1006+++ common-project-config.pri 1970-01-01 00:00:00 +0000
1007@@ -1,41 +0,0 @@
1008-#-----------------------------------------------------------------------------
1009-# Common configuration for all projects.
1010-#-----------------------------------------------------------------------------
1011-
1012-# we don't like warnings...
1013-QMAKE_CXXFLAGS += -Werror
1014-# Disable RTTI
1015-QMAKE_CXXFLAGS += -fno-exceptions -fno-rtti
1016-
1017-TOP_SRC_DIR = $$PWD
1018-TOP_BUILD_DIR = $${TOP_SRC_DIR}/$(BUILD_DIR)
1019-
1020-include(coverage.pri)
1021-
1022-#-----------------------------------------------------------------------------
1023-# setup the installation prefix
1024-#-----------------------------------------------------------------------------
1025-INSTALL_PREFIX = /usr # default installation prefix
1026-
1027-# default prefix can be overriden by defining PREFIX when running qmake
1028-isEmpty(PREFIX) {
1029- message("====")
1030- message("==== NOTE: To override the installation path run: `qmake PREFIX=/custom/path'")
1031- message("==== (current installation path is `$${INSTALL_PREFIX}')")
1032-} else {
1033- INSTALL_PREFIX = $${PREFIX}
1034- message("====")
1035- message("==== install prefix set to `$${INSTALL_PREFIX}'")
1036-}
1037-
1038-INSTALL_LIBDIR = $${INSTALL_PREFIX}/lib
1039-
1040-isEmpty(LIBDIR) {
1041- message("====")
1042- message("==== NOTE: To override the library installation path run: `qmake LIBDIR=/custom/path'")
1043- message("==== (current installation path is `$${INSTALL_LIBDIR}')")
1044-} else {
1045- INSTALL_LIBDIR = $${LIBDIR}
1046- message("====")
1047- message("==== install prefix set to `$${INSTALL_LIBDIR}'")
1048-}
1049
1050=== removed file 'common-vars.pri'
1051--- common-vars.pri 2014-06-02 06:53:38 +0000
1052+++ common-vars.pri 1970-01-01 00:00:00 +0000
1053@@ -1,6 +0,0 @@
1054-#-----------------------------------------------------------------------------
1055-# Common variables for all projects.
1056-#-----------------------------------------------------------------------------
1057-
1058-PROJECT_NAME = unity_webapps_chromium
1059-PROJECT_VERSION = 3.2
1060
1061=== removed file 'coverage.pri'
1062--- coverage.pri 2014-05-19 14:04:19 +0000
1063+++ coverage.pri 1970-01-01 00:00:00 +0000
1064@@ -1,49 +0,0 @@
1065-# Coverage
1066-CONFIG(coverage) {
1067- OBJECTS_DIR =
1068- MOC_DIR =
1069- TOP_SRC_DIR = $$PWD
1070-
1071- LIBS += -lgcov
1072- QMAKE_CXXFLAGS += --coverage
1073- QMAKE_LDFLAGS += --coverage
1074-
1075- QMAKE_EXTRA_TARGETS += coverage cov
1076- QMAKE_EXTRA_TARGETS += clean-gcno clean-gcda coverage-html \
1077- generate-coverage-html clean-coverage-html coverage-gcovr \
1078- generate-gcovr generate-coverage-gcovr clean-coverage-gcovr
1079-
1080- clean-gcno.commands = \
1081- "@echo Removing old coverage instrumentation"; \
1082- "find -name '*.gcno' -print | xargs -r rm"
1083-
1084- clean-gcda.commands = \
1085- "@echo Removing old coverage results"; \
1086- "find -name '*.gcda' -print | xargs -r rm"
1087-
1088- coverage-html.depends = clean-gcda check generate-coverage-html
1089-
1090- generate-coverage-html.commands = \
1091- "@echo Collecting coverage data"; \
1092- "lcov --directory $${TOP_SRC_DIR} --capture --output-file coverage.info --no-checksum --compat-libtool"; \
1093- "lcov --extract coverage.info \"*/messaging-host/*.cpp\" -o coverage.info"; \
1094- "lcov --remove coverage.info \"moc_*.cpp\" --remove coverage.info \"tests/*.cpp\" -o coverage.info"; \
1095- "LANG=C genhtml --prefix $${TOP_SRC_DIR} --output-directory coverage-html --title \"Code Coverage\" --legend --show-details coverage.info"
1096-
1097- clean-coverage-html.depends = clean-gcda
1098- clean-coverage-html.commands = \
1099- "lcov --directory $${TOP_SRC_DIR} -z"; \
1100- "rm -rf coverage.info coverage-html"
1101-
1102- coverage-gcovr.depends = clean-gcda check generate-coverage-gcovr
1103-
1104- generate-coverage-gcovr.commands = \
1105- "@echo Generating coverage GCOVR report"; \
1106- "gcovr -x -r $${TOP_SRC_DIR} -o $${TOP_SRC_DIR}/coverage.xml -e \".*/moc_.*\" -e \"tests/.*\" -e \".*\\.h\""
1107-
1108- clean-coverage-gcovr.depends = clean-gcda
1109- clean-coverage-gcovr.commands = \
1110- "rm -rf $${TOP_SRC_DIR}/coverage.xml"
1111-
1112- QMAKE_CLEAN += *.gcda *.gcno coverage.info coverage.xml
1113-}
1114
1115=== modified file 'debian/changelog'
1116--- debian/changelog 2015-01-19 16:49:41 +0000
1117+++ debian/changelog 2015-10-07 04:25:10 +0000
1118@@ -1,3 +1,10 @@
1119+unity-chromium-extension (3.2.1+15.04.20150119-0ubuntu1) vivid; urgency=medium
1120+
1121+ * Fixes: 1469601, by changing the notification method to use the pageAction
1122+ facility for display.
1123+
1124+ -- Justin McPherson <justin.mcpherson@canonical.com> Tue, 30 Jun 2015 13:18:59 +1000
1125+
1126 unity-chromium-extension (3.2.0+15.04.20150119-0ubuntu1) vivid; urgency=medium
1127
1128 [ Justin McPherson ]
1129
1130=== modified file 'debian/control'
1131--- debian/control 2014-12-17 14:18:53 +0000
1132+++ debian/control 2015-10-07 04:25:10 +0000
1133@@ -1,17 +1,19 @@
1134 Source: unity-chromium-extension
1135 Priority: optional
1136-Maintainer: Ubuntu Desktop Team <ubuntu-desktop@lists.ubuntu.com>
1137-Build-Depends: chromium-browser (>= 34.0.1847.116-0ubuntu2),
1138- debhelper (>= 9),
1139+Maintainer: Ubuntu Webapps Team <webapps@lists.ubuntu.com>
1140+Build-Depends: debhelper (>= 9),
1141 dh-autoreconf,
1142 libglib2.0-dev,
1143- libunity-webapps-dev (>= 1.8.0),
1144+ libunity-webapps-dev (>= 1.8.0) [!armhf],
1145+ libjson-glib-dev,
1146+ libclick-0.4-dev,
1147+ libubuntu-app-launch2-dev,
1148 openssl,
1149 pkg-config,
1150 vim-common,
1151 zip,
1152 qt5-default,
1153- qt5-qmake,
1154+ cmake,
1155 xvfb,
1156 Standards-Version: 3.9.5
1157 Section: gnome
1158@@ -25,9 +27,15 @@
1159 Architecture: any
1160 Depends: chromium-browser (>= 34.0.1847.116-0ubuntu2),
1161 unity-webapps-service,
1162+ unity-webapps-extension-process,
1163 webbrowser-app,
1164 ${misc:Depends},
1165 Breaks: libunity-webapps-chromium,
1166 Replaces: libunity-webapps-chromium,
1167 Description: Unity WebApp extension for the chromium browser
1168 Chromium browser extension for Unity WebApp integration
1169+
1170+Package: unity-webapps-extension-process
1171+Architecture: any
1172+Depends: ${misc:Depends},
1173+Description: Unity WebApp extension for installing or activating local web apps.
1174
1175=== modified file 'debian/unity-chromium-extension.install'
1176--- debian/unity-chromium-extension.install 2014-05-22 07:11:49 +0000
1177+++ debian/unity-chromium-extension.install 2015-10-07 04:25:10 +0000
1178@@ -1,4 +1,3 @@
1179-etc/chromium/native-messaging-hosts/com.canonical.webapp.installer.json
1180-usr/lib/libunity-chromium/unity-webapps.crx
1181+etc/chromium/native-messaging-hosts/com.canonical.webapp.extension.json
1182+usr/lib/*/libunity-chromium/unity-webapps.crx
1183 usr/share/chromium/extensions/*.json
1184-usr/share/unity-webapps/bin/unity-webapps-messaging-host
1185
1186=== added file 'debian/unity-webapps-extension-process.install'
1187--- debian/unity-webapps-extension-process.install 1970-01-01 00:00:00 +0000
1188+++ debian/unity-webapps-extension-process.install 2015-10-07 04:25:10 +0000
1189@@ -0,0 +1,1 @@
1190+usr/share/unity-webapps/bin/*
1191
1192=== added file 'messaging-host/CMakeLists.txt'
1193--- messaging-host/CMakeLists.txt 1970-01-01 00:00:00 +0000
1194+++ messaging-host/CMakeLists.txt 2015-10-07 04:25:10 +0000
1195@@ -0,0 +1,101 @@
1196+# vim:expandtab:shiftwidth=2:tabstop=2:
1197+
1198+# Copyright (C) 2015 Canonical Ltd.
1199+
1200+# This library is free software; you can redistribute it and/or
1201+# modify it under the terms of the GNU Lesser General Public
1202+# License as published by the Free Software Foundation; either
1203+# version 2.1 of the License, or (at your option) any later version.
1204+
1205+# This library is distributed in the hope that it will be useful,
1206+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1207+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1208+# Lesser General Public License for more details.
1209+
1210+# You should have received a copy of the GNU Lesser GeneraGl Public
1211+# License along with this library; if not, write to the Free Software
1212+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1213+
1214+cmake_minimum_required(VERSION 2.8.11)
1215+
1216+project(messaging-host)
1217+
1218+set(EXTENSION_NAME webapps-extension)
1219+set(EXTENSION_MANIFEST com.canonical.webapp.extension.json)
1220+set(WEBAPPS_BINDIR ${CMAKE_INSTALL_FULL_DATADIR}/unity-webapps/bin)
1221+
1222+set(CMAKE_INCLUDE_CURRENT_DIR ON)
1223+set(CMAKE_AUTOMOC ON)
1224+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
1225+set(SRC)
1226+
1227+find_package(PkgConfig)
1228+find_package(Qt5Core)
1229+
1230+pkg_check_modules(GLIB glib-2.0 REQUIRED)
1231+pkg_check_modules(GOBJECT gobject-2.0 REQUIRED)
1232+pkg_check_modules(JSON_GLIB json-glib-1.0 REQUIRED)
1233+pkg_check_modules(CLICK click-0.4 REQUIRED)
1234+pkg_check_modules(UBUNTU_APP_LAUNCH ubuntu-app-launch-2 REQUIRED)
1235+pkg_check_modules(WEBAPPS libunity_webapps-0.2)
1236+pkg_check_modules(WEBAPPS_REPO libunity-webapps-repository)
1237+
1238+# Build and install chromium's extension manifest
1239+configure_file(
1240+ ${EXTENSION_MANIFEST}.in
1241+ ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_MANIFEST}
1242+)
1243+
1244+install(
1245+ FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_MANIFEST}
1246+ DESTINATION /etc/chromium/native-messaging-hosts
1247+)
1248+
1249+list(
1250+ APPEND SRC
1251+ main.cpp
1252+ connection.cpp
1253+ inactivity-timer.cpp
1254+ service.cpp
1255+ service-handler.cpp
1256+ click-handler.cpp
1257+)
1258+add_definitions(-DHAVE_CLICK_SUPPORT=1)
1259+
1260+if(DEFINED WEBAPPS_FOUND AND WEBAPPS_FOUND EQUAL 1)
1261+ if(DEFINED WEBAPPS_REPO_FOUND AND WEBAPPS_REPO_FOUND EQUAL 1)
1262+ list(APPEND SRC webapps-handler.cpp webapps-process.cpp)
1263+ add_definitions(-DHAVE_UNITY_WEBAPPS=1)
1264+ endif()
1265+endif()
1266+
1267+include_directories(
1268+ ${GLIB_INCLUDE_DIRS}
1269+ ${JSON_GLIB_INCLUDE_DIRS}
1270+ ${UBUNTU_APP_LAUNCH_INCLUDE_DIRS}
1271+ ${WEBAPPS_INCLUDE_DIRS}
1272+ ${WEBAPPS_REPO_INCLUDE_DIRS}
1273+)
1274+
1275+add_executable(
1276+ ${EXTENSION_NAME}
1277+
1278+ ${SRC}
1279+)
1280+
1281+target_link_libraries(
1282+ ${EXTENSION_NAME}
1283+
1284+ Qt5::Core
1285+ ${GLIB_LIBRARIES}
1286+ ${WEBAPPS_LIBRARIES}
1287+ ${WEBAPPS_REPO_LIBRARIES}
1288+ ${JSON_GLIB_LIBRARIES}
1289+ ${CLICK_LIBRARIES}
1290+ ${UBUNTU_APP_LAUNCH_LIBRARIES}
1291+)
1292+
1293+install(
1294+ TARGETS ${EXTENSION_NAME}
1295+ RUNTIME DESTINATION ${WEBAPPS_BINDIR}
1296+)
1297
1298=== removed file 'messaging-host/Makefile.am'
1299--- messaging-host/Makefile.am 2014-05-14 07:59:30 +0000
1300+++ messaging-host/Makefile.am 1970-01-01 00:00:00 +0000
1301@@ -1,2 +0,0 @@
1302-EXTRA_DIST += \
1303- installation-host
1304
1305=== added file 'messaging-host/click-handler.cpp'
1306--- messaging-host/click-handler.cpp 1970-01-01 00:00:00 +0000
1307+++ messaging-host/click-handler.cpp 2015-10-07 04:25:10 +0000
1308@@ -0,0 +1,386 @@
1309+/*
1310+ * Copyright (C) 2015 Canonical Ltd.
1311+ *
1312+ * This file is part of webapps-extension
1313+ *
1314+ * This program is free software: you can redistribute it and/or modify it
1315+ * under the terms of the GNU General Public License version 3, as published
1316+ * by the Free Software Foundation.
1317+ *
1318+ * This program is distributed in the hope that it will be useful, but
1319+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1320+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1321+ * PURPOSE. See the GNU General Public License for more details.
1322+ *
1323+ * You should have received a copy of the GNU General Public License along
1324+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1325+ *
1326+ * Author: Justin McPherson <justin.mcpherson@canonical.com>
1327+ *
1328+ */
1329+
1330+#if defined(HAVE_UNITY_WEBAPPS)
1331+extern "C" {
1332+#include <unity-webapps-permissions.h>
1333+}
1334+#endif
1335+
1336+#include <click-0.4/click.h>
1337+#include <ubuntu-app-launch.h>
1338+
1339+#include "click-handler.h"
1340+
1341+#include <QUrl>
1342+#include <QDebug>
1343+
1344+namespace UnityWebapps {
1345+
1346+namespace {
1347+static const gchar* maintainer_key = "maintainer";
1348+static const gchar* title_key = "title";
1349+static const gchar* name_key = "name";
1350+static const gchar* version_key = "version";
1351+static const gchar* maintainer_name = "Webapps Team <webapps@lists.launchpad.net>";
1352+static const gchar* directory_key = "_directory";
1353+static const gchar* hooks_key = "hooks";
1354+static const gchar* urls_key = "urls";
1355+static const gchar* desktop_key = "desktop";
1356+static const gchar* domain_suffix_key = "domain-suffix";
1357+static const gchar* launch_method = "launch_click";
1358+static const gchar* available_method = "click_available";
1359+
1360+gchar* dispatcherFilenameFromManifest(JsonObject *manifest)
1361+{
1362+ const gchar* directory = json_object_get_string_member(manifest, directory_key);
1363+ JsonObject* hooks = json_object_get_object_member(manifest, hooks_key);
1364+ if (directory == nullptr || hooks == nullptr) {
1365+ return nullptr;
1366+ }
1367+
1368+ const gchar* dispatcher_filename = nullptr;
1369+
1370+ // Search objects in hooks for urls key
1371+ json_object_foreach_member(hooks, [](JsonObject* object, const gchar* member_name, JsonNode* member_node, gpointer user_data) {
1372+ const gchar** df = static_cast<const gchar**>(user_data);
1373+ if (*df != nullptr)
1374+ return;
1375+ if (json_node_get_node_type(member_node) != JSON_NODE_OBJECT)
1376+ return;
1377+
1378+ JsonObject *member_object = json_node_get_object(member_node);
1379+ json_object_foreach_member(member_object, [](JsonObject* object, const gchar* member_name, JsonNode* member_node, gpointer user_data) {
1380+ if (g_ascii_strncasecmp(urls_key, member_name, strlen(urls_key)) == 0) {
1381+ const gchar** df = static_cast<const gchar**>(user_data);
1382+ *df = json_object_get_string_member(object, urls_key);
1383+ }
1384+ }, user_data);
1385+ }, &dispatcher_filename);
1386+
1387+ if (dispatcher_filename == nullptr) {
1388+ return nullptr;
1389+ }
1390+
1391+ return g_strjoin("/", directory, dispatcher_filename, nullptr);
1392+}
1393+
1394+gchar* appLaunchAppIdFromManifest(JsonObject *manifest)
1395+{
1396+ JsonObject* hooks = json_object_get_object_member(manifest, hooks_key);
1397+ if (hooks == nullptr) {
1398+ return nullptr;
1399+ }
1400+
1401+ // Find hook used in creation of desktop file
1402+ gchar* hook_name = nullptr;
1403+ json_object_foreach_member(hooks, [](JsonObject* object, const gchar* member_name, JsonNode* member_node, gpointer user_data) {
1404+ gchar** hn = static_cast<gchar**>(user_data);
1405+ if (*hn != nullptr)
1406+ return;
1407+ if (json_node_get_node_type(member_node) != JSON_NODE_OBJECT)
1408+ return;
1409+
1410+ JsonObject *member_object = json_node_get_object(member_node);
1411+ if (json_object_has_member(member_object, desktop_key)) {
1412+ *hn = g_strdup(member_name);
1413+ }
1414+ }, &hook_name);
1415+
1416+ if (hook_name == nullptr) {
1417+ return nullptr;
1418+ }
1419+
1420+ const gchar* app_name = json_object_get_string_member(manifest, name_key);
1421+ const gchar* app_version = json_object_get_string_member(manifest, version_key);
1422+ if (app_name == nullptr || app_version == nullptr) {
1423+ g_free(hook_name);
1424+ return nullptr;
1425+ }
1426+
1427+ gchar *result = g_strjoin("_", app_name, hook_name, app_version, nullptr);
1428+ g_free(hook_name);
1429+ return result;
1430+}
1431+
1432+GList* domainsFromDispatcherFile(const gchar* dispatcher_filename)
1433+{
1434+ GList *domains = nullptr;
1435+ JsonParser* parser = json_parser_new();
1436+ GError* error = nullptr;
1437+ if (!json_parser_load_from_file(parser, dispatcher_filename, &error)) {
1438+ qDebug() << "Error parsing URL dispatched JSON" << error->message;
1439+ return nullptr;
1440+ }
1441+
1442+ JsonNode* root = json_parser_get_root(parser);
1443+ if (json_node_get_node_type(root) != JSON_NODE_ARRAY) {
1444+ qDebug() << "Unexpected contents of URL dispatcher JSON file";
1445+ return nullptr;
1446+ }
1447+
1448+ JsonArray* domains_array = json_node_get_array(root);
1449+ json_array_foreach_element(domains_array, [](JsonArray*, guint index, JsonNode* element_node, gpointer user_data) {
1450+ if (json_node_get_node_type(element_node) == JSON_NODE_OBJECT) {
1451+ JsonObject *object = json_node_get_object(element_node);
1452+ const gchar *domain_suffix = json_object_get_string_member(object, domain_suffix_key);
1453+ if (domain_suffix != nullptr) {
1454+ GList** domains = static_cast<GList**>(user_data);
1455+ *domains = g_list_append(*domains, g_strdup(domain_suffix));
1456+ }
1457+ }
1458+ }, &domains);
1459+
1460+ g_object_unref(parser);
1461+
1462+ return domains;
1463+}
1464+
1465+}
1466+
1467+class ClickHandlerPrivate
1468+{
1469+ Q_DECLARE_PUBLIC(ClickHandler)
1470+
1471+public:
1472+ inline ClickHandlerPrivate(ClickHandler *service);
1473+ inline ~ClickHandlerPrivate();
1474+
1475+ GList* findMatchingApplications(const QUrl& url);
1476+
1477+private:
1478+ ClickDB* getDatabase();
1479+
1480+ ClickHandler *q_ptr;
1481+ ClickDB *clickDb;
1482+};
1483+
1484+
1485+ClickHandlerPrivate::ClickHandlerPrivate(ClickHandler *service)
1486+ : q_ptr(service)
1487+ , clickDb(nullptr)
1488+{
1489+}
1490+
1491+ClickHandlerPrivate::~ClickHandlerPrivate()
1492+{
1493+ if (clickDb != nullptr) {
1494+ g_object_unref(G_OBJECT(clickDb));
1495+ }
1496+}
1497+
1498+GList* ClickHandlerPrivate::findMatchingApplications(const QUrl& url)
1499+{
1500+ GError *error = nullptr;
1501+ JsonArray *manifests = click_db_get_manifests(getDatabase(), true, &error);
1502+ if (error != nullptr) {
1503+ qDebug() << __func__ << "error: " << error->message;
1504+ g_error_free(error);
1505+ return nullptr;
1506+ }
1507+
1508+ struct _context {
1509+ GList *matching_apps;
1510+ const QUrl& visited_url;
1511+ } context{nullptr, url};
1512+
1513+ json_array_foreach_element(manifests, [](JsonArray*, guint index, JsonNode* element_node, gpointer user_data) {
1514+ _context* context = static_cast<_context*>(user_data);
1515+
1516+ if (json_node_get_node_type(element_node) != JSON_NODE_OBJECT) {
1517+ return;
1518+ }
1519+ JsonObject *manifest = json_node_get_object(element_node);
1520+
1521+ // Look for maintainer == Webapps Team <webapps@lists.launchpad.net>
1522+ if (qgetenv("UNITY_WEBAPPS_IGNORE_MAINTAINER") != QByteArrayLiteral("1")) {
1523+ const gchar *maintainer = json_object_get_string_member(manifest, maintainer_key);
1524+ if (maintainer == nullptr ||
1525+ g_ascii_strncasecmp(maintainer, maintainer_name, strlen(maintainer_name)) != 0) {
1526+ return;
1527+ }
1528+ }
1529+
1530+ // Look at url dispatcher
1531+ gchar* dispatcher_filename = dispatcherFilenameFromManifest(manifest);
1532+ if (dispatcher_filename == nullptr) {
1533+ return;
1534+ }
1535+
1536+ GList* domains = domainsFromDispatcherFile(dispatcher_filename);
1537+ if (domains == nullptr) {
1538+ g_free(dispatcher_filename);
1539+ return;
1540+ }
1541+
1542+ for (GList *item = domains; item->next != nullptr; item = item->next) {
1543+ QStringList visited_url_parts = context->visited_url.host().split(".");
1544+ QStringList test_url_parts = QString::fromLatin1((gchar*)item->data).split(".");
1545+ int visited_length = visited_url_parts.length();
1546+ int test_length = test_url_parts.length();
1547+ if (visited_length == test_length) {
1548+ if (visited_url_parts == test_url_parts) {
1549+ json_object_ref(manifest);
1550+ context->matching_apps = g_list_append(context->matching_apps, manifest);
1551+ }
1552+ } else {
1553+ // Every part of test url must match
1554+ if (visited_length >= test_length) {
1555+ bool match = true;
1556+ for (int i = 1; i < test_length + 1; ++i) {
1557+ if (test_url_parts.at(test_length - i) != visited_url_parts.at(visited_length - i)) {
1558+ match = false;
1559+ break;
1560+ }
1561+ }
1562+ if (match) {
1563+ json_object_ref(manifest);
1564+ context->matching_apps = g_list_append(context->matching_apps, manifest);
1565+ }
1566+ }
1567+ }
1568+ }
1569+ g_list_free_full(domains, g_free);
1570+ g_free(dispatcher_filename);
1571+ }, &context);
1572+
1573+ return context.matching_apps;
1574+}
1575+
1576+
1577+
1578+ClickDB* ClickHandlerPrivate::getDatabase()
1579+{
1580+ if (clickDb == nullptr) {
1581+ GError *error = nullptr;
1582+ clickDb = click_db_new();
1583+ click_db_read(clickDb, nullptr, &error);
1584+ if (error != nullptr) {
1585+ qDebug() << __func__ << "error: " << error->message;
1586+ g_error_free(error);
1587+ g_object_unref(clickDb);
1588+ clickDb = nullptr;
1589+ }
1590+ }
1591+
1592+ return clickDb;
1593+}
1594+
1595+
1596+ClickHandler::ClickHandler(QObject *parent)
1597+ : QObject(parent)
1598+ , d_ptr(new ClickHandlerPrivate(this))
1599+{
1600+}
1601+
1602+ClickHandler::~ClickHandler()
1603+{
1604+ delete d_ptr;
1605+}
1606+
1607+QVariantMap ClickHandler::click_available(const QVariantMap &message)
1608+{
1609+ Q_D(ClickHandler);
1610+
1611+ QVariantMap reply;
1612+ reply.insert("method", available_method);
1613+ if (!message.contains("url")) {
1614+ reply.insert("error", QStringLiteral("malformed request"));
1615+ return reply;
1616+ }
1617+
1618+ QString url = message.value("url").toString();
1619+
1620+ GList *matching_apps = d->findMatchingApplications(QUrl(url));
1621+
1622+ if (matching_apps == nullptr) {
1623+ reply.insert("available", false);
1624+ return reply;
1625+ }
1626+
1627+ // First element is OK
1628+ JsonObject* package_object = static_cast<JsonObject*>(matching_apps->data);
1629+
1630+ const gchar *appName = json_object_get_string_member(package_object, title_key);
1631+ const gchar *appDomain = nullptr; /* something from url dispatcher?*/
1632+ const gchar *appVersion = json_object_get_string_member(package_object, version_key);
1633+
1634+#if defined(HAVE_UNITY_WEBAPPS)
1635+ if (unity_webapps_permissions_get_domain_dontask(appDomain) ||
1636+ unity_webapps_permissions_get_domain_allowed(appDomain)) {
1637+ reply.insert("available", false);
1638+ for (GList *item = matching_apps; item->next != nullptr; item = item->next) {
1639+ json_object_unref(static_cast<JsonObject*>(item->data));
1640+ }
1641+ return reply;
1642+ }
1643+#endif
1644+ reply.insert("available", true);
1645+ reply.insert("appName", QString::fromUtf8(appName));
1646+ reply.insert("appDomain", QString::fromUtf8(appDomain));
1647+ reply.insert("appVersion", QString::fromUtf8(appVersion));
1648+
1649+ for (GList *item = matching_apps; item->next != nullptr; item = item->next) {
1650+ json_object_unref(static_cast<JsonObject*>(item->data));
1651+ }
1652+
1653+ return reply;
1654+}
1655+
1656+QVariantMap ClickHandler::launch_click(const QVariantMap& message)
1657+{
1658+ Q_D(ClickHandler);
1659+
1660+ QVariantMap reply;
1661+ reply.insert("method", launch_method);
1662+
1663+ if (!message.contains("url")) {
1664+ reply.insert("error", QLatin1String("malformed request"));
1665+ return reply;
1666+ }
1667+
1668+ QString url = message.value("url").toString();
1669+ reply.insert("url", url);
1670+
1671+ GList *matching_apps = d->findMatchingApplications(QUrl(url));
1672+ if (matching_apps == nullptr) {
1673+ reply.insert("launched", false);
1674+ reply.insert("available", false);
1675+ return reply;
1676+ }
1677+
1678+ // Grab first, convert to an "app id"
1679+ JsonObject* manifest = (JsonObject*)matching_apps->data;
1680+
1681+ gchar* app_id = appLaunchAppIdFromManifest(manifest);
1682+ if (app_id == nullptr) {
1683+ reply.insert("launched", false);
1684+ return reply;
1685+ }
1686+
1687+ gboolean app_launched = ubuntu_app_launch_start_application(app_id, nullptr);
1688+ g_free(app_id);
1689+
1690+ reply.insert("launched", bool(app_launched));
1691+ return reply;
1692+}
1693+
1694+} // namespace
1695
1696=== added file 'messaging-host/click-handler.h'
1697--- messaging-host/click-handler.h 1970-01-01 00:00:00 +0000
1698+++ messaging-host/click-handler.h 2015-10-07 04:25:10 +0000
1699@@ -0,0 +1,55 @@
1700+/*
1701+ * Copyright (C) 2015 Canonical Ltd.
1702+ *
1703+ * This file is part of unity-chromium-extension
1704+ *
1705+ * This program is free software: you can redistribute it and/or modify it
1706+ * under the terms of the GNU General Public License version 3, as published
1707+ * by the Free Software Foundation.
1708+ *
1709+ * This program is distributed in the hope that it will be useful, but
1710+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1711+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1712+ * PURPOSE. See the GNU General Public License for more details.
1713+ *
1714+ * You should have received a copy of the GNU General Public License along
1715+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1716+ *
1717+ * Author: Justin McPherson <justin.mcpherson@canonical.com>
1718+ *
1719+ */
1720+
1721+#ifndef UNITY_WEBAPPS_CLICK_HANDLER
1722+#define UNITY_WEBAPPS_CLICK_HANDLER
1723+
1724+#include <QObject>
1725+#include <QVariantMap>
1726+
1727+namespace UnityWebapps {
1728+
1729+class ClickHandlerPrivate;
1730+class ClickHandler : public QObject
1731+{
1732+ Q_OBJECT
1733+
1734+public:
1735+ explicit ClickHandler(QObject *parent = 0);
1736+ ~ClickHandler();
1737+
1738+public Q_SLOTS:
1739+ QVariantMap click_available(const QVariantMap& message);
1740+ QVariantMap launch_click(const QVariantMap& message);
1741+
1742+#if defined(UCX_UNDER_TEST)
1743+public:
1744+#else
1745+private:
1746+#endif
1747+
1748+ ClickHandlerPrivate *d_ptr;
1749+ Q_DECLARE_PRIVATE(ClickHandler)
1750+};
1751+
1752+} // namespace
1753+
1754+#endif // UNITY_WEBAPPS_CLICK_HANDLER
1755
1756=== added file 'messaging-host/com.canonical.webapp.extension.json.in'
1757--- messaging-host/com.canonical.webapp.extension.json.in 1970-01-01 00:00:00 +0000
1758+++ messaging-host/com.canonical.webapp.extension.json.in 2015-10-07 04:25:10 +0000
1759@@ -0,0 +1,9 @@
1760+{
1761+ "name": "com.canonical.webapp.extension",
1762+ "description": "Canonical WebApp Extension Host",
1763+ "path": "${WEBAPPS_BINDIR}/${EXTENSION_NAME}",
1764+ "type": "stdio",
1765+ "allowed_origins": [
1766+ "chrome-extension://pmoflmbbcfgacopiikdcpmbiellfihdg/"
1767+ ]
1768+}
1769
1770=== removed file 'messaging-host/com.canonical.webapp.installer.json.in'
1771--- messaging-host/com.canonical.webapp.installer.json.in 2014-05-21 12:32:50 +0000
1772+++ messaging-host/com.canonical.webapp.installer.json.in 1970-01-01 00:00:00 +0000
1773@@ -1,9 +0,0 @@
1774-{
1775- '"name": "com.canonical.webapp.installer"',
1776- '"description": "Canonical WebApp Installation Host"',
1777- '"path": "$${target.path}/$${TARGET}"',
1778- '"type": "stdio"',
1779- '"allowed_origins"': [
1780- '"chrome-extension://pmoflmbbcfgacopiikdcpmbiellfihdg/"'
1781- ]
1782-}
1783
1784=== modified file 'messaging-host/main.cpp'
1785--- messaging-host/main.cpp 2014-06-20 06:16:48 +0000
1786+++ messaging-host/main.cpp 2015-10-07 04:25:10 +0000
1787@@ -21,12 +21,22 @@
1788 #include "connection.h"
1789 #include "inactivity-timer.h"
1790 #include "service.h"
1791+#include "service-handler.h"
1792+#if defined(HAVE_UNITY_WEBAPPS)
1793+#include "webapps-process.h"
1794 #include "webapps-handler.h"
1795-#include "webapps-process.h"
1796+#endif
1797+#if defined(HAVE_CLICK_SUPPORT)
1798+#include "click-handler.h"
1799+#endif
1800
1801 #include <QCoreApplication>
1802 #include <QDebug>
1803
1804+namespace {
1805+// Time in milliseconds before process exits from timeout.
1806+const int INACTIVE_TIMEOUT = 2 * 60 * 1000;
1807+}
1808
1809 void syslogOutputHandler(QtMsgType type, const QMessageLogContext &, const QString &msg)
1810 {
1811@@ -61,13 +71,24 @@
1812
1813 QCoreApplication app(argc, argv);
1814
1815+ UnityWebapps::Service service;
1816+
1817+ // Handle service wide messages
1818+ UnityWebapps::ServiceHandler service_handler;
1819+ service.addHandler(&service_handler);
1820+
1821+#if defined(HAVE_UNITY_WEBAPPS)
1822 UnityWebapps::Process process;
1823-
1824- UnityWebapps::Service service;
1825- UnityWebapps::WebappsHandler handler;
1826- service.addHandler(&handler);
1827-
1828- UnityWebapps::InactivityTimer inactivityTimer(2 * 60 * 1000);
1829+ UnityWebapps::WebappsHandler apt_handler;
1830+ service.addHandler(&apt_handler);
1831+#endif
1832+
1833+#if defined(HAVE_CLICK_SUPPORT)
1834+ UnityWebapps::ClickHandler click_handler;
1835+ service.addHandler(&click_handler);
1836+#endif
1837+
1838+ UnityWebapps::InactivityTimer inactivityTimer(INACTIVE_TIMEOUT);
1839 QObject::connect(&inactivityTimer, SIGNAL(timeout()), &app, SLOT(quit()));
1840 inactivityTimer.watchObject(&service);
1841
1842@@ -88,4 +109,3 @@
1843
1844 return r;
1845 }
1846-
1847
1848=== removed file 'messaging-host/messaging-host.pro'
1849--- messaging-host/messaging-host.pro 2014-06-20 06:16:48 +0000
1850+++ messaging-host/messaging-host.pro 1970-01-01 00:00:00 +0000
1851@@ -1,42 +0,0 @@
1852-include(../common-project-config.pri)
1853-
1854-TEMPLATE = app
1855-TARGET = unity-webapps-messaging-host
1856-
1857-CONFIG += \
1858- link_pkgconfig \
1859- qt
1860-
1861-QT += \
1862- core
1863-
1864-PKGCONFIG += \
1865- glib-2.0 \
1866- gobject-2.0 \
1867- libunity_webapps-0.2 \
1868- libunity-webapps-repository \
1869-
1870-SOURCES = \
1871- connection.cpp \
1872- inactivity-timer.cpp \
1873- main.cpp \
1874- service.cpp \
1875- webapps-handler.cpp \
1876- webapps-process.cpp \
1877-
1878-HEADERS = \
1879- connection.h \
1880- inactivity-timer.h \
1881- service.h \
1882- webapps-handler.h \
1883- webapps-process.h \
1884-
1885-target.path = $${INSTALL_PREFIX}/share/unity-webapps/bin
1886-INSTALLS += target
1887-
1888-QMAKE_SUBSTITUTES += \
1889- com.canonical.webapp.installer.json.in
1890-
1891-manifest.path = "/etc/chromium/native-messaging-hosts"
1892-manifest.files = com.canonical.webapp.installer.json
1893-INSTALLS += manifest
1894
1895=== added file 'messaging-host/service-handler.cpp'
1896--- messaging-host/service-handler.cpp 1970-01-01 00:00:00 +0000
1897+++ messaging-host/service-handler.cpp 2015-10-07 04:25:10 +0000
1898@@ -0,0 +1,75 @@
1899+/*
1900+ * Copyright (C) 2015 Canonical Ltd.
1901+ *
1902+ * This file is part of webapps-extension
1903+ *
1904+ * This program is free software: you can redistribute it and/or modify it
1905+ * under the terms of the GNU General Public License version 3, as published
1906+ * by the Free Software Foundation.
1907+ *
1908+ * This program is distributed in the hope that it will be useful, but
1909+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1910+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1911+ * PURPOSE. See the GNU General Public License for more details.
1912+ *
1913+ * You should have received a copy of the GNU General Public License along
1914+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1915+ *
1916+ * Author: Justin McPherson <justin.mcpherson@canonical.com>
1917+ *
1918+ */
1919+
1920+#include "service-handler.h"
1921+
1922+#include <QDebug>
1923+#include <QRegularExpression>
1924+
1925+
1926+namespace UnityWebapps {
1927+
1928+class ServiceHandlerPrivate
1929+{
1930+ Q_DECLARE_PUBLIC(ServiceHandler)
1931+
1932+public:
1933+ ServiceHandlerPrivate(ServiceHandler *service);
1934+ ~ServiceHandlerPrivate();
1935+
1936+private:
1937+ mutable ServiceHandler *q_ptr;
1938+};
1939+
1940+
1941+ServiceHandlerPrivate::ServiceHandlerPrivate(ServiceHandler *service)
1942+ : q_ptr(service)
1943+{
1944+}
1945+
1946+ServiceHandlerPrivate::~ServiceHandlerPrivate()
1947+{
1948+}
1949+
1950+
1951+ServiceHandler::ServiceHandler(QObject *parent)
1952+ : QObject(parent)
1953+ , d_ptr(new ServiceHandlerPrivate(this))
1954+{
1955+}
1956+
1957+ServiceHandler::~ServiceHandler()
1958+{
1959+ delete d_ptr;
1960+}
1961+
1962+QVariantMap ServiceHandler::ping(const QVariantMap &message)
1963+{
1964+ Q_UNUSED(message);
1965+
1966+ QVariantMap reply;
1967+
1968+ reply.insert("pong", QLatin1String("alive"));
1969+
1970+ return reply;
1971+}
1972+
1973+} // namespace
1974
1975=== added file 'messaging-host/service-handler.h'
1976--- messaging-host/service-handler.h 1970-01-01 00:00:00 +0000
1977+++ messaging-host/service-handler.h 2015-10-07 04:25:10 +0000
1978@@ -0,0 +1,54 @@
1979+/*
1980+ * Copyright (C) 2015 Canonical Ltd.
1981+ *
1982+ * This file is part of unity-chromium-extension
1983+ *
1984+ * This program is free software: you can redistribute it and/or modify it
1985+ * under the terms of the GNU General Public License version 3, as published
1986+ * by the Free Software Foundation.
1987+ *
1988+ * This program is distributed in the hope that it will be useful, but
1989+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1990+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1991+ * PURPOSE. See the GNU General Public License for more details.
1992+ *
1993+ * You should have received a copy of the GNU General Public License along
1994+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1995+ *
1996+ * Author: Justin McPherson <justin.mcpherson@canonical.com>
1997+ *
1998+ */
1999+
2000+#ifndef UNITY_WEBAPPS_SERVICE_HANDLER
2001+#define UNITY_WEBAPPS_SERVICE_HANDLER
2002+
2003+#include <QObject>
2004+#include <QVariantMap>
2005+
2006+namespace UnityWebapps {
2007+
2008+class ServiceHandlerPrivate;
2009+class ServiceHandler : public QObject
2010+{
2011+ Q_OBJECT
2012+
2013+public:
2014+ explicit ServiceHandler(QObject *parent = 0);
2015+ ~ServiceHandler();
2016+
2017+public Q_SLOTS:
2018+ QVariantMap ping(const QVariantMap &message);
2019+
2020+#if defined(UCX_UNDER_TEST)
2021+public:
2022+#else
2023+private:
2024+#endif
2025+ ServiceHandlerPrivate *d_ptr;
2026+ Q_DECLARE_PRIVATE(ServiceHandler)
2027+};
2028+
2029+} // namespace
2030+
2031+#endif // UNITY_WEBAPPS_SERVICE_HANDLER
2032+
2033
2034=== modified file 'messaging-host/service.cpp'
2035--- messaging-host/service.cpp 2014-05-21 08:18:12 +0000
2036+++ messaging-host/service.cpp 2015-10-07 04:25:10 +0000
2037@@ -45,9 +45,9 @@
2038
2039 } // namespace
2040
2041-ServicePrivate::ServicePrivate(Service *service):
2042- m_isIdle(true),
2043- q_ptr(service)
2044+ServicePrivate::ServicePrivate(Service *service)
2045+ : m_isIdle(true)
2046+ , q_ptr(service)
2047 {
2048 }
2049
2050@@ -59,14 +59,16 @@
2051 {
2052 Q_Q(Service);
2053
2054- if (m_isIdle == isIdle) return;
2055+ if (m_isIdle == isIdle) {
2056+ return;
2057+ }
2058 m_isIdle = isIdle;
2059 Q_EMIT q->isIdleChanged();
2060 }
2061
2062-Service::Service(QObject *parent):
2063- QObject(parent),
2064- d_ptr(new ServicePrivate(this))
2065+Service::Service(QObject *parent)
2066+ : QObject(parent)
2067+ , d_ptr(new ServicePrivate(this))
2068 {
2069 }
2070
2071@@ -83,7 +85,6 @@
2072 void Service::addHandler(QObject *handler)
2073 {
2074 Q_D(Service);
2075-
2076 d->m_handlers.append(handler);
2077 }
2078
2079@@ -92,7 +93,9 @@
2080 Q_D(Service);
2081
2082 QByteArray method = message.value(QStringLiteral("method")).toString().toLatin1();
2083- if (Q_UNLIKELY(method.isEmpty())) return;
2084+ if (Q_UNLIKELY(method.isEmpty())) {
2085+ return;
2086+ }
2087
2088 QByteArray methodSignature = method + "(QVariantMap)";
2089
2090@@ -103,13 +106,17 @@
2091 Q_FOREACH(QObject *handler, d->m_handlers) {
2092 const QMetaObject *metaObject = handler->metaObject();
2093 int index = metaObject->indexOfMethod(methodSignature);
2094- if (index == -1) continue;
2095+ if (index == -1) {
2096+ continue;
2097+ }
2098
2099 QMetaMethod metaMethod = metaObject->method(index);
2100 ok = metaMethod.invoke(handler,
2101 Q_RETURN_ARG(QVariantMap, reply),
2102 Q_ARG(QVariantMap, message));
2103- if (ok) break;
2104+ if (ok) {
2105+ break;
2106+ }
2107 }
2108
2109 if (ok) {
2110
2111=== modified file 'messaging-host/webapps-handler.cpp'
2112--- messaging-host/webapps-handler.cpp 2014-06-23 06:49:03 +0000
2113+++ messaging-host/webapps-handler.cpp 2015-10-07 04:25:10 +0000
2114@@ -48,24 +48,30 @@
2115 UnityWebappsApplicationStatus status,
2116 gpointer user_data);
2117
2118- mutable WebappsHandler *q_ptr;
2119+ WebappsHandler *q_ptr;
2120+ UnityWebappsService *service;
2121 UnityWebappsApplicationRepository *applicationRepository;
2122 };
2123
2124 } // namespace
2125
2126
2127-WebappsHandlerPrivate::WebappsHandlerPrivate(WebappsHandler *service):
2128- q_ptr(service),
2129- applicationRepository(0)
2130+WebappsHandlerPrivate::WebappsHandlerPrivate(WebappsHandler *handler)
2131+ : q_ptr(handler)
2132+ , service(nullptr)
2133+ , applicationRepository(nullptr)
2134 {
2135+ service = unity_webapps_service_new();
2136 }
2137
2138 WebappsHandlerPrivate::~WebappsHandlerPrivate()
2139 {
2140- if (applicationRepository != 0) {
2141+ if (applicationRepository != nullptr) {
2142 g_object_unref(G_OBJECT(applicationRepository));
2143 }
2144+ if (service != nullptr) {
2145+ g_object_unref(service);
2146+ }
2147 }
2148
2149 UnityWebappsApplicationRepository *WebappsHandlerPrivate::getRepository()
2150@@ -285,17 +291,6 @@
2151 return reply;
2152 }
2153
2154-QVariantMap WebappsHandler::ping(const QVariantMap &message)
2155-{
2156- Q_UNUSED(message);
2157-
2158- QVariantMap reply;
2159-
2160- reply.insert("pong", QLatin1String("alive"));
2161-
2162- return reply;
2163-}
2164-
2165 /*
2166 \fn createApplicationDesktopName(QString, QString)
2167
2168@@ -321,4 +316,3 @@
2169
2170 return QStringLiteral("application://%1.desktop").arg(basename);
2171 }
2172-
2173
2174=== modified file 'messaging-host/webapps-handler.h'
2175--- messaging-host/webapps-handler.h 2014-06-23 07:32:13 +0000
2176+++ messaging-host/webapps-handler.h 2015-10-07 04:25:10 +0000
2177@@ -38,7 +38,6 @@
2178 QVariantMap url_loaded(const QVariantMap &message);
2179 QVariantMap dont_ask(const QVariantMap &message);
2180 QVariantMap install(const QVariantMap &message);
2181- QVariantMap ping(const QVariantMap &message);
2182
2183 #if defined(UCX_UNDER_TEST)
2184 public:
2185
2186=== added file 'tests/CMakeLists.txt'
2187--- tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
2188+++ tests/CMakeLists.txt 2015-10-07 04:25:10 +0000
2189@@ -0,0 +1,1 @@
2190+add_subdirectory(unit)
2191
2192=== removed file 'tests/tests.pro'
2193--- tests/tests.pro 2014-05-19 14:04:19 +0000
2194+++ tests/tests.pro 1970-01-01 00:00:00 +0000
2195@@ -1,3 +0,0 @@
2196-TEMPLATE = subdirs
2197-SUBDIRS = \
2198- unit
2199
2200=== added file 'tests/unit/CMakeLists.txt'
2201--- tests/unit/CMakeLists.txt 1970-01-01 00:00:00 +0000
2202+++ tests/unit/CMakeLists.txt 2015-10-07 04:25:10 +0000
2203@@ -0,0 +1,1 @@
2204+add_subdirectory(messaging-host)
2205
2206=== added file 'tests/unit/messaging-host/CMakeLists.txt'
2207--- tests/unit/messaging-host/CMakeLists.txt 1970-01-01 00:00:00 +0000
2208+++ tests/unit/messaging-host/CMakeLists.txt 2015-10-07 04:25:10 +0000
2209@@ -0,0 +1,5 @@
2210+add_subdirectory(connection)
2211+add_subdirectory(inactivity-timer)
2212+add_subdirectory(webapps-handler)
2213+add_subdirectory(click-handler)
2214+add_subdirectory(service)
2215
2216=== added directory 'tests/unit/messaging-host/click-handler'
2217=== added file 'tests/unit/messaging-host/click-handler/CMakeLists.txt'
2218--- tests/unit/messaging-host/click-handler/CMakeLists.txt 1970-01-01 00:00:00 +0000
2219+++ tests/unit/messaging-host/click-handler/CMakeLists.txt 2015-10-07 04:25:10 +0000
2220@@ -0,0 +1,38 @@
2221+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2222+set(CMAKE_INCLUDE_CURRENT_DIR ON)
2223+set(CMAKE_AUTOMOC ON)
2224+
2225+find_package(PkgConfig)
2226+find_package(Qt5Core REQUIRED)
2227+find_package(Qt5Test REQUIRED)
2228+
2229+pkg_check_modules(GLIB glib-2.0 REQUIRED)
2230+pkg_check_modules(GOBJECT gobject-2.0 REQUIRED)
2231+pkg_check_modules(JSON_GLIB json-glib-1.0 REQUIRED)
2232+pkg_check_modules(CLICK click-0.4 REQUIRED)
2233+pkg_check_modules(UBUNTU_APP_LAUNCH ubuntu-app-launch-2 REQUIRED)
2234+
2235+
2236+set(TEST tst_ClickHandler)
2237+set(SOURCES
2238+ ${messaging-host_SOURCE_DIR}/click-handler.cpp
2239+ tst_click-handler.cpp
2240+)
2241+
2242+include_directories(
2243+ ${messaging-host_SOURCE_DIR}
2244+ ${GLIB_INCLUDE_DIRS}
2245+ ${JSON_GLIB_INCLUDE_DIRS}
2246+ ${UBUNTU_APP_LAUNCH_INCLUDE_DIRS}
2247+)
2248+
2249+add_executable(${TEST} ${SOURCES})
2250+
2251+target_link_libraries(${TEST}
2252+ Qt5::Core
2253+ Qt5::Test
2254+ ${GLIB_LIBRARIES}
2255+ ${JSON_GLIB_LIBRARIES}
2256+)
2257+
2258+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2259
2260=== added file 'tests/unit/messaging-host/click-handler/tst_click-handler.cpp'
2261--- tests/unit/messaging-host/click-handler/tst_click-handler.cpp 1970-01-01 00:00:00 +0000
2262+++ tests/unit/messaging-host/click-handler/tst_click-handler.cpp 2015-10-07 04:25:10 +0000
2263@@ -0,0 +1,291 @@
2264+/*
2265+ * Copyright (C) 2015 Canonical Ltd.
2266+ *
2267+ * This file is part of unity-chromium-extension
2268+ *
2269+ * This program is free software: you can redistribute it and/or modify it
2270+ * under the terms of the GNU General Public License version 3, as published
2271+ * by the Free Software Foundation.
2272+ *
2273+ * This program is distributed in the hope that it will be useful, but
2274+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2275+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2276+ * PURPOSE. See the GNU General Public License for more details.
2277+ *
2278+ * You should have received a copy of the GNU General Public License along
2279+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2280+ */
2281+
2282+#include <click-0.4/click.h>
2283+#include <ubuntu-app-launch.h>
2284+
2285+#include "click-handler.h"
2286+
2287+#include <QDebug>
2288+#include <QSignalSpy>
2289+#include <QTest>
2290+
2291+
2292+// {{{ mock implementations
2293+ClickDB* click_db_new(void)
2294+{
2295+ return (ClickDB*)g_object_new(G_TYPE_OBJECT, 0);
2296+}
2297+
2298+void click_db_read(ClickDB* self, const gchar* db_dir, GError** error)
2299+{
2300+}
2301+
2302+JsonArray* click_db_get_manifests(ClickDB* self, gboolean all_versions, GError** error)
2303+{
2304+ const gchar* example_json =
2305+"["
2306+"{"
2307+" \"_directory\": \"/custom/click/.click/users/@all/com.ubuntu.developer.webapps.webapp-gmail\","
2308+" \"_removable\": 1,"
2309+" \"architecture\": \"all\","
2310+" \"description\": \"Gmail (webapp version)\","
2311+" \"framework\": \"ubuntu-sdk-14.10-dev2\","
2312+" \"hooks\": {"
2313+" \"webapp-gmail\": {"
2314+" \"account-application\": \"webapp-gmail.application\","
2315+" \"account-service\": \"webapp-gmail.service\","
2316+" \"apparmor\": \"webapp-gmail.json\","
2317+" \"desktop\": \"webapp-gmail.desktop\","
2318+" \"urls\": \"gmail.url-dispatcher\""
2319+" },"
2320+" \"webapp-gmail-helper\": {"
2321+" \"apparmor\": \"gmail-helper-apparmor.json\","
2322+" \"push-helper\": \"gmail-helper.json\""
2323+" }"
2324+" },"
2325+" \"installed-size\": \"22\","
2326+" \"maintainer\": \"Webapps Team <webapps@lists.launchpad.net>\","
2327+" \"name\": \"com.ubuntu.developer.webapps.webapp-gmail\","
2328+" \"title\": \"webapp-gmail\","
2329+" \"version\": \"1.0.25\""
2330+"},"
2331+"{"
2332+" \"_directory\": \"/custom/click/.click/users/@all/com.ubuntu.developer.webapps.webapp-facebook\","
2333+" \"_removable\": 1,"
2334+" \"architecture\": \"all\","
2335+" \"description\": \"Facebook (webapp version)\","
2336+" \"framework\": \"ubuntu-sdk-14.10\","
2337+" \"hooks\": {"
2338+" \"webapp-facebook\": {"
2339+" \"account-application\": \"webapp-facebook.application\","
2340+" \"account-service\": \"webapp-facebook.service\","
2341+" \"apparmor\": \"webapp-facebook.json\","
2342+" \"content-hub\": \"content-hub/webapp-facebook.json\","
2343+" \"desktop\": \"webapp-facebook.desktop\","
2344+" \"urls\": \"facebook.url-dispatcher\""
2345+" },"
2346+" \"webapp-facebook-helper\": {"
2347+" \"apparmor\": \"facebook-helper-apparmor.json\","
2348+" \"push-helper\": \"facebook-helper.json\""
2349+" }"
2350+" },"
2351+" \"installed-size\": \"887\","
2352+" \"maintainer\": \"Webapps Team <webapps@lists.launchpad.net>\","
2353+" \"name\": \"com.ubuntu.developer.webapps.webapp-facebook\","
2354+" \"title\": \"Facebook\","
2355+" \"version\": \"1.2\""
2356+"}"
2357+"]";
2358+
2359+ JsonParser* parser = json_parser_new();
2360+ if (!json_parser_load_from_data(parser, example_json, strlen(example_json), error)) {
2361+ qDebug() << "Error parsing URL dispatched JSON" << (*error)->message;
2362+ return nullptr;
2363+ }
2364+
2365+ JsonNode *root_node = json_parser_get_root(parser);
2366+ if (json_node_get_node_type(root_node) != JSON_NODE_ARRAY) {
2367+ return nullptr;
2368+ }
2369+
2370+ return json_node_get_array(root_node);
2371+}
2372+
2373+gboolean json_parser_load_from_file(JsonParser *parser, const gchar* filename, GError **error)
2374+{
2375+ const gchar* dispatcher_template =
2376+"["
2377+" {"
2378+" \"protocol\": \"http\","
2379+" \"domain-suffix\": \"%s.com\""
2380+" },"
2381+" {"
2382+" \"protocol\": \"https\","
2383+" \"domain-suffix\": \"%s.com\""
2384+" }"
2385+"]";
2386+
2387+ gchar *dispatcher_json = nullptr;
2388+ if (g_strrstr(filename, "gmail") != NULL) {
2389+ dispatcher_json = g_strdup_printf(dispatcher_template, "google");
2390+ } else if (g_strrstr(filename, "facebook") != NULL) {
2391+ dispatcher_json = g_strdup_printf(dispatcher_template, "facebook");
2392+ }
2393+
2394+ if (!json_parser_load_from_data(parser, dispatcher_json, strlen(dispatcher_json), error)) {
2395+ qDebug() << "Error parsing URL dispatched JSON" << (*error)->message;
2396+ g_free(dispatcher_json);
2397+ return false;
2398+ }
2399+
2400+ g_free(dispatcher_json);
2401+
2402+ return true;
2403+}
2404+
2405+gboolean ubuntu_app_launch_start_application(const gchar* appid, const gchar* const* uris)
2406+{
2407+ return true;
2408+}
2409+// }}}
2410+
2411+class ClickHandlerTest : public QObject
2412+{
2413+ Q_OBJECT
2414+
2415+public:
2416+ ClickHandlerTest();
2417+
2418+private Q_SLOTS:
2419+ void testClickAvailableReturnsMethodName();
2420+ void testClickAvailableUrlMustBeValid();
2421+ void testClickAvailableApps_data();
2422+ void testClickAvailableApps();
2423+ void testLaunchClickReturnsMethodName();
2424+ void testLaunchClickUrlMustBeValid();
2425+ void testLaunchClick_data();
2426+ void testLaunchClick();
2427+};
2428+
2429+ClickHandlerTest::ClickHandlerTest():
2430+ QObject(nullptr)
2431+{
2432+}
2433+
2434+void ClickHandlerTest::testClickAvailableReturnsMethodName()
2435+{
2436+ UnityWebapps::ClickHandler handler;
2437+
2438+ QVariantMap message;
2439+ message.insert("method", "click_available");
2440+
2441+ QVariantMap reply = handler.click_available(message);
2442+
2443+ QVERIFY(!reply.empty());
2444+ QCOMPARE(reply.value("method").toString(), QStringLiteral("click_available"));
2445+}
2446+
2447+void ClickHandlerTest::testClickAvailableUrlMustBeValid()
2448+{
2449+ UnityWebapps::ClickHandler handler;
2450+
2451+ QVariantMap message;
2452+ message.insert("method", "click_available");
2453+
2454+ QVariantMap reply = handler.click_available(message);
2455+
2456+ QVERIFY(!reply.empty());
2457+ QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
2458+}
2459+
2460+void ClickHandlerTest::testClickAvailableApps_data()
2461+{
2462+ QTest::addColumn<QString>("url");
2463+ QTest::addColumn<bool>("available");
2464+ QTest::addColumn<QString>("appName");
2465+ QTest::addColumn<QString>("appDomain");
2466+ QTest::addColumn<QString>("appVersion");
2467+
2468+ QTest::newRow("available") << "https://mail.google.com/" << true << "webapp-gmail" << "mail.google.com" << "1.0.25";
2469+ QTest::newRow("available") << "https://m.facebook.com/" << true << "Facebook" << "m.facebook.com" << "1.2";
2470+ QTest::newRow("not_available") << "http://www.example.com/" << false << "None" << "None" << "0.0.0";
2471+}
2472+
2473+void ClickHandlerTest::testClickAvailableApps()
2474+{
2475+ QFETCH(QString, url);
2476+ QFETCH(bool, available);
2477+ QFETCH(QString, appName);
2478+ QFETCH(QString, appDomain);
2479+ QFETCH(QString, appVersion);
2480+
2481+ UnityWebapps::ClickHandler handler;
2482+
2483+ QVariantMap message;
2484+ message.insert("method", "click_available");
2485+ message.insert("url", url);
2486+
2487+ QVariantMap reply = handler.click_available(message);
2488+
2489+ QVERIFY(!reply.empty());
2490+ QCOMPARE(reply.value("available").toBool(), available);
2491+ if (available) {
2492+ QCOMPARE(appName, reply.value("appName").toString());
2493+ // QCOMPARE(appDomain, reply.value("appDomain").toString()); // Not currently available
2494+ QCOMPARE(appVersion, reply.value("appVersion").toString());
2495+ }
2496+}
2497+
2498+void ClickHandlerTest::testLaunchClickReturnsMethodName()
2499+{
2500+ UnityWebapps::ClickHandler handler;
2501+
2502+ QVariantMap message;
2503+ message.insert("method", "launch_click");
2504+
2505+ QVariantMap reply = handler.launch_click(message);
2506+
2507+ QVERIFY(!reply.empty());
2508+ QCOMPARE(reply.value("method").toString(), QStringLiteral("launch_click"));
2509+}
2510+
2511+void ClickHandlerTest::testLaunchClickUrlMustBeValid()
2512+{
2513+ UnityWebapps::ClickHandler handler;
2514+
2515+ QVariantMap message;
2516+ message.insert("method", "launch_click");
2517+
2518+ QVariantMap reply = handler.click_available(message);
2519+
2520+ QVERIFY(!reply.empty());
2521+ QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
2522+}
2523+
2524+void ClickHandlerTest::testLaunchClick_data()
2525+{
2526+ QTest::addColumn<QString>("url");
2527+ QTest::addColumn<bool>("success");
2528+
2529+ QTest::newRow("launchable") << "https://mail.google.com/" << true;
2530+ QTest::newRow("launchable") << "https://m.facebook.com/" << true;
2531+ QTest::newRow("not_launchable") << "http://www.example.com/" << false;
2532+}
2533+
2534+void ClickHandlerTest::testLaunchClick()
2535+{
2536+ QFETCH(QString, url);
2537+ QFETCH(bool, success);
2538+
2539+ UnityWebapps::ClickHandler handler;
2540+
2541+ QVariantMap message;
2542+ message.insert("method", "launch_click");
2543+ message.insert("url", url);
2544+
2545+ QVariantMap reply = handler.launch_click(message);
2546+
2547+ QVERIFY(!reply.empty());
2548+ QCOMPARE(reply.value("launched").toBool(), success);
2549+}
2550+
2551+
2552+QTEST_MAIN(ClickHandlerTest);
2553+
2554+#include "tst_click-handler.moc"
2555
2556=== added directory 'tests/unit/messaging-host/connection'
2557=== removed file 'tests/unit/messaging-host/connection-host.cpp'
2558--- tests/unit/messaging-host/connection-host.cpp 2014-05-20 12:21:50 +0000
2559+++ tests/unit/messaging-host/connection-host.cpp 1970-01-01 00:00:00 +0000
2560@@ -1,71 +0,0 @@
2561-/*
2562- * Copyright (C) 2014 Canonical Ltd.
2563- *
2564- * This file is part of unity-chromium-extension
2565- *
2566- * This program is free software: you can redistribute it and/or modify it
2567- * under the terms of the GNU General Public License version 3, as published
2568- * by the Free Software Foundation.
2569- *
2570- * This program is distributed in the hope that it will be useful, but
2571- * WITHOUT ANY WARRANTY; without even the implied warranties of
2572- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2573- * PURPOSE. See the GNU General Public License for more details.
2574- *
2575- * You should have received a copy of the GNU General Public License along
2576- * with this program. If not, see <http://www.gnu.org/licenses/>.
2577- */
2578-
2579-#include <QCoreApplication>
2580-#include <QDebug>
2581-#include "connection.h"
2582-
2583-class Handler: public QObject
2584-{
2585- Q_OBJECT
2586-
2587-public:
2588- Handler(): QObject() {}
2589-
2590- bool openConnection();
2591-
2592-public Q_SLOTS:
2593- void onMessageReceived(const QVariantMap &message);
2594-
2595-private:
2596- UnityWebapps::Connection m_connection;
2597-};
2598-
2599-bool Handler::openConnection()
2600-{
2601- QObject::connect(&m_connection,
2602- SIGNAL(messageReceived(const QVariantMap &)),
2603- this,
2604- SLOT(onMessageReceived(const QVariantMap &)));
2605- return m_connection.open();
2606-}
2607-
2608-void Handler::onMessageReceived(const QVariantMap &message)
2609-{
2610- // Generate a predictable reply
2611- QVariantMap reply;
2612- reply.insert("count", message.count());
2613- QStringList keys = message.uniqueKeys();
2614- reply.insert("keys", keys);
2615- m_connection.postMessage(reply);
2616-}
2617-
2618-int main(int argc, char **argv)
2619-{
2620- QCoreApplication app(argc, argv);
2621- Handler handler;
2622-
2623- if (!handler.openConnection()) {
2624- qCritical() << "Connection::open() failed!";
2625- return EXIT_FAILURE;
2626- }
2627-
2628- return app.exec();
2629-}
2630-
2631-#include "connection-host.moc"
2632
2633=== added file 'tests/unit/messaging-host/connection/CMakeLists.txt'
2634--- tests/unit/messaging-host/connection/CMakeLists.txt 1970-01-01 00:00:00 +0000
2635+++ tests/unit/messaging-host/connection/CMakeLists.txt 2015-10-07 04:25:10 +0000
2636@@ -0,0 +1,40 @@
2637+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2638+set(CMAKE_INCLUDE_CURRENT_DIR ON)
2639+set(CMAKE_AUTOMOC ON)
2640+
2641+find_package(Qt5Core REQUIRED)
2642+find_package(Qt5Test REQUIRED)
2643+
2644+# Test server process
2645+add_executable(
2646+ connection-host
2647+
2648+ ${messaging-host_SOURCE_DIR}/connection.cpp
2649+ connection-host.cpp
2650+)
2651+
2652+target_link_libraries(
2653+ connection-host
2654+
2655+ Qt5::Core
2656+)
2657+
2658+# Test proper
2659+set(TEST tst_Connection)
2660+set(SOURCES
2661+ tst_connection.cpp
2662+)
2663+
2664+add_executable(${TEST} ${SOURCES})
2665+add_dependencies(${TEST} connection-host)
2666+
2667+include_directories(${messaging-host_SOURCE_DIR})
2668+
2669+target_link_libraries(
2670+ ${TEST}
2671+
2672+ Qt5::Core
2673+ Qt5::Test
2674+)
2675+
2676+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2677
2678=== added file 'tests/unit/messaging-host/connection/connection-host.cpp'
2679--- tests/unit/messaging-host/connection/connection-host.cpp 1970-01-01 00:00:00 +0000
2680+++ tests/unit/messaging-host/connection/connection-host.cpp 2015-10-07 04:25:10 +0000
2681@@ -0,0 +1,71 @@
2682+/*
2683+ * Copyright (C) 2014 Canonical Ltd.
2684+ *
2685+ * This file is part of unity-chromium-extension
2686+ *
2687+ * This program is free software: you can redistribute it and/or modify it
2688+ * under the terms of the GNU General Public License version 3, as published
2689+ * by the Free Software Foundation.
2690+ *
2691+ * This program is distributed in the hope that it will be useful, but
2692+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2693+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2694+ * PURPOSE. See the GNU General Public License for more details.
2695+ *
2696+ * You should have received a copy of the GNU General Public License along
2697+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2698+ */
2699+
2700+#include <QCoreApplication>
2701+#include <QDebug>
2702+#include "connection.h"
2703+
2704+class Handler: public QObject
2705+{
2706+ Q_OBJECT
2707+
2708+public:
2709+ Handler(): QObject() {}
2710+
2711+ bool openConnection();
2712+
2713+public Q_SLOTS:
2714+ void onMessageReceived(const QVariantMap &message);
2715+
2716+private:
2717+ UnityWebapps::Connection m_connection;
2718+};
2719+
2720+bool Handler::openConnection()
2721+{
2722+ QObject::connect(&m_connection,
2723+ SIGNAL(messageReceived(const QVariantMap &)),
2724+ this,
2725+ SLOT(onMessageReceived(const QVariantMap &)));
2726+ return m_connection.open();
2727+}
2728+
2729+void Handler::onMessageReceived(const QVariantMap &message)
2730+{
2731+ // Generate a predictable reply
2732+ QVariantMap reply;
2733+ reply.insert("count", message.count());
2734+ QStringList keys = message.uniqueKeys();
2735+ reply.insert("keys", keys);
2736+ m_connection.postMessage(reply);
2737+}
2738+
2739+int main(int argc, char **argv)
2740+{
2741+ QCoreApplication app(argc, argv);
2742+ Handler handler;
2743+
2744+ if (!handler.openConnection()) {
2745+ qCritical() << "Connection::open() failed!";
2746+ return EXIT_FAILURE;
2747+ }
2748+
2749+ return app.exec();
2750+}
2751+
2752+#include "connection-host.moc"
2753
2754=== added file 'tests/unit/messaging-host/connection/tst_connection.cpp'
2755--- tests/unit/messaging-host/connection/tst_connection.cpp 1970-01-01 00:00:00 +0000
2756+++ tests/unit/messaging-host/connection/tst_connection.cpp 2015-10-07 04:25:10 +0000
2757@@ -0,0 +1,112 @@
2758+/*
2759+ * Copyright (C) 2014 Canonical Ltd.
2760+ *
2761+ * This file is part of unity-chromium-extension
2762+ *
2763+ * This program is free software: you can redistribute it and/or modify it
2764+ * under the terms of the GNU General Public License version 3, as published
2765+ * by the Free Software Foundation.
2766+ *
2767+ * This program is distributed in the hope that it will be useful, but
2768+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2769+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2770+ * PURPOSE. See the GNU General Public License for more details.
2771+ *
2772+ * You should have received a copy of the GNU General Public License along
2773+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2774+ */
2775+
2776+#include <QByteArray>
2777+#include <QDebug>
2778+#include <QJsonDocument>
2779+#include <QProcess>
2780+#include <QSet>
2781+#include <QSignalSpy>
2782+#include <QTest>
2783+
2784+class ConnectionTest: public QObject
2785+{
2786+ Q_OBJECT
2787+
2788+public:
2789+ ConnectionTest();
2790+
2791+ void postMessage(const QByteArray &message);
2792+ QByteArray readReply();
2793+ QVariantMap jsonToMap(const QByteArray &json);
2794+
2795+private Q_SLOTS:
2796+ void init();
2797+ void cleanup();
2798+ void testMessaging();
2799+
2800+private:
2801+ QProcess m_process;
2802+};
2803+
2804+ConnectionTest::ConnectionTest():
2805+ QObject(0)
2806+{
2807+ m_process.setProgram("./connection-host");
2808+ m_process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
2809+ m_process.setReadChannel(QProcess::StandardOutput);
2810+}
2811+
2812+void ConnectionTest::postMessage(const QByteArray &message)
2813+{
2814+ quint32 length = message.length();
2815+
2816+ m_process.write((char *)&length, sizeof(length));
2817+ m_process.write(message);
2818+}
2819+
2820+QByteArray ConnectionTest::readReply()
2821+{
2822+ quint32 length;
2823+ m_process.waitForReadyRead();
2824+ m_process.read((char *)&length, sizeof(length));
2825+ return m_process.read(length);
2826+}
2827+
2828+QVariantMap ConnectionTest::jsonToMap(const QByteArray &json)
2829+{
2830+ QJsonDocument doc = QJsonDocument::fromJson(json);
2831+ return doc.toVariant().toMap();
2832+}
2833+
2834+void ConnectionTest::init()
2835+{
2836+ m_process.start();
2837+ m_process.waitForStarted();
2838+}
2839+
2840+void ConnectionTest::cleanup()
2841+{
2842+ m_process.kill();
2843+ m_process.waitForFinished();
2844+}
2845+
2846+void ConnectionTest::testMessaging()
2847+{
2848+ postMessage("{\"msg\":\"hi\"}");
2849+ QVariantMap reply = jsonToMap(readReply());
2850+ QCOMPARE(reply.count(), 2);
2851+ QCOMPARE(reply.value("count").toInt(), 1);
2852+ QCOMPARE(reply.value("keys").toStringList(), QStringList() << "msg");
2853+
2854+ postMessage("{\"list\": [\"one\", \"two\"],"
2855+ "\"name\": \"Tom\","
2856+ "\"number\": 23}");
2857+ reply = jsonToMap(readReply());
2858+ QCOMPARE(reply.count(), 2);
2859+ QCOMPARE(reply.value("count").toInt(), 3);
2860+ QSet<QString> expectedKeys;
2861+ expectedKeys << "list" << "name" << "number";
2862+ QCOMPARE(reply.value("keys").toStringList().toSet(), expectedKeys);
2863+
2864+ m_process.terminate();
2865+}
2866+
2867+QTEST_MAIN(ConnectionTest);
2868+
2869+#include "tst_connection.moc"
2870
2871=== added directory 'tests/unit/messaging-host/inactivity-timer'
2872=== added file 'tests/unit/messaging-host/inactivity-timer/CMakeLists.txt'
2873--- tests/unit/messaging-host/inactivity-timer/CMakeLists.txt 1970-01-01 00:00:00 +0000
2874+++ tests/unit/messaging-host/inactivity-timer/CMakeLists.txt 2015-10-07 04:25:10 +0000
2875@@ -0,0 +1,23 @@
2876+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2877+set(CMAKE_INCLUDE_CURRENT_DIR ON)
2878+set(CMAKE_AUTOMOC ON)
2879+
2880+find_package(Qt5Core REQUIRED)
2881+find_package(Qt5Test REQUIRED)
2882+
2883+set(TEST tst_InactivityTimer)
2884+set(SOURCES
2885+ ${messaging-host_SOURCE_DIR}/inactivity-timer.cpp
2886+ tst_inactivity_timer.cpp
2887+)
2888+
2889+add_executable(${TEST} ${SOURCES})
2890+
2891+include_directories(${messaging-host_SOURCE_DIR})
2892+
2893+target_link_libraries(${TEST}
2894+ Qt5::Core
2895+ Qt5::Test
2896+)
2897+
2898+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2899
2900=== added file 'tests/unit/messaging-host/inactivity-timer/tst_inactivity_timer.cpp'
2901--- tests/unit/messaging-host/inactivity-timer/tst_inactivity_timer.cpp 1970-01-01 00:00:00 +0000
2902+++ tests/unit/messaging-host/inactivity-timer/tst_inactivity_timer.cpp 2015-10-07 04:25:10 +0000
2903@@ -0,0 +1,125 @@
2904+/*
2905+ * Copyright (C) 2014 Canonical Ltd.
2906+ *
2907+ * This file is part of unity-chromium-extension
2908+ *
2909+ * This program is free software: you can redistribute it and/or modify it
2910+ * under the terms of the GNU General Public License version 3, as published
2911+ * by the Free Software Foundation.
2912+ *
2913+ * This program is distributed in the hope that it will be useful, but
2914+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2915+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2916+ * PURPOSE. See the GNU General Public License for more details.
2917+ *
2918+ * You should have received a copy of the GNU General Public License along
2919+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2920+ */
2921+
2922+#include "inactivity-timer.h"
2923+
2924+#include <QDebug>
2925+#include <QSignalSpy>
2926+#include <QTest>
2927+
2928+using namespace UnityWebapps;
2929+
2930+class Service: public QObject
2931+{
2932+ Q_OBJECT
2933+ Q_PROPERTY(bool isIdle READ isIdle NOTIFY isIdleChanged)
2934+
2935+public:
2936+ Service(): QObject(), m_isIdle(true) {}
2937+
2938+ bool isIdle() const { return m_isIdle; }
2939+
2940+ void setIdle(bool idle) {
2941+ if (idle == m_isIdle) return;
2942+ m_isIdle = idle;
2943+ Q_EMIT isIdleChanged();
2944+ }
2945+
2946+Q_SIGNALS:
2947+ void isIdleChanged();
2948+
2949+private:
2950+ bool m_isIdle;
2951+};
2952+
2953+class InactivityTimerTest: public QObject
2954+{
2955+ Q_OBJECT
2956+
2957+public:
2958+ InactivityTimerTest();
2959+
2960+private Q_SLOTS:
2961+ void testAlwaysIdle();
2962+ void testBecomeIdle();
2963+ void testManyServices();
2964+};
2965+
2966+InactivityTimerTest::InactivityTimerTest():
2967+ QObject(0)
2968+{
2969+}
2970+
2971+void InactivityTimerTest::testAlwaysIdle()
2972+{
2973+ InactivityTimer timer(10);
2974+ QSignalSpy timeout(&timer, SIGNAL(timeout()));
2975+
2976+ Service service;
2977+ timer.watchObject(&service);
2978+
2979+ QVERIFY(timeout.wait(100));
2980+}
2981+
2982+void InactivityTimerTest::testBecomeIdle()
2983+{
2984+ InactivityTimer timer(10);
2985+ QSignalSpy timeout(&timer, SIGNAL(timeout()));
2986+
2987+ Service service;
2988+ service.setIdle(false);
2989+ timer.watchObject(&service);
2990+
2991+ /* No signal should be emitted, as the service is not idle */
2992+ QVERIFY(!timeout.wait(100));
2993+
2994+ service.setIdle(true);
2995+ QVERIFY(timeout.wait(100));
2996+}
2997+
2998+void InactivityTimerTest::testManyServices()
2999+{
3000+ InactivityTimer timer(50);
3001+ QSignalSpy timeout(&timer, SIGNAL(timeout()));
3002+
3003+ Service service1;
3004+ timer.watchObject(&service1);
3005+
3006+ Service service2;
3007+ timer.watchObject(&service2);
3008+
3009+ Service service3;
3010+ service3.setIdle(false);
3011+ timer.watchObject(&service3);
3012+
3013+ /* No signal should be emitted, as service3 is not idle */
3014+ QVERIFY(!timeout.wait(100));
3015+
3016+ /* Now set it is as idle, but soon afterwards set service1 as busy */
3017+ service3.setIdle(true);
3018+ QTest::qWait(10);
3019+ service1.setIdle(false);
3020+ QVERIFY(!timeout.wait(100));
3021+
3022+ service1.setIdle(true);
3023+ QVERIFY(timeout.wait(100));
3024+}
3025+
3026+QTEST_MAIN(InactivityTimerTest);
3027+
3028+#include "tst_inactivity_timer.moc"
3029
3030=== removed file 'tests/unit/messaging-host/messaging-host.pri'
3031--- tests/unit/messaging-host/messaging-host.pri 2014-05-21 08:18:12 +0000
3032+++ tests/unit/messaging-host/messaging-host.pri 1970-01-01 00:00:00 +0000
3033@@ -1,9 +0,0 @@
3034-include(../../../common-project-config.pri)
3035-
3036-CONFIG += \
3037- debug
3038-
3039-SRC_DIR = $${TOP_SRC_DIR}/messaging-host
3040-
3041-INCLUDEPATH += \
3042- $${SRC_DIR}
3043
3044=== removed file 'tests/unit/messaging-host/messaging-host.pro'
3045--- tests/unit/messaging-host/messaging-host.pro 2014-05-23 10:16:49 +0000
3046+++ tests/unit/messaging-host/messaging-host.pro 1970-01-01 00:00:00 +0000
3047@@ -1,12 +0,0 @@
3048-TEMPLATE = subdirs
3049-SUBDIRS = \
3050- tst_connection \
3051- tst_connection_host \
3052- tst_inactivity_timer.pro \
3053- tst_service.pro \
3054- tst_webapps-handler.pro \
3055-
3056-tst_connection.file = tst_connection.pro
3057-tst_connection_host.file = tst_connection_host.pro
3058-
3059-tst_connection.depends = tst_connection_host
3060
3061=== added directory 'tests/unit/messaging-host/service'
3062=== added file 'tests/unit/messaging-host/service/CMakeLists.txt'
3063--- tests/unit/messaging-host/service/CMakeLists.txt 1970-01-01 00:00:00 +0000
3064+++ tests/unit/messaging-host/service/CMakeLists.txt 2015-10-07 04:25:10 +0000
3065@@ -0,0 +1,23 @@
3066+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
3067+set(CMAKE_INCLUDE_CURRENT_DIR ON)
3068+set(CMAKE_AUTOMOC ON)
3069+
3070+find_package(Qt5Core REQUIRED)
3071+find_package(Qt5Test REQUIRED)
3072+
3073+set(TEST tst_Service)
3074+set(SOURCES
3075+ ${messaging-host_SOURCE_DIR}/service.cpp
3076+ tst_service.cpp
3077+)
3078+
3079+add_executable(${TEST} ${SOURCES})
3080+
3081+include_directories(${messaging-host_SOURCE_DIR})
3082+
3083+target_link_libraries(${TEST}
3084+ Qt5::Core
3085+ Qt5::Test
3086+)
3087+
3088+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
3089
3090=== added file 'tests/unit/messaging-host/service/tst_service.cpp'
3091--- tests/unit/messaging-host/service/tst_service.cpp 1970-01-01 00:00:00 +0000
3092+++ tests/unit/messaging-host/service/tst_service.cpp 2015-10-07 04:25:10 +0000
3093@@ -0,0 +1,189 @@
3094+/*
3095+ * Copyright (C) 2014 Canonical Ltd.
3096+ *
3097+ * This file is part of unity-chromium-extension
3098+ *
3099+ * This program is free software: you can redistribute it and/or modify it
3100+ * under the terms of the GNU General Public License version 3, as published
3101+ * by the Free Software Foundation.
3102+ *
3103+ * This program is distributed in the hope that it will be useful, but
3104+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3105+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3106+ * PURPOSE. See the GNU General Public License for more details.
3107+ *
3108+ * You should have received a copy of the GNU General Public License along
3109+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3110+ */
3111+
3112+#include "service.h"
3113+
3114+#include <QDebug>
3115+#include <QSignalSpy>
3116+#include <QTest>
3117+
3118+class Handler1: public QObject
3119+{
3120+ Q_OBJECT
3121+
3122+public:
3123+ Handler1() {}
3124+
3125+public Q_SLOTS:
3126+ QVariantMap sayHello(const QVariantMap &params);
3127+ QVariantMap countArguments(const QVariantMap &params);
3128+};
3129+
3130+QVariantMap Handler1::sayHello(const QVariantMap &params)
3131+{
3132+ QVariantMap reply;
3133+ reply.insert("greeting",
3134+ QString("Hello %1").arg(params.value("name").toString()));
3135+ return reply;
3136+}
3137+
3138+QVariantMap Handler1::countArguments(const QVariantMap &params)
3139+{
3140+ QVariantMap reply;
3141+ // We subtract one, because that's the "method" field
3142+ reply.insert("count", params.count() - 1);
3143+ return reply;
3144+}
3145+
3146+class Handler2: public QObject
3147+{
3148+ Q_OBJECT
3149+
3150+public:
3151+ Handler2() {}
3152+
3153+public Q_SLOTS:
3154+ QVariantMap listArguments(const QVariantMap &params);
3155+};
3156+
3157+QVariantMap Handler2::listArguments(const QVariantMap &params)
3158+{
3159+ QVariantMap reply;
3160+ QStringList arguments = params.keys();
3161+ arguments.removeAll("method");
3162+ reply.insert("arguments", arguments);
3163+ return reply;
3164+}
3165+
3166+class ServiceTest: public QObject
3167+{
3168+ Q_OBJECT
3169+
3170+public:
3171+ ServiceTest();
3172+
3173+private Q_SLOTS:
3174+ void testNoHandlers();
3175+ void testNonExisting();
3176+ void testHandling();
3177+};
3178+
3179+ServiceTest::ServiceTest():
3180+ QObject(0)
3181+{
3182+}
3183+
3184+void ServiceTest::testNoHandlers()
3185+{
3186+ UnityWebapps::Service service;
3187+ QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
3188+
3189+ QVariantMap message;
3190+ message.insert("method", QString("sayHello"));
3191+ message.insert("name", QString("Tom"));
3192+ service.handleMessage(message);
3193+
3194+ QCOMPARE(messageHandled.count(), 0);
3195+ QVERIFY(service.isIdle());
3196+}
3197+
3198+void ServiceTest::testNonExisting()
3199+{
3200+ UnityWebapps::Service service;
3201+ QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
3202+
3203+ Handler1 handler1;
3204+ service.addHandler(&handler1);
3205+
3206+ QVariantMap message;
3207+ message.insert("method", QString("nonExistingMethod"));
3208+ service.handleMessage(message);
3209+
3210+ QCOMPARE(messageHandled.count(), 0);
3211+ QVERIFY(service.isIdle());
3212+
3213+ // Add the second service (it still should fail)
3214+ Handler2 handler2;
3215+ service.addHandler(&handler2);
3216+
3217+ service.handleMessage(message);
3218+
3219+ QCOMPARE(messageHandled.count(), 0);
3220+ QVERIFY(service.isIdle());
3221+}
3222+
3223+void ServiceTest::testHandling()
3224+{
3225+ UnityWebapps::Service service;
3226+ QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
3227+ QSignalSpy isIdleChanged(&service, SIGNAL(isIdleChanged()));
3228+ QVERIFY(service.isIdle());
3229+
3230+ Handler1 handler1;
3231+ service.addHandler(&handler1);
3232+
3233+ QVariantMap message;
3234+ message.insert("method", QString("sayHello"));
3235+ message.insert("name", QString("Tom"));
3236+ service.handleMessage(message);
3237+
3238+ QCOMPARE(messageHandled.count(), 1);
3239+ QVariantMap reply = messageHandled.at(0).at(0).toMap();
3240+ QCOMPARE(reply.value("greeting").toString(), QString("Hello Tom"));
3241+ messageHandled.clear();
3242+ QCOMPARE(isIdleChanged.count(), 2);
3243+ isIdleChanged.clear();
3244+ QVERIFY(service.isIdle());
3245+
3246+ // Make sure it continues to work when we add a second handler
3247+ Handler2 handler2;
3248+ service.addHandler(&handler2);
3249+ service.handleMessage(message);
3250+
3251+ QCOMPARE(messageHandled.count(), 1);
3252+ reply = messageHandled.at(0).at(0).toMap();
3253+ QCOMPARE(reply.value("greeting").toString(), QString("Hello Tom"));
3254+ messageHandled.clear();
3255+ QCOMPARE(isIdleChanged.count(), 2);
3256+ isIdleChanged.clear();
3257+ QVERIFY(service.isIdle());
3258+
3259+ // Test a method from the second handler
3260+ message.clear();
3261+ message.insert("method", QString("listArguments"));
3262+ message.insert("number", 1);
3263+ message.insert("string", QString("Hello"));
3264+ message.insert("boolean", false);
3265+ service.handleMessage(message);
3266+
3267+ QCOMPARE(messageHandled.count(), 1);
3268+ reply = messageHandled.at(0).at(0).toMap();
3269+ QVERIFY(reply.contains("arguments"));
3270+ QStringList expectedArguments;
3271+ expectedArguments << "number" << "string" << "boolean";
3272+ QCOMPARE(reply.value("arguments").toStringList().toSet(),
3273+ expectedArguments.toSet());
3274+ messageHandled.clear();
3275+ QCOMPARE(isIdleChanged.count(), 2);
3276+ isIdleChanged.clear();
3277+ QVERIFY(service.isIdle());
3278+}
3279+
3280+QTEST_MAIN(ServiceTest);
3281+
3282+#include "tst_service.moc"
3283
3284=== removed file 'tests/unit/messaging-host/tst_connection.cpp'
3285--- tests/unit/messaging-host/tst_connection.cpp 2014-05-20 12:21:50 +0000
3286+++ tests/unit/messaging-host/tst_connection.cpp 1970-01-01 00:00:00 +0000
3287@@ -1,112 +0,0 @@
3288-/*
3289- * Copyright (C) 2014 Canonical Ltd.
3290- *
3291- * This file is part of unity-chromium-extension
3292- *
3293- * This program is free software: you can redistribute it and/or modify it
3294- * under the terms of the GNU General Public License version 3, as published
3295- * by the Free Software Foundation.
3296- *
3297- * This program is distributed in the hope that it will be useful, but
3298- * WITHOUT ANY WARRANTY; without even the implied warranties of
3299- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3300- * PURPOSE. See the GNU General Public License for more details.
3301- *
3302- * You should have received a copy of the GNU General Public License along
3303- * with this program. If not, see <http://www.gnu.org/licenses/>.
3304- */
3305-
3306-#include <QByteArray>
3307-#include <QDebug>
3308-#include <QJsonDocument>
3309-#include <QProcess>
3310-#include <QSet>
3311-#include <QSignalSpy>
3312-#include <QTest>
3313-
3314-class ConnectionTest: public QObject
3315-{
3316- Q_OBJECT
3317-
3318-public:
3319- ConnectionTest();
3320-
3321- void postMessage(const QByteArray &message);
3322- QByteArray readReply();
3323- QVariantMap jsonToMap(const QByteArray &json);
3324-
3325-private Q_SLOTS:
3326- void init();
3327- void cleanup();
3328- void testMessaging();
3329-
3330-private:
3331- QProcess m_process;
3332-};
3333-
3334-ConnectionTest::ConnectionTest():
3335- QObject(0)
3336-{
3337- m_process.setProgram("./connection-host");
3338- m_process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
3339- m_process.setReadChannel(QProcess::StandardOutput);
3340-}
3341-
3342-void ConnectionTest::postMessage(const QByteArray &message)
3343-{
3344- quint32 length = message.length();
3345-
3346- m_process.write((char *)&length, sizeof(length));
3347- m_process.write(message);
3348-}
3349-
3350-QByteArray ConnectionTest::readReply()
3351-{
3352- quint32 length;
3353- m_process.waitForReadyRead();
3354- m_process.read((char *)&length, sizeof(length));
3355- return m_process.read(length);
3356-}
3357-
3358-QVariantMap ConnectionTest::jsonToMap(const QByteArray &json)
3359-{
3360- QJsonDocument doc = QJsonDocument::fromJson(json);
3361- return doc.toVariant().toMap();
3362-}
3363-
3364-void ConnectionTest::init()
3365-{
3366- m_process.start();
3367- m_process.waitForStarted();
3368-}
3369-
3370-void ConnectionTest::cleanup()
3371-{
3372- m_process.kill();
3373- m_process.waitForFinished();
3374-}
3375-
3376-void ConnectionTest::testMessaging()
3377-{
3378- postMessage("{\"msg\":\"hi\"}");
3379- QVariantMap reply = jsonToMap(readReply());
3380- QCOMPARE(reply.count(), 2);
3381- QCOMPARE(reply.value("count").toInt(), 1);
3382- QCOMPARE(reply.value("keys").toStringList(), QStringList() << "msg");
3383-
3384- postMessage("{\"list\": [\"one\", \"two\"],"
3385- "\"name\": \"Tom\","
3386- "\"number\": 23}");
3387- reply = jsonToMap(readReply());
3388- QCOMPARE(reply.count(), 2);
3389- QCOMPARE(reply.value("count").toInt(), 3);
3390- QSet<QString> expectedKeys;
3391- expectedKeys << "list" << "name" << "number";
3392- QCOMPARE(reply.value("keys").toStringList().toSet(), expectedKeys);
3393-
3394- m_process.terminate();
3395-}
3396-
3397-QTEST_MAIN(ConnectionTest);
3398-
3399-#include "tst_connection.moc"
3400
3401=== removed file 'tests/unit/messaging-host/tst_connection.pro'
3402--- tests/unit/messaging-host/tst_connection.pro 2014-05-21 08:18:12 +0000
3403+++ tests/unit/messaging-host/tst_connection.pro 1970-01-01 00:00:00 +0000
3404@@ -1,14 +0,0 @@
3405-include(messaging-host.pri)
3406-
3407-TARGET = tst_connection
3408-
3409-QT += \
3410- core \
3411- testlib
3412-
3413-SOURCES += \
3414- tst_connection.cpp
3415-
3416-check.commands = "xvfb-run -s '-screen 0 640x480x24' -a ./$${TARGET}"
3417-check.depends = $${TARGET}
3418-QMAKE_EXTRA_TARGETS += check
3419
3420=== removed file 'tests/unit/messaging-host/tst_connection_host.pro'
3421--- tests/unit/messaging-host/tst_connection_host.pro 2014-05-21 08:18:12 +0000
3422+++ tests/unit/messaging-host/tst_connection_host.pro 1970-01-01 00:00:00 +0000
3423@@ -1,14 +0,0 @@
3424-include(messaging-host.pri)
3425-
3426-TEMPLATE = app
3427-TARGET = connection-host
3428-
3429-QT += \
3430- core
3431-
3432-SOURCES = \
3433- $${SRC_DIR}/connection.cpp \
3434- connection-host.cpp
3435-
3436-HEADERS = \
3437- $${SRC_DIR}/connection.h \
3438
3439=== removed file 'tests/unit/messaging-host/tst_inactivity_timer.cpp'
3440--- tests/unit/messaging-host/tst_inactivity_timer.cpp 2014-05-21 08:18:12 +0000
3441+++ tests/unit/messaging-host/tst_inactivity_timer.cpp 1970-01-01 00:00:00 +0000
3442@@ -1,125 +0,0 @@
3443-/*
3444- * Copyright (C) 2014 Canonical Ltd.
3445- *
3446- * This file is part of unity-chromium-extension
3447- *
3448- * This program is free software: you can redistribute it and/or modify it
3449- * under the terms of the GNU General Public License version 3, as published
3450- * by the Free Software Foundation.
3451- *
3452- * This program is distributed in the hope that it will be useful, but
3453- * WITHOUT ANY WARRANTY; without even the implied warranties of
3454- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3455- * PURPOSE. See the GNU General Public License for more details.
3456- *
3457- * You should have received a copy of the GNU General Public License along
3458- * with this program. If not, see <http://www.gnu.org/licenses/>.
3459- */
3460-
3461-#include "inactivity-timer.h"
3462-
3463-#include <QDebug>
3464-#include <QSignalSpy>
3465-#include <QTest>
3466-
3467-using namespace UnityWebapps;
3468-
3469-class Service: public QObject
3470-{
3471- Q_OBJECT
3472- Q_PROPERTY(bool isIdle READ isIdle NOTIFY isIdleChanged)
3473-
3474-public:
3475- Service(): QObject(), m_isIdle(true) {}
3476-
3477- bool isIdle() const { return m_isIdle; }
3478-
3479- void setIdle(bool idle) {
3480- if (idle == m_isIdle) return;
3481- m_isIdle = idle;
3482- Q_EMIT isIdleChanged();
3483- }
3484-
3485-Q_SIGNALS:
3486- void isIdleChanged();
3487-
3488-private:
3489- bool m_isIdle;
3490-};
3491-
3492-class InactivityTimerTest: public QObject
3493-{
3494- Q_OBJECT
3495-
3496-public:
3497- InactivityTimerTest();
3498-
3499-private Q_SLOTS:
3500- void testAlwaysIdle();
3501- void testBecomeIdle();
3502- void testManyServices();
3503-};
3504-
3505-InactivityTimerTest::InactivityTimerTest():
3506- QObject(0)
3507-{
3508-}
3509-
3510-void InactivityTimerTest::testAlwaysIdle()
3511-{
3512- InactivityTimer timer(10);
3513- QSignalSpy timeout(&timer, SIGNAL(timeout()));
3514-
3515- Service service;
3516- timer.watchObject(&service);
3517-
3518- QVERIFY(timeout.wait(100));
3519-}
3520-
3521-void InactivityTimerTest::testBecomeIdle()
3522-{
3523- InactivityTimer timer(10);
3524- QSignalSpy timeout(&timer, SIGNAL(timeout()));
3525-
3526- Service service;
3527- service.setIdle(false);
3528- timer.watchObject(&service);
3529-
3530- /* No signal should be emitted, as the service is not idle */
3531- QVERIFY(!timeout.wait(100));
3532-
3533- service.setIdle(true);
3534- QVERIFY(timeout.wait(100));
3535-}
3536-
3537-void InactivityTimerTest::testManyServices()
3538-{
3539- InactivityTimer timer(50);
3540- QSignalSpy timeout(&timer, SIGNAL(timeout()));
3541-
3542- Service service1;
3543- timer.watchObject(&service1);
3544-
3545- Service service2;
3546- timer.watchObject(&service2);
3547-
3548- Service service3;
3549- service3.setIdle(false);
3550- timer.watchObject(&service3);
3551-
3552- /* No signal should be emitted, as service3 is not idle */
3553- QVERIFY(!timeout.wait(100));
3554-
3555- /* Now set it is as idle, but soon afterwards set service1 as busy */
3556- service3.setIdle(true);
3557- QTest::qWait(10);
3558- service1.setIdle(false);
3559- QVERIFY(!timeout.wait(100));
3560-
3561- service1.setIdle(true);
3562- QVERIFY(timeout.wait(100));
3563-}
3564-
3565-QTEST_MAIN(InactivityTimerTest);
3566-
3567-#include "tst_inactivity_timer.moc"
3568
3569=== removed file 'tests/unit/messaging-host/tst_inactivity_timer.pro'
3570--- tests/unit/messaging-host/tst_inactivity_timer.pro 2014-05-21 08:18:12 +0000
3571+++ tests/unit/messaging-host/tst_inactivity_timer.pro 1970-01-01 00:00:00 +0000
3572@@ -1,18 +0,0 @@
3573-include(messaging-host.pri)
3574-
3575-TARGET = tst_inactivity_timer
3576-
3577-QT += \
3578- core \
3579- testlib
3580-
3581-SOURCES += \
3582- $${SRC_DIR}/inactivity-timer.cpp \
3583- tst_inactivity_timer.cpp
3584-
3585-HEADERS += \
3586- $${SRC_DIR}/inactivity-timer.h
3587-
3588-check.commands = "xvfb-run -s '-screen 0 640x480x24' -a ./$${TARGET}"
3589-check.depends = $${TARGET}
3590-QMAKE_EXTRA_TARGETS += check
3591
3592=== removed file 'tests/unit/messaging-host/tst_service.cpp'
3593--- tests/unit/messaging-host/tst_service.cpp 2014-05-21 08:18:12 +0000
3594+++ tests/unit/messaging-host/tst_service.cpp 1970-01-01 00:00:00 +0000
3595@@ -1,189 +0,0 @@
3596-/*
3597- * Copyright (C) 2014 Canonical Ltd.
3598- *
3599- * This file is part of unity-chromium-extension
3600- *
3601- * This program is free software: you can redistribute it and/or modify it
3602- * under the terms of the GNU General Public License version 3, as published
3603- * by the Free Software Foundation.
3604- *
3605- * This program is distributed in the hope that it will be useful, but
3606- * WITHOUT ANY WARRANTY; without even the implied warranties of
3607- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3608- * PURPOSE. See the GNU General Public License for more details.
3609- *
3610- * You should have received a copy of the GNU General Public License along
3611- * with this program. If not, see <http://www.gnu.org/licenses/>.
3612- */
3613-
3614-#include "service.h"
3615-
3616-#include <QDebug>
3617-#include <QSignalSpy>
3618-#include <QTest>
3619-
3620-class Handler1: public QObject
3621-{
3622- Q_OBJECT
3623-
3624-public:
3625- Handler1() {}
3626-
3627-public Q_SLOTS:
3628- QVariantMap sayHello(const QVariantMap &params);
3629- QVariantMap countArguments(const QVariantMap &params);
3630-};
3631-
3632-QVariantMap Handler1::sayHello(const QVariantMap &params)
3633-{
3634- QVariantMap reply;
3635- reply.insert("greeting",
3636- QString("Hello %1").arg(params.value("name").toString()));
3637- return reply;
3638-}
3639-
3640-QVariantMap Handler1::countArguments(const QVariantMap &params)
3641-{
3642- QVariantMap reply;
3643- // We subtract one, because that's the "method" field
3644- reply.insert("count", params.count() - 1);
3645- return reply;
3646-}
3647-
3648-class Handler2: public QObject
3649-{
3650- Q_OBJECT
3651-
3652-public:
3653- Handler2() {}
3654-
3655-public Q_SLOTS:
3656- QVariantMap listArguments(const QVariantMap &params);
3657-};
3658-
3659-QVariantMap Handler2::listArguments(const QVariantMap &params)
3660-{
3661- QVariantMap reply;
3662- QStringList arguments = params.keys();
3663- arguments.removeAll("method");
3664- reply.insert("arguments", arguments);
3665- return reply;
3666-}
3667-
3668-class ServiceTest: public QObject
3669-{
3670- Q_OBJECT
3671-
3672-public:
3673- ServiceTest();
3674-
3675-private Q_SLOTS:
3676- void testNoHandlers();
3677- void testNonExisting();
3678- void testHandling();
3679-};
3680-
3681-ServiceTest::ServiceTest():
3682- QObject(0)
3683-{
3684-}
3685-
3686-void ServiceTest::testNoHandlers()
3687-{
3688- UnityWebapps::Service service;
3689- QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
3690-
3691- QVariantMap message;
3692- message.insert("method", QString("sayHello"));
3693- message.insert("name", QString("Tom"));
3694- service.handleMessage(message);
3695-
3696- QCOMPARE(messageHandled.count(), 0);
3697- QVERIFY(service.isIdle());
3698-}
3699-
3700-void ServiceTest::testNonExisting()
3701-{
3702- UnityWebapps::Service service;
3703- QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
3704-
3705- Handler1 handler1;
3706- service.addHandler(&handler1);
3707-
3708- QVariantMap message;
3709- message.insert("method", QString("nonExistingMethod"));
3710- service.handleMessage(message);
3711-
3712- QCOMPARE(messageHandled.count(), 0);
3713- QVERIFY(service.isIdle());
3714-
3715- // Add the second service (it still should fail)
3716- Handler2 handler2;
3717- service.addHandler(&handler2);
3718-
3719- service.handleMessage(message);
3720-
3721- QCOMPARE(messageHandled.count(), 0);
3722- QVERIFY(service.isIdle());
3723-}
3724-
3725-void ServiceTest::testHandling()
3726-{
3727- UnityWebapps::Service service;
3728- QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
3729- QSignalSpy isIdleChanged(&service, SIGNAL(isIdleChanged()));
3730- QVERIFY(service.isIdle());
3731-
3732- Handler1 handler1;
3733- service.addHandler(&handler1);
3734-
3735- QVariantMap message;
3736- message.insert("method", QString("sayHello"));
3737- message.insert("name", QString("Tom"));
3738- service.handleMessage(message);
3739-
3740- QCOMPARE(messageHandled.count(), 1);
3741- QVariantMap reply = messageHandled.at(0).at(0).toMap();
3742- QCOMPARE(reply.value("greeting").toString(), QString("Hello Tom"));
3743- messageHandled.clear();
3744- QCOMPARE(isIdleChanged.count(), 2);
3745- isIdleChanged.clear();
3746- QVERIFY(service.isIdle());
3747-
3748- // Make sure it continues to work when we add a second handler
3749- Handler2 handler2;
3750- service.addHandler(&handler2);
3751- service.handleMessage(message);
3752-
3753- QCOMPARE(messageHandled.count(), 1);
3754- reply = messageHandled.at(0).at(0).toMap();
3755- QCOMPARE(reply.value("greeting").toString(), QString("Hello Tom"));
3756- messageHandled.clear();
3757- QCOMPARE(isIdleChanged.count(), 2);
3758- isIdleChanged.clear();
3759- QVERIFY(service.isIdle());
3760-
3761- // Test a method from the second handler
3762- message.clear();
3763- message.insert("method", QString("listArguments"));
3764- message.insert("number", 1);
3765- message.insert("string", QString("Hello"));
3766- message.insert("boolean", false);
3767- service.handleMessage(message);
3768-
3769- QCOMPARE(messageHandled.count(), 1);
3770- reply = messageHandled.at(0).at(0).toMap();
3771- QVERIFY(reply.contains("arguments"));
3772- QStringList expectedArguments;
3773- expectedArguments << "number" << "string" << "boolean";
3774- QCOMPARE(reply.value("arguments").toStringList().toSet(),
3775- expectedArguments.toSet());
3776- messageHandled.clear();
3777- QCOMPARE(isIdleChanged.count(), 2);
3778- isIdleChanged.clear();
3779- QVERIFY(service.isIdle());
3780-}
3781-
3782-QTEST_MAIN(ServiceTest);
3783-
3784-#include "tst_service.moc"
3785
3786=== removed file 'tests/unit/messaging-host/tst_service.pro'
3787--- tests/unit/messaging-host/tst_service.pro 2014-05-21 08:18:12 +0000
3788+++ tests/unit/messaging-host/tst_service.pro 1970-01-01 00:00:00 +0000
3789@@ -1,18 +0,0 @@
3790-include(messaging-host.pri)
3791-
3792-TARGET = tst_service
3793-
3794-QT += \
3795- core \
3796- testlib
3797-
3798-SOURCES += \
3799- $${SRC_DIR}/service.cpp \
3800- tst_service.cpp
3801-
3802-HEADERS += \
3803- $${SRC_DIR}/service.h
3804-
3805-check.commands = "xvfb-run -s '-screen 0 640x480x24' -a ./$${TARGET}"
3806-check.depends = $${TARGET}
3807-QMAKE_EXTRA_TARGETS += check
3808
3809=== removed file 'tests/unit/messaging-host/tst_webapps-handler.cpp'
3810--- tests/unit/messaging-host/tst_webapps-handler.cpp 2014-06-23 07:32:13 +0000
3811+++ tests/unit/messaging-host/tst_webapps-handler.cpp 1970-01-01 00:00:00 +0000
3812@@ -1,354 +0,0 @@
3813-/*
3814- * Copyright (C) 2014 Canonical Ltd.
3815- *
3816- * This file is part of unity-chromium-extension
3817- *
3818- * This program is free software: you can redistribute it and/or modify it
3819- * under the terms of the GNU General Public License version 3, as published
3820- * by the Free Software Foundation.
3821- *
3822- * This program is distributed in the hope that it will be useful, but
3823- * WITHOUT ANY WARRANTY; without even the implied warranties of
3824- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3825- * PURPOSE. See the GNU General Public License for more details.
3826- *
3827- * You should have received a copy of the GNU General Public License along
3828- * with this program. If not, see <http://www.gnu.org/licenses/>.
3829- */
3830-
3831-extern "C" {
3832-#include <unity-webapps-permissions.h>
3833-#include <unity-webapps-application-repository.h>
3834-}
3835-
3836-#include "webapps-handler.h"
3837-
3838-#include <QDebug>
3839-#include <QSignalSpy>
3840-#include <QTest>
3841-
3842-
3843-// {{{ mock implementations
3844-struct AppInfo {
3845- bool install;
3846- bool allowed;
3847- bool dontask;
3848- UnityWebappsApplicationStatus status;
3849- QString name;
3850- QString domain;
3851-};
3852-
3853-QMap<QString, AppInfo> _mock_app_info;
3854-
3855-UnityWebappsApplicationRepository *unity_webapps_application_repository_new_default()
3856-{
3857- return (UnityWebappsApplicationRepository*)g_object_new(G_TYPE_OBJECT, 0);
3858-}
3859-
3860-gboolean unity_webapps_application_repository_prepare(UnityWebappsApplicationRepository *repository)
3861-{
3862- Q_UNUSED(repository);
3863-
3864- return true;
3865-}
3866-
3867-GList * unity_webapps_application_repository_resolve_url(UnityWebappsApplicationRepository *repository, const gchar *url)
3868-{
3869- Q_UNUSED(repository);
3870-
3871- if (!_mock_app_info.contains(QString::fromUtf8(url))) {
3872- return 0;
3873- }
3874-
3875- return g_list_append((GList*)0, (gpointer)g_strdup(url));
3876-}
3877-
3878-UnityWebappsApplicationStatus
3879-unity_webapps_application_repository_get_resolved_application_status(
3880- UnityWebappsApplicationRepository *repository,
3881- const gchar *application
3882-)
3883-{
3884- Q_UNUSED(repository);
3885-
3886- if (!_mock_app_info.contains(QString::fromUtf8(application))) {
3887- return UNITY_WEBAPPS_APPLICATION_STATUS_UNRESOLVED;
3888- }
3889-
3890- return _mock_app_info.value(QString::fromUtf8(application)).status;
3891-}
3892-
3893-const gchar *
3894-unity_webapps_application_repository_get_resolved_application_name(UnityWebappsApplicationRepository *repository,
3895- const gchar *application)
3896-{
3897- Q_UNUSED(repository);
3898-
3899- if (!_mock_app_info.contains(QString::fromUtf8(application))) {
3900- return 0;
3901- }
3902-
3903- return g_strdup(_mock_app_info.value(QString::fromUtf8(application)).name.toLocal8Bit().constData());
3904-}
3905-
3906-const gchar *
3907-unity_webapps_application_repository_get_resolved_application_domain(UnityWebappsApplicationRepository *repository,
3908- const gchar *application)
3909-{
3910- Q_UNUSED(repository);
3911-
3912- if (!_mock_app_info.contains(QString::fromUtf8(application))) {
3913- return 0;
3914- }
3915-
3916- return g_strdup(_mock_app_info.value(QString::fromUtf8(application)).domain.toLocal8Bit().constData());
3917-}
3918-
3919-
3920-gboolean unity_webapps_permissions_get_domain_allowed(const gchar *domain)
3921-{
3922- Q_FOREACH(const QString &key, _mock_app_info.keys()) {
3923- AppInfo appInfo = _mock_app_info.value(key);
3924- if (appInfo.domain == QLatin1String(domain)) {
3925- return appInfo.allowed;
3926- }
3927- }
3928-
3929- return false;
3930-}
3931-
3932-gboolean unity_webapps_permissions_get_domain_dontask(const gchar *domain)
3933-{
3934- Q_FOREACH(const QString &key, _mock_app_info.keys()) {
3935- AppInfo appInfo = _mock_app_info.value(key);
3936- if (appInfo.domain == QLatin1String(domain)) {
3937- return appInfo.dontask;
3938- }
3939- }
3940-
3941- return false;
3942-}
3943-
3944-void unity_webapps_permissions_dontask_domain(const gchar *domain)
3945-{
3946- Q_UNUSED(domain);
3947-}
3948-
3949-void
3950-unity_webapps_application_repository_install_application(UnityWebappsApplicationRepository *repository, const gchar *name,
3951- UnityWebappsApplicationRepositoryInstallCallback callback, gpointer user_data)
3952-{
3953- Q_UNUSED(repository);
3954- Q_UNUSED(name);
3955- Q_UNUSED(callback);
3956- Q_UNUSED(user_data);
3957-}
3958-
3959-// }}}
3960-
3961-
3962-class WebappsHandlerTest : public QObject
3963-{
3964- Q_OBJECT
3965-
3966-public:
3967- WebappsHandlerTest();
3968-
3969-private Q_SLOTS:
3970- void initTestCase();
3971- void cleanupTestCase();
3972- void testUrlLoadedMalformedRequest();
3973- void testUrlLoaded_data();
3974- void testUrlLoaded();
3975- void testDontAskMalformedRequest();
3976- void testDontAsk_data();
3977- void testDontAsk();
3978- void testInstallMalformedRequest();
3979- void testInstall_data();
3980- void testInstall();
3981- void testCreateApplicationDesktopName_data();
3982- void testCreateApplicationDesktopName();
3983-};
3984-
3985-WebappsHandlerTest::WebappsHandlerTest():
3986- QObject(0)
3987-{
3988-}
3989-
3990-
3991-void WebappsHandlerTest::initTestCase()
3992-{
3993- _mock_app_info.insert("https://mail.google.com/", { true, false, false, UNITY_WEBAPPS_APPLICATION_STATUS_AVAILABLE, "Gmail", "mail.google.com" });
3994- _mock_app_info.insert("http://www.tumblr.com/", { false, true, true, UNITY_WEBAPPS_APPLICATION_STATUS_AVAILABLE, "Tumblr", "www.tumblr.com" });
3995-}
3996-
3997-void WebappsHandlerTest::cleanupTestCase()
3998-{
3999-}
4000-
4001-void WebappsHandlerTest::testUrlLoadedMalformedRequest()
4002-{
4003- UnityWebapps::WebappsHandler handler;
4004-
4005- QVariantMap message;
4006- message.insert("method", QString("url_loaded"));
4007-
4008- QVariantMap reply = handler.url_loaded(message);
4009-
4010- QVERIFY(!reply.empty());
4011- QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
4012-}
4013-
4014-void WebappsHandlerTest::testUrlLoaded_data()
4015-{
4016- QTest::addColumn<QString>("url");
4017- QTest::addColumn<bool>("available");
4018- QTest::addColumn<QString>("appName");
4019- QTest::addColumn<QString>("appDomain");
4020-
4021- QTest::newRow("available") << "https://mail.google.com/" << true << "Gmail" << "mail.google.com";
4022- QTest::newRow("not_available") << "http://www.example.com/" << false << "None" << "None";
4023-}
4024-
4025-void WebappsHandlerTest::testUrlLoaded()
4026-{
4027- QFETCH(QString, url);
4028- QFETCH(bool, available);
4029- QFETCH(QString, appName);
4030- QFETCH(QString, appDomain);
4031-
4032- QVariantMap message;
4033- message.insert("method", QString("url_loaded"));
4034- message.insert("url", url);
4035-
4036- UnityWebapps::WebappsHandler handler;
4037- QVariantMap reply = handler.url_loaded(message);
4038-
4039- QVERIFY(!reply.empty());
4040- QCOMPARE(reply.value("available").toBool(), available);
4041- if (available) {
4042- QCOMPARE(appName, reply.value("appName").toString());
4043- QCOMPARE(appDomain, reply.value("appDomain").toString());
4044- }
4045-}
4046-
4047-void WebappsHandlerTest::testDontAskMalformedRequest()
4048-{
4049- UnityWebapps::WebappsHandler handler;
4050-
4051- QVariantMap message;
4052- message.insert("method", QString("dont_ask"));
4053-
4054- QVariantMap reply = handler.url_loaded(message);
4055-
4056- QVERIFY(!reply.empty());
4057- QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
4058-}
4059-
4060-void WebappsHandlerTest::testDontAsk_data()
4061-{
4062- QTest::addColumn<QString>("url");
4063- QTest::addColumn<bool>("available");
4064-
4065- QTest::newRow("ask") << "https://mail.google.com/" << true;
4066- QTest::newRow("dont_ask") << "http://www.tumblr.com/" << true;
4067- QTest::newRow("no app") << "http://www.example.com/" << false;
4068-}
4069-
4070-void WebappsHandlerTest::testDontAsk()
4071-{
4072- QFETCH(QString, url);
4073- QFETCH(bool, available);
4074-
4075- UnityWebapps::WebappsHandler handler;
4076-
4077- QVariantMap message;
4078- message.insert("method", QString("dont_ask"));
4079- message.insert("url", url);
4080-
4081- QVariantMap reply = handler.dont_ask(message);
4082-
4083- QVERIFY(!reply.empty());
4084- if (available) {
4085- QCOMPARE(reply.value("dont_ask").toBool(), true);
4086- } else {
4087- QCOMPARE(reply.value("dont_ask").toBool(), false);
4088- QCOMPARE(reply.value("available").toBool(), false);
4089- }
4090-}
4091-
4092-void WebappsHandlerTest::testInstallMalformedRequest()
4093-{
4094- UnityWebapps::WebappsHandler handler;
4095-
4096- QVariantMap message;
4097- message.insert("method", QString("install"));
4098-
4099- QVariantMap reply = handler.url_loaded(message);
4100-
4101- QVERIFY(!reply.empty());
4102- QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
4103-}
4104-
4105-void WebappsHandlerTest::testInstall_data()
4106-{
4107- QTest::addColumn<QString>("url");
4108- QTest::addColumn<bool>("available");
4109- QTest::addColumn<bool>("installed");
4110-
4111- QTest::newRow("installs") << "https://mail.google.com/" << true << true;
4112- QTest::newRow("wont install") << "http://www.tumblr.com/" << true << false;
4113- QTest::newRow("no app") << "http://www.example.com/" << false << false;
4114-}
4115-
4116-void WebappsHandlerTest::testInstall()
4117-{
4118- QFETCH(QString, url);
4119- QFETCH(bool, available);
4120- QFETCH(bool, installed);
4121-
4122- QVariantMap message;
4123- message.insert("method", QString("install"));
4124- message.insert("url", url);
4125-
4126- UnityWebapps::WebappsHandler handler;
4127- QVariantMap reply = handler.install(message);
4128-
4129- QVERIFY(!reply.empty());
4130- QCOMPARE(reply.value("installed").toBool(), installed);
4131- if (!available) {
4132- QCOMPARE(reply.value("available").toBool(), false);
4133- }
4134-}
4135-
4136-void WebappsHandlerTest::testCreateApplicationDesktopName_data()
4137-{
4138- QTest::addColumn<QString>("appName");
4139- QTest::addColumn<QString>("appDomain");
4140- QTest::addColumn<QString>("expected_uri");
4141-
4142- // Behaviour
4143- QTest::newRow("strip whitespace") << "White Space Name" << "example.com" << "application://WhiteSpaceNameexamplecom.desktop";
4144- QTest::newRow("strip special chars") << "%$special%^" << "example.com" << "application://specialexamplecom.desktop";
4145- QTest::newRow("numbers allowed") << "13monkeys" << "example.com" << "application://13monkeysexamplecom.desktop";
4146- QTest::newRow("combined") << "##12combined test$%67" << "example.com" << "application://12combinedtest67examplecom.desktop";
4147-
4148- // Examples
4149- QTest::newRow("live example 1") << "FacebookMessanger" << "facebook.com" << "application://FacebookMessangerfacebookcom.desktop";
4150- QTest::newRow("live example 2") << "Gmail" << "mail.google.com" << "application://Gmailmailgooglecom.desktop";
4151- QTest::newRow("live example 3") << "GooglePlus" << "plus.google.com" << "application://GooglePlusplusgooglecom.desktop";
4152-}
4153-
4154-void WebappsHandlerTest::testCreateApplicationDesktopName()
4155-{
4156- QFETCH(QString, appName);
4157- QFETCH(QString, appDomain);
4158- QFETCH(QString, expected_uri);
4159-
4160- UnityWebapps::WebappsHandler handler;
4161- QCOMPARE(handler.createApplicationDesktopName(appName, appDomain), expected_uri);
4162-}
4163-
4164-QTEST_MAIN(WebappsHandlerTest);
4165-
4166-#include "tst_webapps-handler.moc"
4167
4168=== removed file 'tests/unit/messaging-host/tst_webapps-handler.pro'
4169--- tests/unit/messaging-host/tst_webapps-handler.pro 2014-06-23 07:32:13 +0000
4170+++ tests/unit/messaging-host/tst_webapps-handler.pro 1970-01-01 00:00:00 +0000
4171@@ -1,32 +0,0 @@
4172-include(messaging-host.pri)
4173-
4174-TARGET = tst_webapps-handler
4175-
4176-QMAKE_CXXFLAGS += -std=c++11
4177-
4178-CONFIG += \
4179- link_pkgconfig \
4180- qt
4181-
4182-QT += \
4183- core \
4184- testlib
4185-
4186-PKGCONFIG += \
4187- glib-2.0 \
4188- gobject-2.0 \
4189- libunity_webapps-0.2 \
4190- libunity-webapps-repository \
4191-
4192-DEFINES += UCX_UNDER_TEST
4193-
4194-SOURCES += \
4195- $${SRC_DIR}/webapps-handler.cpp \
4196- tst_webapps-handler.cpp
4197-
4198-HEADERS += \
4199- $${SRC_DIR}/webapps-handler.h
4200-
4201-check.commands = "xvfb-run -s '-screen 0 640x480x24' -a ./$${TARGET}"
4202-check.depends = $${TARGET}
4203-QMAKE_EXTRA_TARGETS += check
4204
4205=== added directory 'tests/unit/messaging-host/webapps-handler'
4206=== added file 'tests/unit/messaging-host/webapps-handler/CMakeLists.txt'
4207--- tests/unit/messaging-host/webapps-handler/CMakeLists.txt 1970-01-01 00:00:00 +0000
4208+++ tests/unit/messaging-host/webapps-handler/CMakeLists.txt 2015-10-07 04:25:10 +0000
4209@@ -0,0 +1,47 @@
4210+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
4211+set(CMAKE_INCLUDE_CURRENT_DIR ON)
4212+set(CMAKE_AUTOMOC ON)
4213+
4214+find_package(PkgConfig)
4215+find_package(Qt5Core REQUIRED)
4216+find_package(Qt5Test REQUIRED)
4217+
4218+pkg_check_modules(GLIB glib-2.0 REQUIRED)
4219+pkg_check_modules(GOBJECT gobject-2.0 REQUIRED)
4220+pkg_check_modules(WEBAPPS libunity_webapps-0.2)
4221+pkg_check_modules(WEBAPPS_REPO libunity-webapps-repository)
4222+
4223+set(TEST tst_WebappsHandler)
4224+set(SOURCES
4225+ ${messaging-host_SOURCE_DIR}/webapps-handler.cpp
4226+ tst_webapps-handler.cpp
4227+)
4228+
4229+
4230+include_directories(
4231+ ${messaging-host_SOURCE_DIR}
4232+ ${GLIB_INCLUDE_DIRS}
4233+ ${WEBAPPS_INCLUDE_DIRS}
4234+ ${WEBAPPS_REPO_INCLUDE_DIRS}
4235+)
4236+
4237+if(DEFINED WEBAPPS_FOUND AND WEBAPPS_FOUND EQUAL 1)
4238+ if(DEFINED WEBAPPS_REPO_FOUND AND WEBAPPS_REPO_FOUND EQUAL 1)
4239+ add_definitions(
4240+ -DHAVE_UNITY_WEBAPPS=1
4241+ -DUCX_UNDER_TEST=1
4242+ )
4243+ add_executable(${TEST} ${SOURCES})
4244+ target_link_libraries(
4245+ ${TEST}
4246+
4247+ Qt5::Core
4248+ Qt5::Test
4249+ ${GLIB_LIBRARIES}
4250+ ${GOBJECT_LIBRARIES}
4251+ ${WEBAPPS_LIBRARIES}
4252+ ${WEBAPPS_REPO_LIBRARIES}
4253+ )
4254+ add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
4255+ endif()
4256+endif()
4257
4258=== added file 'tests/unit/messaging-host/webapps-handler/tst_webapps-handler.cpp'
4259--- tests/unit/messaging-host/webapps-handler/tst_webapps-handler.cpp 1970-01-01 00:00:00 +0000
4260+++ tests/unit/messaging-host/webapps-handler/tst_webapps-handler.cpp 2015-10-07 04:25:10 +0000
4261@@ -0,0 +1,354 @@
4262+/*
4263+ * Copyright (C) 2014 Canonical Ltd.
4264+ *
4265+ * This file is part of unity-chromium-extension
4266+ *
4267+ * This program is free software: you can redistribute it and/or modify it
4268+ * under the terms of the GNU General Public License version 3, as published
4269+ * by the Free Software Foundation.
4270+ *
4271+ * This program is distributed in the hope that it will be useful, but
4272+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4273+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4274+ * PURPOSE. See the GNU General Public License for more details.
4275+ *
4276+ * You should have received a copy of the GNU General Public License along
4277+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4278+ */
4279+
4280+extern "C" {
4281+#include <unity-webapps-permissions.h>
4282+#include <unity-webapps-application-repository.h>
4283+}
4284+
4285+#include "webapps-handler.h"
4286+
4287+#include <QDebug>
4288+#include <QSignalSpy>
4289+#include <QTest>
4290+
4291+
4292+// {{{ mock implementations
4293+struct AppInfo {
4294+ bool install;
4295+ bool allowed;
4296+ bool dontask;
4297+ UnityWebappsApplicationStatus status;
4298+ QString name;
4299+ QString domain;
4300+};
4301+
4302+QMap<QString, AppInfo> _mock_app_info;
4303+
4304+UnityWebappsApplicationRepository *unity_webapps_application_repository_new_default()
4305+{
4306+ return (UnityWebappsApplicationRepository*)g_object_new(G_TYPE_OBJECT, 0);
4307+}
4308+
4309+gboolean unity_webapps_application_repository_prepare(UnityWebappsApplicationRepository *repository)
4310+{
4311+ Q_UNUSED(repository);
4312+
4313+ return true;
4314+}
4315+
4316+GList * unity_webapps_application_repository_resolve_url(UnityWebappsApplicationRepository *repository, const gchar *url)
4317+{
4318+ Q_UNUSED(repository);
4319+
4320+ if (!_mock_app_info.contains(QString::fromUtf8(url))) {
4321+ return 0;
4322+ }
4323+
4324+ return g_list_append((GList*)0, (gpointer)g_strdup(url));
4325+}
4326+
4327+UnityWebappsApplicationStatus
4328+unity_webapps_application_repository_get_resolved_application_status(
4329+ UnityWebappsApplicationRepository *repository,
4330+ const gchar *application
4331+)
4332+{
4333+ Q_UNUSED(repository);
4334+
4335+ if (!_mock_app_info.contains(QString::fromUtf8(application))) {
4336+ return UNITY_WEBAPPS_APPLICATION_STATUS_UNRESOLVED;
4337+ }
4338+
4339+ return _mock_app_info.value(QString::fromUtf8(application)).status;
4340+}
4341+
4342+const gchar *
4343+unity_webapps_application_repository_get_resolved_application_name(UnityWebappsApplicationRepository *repository,
4344+ const gchar *application)
4345+{
4346+ Q_UNUSED(repository);
4347+
4348+ if (!_mock_app_info.contains(QString::fromUtf8(application))) {
4349+ return 0;
4350+ }
4351+
4352+ return g_strdup(_mock_app_info.value(QString::fromUtf8(application)).name.toLocal8Bit().constData());
4353+}
4354+
4355+const gchar *
4356+unity_webapps_application_repository_get_resolved_application_domain(UnityWebappsApplicationRepository *repository,
4357+ const gchar *application)
4358+{
4359+ Q_UNUSED(repository);
4360+
4361+ if (!_mock_app_info.contains(QString::fromUtf8(application))) {
4362+ return 0;
4363+ }
4364+
4365+ return g_strdup(_mock_app_info.value(QString::fromUtf8(application)).domain.toLocal8Bit().constData());
4366+}
4367+
4368+
4369+gboolean unity_webapps_permissions_get_domain_allowed(const gchar *domain)
4370+{
4371+ Q_FOREACH(const QString &key, _mock_app_info.keys()) {
4372+ AppInfo appInfo = _mock_app_info.value(key);
4373+ if (appInfo.domain == QLatin1String(domain)) {
4374+ return appInfo.allowed;
4375+ }
4376+ }
4377+
4378+ return false;
4379+}
4380+
4381+gboolean unity_webapps_permissions_get_domain_dontask(const gchar *domain)
4382+{
4383+ Q_FOREACH(const QString &key, _mock_app_info.keys()) {
4384+ AppInfo appInfo = _mock_app_info.value(key);
4385+ if (appInfo.domain == QLatin1String(domain)) {
4386+ return appInfo.dontask;
4387+ }
4388+ }
4389+
4390+ return false;
4391+}
4392+
4393+void unity_webapps_permissions_dontask_domain(const gchar *domain)
4394+{
4395+ Q_UNUSED(domain);
4396+}
4397+
4398+void
4399+unity_webapps_application_repository_install_application(UnityWebappsApplicationRepository *repository, const gchar *name,
4400+ UnityWebappsApplicationRepositoryInstallCallback callback, gpointer user_data)
4401+{
4402+ Q_UNUSED(repository);
4403+ Q_UNUSED(name);
4404+ Q_UNUSED(callback);
4405+ Q_UNUSED(user_data);
4406+}
4407+
4408+// }}}
4409+
4410+
4411+class WebappsHandlerTest : public QObject
4412+{
4413+ Q_OBJECT
4414+
4415+public:
4416+ WebappsHandlerTest();
4417+
4418+private Q_SLOTS:
4419+ void initTestCase();
4420+ void cleanupTestCase();
4421+ void testUrlLoadedMalformedRequest();
4422+ void testUrlLoaded_data();
4423+ void testUrlLoaded();
4424+ void testDontAskMalformedRequest();
4425+ void testDontAsk_data();
4426+ void testDontAsk();
4427+ void testInstallMalformedRequest();
4428+ void testInstall_data();
4429+ void testInstall();
4430+ void testCreateApplicationDesktopName_data();
4431+ void testCreateApplicationDesktopName();
4432+};
4433+
4434+WebappsHandlerTest::WebappsHandlerTest():
4435+ QObject(0)
4436+{
4437+}
4438+
4439+
4440+void WebappsHandlerTest::initTestCase()
4441+{
4442+ _mock_app_info.insert("https://mail.google.com/", { true, false, false, UNITY_WEBAPPS_APPLICATION_STATUS_AVAILABLE, "Gmail", "mail.google.com" });
4443+ _mock_app_info.insert("http://www.tumblr.com/", { false, true, true, UNITY_WEBAPPS_APPLICATION_STATUS_AVAILABLE, "Tumblr", "www.tumblr.com" });
4444+}
4445+
4446+void WebappsHandlerTest::cleanupTestCase()
4447+{
4448+}
4449+
4450+void WebappsHandlerTest::testUrlLoadedMalformedRequest()
4451+{
4452+ UnityWebapps::WebappsHandler handler;
4453+
4454+ QVariantMap message;
4455+ message.insert("method", QString("url_loaded"));
4456+
4457+ QVariantMap reply = handler.url_loaded(message);
4458+
4459+ QVERIFY(!reply.empty());
4460+ QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
4461+}
4462+
4463+void WebappsHandlerTest::testUrlLoaded_data()
4464+{
4465+ QTest::addColumn<QString>("url");
4466+ QTest::addColumn<bool>("available");
4467+ QTest::addColumn<QString>("appName");
4468+ QTest::addColumn<QString>("appDomain");
4469+
4470+ QTest::newRow("available") << "https://mail.google.com/" << true << "Gmail" << "mail.google.com";
4471+ QTest::newRow("not_available") << "http://www.example.com/" << false << "None" << "None";
4472+}
4473+
4474+void WebappsHandlerTest::testUrlLoaded()
4475+{
4476+ QFETCH(QString, url);
4477+ QFETCH(bool, available);
4478+ QFETCH(QString, appName);
4479+ QFETCH(QString, appDomain);
4480+
4481+ QVariantMap message;
4482+ message.insert("method", QString("url_loaded"));
4483+ message.insert("url", url);
4484+
4485+ UnityWebapps::WebappsHandler handler;
4486+ QVariantMap reply = handler.url_loaded(message);
4487+
4488+ QVERIFY(!reply.empty());
4489+ QCOMPARE(reply.value("available").toBool(), available);
4490+ if (available) {
4491+ QCOMPARE(appName, reply.value("appName").toString());
4492+ QCOMPARE(appDomain, reply.value("appDomain").toString());
4493+ }
4494+}
4495+
4496+void WebappsHandlerTest::testDontAskMalformedRequest()
4497+{
4498+ UnityWebapps::WebappsHandler handler;
4499+
4500+ QVariantMap message;
4501+ message.insert("method", QString("dont_ask"));
4502+
4503+ QVariantMap reply = handler.url_loaded(message);
4504+
4505+ QVERIFY(!reply.empty());
4506+ QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
4507+}
4508+
4509+void WebappsHandlerTest::testDontAsk_data()
4510+{
4511+ QTest::addColumn<QString>("url");
4512+ QTest::addColumn<bool>("available");
4513+
4514+ QTest::newRow("ask") << "https://mail.google.com/" << true;
4515+ QTest::newRow("dont_ask") << "http://www.tumblr.com/" << true;
4516+ QTest::newRow("no app") << "http://www.example.com/" << false;
4517+}
4518+
4519+void WebappsHandlerTest::testDontAsk()
4520+{
4521+ QFETCH(QString, url);
4522+ QFETCH(bool, available);
4523+
4524+ UnityWebapps::WebappsHandler handler;
4525+
4526+ QVariantMap message;
4527+ message.insert("method", QString("dont_ask"));
4528+ message.insert("url", url);
4529+
4530+ QVariantMap reply = handler.dont_ask(message);
4531+
4532+ QVERIFY(!reply.empty());
4533+ if (available) {
4534+ QCOMPARE(reply.value("dont_ask").toBool(), true);
4535+ } else {
4536+ QCOMPARE(reply.value("dont_ask").toBool(), false);
4537+ QCOMPARE(reply.value("available").toBool(), false);
4538+ }
4539+}
4540+
4541+void WebappsHandlerTest::testInstallMalformedRequest()
4542+{
4543+ UnityWebapps::WebappsHandler handler;
4544+
4545+ QVariantMap message;
4546+ message.insert("method", QString("install"));
4547+
4548+ QVariantMap reply = handler.url_loaded(message);
4549+
4550+ QVERIFY(!reply.empty());
4551+ QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
4552+}
4553+
4554+void WebappsHandlerTest::testInstall_data()
4555+{
4556+ QTest::addColumn<QString>("url");
4557+ QTest::addColumn<bool>("available");
4558+ QTest::addColumn<bool>("installed");
4559+
4560+ QTest::newRow("installs") << "https://mail.google.com/" << true << true;
4561+ QTest::newRow("wont install") << "http://www.tumblr.com/" << true << false;
4562+ QTest::newRow("no app") << "http://www.example.com/" << false << false;
4563+}
4564+
4565+void WebappsHandlerTest::testInstall()
4566+{
4567+ QFETCH(QString, url);
4568+ QFETCH(bool, available);
4569+ QFETCH(bool, installed);
4570+
4571+ QVariantMap message;
4572+ message.insert("method", QString("install"));
4573+ message.insert("url", url);
4574+
4575+ UnityWebapps::WebappsHandler handler;
4576+ QVariantMap reply = handler.install(message);
4577+
4578+ QVERIFY(!reply.empty());
4579+ QCOMPARE(reply.value("installed").toBool(), installed);
4580+ if (!available) {
4581+ QCOMPARE(reply.value("available").toBool(), false);
4582+ }
4583+}
4584+
4585+void WebappsHandlerTest::testCreateApplicationDesktopName_data()
4586+{
4587+ QTest::addColumn<QString>("appName");
4588+ QTest::addColumn<QString>("appDomain");
4589+ QTest::addColumn<QString>("expected_uri");
4590+
4591+ // Behaviour
4592+ QTest::newRow("strip whitespace") << "White Space Name" << "example.com" << "application://WhiteSpaceNameexamplecom.desktop";
4593+ QTest::newRow("strip special chars") << "%$special%^" << "example.com" << "application://specialexamplecom.desktop";
4594+ QTest::newRow("numbers allowed") << "13monkeys" << "example.com" << "application://13monkeysexamplecom.desktop";
4595+ QTest::newRow("combined") << "##12combined test$%67" << "example.com" << "application://12combinedtest67examplecom.desktop";
4596+
4597+ // Examples
4598+ QTest::newRow("live example 1") << "FacebookMessanger" << "facebook.com" << "application://FacebookMessangerfacebookcom.desktop";
4599+ QTest::newRow("live example 2") << "Gmail" << "mail.google.com" << "application://Gmailmailgooglecom.desktop";
4600+ QTest::newRow("live example 3") << "GooglePlus" << "plus.google.com" << "application://GooglePlusplusgooglecom.desktop";
4601+}
4602+
4603+void WebappsHandlerTest::testCreateApplicationDesktopName()
4604+{
4605+ QFETCH(QString, appName);
4606+ QFETCH(QString, appDomain);
4607+ QFETCH(QString, expected_uri);
4608+
4609+ UnityWebapps::WebappsHandler handler;
4610+ QCOMPARE(handler.createApplicationDesktopName(appName, appDomain), expected_uri);
4611+}
4612+
4613+QTEST_MAIN(WebappsHandlerTest);
4614+
4615+#include "tst_webapps-handler.moc"
4616
4617=== removed file 'tests/unit/unit.pro'
4618--- tests/unit/unit.pro 2014-05-20 12:21:50 +0000
4619+++ tests/unit/unit.pro 1970-01-01 00:00:00 +0000
4620@@ -1,3 +0,0 @@
4621-TEMPLATE = subdirs
4622-SUBDIRS = \
4623- messaging-host
4624
4625=== removed file 'unity-chromium-extension.pro'
4626--- unity-chromium-extension.pro 2014-05-19 14:04:19 +0000
4627+++ unity-chromium-extension.pro 1970-01-01 00:00:00 +0000
4628@@ -1,14 +0,0 @@
4629-include(common-project-config.pri)
4630-include(common-vars.pri)
4631-
4632-TEMPLATE = subdirs
4633-SUBDIRS = \
4634- chromium-extension \
4635- messaging-host \
4636- tests
4637-
4638-tests.depends = messaging-host
4639-
4640-DISTNAME = $${PROJECT_NAME}-$${PROJECT_VERSION}
4641-dist.commands = "bzr export $${DISTNAME}.tar.bz2"
4642-QMAKE_EXTRA_TARGETS += dist

Subscribers

People subscribed via source and target branches

to all changes: