Merge lp:~larryprice/libertine-scope/preview-2 into lp:~larryprice/libertine-scope/libertine-store-search
- preview-2
- Merge into libertine-store-search
Status: | Merged |
---|---|
Approved by: | Larry Price |
Approved revision: | 105 |
Merged at revision: | 101 |
Proposed branch: | lp:~larryprice/libertine-scope/preview-2 |
Merge into: | lp:~larryprice/libertine-scope/libertine-store-search |
Diff against target: |
1298 lines (+909/-82) 18 files modified
scope/store/i18n.h (+0/-1) scope/store/package.cpp (+52/-0) scope/store/package.h (+57/-0) scope/store/preview.cpp (+220/-0) scope/store/preview.h (+74/-0) scope/store/query.cpp (+13/-37) scope/store/query.h (+3/-1) scope/store/scope.cpp (+5/-3) scope/store/service_manager.cpp (+18/-6) scope/store/service_manager.h (+7/-3) service/libertine_service/apt.py (+37/-4) service/libertine_service/dbus.py (+10/-5) tests/scope/apps/test_preview.cpp (+0/-1) tests/scope/store/CMakeLists.txt (+3/-0) tests/scope/store/mock_service_manager.h (+46/-0) tests/scope/store/test_package.cpp (+107/-0) tests/scope/store/test_preview.cpp (+196/-0) tests/scope/store/test_query.cpp (+61/-21) |
To merge this branch: | bzr merge lp:~larryprice/libertine-scope/preview-2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brandon Schaefer (community) | Approve | ||
Christopher Townsend (community) | Approve | ||
Libertine CI Bot (community) | continuous-integration | Approve | |
Review via email: mp+302839@code.launchpad.net |
This proposal supersedes a proposal from 2016-07-26.
Commit message
Preview for the libertine store and initial AppStream integration into the service.
Description of the change
Preview for the libertine store and initial AppStream integration into the service.
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal | # |
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:91
https:/
Executed test runs:
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:92
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:94
https:/
Executed test runs:
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 95. By Larry Price
-
Removing appstream code so i can do it in a separate branch
- 96. By Larry Price
-
Fix compile issue
- 97. By Larry Price
-
merge
- 98. By Larry Price
-
purging ratings - not feasible for this draft
- 99. By Larry Price
-
merge
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:94
https:/
Executed test runs:
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Libertine CI Bot (libertine-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:94
https:/
Executed test runs:
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 100. By Larry Price
-
Merge
Libertine CI Bot (libertine-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:94
https:/
Executed test runs:
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:100
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 101. By Larry Price
-
Proper directory name
- 102. By Larry Price
-
merge
- 103. By Larry Price
-
forget about fun, work, and pink
- 104. By Larry Price
-
merge
- 105. By Larry Price
-
Merge with parent
Christopher Townsend (townsend) wrote : | # |
Ok, this is good with me. I'm going to get an extra set of eyes on the code though.
Brandon Schaefer (brandontschaefer) wrote : | # |
lgtm
Christopher Townsend (townsend) wrote : | # |
Ok, I think we can merge this into the base MP.
Preview Diff
1 | === modified file 'scope/store/i18n.h' |
2 | --- scope/store/i18n.h 2016-09-01 17:12:55 +0000 |
3 | +++ scope/store/i18n.h 2016-09-15 17:01:59 +0000 |
4 | @@ -60,4 +60,3 @@ |
5 | } |
6 | |
7 | #endif /* LIBERTINE_STORE_I18N_H_ */ |
8 | - |
9 | |
10 | === added file 'scope/store/package.cpp' |
11 | --- scope/store/package.cpp 1970-01-01 00:00:00 +0000 |
12 | +++ scope/store/package.cpp 2016-09-15 17:01:59 +0000 |
13 | @@ -0,0 +1,52 @@ |
14 | +/* |
15 | + * Copyright 2016 Canonical Ltd. |
16 | + * |
17 | + * This program is free software: you can redistribute it and/or modify it under |
18 | + * the terms of the GNU General Public License, version 3, as published by the |
19 | + * Free Software Foundation. |
20 | + * |
21 | + * This program is distributed in the hope that it will be useful, |
22 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
23 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
24 | + * GNU General Public License for more details. |
25 | + * |
26 | + * You should have received a copy of the GNU General Public License |
27 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
28 | + */ |
29 | +#include "scope/store/package.h" |
30 | + |
31 | + |
32 | +Libertine::Store::Package Libertine::Store::Package:: |
33 | +from_map(QVariantMap const& pkgMap) |
34 | +{ |
35 | + Package pkg; |
36 | + pkg.name = pkgMap["name"].toString().toStdString(); |
37 | + pkg.summary = pkgMap["summary"].toString().toStdString(); |
38 | + pkg.description = pkgMap["description"].toString().toStdString(); |
39 | + pkg.icon = pkgMap["icon"].toString().toStdString(); |
40 | + pkg.publisher = pkgMap["publisher"].toString().toStdString(); |
41 | + pkg.website = pkgMap["website"].toString().toStdString(); |
42 | + pkg.license = pkgMap["license"].toString().toStdString(); |
43 | + pkg.id = pkgMap["id"].toString().toStdString(); |
44 | + |
45 | + for (auto const& screenshot: pkgMap["screenshots"].toStringList()) |
46 | + { |
47 | + pkg.screenshots.push_back(screenshot.toStdString()); |
48 | + } |
49 | + |
50 | + return pkg; |
51 | +} |
52 | + |
53 | + |
54 | +QList<Libertine::Store::Package> Libertine::Store::Package:: |
55 | +from_map(QList<QVariantMap> const& pkgMap) |
56 | +{ |
57 | + QList<Package> pkgs; |
58 | + |
59 | + for (auto const& pkg: pkgMap) |
60 | + { |
61 | + pkgs << Package::from_map(pkg); |
62 | + } |
63 | + |
64 | + return pkgs; |
65 | +} |
66 | |
67 | === added file 'scope/store/package.h' |
68 | --- scope/store/package.h 1970-01-01 00:00:00 +0000 |
69 | +++ scope/store/package.h 2016-09-15 17:01:59 +0000 |
70 | @@ -0,0 +1,57 @@ |
71 | +/* |
72 | + * Copyright 2016 Canonical Ltd. |
73 | + * |
74 | + * This program is free software: you can redistribute it and/or modify it under |
75 | + * the terms of the GNU General Public License, version 3, as published by the |
76 | + * Free Software Foundation. |
77 | + * |
78 | + * This program is distributed in the hope that it will be useful, |
79 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
80 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
81 | + * GNU General Public License for more details. |
82 | + * |
83 | + * You should have received a copy of the GNU General Public License |
84 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
85 | + */ |
86 | +#ifndef LIBERTINE_STORE_PACKAGE_H_ |
87 | +#define LIBERTINE_STORE_PACKAGE_H_ |
88 | + |
89 | + |
90 | +#include <QList> |
91 | +#include <QVariant> |
92 | + |
93 | + |
94 | +namespace Libertine |
95 | +{ |
96 | +namespace Store |
97 | +{ |
98 | + |
99 | + |
100 | +class Package |
101 | +{ |
102 | +public: |
103 | + explicit Package() = default; |
104 | + virtual ~Package() = default; |
105 | + |
106 | + static Package from_map(QVariantMap const&); |
107 | + static QList<Package> from_map(QList<QVariantMap> const&); |
108 | + |
109 | + |
110 | + std::string id; |
111 | + std::string name; |
112 | + std::string summary; |
113 | + |
114 | + std::string description; |
115 | + std::string icon; |
116 | + std::string publisher; |
117 | + std::string website; |
118 | + std::string license; |
119 | + |
120 | + std::vector<std::string> screenshots; |
121 | +}; |
122 | + |
123 | + |
124 | +} // Store |
125 | +} // Libertine |
126 | + |
127 | +#endif // LIBERTINE_STORE_PACKAGE_H_ |
128 | |
129 | === added file 'scope/store/preview.cpp' |
130 | --- scope/store/preview.cpp 1970-01-01 00:00:00 +0000 |
131 | +++ scope/store/preview.cpp 2016-09-15 17:01:59 +0000 |
132 | @@ -0,0 +1,220 @@ |
133 | +/* |
134 | + * Copyright 2016 Canonical Ltd. |
135 | + * |
136 | + * This program is free software: you can redistribute it and/or modify it under |
137 | + * the terms of the GNU General Public License, version 3, as published by the |
138 | + * Free Software Foundation. |
139 | + * |
140 | + * This program is distributed in the hope that it will be useful, |
141 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
142 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
143 | + * GNU General Public License for more details. |
144 | + * |
145 | + * You should have received a copy of the GNU General Public License |
146 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
147 | + */ |
148 | +#include "scope/store/preview.h" |
149 | + |
150 | + |
151 | +#include "scope/store/i18n.h" |
152 | +#include "scope/store/service_manager.h" |
153 | +#include <unity/UnityExceptions.h> |
154 | +#include <unity/scopes/ColumnLayout.h> |
155 | +#include <unity/scopes/PreviewReply.h> |
156 | +#include <unity/scopes/Variant.h> |
157 | +#include <unity/scopes/VariantBuilder.h> |
158 | +#include <unity/scopes/ActionMetadata.h> |
159 | +#include <unity/scopes/Result.h> |
160 | +#include <QDebug> |
161 | + |
162 | + |
163 | +namespace usc = unity::scopes; |
164 | + |
165 | + |
166 | +namespace |
167 | +{ |
168 | +static auto constexpr HEADER_ID = "hdr"; |
169 | +static auto constexpr ACTIONS_ID = "buttons"; |
170 | +static auto constexpr METADATA_ID = "other_metadata"; |
171 | +static auto constexpr SUMMARY_ID = "summary"; |
172 | +static auto constexpr SCREENSHOTS_ID = "screenshots"; |
173 | +static auto const SUMMARY_TITLE = _("Info"); |
174 | +static auto const ACTION_INSTALL = _("Install"); |
175 | +static auto const METADATA_PUBLISHER = _("Publisher/Creator"); |
176 | +static auto const METADATA_WEBSITE = _("Website"); |
177 | +static auto const METADATA_LICENSE = _("License"); |
178 | + |
179 | + |
180 | +static usc::PreviewWidgetList |
181 | +headerWidgets(Libertine::Store::Package const& app) |
182 | +{ |
183 | + usc::PreviewWidget header(HEADER_ID, "header"); |
184 | + header.add_attribute_value("title", usc::Variant(app.name)); |
185 | + header.add_attribute_value("subtitle", usc::Variant(app.summary)); |
186 | + header.add_attribute_value("mascot", usc::Variant(app.icon)); |
187 | + header.add_attribute_value("fallback", usc::Variant("image://theme/placeholder-app-icon")); |
188 | + |
189 | + usc::PreviewWidgetList widgets; |
190 | + widgets.push_back(header); |
191 | + |
192 | + qDebug() << "Pushed widgets for package:" << QString::fromStdString(app.name); |
193 | + return widgets; |
194 | +} |
195 | + |
196 | + |
197 | +static usc::PreviewWidget |
198 | +metadataWidgets(Libertine::Store::Package const& app) |
199 | +{ |
200 | + usc::PreviewWidget widget(METADATA_ID, "table"); |
201 | + usc::VariantArray values; |
202 | + if (!app.publisher.empty()) |
203 | + { |
204 | + values.push_back(usc::Variant{usc::VariantArray{usc::Variant{METADATA_PUBLISHER}, usc::Variant{app.publisher}}}); |
205 | + } |
206 | + if (!app.website.empty()) |
207 | + { |
208 | + values.push_back(usc::Variant{usc::VariantArray{usc::Variant{METADATA_WEBSITE}, usc::Variant{app.website}}}); |
209 | + } |
210 | + if (!app.license.empty()) |
211 | + { |
212 | + values.push_back(usc::Variant{usc::VariantArray{usc::Variant{METADATA_LICENSE}, usc::Variant{app.license}}}); |
213 | + } |
214 | + |
215 | + widget.add_attribute_value("values", usc::Variant(values)); |
216 | + return widget; |
217 | +} |
218 | + |
219 | + |
220 | +static usc::PreviewWidget |
221 | +buttonWidgets(Libertine::Store::Package const&) |
222 | +{ |
223 | + usc::PreviewWidget buttons(ACTIONS_ID, "actions"); |
224 | + usc::VariantBuilder builder; |
225 | + builder.add_tuple( |
226 | + { |
227 | + {"id", usc::Variant("install_xapp")}, |
228 | + {"label", usc::Variant(ACTION_INSTALL)}, |
229 | + }); |
230 | + buttons.add_attribute_value("actions", builder.end()); |
231 | + return buttons; |
232 | +} |
233 | + |
234 | + |
235 | +static usc::PreviewWidget |
236 | +descriptionWidgets(Libertine::Store::Package const& app) |
237 | +{ |
238 | + usc::PreviewWidget summary(SUMMARY_ID, "text"); |
239 | + summary.add_attribute_value("title", usc::Variant(SUMMARY_TITLE)); |
240 | + summary.add_attribute_value("text", usc::Variant(app.description)); |
241 | + return summary; |
242 | +} |
243 | + |
244 | + |
245 | +static usc::PreviewWidget |
246 | +screenshotWidgets(Libertine::Store::Package const& app) |
247 | +{ |
248 | + usc::PreviewWidget gallery(SCREENSHOTS_ID, "gallery"); |
249 | + usc::VariantArray arr; |
250 | + for (auto const& screenshot: app.screenshots) |
251 | + { |
252 | + arr.push_back(usc::Variant(screenshot)); |
253 | + } |
254 | + gallery.add_attribute_value("sources", usc::Variant(arr)); |
255 | + return gallery; |
256 | +} |
257 | + |
258 | + |
259 | +static usc::PreviewWidgetList |
260 | +createWidgets(Libertine::Store::Package const& app) |
261 | +{ |
262 | + auto widgets = headerWidgets(app); |
263 | + widgets.push_back(buttonWidgets(app)); |
264 | + widgets.push_back(metadataWidgets(app)); |
265 | + if (!app.screenshots.empty()) |
266 | + { |
267 | + widgets.push_back(screenshotWidgets(app)); |
268 | + } |
269 | + widgets.push_back(descriptionWidgets(app)); |
270 | + |
271 | + return widgets; |
272 | +} |
273 | +} |
274 | + |
275 | + |
276 | +Libertine::Store::Preview:: |
277 | +Preview(usc::Result const& result, |
278 | + usc::ActionMetadata const& metadata, |
279 | + std::shared_ptr<ServiceManager> const& service) |
280 | + : PreviewQueryBase(result, metadata) |
281 | + , service_(service) |
282 | +{ |
283 | +} |
284 | + |
285 | + |
286 | +void Libertine::Store::Preview:: |
287 | +cancelled() |
288 | +{ |
289 | +} |
290 | + |
291 | + |
292 | +void Libertine::Store::Preview:: |
293 | +createSingleColumnLayout(Package const& app) |
294 | +{ |
295 | + oneColumn.column.push_back(HEADER_ID); |
296 | + oneColumn.column.push_back(ACTIONS_ID); |
297 | + oneColumn.column.push_back(METADATA_ID); |
298 | + if (!app.screenshots.empty()) |
299 | + { |
300 | + oneColumn.column.push_back(SCREENSHOTS_ID); |
301 | + } |
302 | + oneColumn.column.push_back(SUMMARY_ID); |
303 | +} |
304 | + |
305 | + |
306 | +void Libertine::Store::Preview:: |
307 | +createDualColumnLayout(Package const& app) |
308 | +{ |
309 | + twoColumns.column1.push_back(HEADER_ID); |
310 | + twoColumns.column1.push_back(ACTIONS_ID); |
311 | + twoColumns.column1.push_back(SUMMARY_ID); |
312 | + twoColumns.column2.push_back(METADATA_ID); |
313 | + if (!app.screenshots.empty()) |
314 | + { |
315 | + twoColumns.column2.push_back(SCREENSHOTS_ID); |
316 | + } |
317 | +} |
318 | + |
319 | + |
320 | +void Libertine::Store::Preview:: |
321 | +run(usc::PreviewReplyProxy const& reply) |
322 | +{ |
323 | + auto app = service_->app_info(QString::fromStdString(result()["id"].get_string())); |
324 | + auto widgets = createWidgets(app); |
325 | + |
326 | + createSingleColumnLayout(app); |
327 | + createDualColumnLayout(app); |
328 | + |
329 | + registerLayouts(reply); |
330 | + reply->push(widgets); |
331 | +} |
332 | + |
333 | + |
334 | +void Libertine::Store::Preview:: |
335 | +registerLayouts(unity::scopes::PreviewReplyProxy const& reply) |
336 | +{ |
337 | + usc::ColumnLayout layout1col(1); |
338 | + layout1col.add_column(oneColumn.column); |
339 | + |
340 | + usc::ColumnLayout layout2col(2); |
341 | + layout2col.add_column(twoColumns.column1); |
342 | + layout2col.add_column(twoColumns.column2); |
343 | + |
344 | + try |
345 | + { |
346 | + reply->register_layout({layout1col, layout2col}); |
347 | + } |
348 | + catch (unity::LogicException const& e) |
349 | + { |
350 | + qWarning() << "Failed to register layout:" << QString::fromStdString(e.what()); |
351 | + } |
352 | +} |
353 | |
354 | === added file 'scope/store/preview.h' |
355 | --- scope/store/preview.h 1970-01-01 00:00:00 +0000 |
356 | +++ scope/store/preview.h 2016-09-15 17:01:59 +0000 |
357 | @@ -0,0 +1,74 @@ |
358 | +/* |
359 | + * Copyright 2016 Canonical Ltd. |
360 | + * |
361 | + * This program is free software: you can redistribute it and/or modify it under |
362 | + * the terms of the GNU General Public License, version 3, as published by the |
363 | + * Free Software Foundation. |
364 | + * |
365 | + * This program is distributed in the hope that it will be useful, |
366 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
367 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
368 | + * GNU General Public License for more details. |
369 | + * |
370 | + * You should have received a copy of the GNU General Public License |
371 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
372 | + */ |
373 | +#ifndef LIBERTINE_STORE_PREVIEW_H |
374 | +#define LIBERTINE_STORE_PREVIEW_H |
375 | + |
376 | +#include <unity/scopes/PreviewQueryBase.h> |
377 | + |
378 | + |
379 | +namespace Libertine |
380 | +{ |
381 | +namespace Store |
382 | +{ |
383 | + |
384 | + |
385 | +class ServiceManager; |
386 | +class Package; |
387 | + |
388 | + |
389 | +class Preview |
390 | +: public unity::scopes::PreviewQueryBase |
391 | +{ |
392 | +public: |
393 | + explicit Preview(unity::scopes::Result const& result, |
394 | + unity::scopes::ActionMetadata const& metadata, |
395 | + std::shared_ptr<ServiceManager> const& service); |
396 | + |
397 | + virtual ~Preview() = default; |
398 | + |
399 | + virtual void |
400 | + cancelled() override; |
401 | + |
402 | + virtual void |
403 | + run(unity::scopes::PreviewReplyProxy const& reply) override; |
404 | + |
405 | +private: |
406 | + void |
407 | + registerLayouts(unity::scopes::PreviewReplyProxy const& reply); |
408 | + |
409 | + void |
410 | + createSingleColumnLayout(Package const& app); |
411 | + |
412 | + void |
413 | + createDualColumnLayout(Package const& app); |
414 | + |
415 | + struct { |
416 | + std::vector<std::string> column; |
417 | + } oneColumn; |
418 | + |
419 | + struct { |
420 | + std::vector<std::string> column1; |
421 | + std::vector<std::string> column2; |
422 | + } twoColumns; |
423 | + |
424 | + std::shared_ptr<ServiceManager> service_; |
425 | +}; |
426 | + |
427 | + |
428 | +} |
429 | +} |
430 | + |
431 | +#endif /* LIBERTINE_STORE_PREVIEW_H */ |
432 | |
433 | === modified file 'scope/store/query.cpp' |
434 | --- scope/store/query.cpp 2016-09-01 15:58:02 +0000 |
435 | +++ scope/store/query.cpp 2016-09-15 17:01:59 +0000 |
436 | @@ -20,7 +20,6 @@ |
437 | #include <unity/scopes/SearchReply.h> |
438 | #include <unity/scopes/CategoryRenderer.h> |
439 | #include <unity/scopes/VariantBuilder.h> |
440 | -#include <sstream> |
441 | #include <QtDBus> |
442 | #include <QDebug> |
443 | |
444 | @@ -65,27 +64,9 @@ |
445 | } |
446 | )"; |
447 | |
448 | -static std::string render_rating_stars(double rating) |
449 | -{ |
450 | - std::ostringstream ss; |
451 | - int rounded; |
452 | - |
453 | - if (rating < 0.0f) { |
454 | - rounded = 0; |
455 | - } else if (rating > 5.0f) { |
456 | - rounded = 5; |
457 | - } else { |
458 | - rounded = floor(rating); |
459 | - } |
460 | - |
461 | - for (int i = 0; i < rounded; i++) { |
462 | - ss << "★"; |
463 | - } |
464 | - for (int j = 0; j < 5 - rounded; j++) { |
465 | - ss << "☆"; |
466 | - } |
467 | - return ss.str(); |
468 | -} |
469 | + |
470 | +static auto const SINGLE_RESULT_FOUND = _("%1 result found"); |
471 | +static auto const MULTIPLE_RESULTS_FOUND = _("%1 results found"); |
472 | } |
473 | |
474 | |
475 | @@ -94,9 +75,9 @@ |
476 | |
477 | |
478 | Libertine::Store::Query:: |
479 | -Query(usc::CannedQuery const& query, |
480 | - usc::SearchMetadata const& metadata, |
481 | - std::shared_ptr<ServiceManager> const& service) |
482 | +Query(usc::CannedQuery const& query, |
483 | + usc::SearchMetadata const& metadata, |
484 | + std::shared_ptr<ServiceManager> const& service) |
485 | : usc::SearchQueryBase(query, metadata) |
486 | , service_(service) |
487 | { |
488 | @@ -139,20 +120,15 @@ |
489 | for (auto const& result: results) |
490 | { |
491 | usc::CategorisedResult cr(category); |
492 | - cr.set_title(result.toStdString()); |
493 | - cr["subtitle"] = "Publisher Placeholder"; |
494 | - cr["rating"] = render_rating_stars(3); |
495 | - |
496 | - usc::VariantBuilder builder; |
497 | - builder.add_tuple({ |
498 | - {"value", cr["rating"]}, |
499 | - }); |
500 | - cr["attributes"] = builder.end(); |
501 | - |
502 | - cr.set_uri(self_uri); |
503 | + cr.set_title(result.name); |
504 | + cr["subtitle"] = result.summary; |
505 | + cr["id"] = result.id; |
506 | + cr.set_art(result.icon); |
507 | + cr.set_uri("appid://" + result.id); |
508 | + |
509 | if (!reply->push(cr)) |
510 | { |
511 | - qCritical() << "Error while adding result " << result; |
512 | + qCritical() << "Error while adding result " << QString::fromStdString(result.name); |
513 | return; |
514 | } |
515 | } |
516 | |
517 | === modified file 'scope/store/query.h' |
518 | --- scope/store/query.h 2016-07-18 20:41:41 +0000 |
519 | +++ scope/store/query.h 2016-09-15 17:01:59 +0000 |
520 | @@ -16,7 +16,7 @@ |
521 | #ifndef LIBERTINE_STORE_QUERY_H_ |
522 | #define LIBERTINE_STORE_QUERY_H_ |
523 | |
524 | -#include "scope/store/service_manager.h" |
525 | + |
526 | #include <unity/scopes/ReplyProxyFwd.h> |
527 | #include <unity/scopes/SearchQueryBase.h> |
528 | |
529 | @@ -28,6 +28,8 @@ |
530 | namespace Store |
531 | { |
532 | |
533 | +class ServiceManager; |
534 | + |
535 | /** |
536 | * Engine to run a specific store query. |
537 | */ |
538 | |
539 | === modified file 'scope/store/scope.cpp' |
540 | --- scope/store/scope.cpp 2016-08-04 14:56:27 +0000 |
541 | +++ scope/store/scope.cpp 2016-09-15 17:01:59 +0000 |
542 | @@ -20,7 +20,9 @@ |
543 | #include "scope/store/scope.h" |
544 | |
545 | #include "scope/store/i18n.h" |
546 | +#include "scope/store/preview.h" |
547 | #include "scope/store/query.h" |
548 | +#include "scope/store/service_manager.h" |
549 | |
550 | |
551 | namespace usc = unity::scopes; |
552 | @@ -45,8 +47,8 @@ |
553 | |
554 | |
555 | usc::PreviewQueryBase::UPtr Libertine::Store::Scope:: |
556 | -preview(usc::Result const&, |
557 | - usc::ActionMetadata const&) |
558 | +preview(usc::Result const& result, |
559 | + usc::ActionMetadata const& metadata) |
560 | { |
561 | - return usc::PreviewQueryBase::UPtr(); |
562 | + return usc::PreviewQueryBase::UPtr(new Preview(result, metadata, std::make_shared<ServiceManager>())); |
563 | } |
564 | |
565 | === modified file 'scope/store/service_manager.cpp' |
566 | --- scope/store/service_manager.cpp 2016-08-31 17:59:10 +0000 |
567 | +++ scope/store/service_manager.cpp 2016-09-15 17:01:59 +0000 |
568 | @@ -17,20 +17,36 @@ |
569 | |
570 | #include <QtDBus> |
571 | #include <QDebug> |
572 | +#include <QDBusMetaType> |
573 | |
574 | namespace |
575 | { |
576 | constexpr auto SEARCH_CACHE_METHOD = "search"; |
577 | +constexpr auto APP_INFO_METHOD = "app_info"; |
578 | constexpr auto LIBERTINE_SERVICE_DESTINATION = "com.canonical.libertine.ContainerManager"; |
579 | constexpr auto LIBERTINE_SERVICE_INTERFACE = "com.canonical.libertine.ContainerManager"; |
580 | constexpr auto LIBERTINE_SERVICE_OBJECT = "/Manager"; |
581 | } |
582 | |
583 | |
584 | -QStringList Libertine::Store::ServiceManager:: |
585 | +Libertine::Store::ServiceManager:: |
586 | +ServiceManager() |
587 | +{ |
588 | + qDBusRegisterMetaType<QList<QVariantMap > >(); |
589 | +} |
590 | + |
591 | + |
592 | +Libertine::Store::Package Libertine::Store::ServiceManager:: |
593 | +app_info(const QString &app_id) const |
594 | +{ |
595 | + return Package::from_map(call<QVariantMap >(APP_INFO_METHOD, QVariant(app_id))); |
596 | +} |
597 | + |
598 | + |
599 | +QList<Libertine::Store::Package> Libertine::Store::ServiceManager:: |
600 | search_cache(const QString &query) const |
601 | { |
602 | - return call<QStringList>(SEARCH_CACHE_METHOD, QVariant(query)); |
603 | + return Package::from_map(call<QList<QVariantMap > >(SEARCH_CACHE_METHOD, QVariant(query))); |
604 | } |
605 | |
606 | |
607 | @@ -62,7 +78,3 @@ |
608 | return QDBusConnection::sessionBus().isConnected(); |
609 | } |
610 | |
611 | - |
612 | -// explicit template declarations so we can define template in implementation file |
613 | -template QStringList Libertine::Store::ServiceManager:: |
614 | -call<QStringList>(QString const&, QVariant const&) const; |
615 | |
616 | === modified file 'scope/store/service_manager.h' |
617 | --- scope/store/service_manager.h 2016-07-18 20:41:41 +0000 |
618 | +++ scope/store/service_manager.h 2016-09-15 17:01:59 +0000 |
619 | @@ -13,13 +13,15 @@ |
620 | * You should have received a copy of the GNU General Public License |
621 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
622 | */ |
623 | - |
624 | #ifndef SERVICE_MANAGER_H |
625 | #define SERVICE_MANAGER_H |
626 | |
627 | +#include "scope/store/package.h" |
628 | + |
629 | #include <QString> |
630 | #include <QVariant> |
631 | |
632 | + |
633 | namespace Libertine |
634 | { |
635 | namespace Store |
636 | @@ -29,10 +31,11 @@ |
637 | class ServiceManager |
638 | { |
639 | public: |
640 | - ServiceManager() = default; |
641 | + explicit ServiceManager(); |
642 | virtual ~ServiceManager() = default; |
643 | |
644 | - virtual QStringList search_cache(QString const& query) const; |
645 | + virtual QList<Package> search_cache(QString const& query) const; |
646 | + virtual Package app_info(QString const& app_id) const; |
647 | |
648 | private: |
649 | bool valid() const; |
650 | @@ -45,4 +48,5 @@ |
651 | } // namespace Libertine |
652 | } // namespace Store |
653 | |
654 | + |
655 | #endif // SERVICE_MANAGER_H |
656 | |
657 | === modified file 'service/libertine_service/apt.py' |
658 | --- service/libertine_service/apt.py 2016-07-18 20:41:41 +0000 |
659 | +++ service/libertine_service/apt.py 2016-09-15 17:01:59 +0000 |
660 | @@ -15,7 +15,7 @@ |
661 | import apt |
662 | import glob |
663 | import os |
664 | - |
665 | +import re |
666 | |
667 | def _use_system_gpg(): |
668 | """ Configures APT to use the system-wide GPG store. Always.""" |
669 | @@ -28,12 +28,10 @@ |
670 | sources_path = os.path.join('/etc', 'apt') |
671 | sources_list = glob.glob(os.path.join(sources_path, 'sources.list.d', '*.list')) |
672 | sources_list.append(os.path.join(sources_path, 'sources.list')) |
673 | - |
674 | sources = '' |
675 | for source in sources_list: |
676 | with open(source) as f: |
677 | sources += f.read() |
678 | - |
679 | return sources |
680 | |
681 | |
682 | @@ -61,10 +59,45 @@ |
683 | return apt_cache |
684 | |
685 | |
686 | -def get_apt_cache(config): |
687 | +def _get_apt_cache(config): |
688 | """ Factory function to get the APT cache obejct. """ |
689 | _use_system_gpg() |
690 | if config.use_local_cache: |
691 | return _get_local_apt_cache() |
692 | else: |
693 | return apt.Cache() |
694 | + |
695 | +class AptCache(object): |
696 | + """docstring for AptCache""" |
697 | + def __init__(self, config): |
698 | + super(AptCache, self).__init__() |
699 | + self.config = config |
700 | + |
701 | + def search(self, query): |
702 | + apps = [] |
703 | + |
704 | + cache = _get_apt_cache(self.config) |
705 | + pkg_keys = [key for key in cache.keys() if re.match(query, key)] |
706 | + for key in pkg_keys: |
707 | + app = {} |
708 | + app["name"] = cache[key].name |
709 | + app["id"] = cache[key].name |
710 | + if len(cache[key].versions) > 0: |
711 | + app["summary"] = cache[key].versions[0].summary |
712 | + app["website"] = cache[key].versions[0].homepage |
713 | + apps.append(app) |
714 | + return apps |
715 | + |
716 | + def app_info(self, app_id): |
717 | + app_data = {} |
718 | + cache = _get_apt_cache(self.config) |
719 | + if app_id in cache: |
720 | + app = cache[app_id] |
721 | + app_data["name"] = app.name |
722 | + app_data["id"] = app.name |
723 | + if len(app.versions) > 0: |
724 | + app_data["summary"] = app.versions[0].summary |
725 | + app_data["website"] = app.versions[0].homepage |
726 | + app_data["description"] = app.versions[0].description |
727 | + |
728 | + return app_data |
729 | |
730 | === modified file 'service/libertine_service/dbus.py' |
731 | --- service/libertine_service/dbus.py 2016-08-31 16:57:31 +0000 |
732 | +++ service/libertine_service/dbus.py 2016-09-15 17:01:59 +0000 |
733 | @@ -15,7 +15,6 @@ |
734 | import dbus |
735 | import dbus.service |
736 | import logging |
737 | -import re |
738 | from libertine_service import apt |
739 | from dbus.mainloop.glib import DBusGMainLoop |
740 | |
741 | @@ -31,7 +30,7 @@ |
742 | |
743 | def __init__(self, config): |
744 | log.info("creating service") |
745 | - self.config = config |
746 | + self.cache = apt.AptCache(config) |
747 | DBusGMainLoop(set_as_default=True) |
748 | try: |
749 | bus_name = dbus.service.BusName(LIBERTINE_SERVICE_NAME, |
750 | @@ -62,11 +61,17 @@ |
751 | |
752 | @dbus.service.method(LIBERTINE_STORE_INTERFACE, |
753 | in_signature='s', |
754 | - out_signature='as') |
755 | + out_signature='aa{sv}') |
756 | def search(self, search_string): |
757 | log.debug("search('{}') called".format(search_string)) |
758 | - cache = apt.get_apt_cache(self.config) |
759 | - return {k: cache[k] for k in cache.keys() if re.match(search_string, k)} |
760 | + return self.cache.search(search_string) |
761 | + |
762 | + @dbus.service.method(LIBERTINE_STORE_INTERFACE, |
763 | + in_signature='s', |
764 | + out_signature='a{sv}') |
765 | + def app_info(self, app_id): |
766 | + log.debug("app_info('{}') called".format(app_id)) |
767 | + return self.cache.app_info(app_id) |
768 | |
769 | @dbus.service.signal(LIBERTINE_STORE_INTERFACE, |
770 | signature='su') |
771 | |
772 | === modified file 'tests/scope/apps/test_preview.cpp' |
773 | --- tests/scope/apps/test_preview.cpp 2016-07-18 13:53:20 +0000 |
774 | +++ tests/scope/apps/test_preview.cpp 2016-09-15 17:01:59 +0000 |
775 | @@ -22,7 +22,6 @@ |
776 | #include <unity/scopes/testing/MockPreviewReply.h> |
777 | #include <unity/scopes/PreviewWidget.h> |
778 | #include <memory> |
779 | -#include <QDir> |
780 | |
781 | |
782 | TEST(TestPreview, pushesWidgetsWithAppInformation) |
783 | |
784 | === modified file 'tests/scope/store/CMakeLists.txt' |
785 | --- tests/scope/store/CMakeLists.txt 2016-07-19 14:18:12 +0000 |
786 | +++ tests/scope/store/CMakeLists.txt 2016-09-15 17:01:59 +0000 |
787 | @@ -1,5 +1,6 @@ |
788 | function(create_test test_name test_file) |
789 | add_executable(${test_name}_exe |
790 | + mock_service_manager.h |
791 | ${test_file}.cpp |
792 | ) |
793 | |
794 | @@ -15,3 +16,5 @@ |
795 | endfunction(create_test) |
796 | |
797 | create_test(test_store_query test_query) |
798 | +create_test(test_store_preview test_preview) |
799 | +create_test(test_store_package test_package) |
800 | |
801 | === added file 'tests/scope/store/mock_service_manager.h' |
802 | --- tests/scope/store/mock_service_manager.h 1970-01-01 00:00:00 +0000 |
803 | +++ tests/scope/store/mock_service_manager.h 2016-09-15 17:01:59 +0000 |
804 | @@ -0,0 +1,46 @@ |
805 | +/* |
806 | + * Copyright 2016 Canonical Ltd. |
807 | + * |
808 | + * This program is free software: you can redistribute it and/or modify it under |
809 | + * the terms of the GNU General Public License, version 3, as published by the |
810 | + * Free Software Foundation. |
811 | + * |
812 | + * This program is distributed in the hope that it will be useful, |
813 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
814 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
815 | + * GNU General Public License for more details. |
816 | + * |
817 | + * You should have received a copy of the GNU General Public License |
818 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
819 | + */ |
820 | + |
821 | +#ifndef _MOCK_SERVICE_MANAGER_H |
822 | +#define _MOCK_SERVICE_MANAGER_H |
823 | + |
824 | +#include "scope/store/service_manager.h" |
825 | +#include <gmock/gmock.h> |
826 | + |
827 | + |
828 | +namespace Libertine |
829 | +{ |
830 | +namespace Store |
831 | +{ |
832 | + |
833 | + |
834 | +class MockServiceManager : public ServiceManager |
835 | +{ |
836 | +public: |
837 | + MockServiceManager() |
838 | + : ServiceManager() |
839 | + { |
840 | + } |
841 | + |
842 | + MOCK_CONST_METHOD1(search_cache, QList<Package>(QString const&)); |
843 | + MOCK_CONST_METHOD1(app_info, Package(QString const&)); |
844 | +}; |
845 | + |
846 | + |
847 | +} // namesapce Store |
848 | +} // namesapce Libertine |
849 | + |
850 | +#endif // _MOCK_SERVICE_MANAGER_H |
851 | |
852 | === added file 'tests/scope/store/test_package.cpp' |
853 | --- tests/scope/store/test_package.cpp 1970-01-01 00:00:00 +0000 |
854 | +++ tests/scope/store/test_package.cpp 2016-09-15 17:01:59 +0000 |
855 | @@ -0,0 +1,107 @@ |
856 | +/* |
857 | + * Copyright 2016 Canonical Ltd. |
858 | + * |
859 | + * This program is free software: you can redistribute it and/or modify it under |
860 | + * the terms of the GNU General Public License, version 3, as published by the |
861 | + * Free Software Foundation. |
862 | + * |
863 | + * This program is distributed in the hope that it will be useful, |
864 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
865 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
866 | + * GNU General Public License for more details. |
867 | + * |
868 | + * You should have received a copy of the GNU General Public License |
869 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
870 | + */ |
871 | +#include "scope/store/package.h" |
872 | + |
873 | +#include <gtest/gtest.h> |
874 | +#include <gmock/gmock.h> |
875 | + |
876 | + |
877 | +namespace |
878 | +{ |
879 | +using namespace Libertine::Store; |
880 | + |
881 | + |
882 | +static QVariantMap |
883 | +attribute_map(QString const& name, QString const& summary, QString const& description, |
884 | + QString const& icon, QString const& publisher, QString const& website, |
885 | + QString const& license, QString const& id, QStringList screenshots) |
886 | +{ |
887 | + QVariantMap attributes; |
888 | + attributes["name"] = name; |
889 | + attributes["summary"] = summary; |
890 | + attributes["description"] = description; |
891 | + attributes["icon"] = icon; |
892 | + attributes["publisher"] = publisher; |
893 | + attributes["website"] = website; |
894 | + attributes["license"] = license; |
895 | + attributes["id"] = id; |
896 | + attributes["screenshots"] = screenshots; |
897 | + return attributes; |
898 | +} |
899 | + |
900 | + |
901 | +static void |
902 | +package_matches_attributes(Package actual, std::string const& name, std::string const& summary, |
903 | + std::string const& description, std::string const& icon, std::string const& publisher, |
904 | + std::string const& website, std::string const& license, std::string const& id, |
905 | + QStringList screenshots) |
906 | +{ |
907 | + EXPECT_EQ(name, actual.name); |
908 | + EXPECT_EQ(summary, actual.summary); |
909 | + EXPECT_EQ(description, actual.description); |
910 | + EXPECT_EQ(icon, actual.icon); |
911 | + EXPECT_EQ(publisher, actual.publisher); |
912 | + EXPECT_EQ(website, actual.website); |
913 | + EXPECT_EQ(license, actual.license); |
914 | + EXPECT_EQ(id, actual.id); |
915 | + |
916 | + ASSERT_EQ(actual.screenshots.size(), screenshots.size()); |
917 | + for (auto i = 0u; i < actual.screenshots.size(); ++i) |
918 | + { |
919 | + EXPECT_EQ(screenshots[i], QString::fromStdString(actual.screenshots[i])); |
920 | + } |
921 | +} |
922 | + |
923 | + |
924 | +TEST(PackageTest, FromMapCreatesSinglePackage) |
925 | +{ |
926 | + QStringList screenshots{"file:///some/image.png", "file:///some/other/image.jpg"}; |
927 | + auto attributeMap = attribute_map("Harry", "The Philosopher's Stone", |
928 | + "Boy with head injury seeks magic rock", |
929 | + "harry.png", "JK", "pottermore.com", "Private", |
930 | + "com.pottermore.harry", screenshots); |
931 | + auto package = Package::from_map(attributeMap); |
932 | + package_matches_attributes(package, "Harry", "The Philosopher's Stone", |
933 | + "Boy with head injury seeks magic rock", |
934 | + "harry.png", "JK", "pottermore.com", "Private", |
935 | + "com.pottermore.harry", screenshots); |
936 | +} |
937 | + |
938 | + |
939 | +TEST(PackageTest, FromMapCreatesListOfPackages) |
940 | +{ |
941 | + QStringList screenshots{"file:///some/image.png", "file:///some/other/image.jpg"}; |
942 | + auto attributePkg1Map = attribute_map("Harry", "The Philosopher's Stone", |
943 | + "Boy with head injury seeks magic rock", |
944 | + "harry.png", "JK", "pottermore.com", "Private", |
945 | + "com.pottermore.harry", screenshots); |
946 | + QStringList screenshots2{"file://imageFor2.png"}; |
947 | + auto attributePkg2Map = attribute_map("Dune", "Classic science fiction", |
948 | + "The spice must flow", "worms.png", |
949 | + "Herbert", "dunebook.net", "Other", |
950 | + "net.dunebook.dune", screenshots2); |
951 | + auto packages = Package::from_map(QList<QVariantMap>{attributePkg1Map, attributePkg2Map}); |
952 | + ASSERT_EQ(2, packages.size()); |
953 | + package_matches_attributes(packages[0], "Harry", "The Philosopher's Stone", |
954 | + "Boy with head injury seeks magic rock", |
955 | + "harry.png", "JK", "pottermore.com", "Private", |
956 | + "com.pottermore.harry", screenshots); |
957 | + package_matches_attributes(packages[1], "Dune", "Classic science fiction", |
958 | + "The spice must flow", "worms.png", |
959 | + "Herbert", "dunebook.net", "Other", |
960 | + "net.dunebook.dune", screenshots2); |
961 | +} |
962 | +} |
963 | |
964 | === added file 'tests/scope/store/test_preview.cpp' |
965 | --- tests/scope/store/test_preview.cpp 1970-01-01 00:00:00 +0000 |
966 | +++ tests/scope/store/test_preview.cpp 2016-09-15 17:01:59 +0000 |
967 | @@ -0,0 +1,196 @@ |
968 | +/* |
969 | + * Copyright 2016 Canonical Ltd. |
970 | + * |
971 | + * This program is free software: you can redistribute it and/or modify it under |
972 | + * the terms of the GNU General Public License, version 3, as published by the |
973 | + * Free Software Foundation. |
974 | + * |
975 | + * This program is distributed in the hope that it will be useful, |
976 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
977 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
978 | + * GNU General Public License for more details. |
979 | + * |
980 | + * You should have received a copy of the GNU General Public License |
981 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
982 | + */ |
983 | +#include "scope/store/preview.h" |
984 | +#include "tests/scope/store/mock_service_manager.h" |
985 | + |
986 | +#include <unity/scopes/ActionMetadata.h> |
987 | +#include <unity/scopes/PreviewWidget.h> |
988 | +#include <unity/scopes/testing/MockPreviewReply.h> |
989 | +#include <unity/scopes/testing/Result.h> |
990 | +#include <gtest/gtest.h> |
991 | +#include <gmock/gmock.h> |
992 | + |
993 | +namespace |
994 | +{ |
995 | +using namespace Libertine::Store; |
996 | + |
997 | + |
998 | +static void |
999 | +verifyHeader(Package const& package, unity::scopes::PreviewWidget const& header) |
1000 | +{ |
1001 | + EXPECT_EQ("hdr", header.id()); |
1002 | + EXPECT_EQ("header", header.widget_type()); |
1003 | + |
1004 | + EXPECT_EQ(package.name, header.attribute_values()["title"].get_string()); |
1005 | + EXPECT_EQ(package.summary, header.attribute_values()["subtitle"].get_string()); |
1006 | + EXPECT_EQ(package.icon, header.attribute_values()["mascot"].get_string()); |
1007 | +} |
1008 | + |
1009 | + |
1010 | +static void |
1011 | +verifyButtons(unity::scopes::PreviewWidget const& buttons) |
1012 | +{ |
1013 | + EXPECT_EQ("buttons", buttons.id()); |
1014 | + EXPECT_EQ("actions", buttons.widget_type()); |
1015 | + auto buttons_actions = buttons.attribute_values()["actions"].get_array(); |
1016 | + ASSERT_EQ(1, buttons_actions.size()); |
1017 | + EXPECT_EQ("install_xapp", buttons_actions[0].get_dict()["id"].get_string()); |
1018 | + EXPECT_EQ("Install", buttons_actions[0].get_dict()["label"].get_string()); |
1019 | +} |
1020 | + |
1021 | + |
1022 | +static void |
1023 | +verifyMetadata(Package const& package, unity::scopes::PreviewWidget const& props) |
1024 | +{ |
1025 | + EXPECT_EQ("other_metadata", props.id()); |
1026 | + EXPECT_EQ("table", props.widget_type()); |
1027 | + |
1028 | + auto propValues = props.attribute_values()["values"].get_array(); |
1029 | + ASSERT_EQ(3, propValues.size()); |
1030 | + ASSERT_EQ(2, propValues[0].get_array().size()); |
1031 | + EXPECT_EQ("Publisher/Creator", propValues[0].get_array()[0].get_string()); |
1032 | + EXPECT_EQ(package.publisher, propValues[0].get_array()[1].get_string()); |
1033 | + ASSERT_EQ(2, propValues[1].get_array().size()); |
1034 | + EXPECT_EQ("Website", propValues[1].get_array()[0].get_string()); |
1035 | + EXPECT_EQ(package.website, propValues[1].get_array()[1].get_string()); |
1036 | + ASSERT_EQ(2, propValues[2].get_array().size()); |
1037 | + EXPECT_EQ("License", propValues[2].get_array()[0].get_string()); |
1038 | + EXPECT_EQ(package.license, propValues[2].get_array()[1].get_string()); |
1039 | +} |
1040 | + |
1041 | + |
1042 | +static void |
1043 | +verifyDescription(Package const& package, unity::scopes::PreviewWidget const& description) |
1044 | +{ |
1045 | + EXPECT_EQ("summary", description.id()); |
1046 | + EXPECT_EQ("text", description.widget_type()); |
1047 | + EXPECT_EQ("Info", description.attribute_values()["title"].get_string()); |
1048 | + EXPECT_EQ(package.description, description.attribute_values()["text"].get_string()); |
1049 | +} |
1050 | + |
1051 | + |
1052 | +static void |
1053 | +verifyScreenshots(Package const& package, unity::scopes::PreviewWidget const& screenshots) |
1054 | +{ |
1055 | + EXPECT_EQ("screenshots", screenshots.id()); |
1056 | + EXPECT_EQ("gallery", screenshots.widget_type()); |
1057 | + |
1058 | + auto sources = screenshots.attribute_values()["sources"].get_array(); |
1059 | + ASSERT_EQ(package.screenshots.size(), sources.size()); |
1060 | + |
1061 | + for (auto i = 0u; i < package.screenshots.size(); ++i) |
1062 | + { |
1063 | + EXPECT_EQ(package.screenshots[i], sources[i].get_string()); |
1064 | + } |
1065 | + |
1066 | +} |
1067 | + |
1068 | + |
1069 | +class StorePreviewTest : public testing::Test |
1070 | +{ |
1071 | +protected: |
1072 | + StorePreviewTest() |
1073 | + : testing::Test() |
1074 | + , result() |
1075 | + , metadata("en_US", "phone") |
1076 | + , list(new unity::scopes::PreviewWidgetList()) |
1077 | + , reply() |
1078 | + , proxy(&reply, [](unity::scopes::PreviewReply*) {}) |
1079 | + , service(new testing::NiceMock<MockServiceManager>()) |
1080 | + { |
1081 | + } |
1082 | + |
1083 | + virtual void |
1084 | + SetUp() |
1085 | + { |
1086 | + EXPECT_CALL(reply, push(testing::_)).WillOnce(testing::SaveArg<0>(list.get())); |
1087 | + } |
1088 | + |
1089 | + void usePackage(Package const& package) |
1090 | + { |
1091 | + result["id"] = unity::scopes::Variant(package.id); |
1092 | + EXPECT_CALL(*service, app_info(QString::fromStdString(package.id))).WillOnce(testing::Return(package)); |
1093 | + } |
1094 | + |
1095 | + unity::scopes::testing::Result result; |
1096 | + unity::scopes::ActionMetadata metadata; |
1097 | + std::unique_ptr<unity::scopes::PreviewWidgetList> list; |
1098 | + testing::NiceMock<unity::scopes::testing::MockPreviewReply> reply; |
1099 | + unity::scopes::PreviewReplyProxy proxy; |
1100 | + std::shared_ptr<testing::NiceMock<MockServiceManager> > service; |
1101 | +}; |
1102 | + |
1103 | + |
1104 | +TEST_F(StorePreviewTest, ShowsDetailedInformationForPackage) |
1105 | +{ |
1106 | + Package package; |
1107 | + package.name = "vim"; |
1108 | + package.summary = "classic text editor"; |
1109 | + package.description = "this or emacs"; |
1110 | + package.icon = "file:///test/file.png"; |
1111 | + package.publisher = "Woody Boyd"; |
1112 | + package.website = "http://canonical.com/"; |
1113 | + package.license = "GPLv8+"; |
1114 | + package.id = "vim.desktop"; |
1115 | + usePackage(package); |
1116 | + |
1117 | + Preview preview(result, metadata, service); |
1118 | + preview.run(proxy); |
1119 | + |
1120 | + ASSERT_NE(nullptr, list); |
1121 | + ASSERT_EQ(4, list->size()); |
1122 | + |
1123 | + verifyHeader(package, list->front()); |
1124 | + list->pop_front(); |
1125 | + verifyButtons(list->front()); |
1126 | + list->pop_front(); |
1127 | + verifyMetadata(package, list->front()); |
1128 | + list->pop_front(); |
1129 | + verifyDescription(package, list->front()); |
1130 | +} |
1131 | + |
1132 | + |
1133 | +TEST_F(StorePreviewTest, ShowsScreenshotsWhenAvailable) |
1134 | +{ |
1135 | + Package package; |
1136 | + package.name = "vim"; |
1137 | + package.summary = "classic text editor"; |
1138 | + package.description = "this or emacs"; |
1139 | + package.icon = "file:///test/file.png"; |
1140 | + package.publisher = "Woody Boyd"; |
1141 | + package.website = "http://canonical.com/"; |
1142 | + package.license = "GPLv8+"; |
1143 | + package.id = "vim.desktop"; |
1144 | + package.screenshots = std::vector<std::string>{"file:///some/string/uri.png", "file:///some/other/string/uri.jpg"}; |
1145 | + usePackage(package); |
1146 | + |
1147 | + Preview preview(result, metadata, service); |
1148 | + preview.run(proxy); |
1149 | + |
1150 | + ASSERT_NE(nullptr, list); |
1151 | + ASSERT_EQ(5, list->size()); |
1152 | + |
1153 | + verifyHeader(package, list->front()); |
1154 | + list->pop_front(); |
1155 | + verifyButtons(list->front()); |
1156 | + list->pop_front(); |
1157 | + verifyMetadata(package, list->front()); |
1158 | + list->pop_front(); |
1159 | + verifyScreenshots(package, list->front()); |
1160 | + list->pop_front(); |
1161 | + verifyDescription(package, list->front()); |
1162 | +} |
1163 | +} |
1164 | |
1165 | === modified file 'tests/scope/store/test_query.cpp' |
1166 | --- tests/scope/store/test_query.cpp 2016-07-20 13:35:09 +0000 |
1167 | +++ tests/scope/store/test_query.cpp 2016-09-15 17:01:59 +0000 |
1168 | @@ -13,9 +13,10 @@ |
1169 | * You should have received a copy of the GNU General Public License |
1170 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1171 | */ |
1172 | - |
1173 | #include "scope/store/query.h" |
1174 | -#include "scope/store/service_manager.h" |
1175 | + |
1176 | + |
1177 | +#include "tests/scope/store/mock_service_manager.h" |
1178 | #include <unity/scopes/SearchMetadata.h> |
1179 | #include <unity/scopes/CannedQuery.h> |
1180 | #include <unity/scopes/testing/MockSearchReply.h> |
1181 | @@ -41,24 +42,20 @@ |
1182 | }; |
1183 | |
1184 | |
1185 | -class MockServiceManager : public ServiceManager |
1186 | -{ |
1187 | -public: |
1188 | - MockServiceManager() |
1189 | - : ServiceManager() |
1190 | - { |
1191 | - } |
1192 | - |
1193 | - MOCK_CONST_METHOD1(search_cache, QStringList(QString const&)); |
1194 | -}; |
1195 | - |
1196 | - |
1197 | MATCHER_P(ResultTitleMatch, title, "") |
1198 | { |
1199 | return arg.contains("title") && arg["title"] == unity::scopes::Variant(title); |
1200 | } |
1201 | |
1202 | |
1203 | +MATCHER_P3(ResultPackageMatch, title, subtitle, id, "") |
1204 | +{ |
1205 | + return arg.contains("title") && arg["title"].get_string() == title && |
1206 | + arg.contains("subtitle") && arg["subtitle"].get_string() == subtitle && |
1207 | + arg.contains("id") && arg["id"].get_string() == id; |
1208 | +} |
1209 | + |
1210 | + |
1211 | class TestStoreQuery : public ::testing::Test |
1212 | { |
1213 | protected: |
1214 | @@ -72,6 +69,21 @@ |
1215 | { |
1216 | } |
1217 | |
1218 | + Package create_package(std::string name, std::string summary, std::string id) |
1219 | + { |
1220 | + Package package; |
1221 | + package.name = name; |
1222 | + package.summary = summary; |
1223 | + package.id = id; |
1224 | + |
1225 | + return package; |
1226 | + } |
1227 | + |
1228 | + void expect_push(std::string title, std::string subtitle, std::string id, bool result = true) |
1229 | + { |
1230 | + EXPECT_CALL(reply_, push(testing::Matcher<unity::scopes::CategorisedResult const&>(ResultPackageMatch(title, subtitle, id)))).WillOnce(testing::Return(result)); |
1231 | + } |
1232 | + |
1233 | unity::scopes::SearchMetadata metadata_; |
1234 | unity::scopes::CannedQuery canned_query_; |
1235 | testing::NiceMock<unity::scopes::testing::MockSearchReply> reply_; |
1236 | @@ -95,7 +107,7 @@ |
1237 | { |
1238 | EXPECT_CALL(reply_, register_category("hint", "", "", testing::_)).WillOnce(testing::Return(category_)); |
1239 | EXPECT_CALL(reply_, push(testing::Matcher<unity::scopes::CategorisedResult const&>(ResultTitleMatch(Query::NO_SEARCH_RESULTS_HINT)))).WillOnce(testing::Return(true)); |
1240 | - EXPECT_CALL(*service_, search_cache(testing::_)).WillOnce(testing::Return(QStringList{})); |
1241 | + EXPECT_CALL(*service_, search_cache(testing::_)).WillOnce(testing::Return(QList<Package>{})); |
1242 | canned_query_.set_query_string("foobar"); |
1243 | |
1244 | Query q(canned_query_, metadata_, service_); |
1245 | @@ -106,8 +118,11 @@ |
1246 | TEST_F(TestStoreQuery, ShowSingleSearchResult) |
1247 | { |
1248 | EXPECT_CALL(reply_, register_category("aptcache", "1 result found", "Application", testing::_)).WillOnce(testing::Return(category_)); |
1249 | - EXPECT_CALL(reply_, push(testing::Matcher<unity::scopes::CategorisedResult const&>(ResultTitleMatch("vim")))).WillOnce(testing::Return(true)); |
1250 | - EXPECT_CALL(*service_, search_cache(testing::_)).WillOnce(testing::Return(QStringList{"vim"})); |
1251 | + |
1252 | + auto package = create_package("vim", "Writin' stuff", "vim.desktop"); |
1253 | + expect_push("vim", "Writin' stuff", "vim.desktop"); |
1254 | + |
1255 | + EXPECT_CALL(*service_, search_cache(testing::_)).WillOnce(testing::Return(QList<Package>{package})); |
1256 | canned_query_.set_query_string("vim"); |
1257 | |
1258 | Query q(canned_query_, metadata_, service_); |
1259 | @@ -118,10 +133,35 @@ |
1260 | TEST_F(TestStoreQuery, ShowMultipleSearchResults) |
1261 | { |
1262 | EXPECT_CALL(reply_, register_category("aptcache", "3 results found", "Application", testing::_)).WillOnce(testing::Return(category_)); |
1263 | - EXPECT_CALL(reply_, push(testing::Matcher<unity::scopes::CategorisedResult const&>(ResultTitleMatch("vim")))).WillOnce(testing::Return(true)); |
1264 | - EXPECT_CALL(reply_, push(testing::Matcher<unity::scopes::CategorisedResult const&>(ResultTitleMatch("vim-common")))).WillOnce(testing::Return(true)); |
1265 | - EXPECT_CALL(reply_, push(testing::Matcher<unity::scopes::CategorisedResult const&>(ResultTitleMatch("vim-uncommon")))).WillOnce(testing::Return(true)); |
1266 | - EXPECT_CALL(*service_, search_cache(testing::_)).WillOnce(testing::Return(QStringList{"vim", "vim-common", "vim-uncommon"})); |
1267 | + |
1268 | + auto vim = create_package("vim", "Writin' stuff", "vim.desktop"); |
1269 | + auto gedit = create_package("gedit", "Writin' gui stuff", "gedit.desktop"); |
1270 | + auto ed = create_package("ed", "Writin' simple stuff", "ed.desktop"); |
1271 | + |
1272 | + expect_push("vim", "Writin' stuff", "vim.desktop"); |
1273 | + expect_push("gedit", "Writin' gui stuff", "gedit.desktop"); |
1274 | + expect_push("ed", "Writin' simple stuff", "ed.desktop"); |
1275 | + |
1276 | + EXPECT_CALL(*service_, search_cache(testing::_)).WillOnce(testing::Return(QList<Package>{vim, gedit, ed})); |
1277 | + canned_query_.set_query_string("vim"); |
1278 | + |
1279 | + Query q(canned_query_, metadata_, service_); |
1280 | + q.run(proxy_); |
1281 | +} |
1282 | + |
1283 | + |
1284 | +TEST_F(TestStoreQuery, FailureToPushEndsQueryPrematurely) |
1285 | +{ |
1286 | + EXPECT_CALL(reply_, register_category("aptcache", "3 results found", "Application", testing::_)).WillOnce(testing::Return(category_)); |
1287 | + |
1288 | + auto vim = create_package("vim", "Writin' stuff", "vim.desktop"); |
1289 | + auto gedit = create_package("gedit", "Writin' gui stuff", "gedit.desktop"); |
1290 | + auto ed = create_package("ed", "Writin' simple stuff", "ed.desktop"); |
1291 | + |
1292 | + expect_push("vim", "Writin' stuff", "vim.desktop"); |
1293 | + expect_push("gedit", "Writin' gui stuff", "gedit.desktop", false); |
1294 | + |
1295 | + EXPECT_CALL(*service_, search_cache(testing::_)).WillOnce(testing::Return(QList<Package>{vim, gedit, ed})); |
1296 | canned_query_.set_query_string("vim"); |
1297 | |
1298 | Query q(canned_query_, metadata_, service_); |
PASSED: Continuous integration, rev:90 /jenkins. canonical. com/libertine/ job/lp- libertine- scope-ci/ 55/ /jenkins. canonical. com/libertine/ job/build/ 210 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=amd64, release= vivid+overlay, testname= default/ 170 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=amd64, release= xenial+ overlay, testname= default/ 170 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=amd64, release= yakkety, testname= default/ 170 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=i386, release= vivid+overlay, testname= default/ 170 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=i386, release= xenial+ overlay, testname= default/ 170 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=i386, release= yakkety, testname= default/ 170 /jenkins. canonical. com/libertine/ job/lp- generic- update- mp/160/ console /jenkins. canonical. com/libertine/ job/build- 0-fetch/ 213 /jenkins. canonical. com/libertine/ job/build- 1-sourcepkg/ release= vivid+overlay/ 198 /jenkins. canonical. com/libertine/ job/build- 1-sourcepkg/ release= xenial+ overlay/ 198 /jenkins. canonical. com/libertine/ job/build- 1-sourcepkg/ release= yakkety/ 198 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= vivid+overlay/ 191 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= vivid+overlay/ 191/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= xenial+ overlay/ 191 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= xenial+ overlay/ 191/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= yakkety/ 191 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= yakkety/ 191/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= vivid+overlay/ 191 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= vivid+overlay/ 191/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= xenial+ overlay/ 191 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= xenial+ overlay/ 191/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= yakkety/ 191 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= yakkety/ 191/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/libertine/ job/lp- libertine- scope-ci/ 55/rebuild
https:/