Merge lp:~larryprice/libertine-scope/preview-2 into lp:~larryprice/libertine-scope/libertine-store-search

Proposed by Larry Price
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
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.

To post a comment you must log in.
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:90
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/55/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/210
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/170
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/170
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=default/170
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/170
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/170
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=yakkety,testname=default/170
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/160/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/213
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/198
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/198
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/198
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/191
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/191/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/191
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/191/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/191
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/191/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/191
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/191/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/191
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/191/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/191
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/191/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/55/rebuild

review: Approve (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:91
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/59/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/libertine/job/build/220/console
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/166/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/223
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/208
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/208
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/208
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/201/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/201/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/201/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/201/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/201/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/201/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/59/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:92
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/61/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/222
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/180
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/180
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=default/180
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/180
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/180
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=yakkety,testname=default/180
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/168/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/225
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/210
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/210
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/210
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/203
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/203/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/203
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/203/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/203
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/203/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/203
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/203/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/203
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/203/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/203
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/203/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/61/rebuild

review: Approve (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:94
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/71/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/libertine/job/build/280/console
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/213/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/282
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/266
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/266
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/266
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/259/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/259/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/259/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/259/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/259/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/259/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/71/rebuild

review: Needs Fixing (continuous-integration)
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

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:94
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/77/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/libertine/job/build/311/console
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/232/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/313
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/297
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/297
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/297
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/291/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/291/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/291/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/291/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/291/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/291/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/77/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

FAILED: Continuous integration, rev:94
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/78/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/libertine/job/build/312/console
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/233/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/314
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/298
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/298
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/298
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/292/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/292/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/292/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/292/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/292/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/292/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/78/rebuild

review: Needs Fixing (continuous-integration)
100. By Larry Price

Merge

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

FAILED: Continuous integration, rev:94
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/79/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/libertine/job/build/313/console
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/234/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/315
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/299
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/299
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/299
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/293/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/293/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/293/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/293/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/293/console
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/293/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/79/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:100
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/80/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/314
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/258
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/258
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=default/258
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/258
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/258
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=yakkety,testname=default/258
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/235/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/316
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/300
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/300
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/300
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/294
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/294/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/294
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/294/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/294
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/294/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/294
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/294/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/294
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/294/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/294
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/294/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-scope-ci/80/rebuild

review: Approve (continuous-integration)
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

Revision history for this message
Christopher Townsend (townsend) wrote :

Ok, this is good with me. I'm going to get an extra set of eyes on the code though.

review: Approve
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

lgtm

review: Approve
Revision history for this message
Christopher Townsend (townsend) wrote :

Ok, I think we can merge this into the base MP.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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_);

Subscribers

People subscribed via source and target branches

to all changes: