Merge lp:~stolowski/unity-scope-click/departments into lp:unity-scope-click/devel

Proposed by Paweł Stołowski
Status: Superseded
Proposed branch: lp:~stolowski/unity-scope-click/departments
Merge into: lp:unity-scope-click/devel
Diff against target: 2394 lines (+1473/-114) (has conflicts)
33 files modified
CMakeLists.txt (+1/-1)
debian/control (+1/-1)
libclickscope/click/CMakeLists.txt (+3/-0)
libclickscope/click/department-lookup.cpp (+84/-0)
libclickscope/click/department-lookup.h (+58/-0)
libclickscope/click/departments.cpp (+164/-0)
libclickscope/click/departments.h (+83/-0)
libclickscope/click/highlights.cpp (+95/-0)
libclickscope/click/highlights.h (+72/-0)
libclickscope/click/index.cpp (+70/-5)
libclickscope/click/index.h (+7/-2)
libclickscope/click/package.h (+1/-0)
libclickscope/click/preview.cpp (+1/-0)
libclickscope/click/scope_activation.cpp (+11/-5)
libclickscope/click/scope_activation.h (+2/-2)
libclickscope/click/webclient.cpp (+2/-1)
libclickscope/click/webclient.h (+1/-1)
libclickscope/tests/CMakeLists.txt (+2/-0)
libclickscope/tests/fake_json.h (+236/-0)
libclickscope/tests/mock_network_access_manager.h (+1/-0)
libclickscope/tests/mock_webclient.h (+2/-2)
libclickscope/tests/test_bootstrap.cpp (+73/-0)
libclickscope/tests/test_departments.cpp (+108/-0)
libclickscope/tests/test_index.cpp (+10/-10)
scope/clickapps/apps-query.cpp (+11/-12)
scope/clickapps/apps-scope.cpp (+5/-6)
scope/clickapps/apps-scope.h (+3/-3)
scope/clickstore/store-query.cpp (+233/-16)
scope/clickstore/store-query.h (+16/-3)
scope/clickstore/store-scope.cpp (+25/-5)
scope/clickstore/store-scope.h (+12/-2)
scope/tests/integration/webclient_integration.cpp (+3/-1)
scope/tests/test_query.cpp (+77/-36)
Text conflict in scope/clickstore/store-scope.cpp
To merge this branch: bzr merge lp:~stolowski/unity-scope-click/departments
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
dobey (community) Needs Fixing
Review via email: mp+219211@code.launchpad.net

This proposal has been superseded by a proposal from 2014-06-18.

Commit message

Add support for departments and highlights.

Description of the change

Add support for departments and highlights.

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

426 +std::map<std::string, std::string> Index::build_headers(const std::string& language)
438 + {"Accept-Language", language},
486 + QSharedPointer<click::web::Response> response(client->call(
487 + get_base_url() + click::BOOTSTRAP_PATH, "GET", false, build_headers("en"), "", params)); //TODO: language

You don't need to do all this work to pass the language around or set Accept-Language manually. It is already added automatically in web::Client::cal().

review: Needs Fixing
Revision history for this message
dobey (dobey) wrote :

Can you also add a commit with --fixes=lp:1209224 to link that bug?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
dobey (dobey) wrote :
review: Needs Fixing
255. By Paweł Stołowski

Forgot about highlights.

256. By Paweł Stołowski

Merged 0.5.0 update branch.

257. By Paweł Stołowski

Merged devel.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
258. By Paweł Stołowski

Reuse code between bootstrap and departments call.

259. By Paweł Stołowski

Cleanups. Check department href in tests.

260. By Paweł Stołowski

Test get_department_info().

261. By Paweł Stołowski

Added tests for broken departments json.

262. By Paweł Stołowski

Don't pass departments with search.

263. By Paweł Stołowski

Test for invalid highlights. Cleanups.

264. By Paweł Stołowski

Reuse push_package().

265. By Paweł Stołowski

Fixed comment.

266. By Paweł Stołowski

Test bootstrap call.

267. By Paweł Stołowski

Merged devel.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-05-27 13:15:52 +0000
3+++ CMakeLists.txt 2014-06-18 18:08:01 +0000
4@@ -21,7 +21,7 @@
5
6 include(FindPkgConfig)
7
8-pkg_check_modules(UNITY_SCOPES REQUIRED libunity-scopes>=0.4.0 libunity-api>=0.1.3)
9+pkg_check_modules(UNITY_SCOPES REQUIRED libunity-scopes>=0.5.0 libunity-api>=0.1.3)
10 add_definitions(${UNITY_SCOPES_CFLAGS} ${UNITY_SCOPES_CFLAGS_OTHER})
11
12 find_package (PkgConfig REQUIRED)
13
14=== modified file 'debian/control'
15--- debian/control 2014-06-13 15:21:16 +0000
16+++ debian/control 2014-06-18 18:08:01 +0000
17@@ -13,7 +13,7 @@
18 libubuntu-download-manager-common-dev (>= 0.3+14.10.20140430-0ubuntu1),
19 libubuntuoneauth-2.0-dev,
20 libunity-api-dev (>= 7.80.7),
21- libunity-scopes-dev (>= 0.4.0),
22+ libunity-scopes-dev (>= 0.5.0),
23 pkg-config,
24 python3-all,
25 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
26
27=== modified file 'libclickscope/click/CMakeLists.txt'
28--- libclickscope/click/CMakeLists.txt 2014-06-13 15:21:16 +0000
29+++ libclickscope/click/CMakeLists.txt 2014-06-18 18:08:01 +0000
30@@ -11,6 +11,9 @@
31 add_library(${SCOPE_LIB_NAME} STATIC
32 configuration.cpp
33 download-manager.cpp
34+ department-lookup.cpp
35+ departments.cpp
36+ highlights.cpp
37 index.cpp
38 interface.cpp
39 key_file_locator.cpp
40
41=== added file 'libclickscope/click/department-lookup.cpp'
42--- libclickscope/click/department-lookup.cpp 1970-01-01 00:00:00 +0000
43+++ libclickscope/click/department-lookup.cpp 2014-06-18 18:08:01 +0000
44@@ -0,0 +1,84 @@
45+/*
46+ * Copyright (C) 2014 Canonical Ltd.
47+ *
48+ * This program is free software: you can redistribute it and/or modify it
49+ * under the terms of the GNU General Public License version 3, as published
50+ * by the Free Software Foundation.
51+ *
52+ * This program is distributed in the hope that it will be useful, but
53+ * WITHOUT ANY WARRANTY; without even the implied warranties of
54+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
55+ * PURPOSE. See the GNU General Public License for more details.
56+ *
57+ * You should have received a copy of the GNU General Public License along
58+ * with this program. If not, see <http://www.gnu.org/licenses/>.
59+ *
60+ * In addition, as a special exception, the copyright holders give
61+ * permission to link the code of portions of this program with the
62+ * OpenSSL library under certain conditions as described in each
63+ * individual source file, and distribute linked combinations
64+ * including the two.
65+ * You must obey the GNU General Public License in all respects
66+ * for all of the code used other than OpenSSL. If you modify
67+ * file(s) with this exception, you may extend this exception to your
68+ * version of the file(s), but you are not obligated to do so. If you
69+ * do not wish to do so, delete this exception statement from your
70+ * version. If you delete this exception statement from all source
71+ * files in the program, then also delete it here.
72+ */
73+
74+#include "department-lookup.h"
75+
76+namespace click
77+{
78+
79+DepartmentLookup::DepartmentLookup()
80+{
81+}
82+
83+void DepartmentLookup::rebuild(const Department::SPtr& dept)
84+{
85+ departments[dept->id()] = dept;
86+ for (auto const& subdep: dept->sub_departments())
87+ {
88+ parent_lut[subdep->id()] = dept;
89+ rebuild(subdep);
90+ }
91+}
92+
93+void DepartmentLookup::rebuild(const std::list<Department::SPtr>& root_departments)
94+{
95+ parent_lut.clear();
96+ departments.clear();
97+ for (auto const& dep: root_departments)
98+ {
99+ rebuild(dep);
100+ }
101+}
102+
103+Department::SPtr DepartmentLookup::get_parent(const std::string& department_id) const
104+{
105+ auto it = parent_lut.find(department_id);
106+ if (it != parent_lut.end())
107+ {
108+ return it->second;
109+ }
110+ return Department::SPtr(nullptr);
111+}
112+
113+Department::SPtr DepartmentLookup::get_department_info(const std::string& department_id) const
114+{
115+ auto it = departments.find(department_id);
116+ if (it != departments.end())
117+ {
118+ return it->second;
119+ }
120+ return nullptr;
121+}
122+
123+int DepartmentLookup::size() const
124+{
125+ return parent_lut.size();
126+}
127+
128+}
129
130=== added file 'libclickscope/click/department-lookup.h'
131--- libclickscope/click/department-lookup.h 1970-01-01 00:00:00 +0000
132+++ libclickscope/click/department-lookup.h 2014-06-18 18:08:01 +0000
133@@ -0,0 +1,58 @@
134+/*
135+ * Copyright (C) 2014 Canonical Ltd.
136+ *
137+ * This program is free software: you can redistribute it and/or modify it
138+ * under the terms of the GNU General Public License version 3, as published
139+ * by the Free Software Foundation.
140+ *
141+ * This program is distributed in the hope that it will be useful, but
142+ * WITHOUT ANY WARRANTY; without even the implied warranties of
143+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
144+ * PURPOSE. See the GNU General Public License for more details.
145+ *
146+ * You should have received a copy of the GNU General Public License along
147+ * with this program. If not, see <http://www.gnu.org/licenses/>.
148+ *
149+ * In addition, as a special exception, the copyright holders give
150+ * permission to link the code of portions of this program with the
151+ * OpenSSL library under certain conditions as described in each
152+ * individual source file, and distribute linked combinations
153+ * including the two.
154+ * You must obey the GNU General Public License in all respects
155+ * for all of the code used other than OpenSSL. If you modify
156+ * file(s) with this exception, you may extend this exception to your
157+ * version of the file(s), but you are not obligated to do so. If you
158+ * do not wish to do so, delete this exception statement from your
159+ * version. If you delete this exception statement from all source
160+ * files in the program, then also delete it here.
161+ */
162+
163+#ifndef CLICK_DEPARTMENT_LOOKUP_H
164+#define CLICK_DEPARTMENT_LOOKUP_H
165+
166+#include "departments.h"
167+#include <string>
168+#include <memory>
169+#include <map>
170+
171+namespace click
172+{
173+
174+class DepartmentLookup
175+{
176+ public:
177+ DepartmentLookup();
178+ void rebuild(const std::list<Department::SPtr>& root_departments);
179+ Department::SPtr get_parent(const std::string& department_id) const;
180+ Department::SPtr get_department_info(const std::string& department_id) const;
181+ int size() const;
182+
183+ private:
184+ void rebuild(const Department::SPtr& dept);
185+ std::map<std::string, Department::SPtr> parent_lut;
186+ std::map<std::string, Department::SPtr> departments;
187+};
188+
189+}
190+
191+#endif
192
193=== added file 'libclickscope/click/departments.cpp'
194--- libclickscope/click/departments.cpp 1970-01-01 00:00:00 +0000
195+++ libclickscope/click/departments.cpp 2014-06-18 18:08:01 +0000
196@@ -0,0 +1,164 @@
197+/*
198+ * Copyright (C) 2014 Canonical Ltd.
199+ *
200+ * This program is free software: you can redistribute it and/or modify it
201+ * under the terms of the GNU General Public License version 3, as published
202+ * by the Free Software Foundation.
203+ *
204+ * This program is distributed in the hope that it will be useful, but
205+ * WITHOUT ANY WARRANTY; without even the implied warranties of
206+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
207+ * PURPOSE. See the GNU General Public License for more details.
208+ *
209+ * You should have received a copy of the GNU General Public License along
210+ * with this program. If not, see <http://www.gnu.org/licenses/>.
211+ *
212+ * In addition, as a special exception, the copyright holders give
213+ * permission to link the code of portions of this program with the
214+ * OpenSSL library under certain conditions as described in each
215+ * individual source file, and distribute linked combinations
216+ * including the two.
217+ * You must obey the GNU General Public License in all respects
218+ * for all of the code used other than OpenSSL. If you modify
219+ * file(s) with this exception, you may extend this exception to your
220+ * version of the file(s), but you are not obligated to do so. If you
221+ * do not wish to do so, delete this exception statement from your
222+ * version. If you delete this exception statement from all source
223+ * files in the program, then also delete it here.
224+ */
225+
226+#include "departments.h"
227+#include <iostream>
228+
229+namespace click
230+{
231+
232+/*Department::Department(const std::string& id, const std::string& name)
233+ : id_(id),
234+ name_(name),
235+ href_(""), //FIXME
236+ has_children_flag_(false)
237+{
238+}*/
239+
240+Department::Department(const std::string& id, const std::string &name, const std::string& href, bool has_children)
241+ : id_(id),
242+ name_(name),
243+ href_(href),
244+ has_children_flag_(has_children)
245+{
246+}
247+
248+std::string Department::id() const
249+{
250+ return id_;
251+}
252+
253+std::string Department::name() const
254+{
255+ return name_;
256+}
257+
258+std::string Department::href() const
259+{
260+ return href_;
261+}
262+
263+bool Department::has_children_flag() const
264+{
265+ return has_children_flag_;
266+}
267+
268+void Department::set_subdepartments(const std::list<Department::SPtr>& deps)
269+{
270+ sub_departments_ = deps;
271+}
272+
273+std::list<Department::SPtr> Department::sub_departments() const
274+{
275+ return sub_departments_;
276+}
277+
278+std::list<Department::SPtr> Department::from_json_node(const Json::Value& node)
279+{
280+ std::list<Department::SPtr> deps;
281+
282+ for (uint i = 0; i < node.size(); i++)
283+ {
284+ auto const item = node[i];
285+ if (item.isObject() && item.isMember(Department::JsonKeys::name))
286+ {
287+ auto name = item[Department::JsonKeys::name].asString();
288+ const bool has_children = item.isMember(Department::JsonKeys::has_children) ? item[Department::JsonKeys::has_children].asBool() : false;
289+
290+ auto const links = item[Department::JsonKeys::links];
291+ auto const self = links[Department::JsonKeys::self];
292+ auto const href = self[Department::JsonKeys::href].asString();
293+
294+ auto dep = std::make_shared<Department>(name, name, href, has_children); //FIXME: id
295+ if (item.isObject() && item.isMember(Department::JsonKeys::embedded))
296+ {
297+ auto const emb = item[Department::JsonKeys::embedded];
298+ if (emb.isObject() && emb.isMember(Department::JsonKeys::department))
299+ {
300+ auto const ditem = emb[Department::JsonKeys::department];
301+ auto const subdeps = from_json_node(ditem);
302+ dep->set_subdepartments(subdeps);
303+ }
304+ }
305+ deps.push_back(dep);
306+ }
307+ }
308+
309+ return deps;
310+}
311+
312+std::list<Department::SPtr> Department::from_json_root_node(const Json::Value& root)
313+{
314+ if (root.isObject() && root.isMember(Department::JsonKeys::embedded))
315+ {
316+ auto const emb = root[Department::JsonKeys::embedded];
317+ if (emb.isObject() && emb.isMember(Department::JsonKeys::department))
318+ {
319+ auto const ditem = emb[Department::JsonKeys::department];
320+ return from_json_node(ditem);
321+ }
322+ }
323+
324+ return std::list<Department::SPtr>();
325+}
326+
327+std::list<Department::SPtr> Department::from_json(const std::string& json)
328+{
329+ Json::Reader reader;
330+ Json::Value root;
331+
332+ try
333+ {
334+ if (!reader.parse(json, root)) {
335+ throw std::runtime_error(reader.getFormattedErrorMessages());
336+ }
337+
338+ if (root.isObject() && root.isMember(Department::JsonKeys::embedded))
339+ {
340+ auto const emb = root[Department::JsonKeys::embedded];
341+ if (emb.isObject() && emb.isMember(Department::JsonKeys::department))
342+ {
343+ auto const ditem = emb[Department::JsonKeys::department];
344+ return from_json_node(ditem);
345+ }
346+ }
347+ }
348+ catch (const std::exception& e)
349+ {
350+ std::cerr << "Error parsing departments: " << e.what() << std::endl;
351+ }
352+ catch (...)
353+ {
354+ std::cerr << "Unknown error when parsing departments" << std::endl;
355+ }
356+
357+ return std::list<Department::SPtr>();
358+}
359+
360+}
361
362=== added file 'libclickscope/click/departments.h'
363--- libclickscope/click/departments.h 1970-01-01 00:00:00 +0000
364+++ libclickscope/click/departments.h 2014-06-18 18:08:01 +0000
365@@ -0,0 +1,83 @@
366+/*
367+ * Copyright (C) 2014 Canonical Ltd.
368+ *
369+ * This program is free software: you can redistribute it and/or modify it
370+ * under the terms of the GNU General Public License version 3, as published
371+ * by the Free Software Foundation.
372+ *
373+ * This program is distributed in the hope that it will be useful, but
374+ * WITHOUT ANY WARRANTY; without even the implied warranties of
375+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
376+ * PURPOSE. See the GNU General Public License for more details.
377+ *
378+ * You should have received a copy of the GNU General Public License along
379+ * with this program. If not, see <http://www.gnu.org/licenses/>.
380+ *
381+ * In addition, as a special exception, the copyright holders give
382+ * permission to link the code of portions of this program with the
383+ * OpenSSL library under certain conditions as described in each
384+ * individual source file, and distribute linked combinations
385+ * including the two.
386+ * You must obey the GNU General Public License in all respects
387+ * for all of the code used other than OpenSSL. If you modify
388+ * file(s) with this exception, you may extend this exception to your
389+ * version of the file(s), but you are not obligated to do so. If you
390+ * do not wish to do so, delete this exception statement from your
391+ * version. If you delete this exception statement from all source
392+ * files in the program, then also delete it here.
393+ */
394+
395+#ifndef CLICK_DEPARTMENTS_H
396+#define CLICK_DEPARTMENTS_H
397+
398+#include <string>
399+#include <list>
400+#include <memory>
401+#include <json/json.h>
402+
403+namespace click
404+{
405+
406+class Department
407+{
408+ public:
409+ typedef std::shared_ptr<Department> SPtr;
410+ typedef std::shared_ptr<Department const> SCPtr;
411+
412+ struct JsonKeys
413+ {
414+ JsonKeys() = delete;
415+ constexpr static const char* name {"name"};
416+ constexpr static const char* embedded {"_embedded"};
417+ constexpr static const char* department {"clickindex:department"};
418+ constexpr static const char* has_children {"has_children"};
419+ constexpr static const char* links {"_links"};
420+ constexpr static const char* self {"self"};
421+ constexpr static const char* href {"href"};
422+ };
423+
424+ //Department(const std::string &id, const std::string &name);
425+ Department(const std::string &id, const std::string &name, const std::string& href, bool has_children);
426+ std::string id() const;
427+ std::string name() const;
428+ std::string href() const;
429+ bool has_children_flag() const;
430+ void set_subdepartments(const std::list<Department::SPtr>& deps);
431+ std::list<Department::SPtr> sub_departments() const;
432+ static std::list<Department::SPtr> from_json(const std::string& json);
433+ static std::list<Department::SPtr> from_json_root_node(const Json::Value& val);
434+
435+ private:
436+ static std::list<Department::SPtr> from_json_node(const Json::Value& val);
437+ std::string id_;
438+ std::string name_;
439+ std::string href_;
440+ bool has_children_flag_;
441+ std::list<Department::SPtr> sub_departments_;
442+};
443+
444+typedef std::list<Department::SPtr> DepartmentList;
445+
446+}
447+
448+#endif
449
450=== added file 'libclickscope/click/highlights.cpp'
451--- libclickscope/click/highlights.cpp 1970-01-01 00:00:00 +0000
452+++ libclickscope/click/highlights.cpp 2014-06-18 18:08:01 +0000
453@@ -0,0 +1,95 @@
454+/*
455+ * Copyright (C) 2014 Canonical Ltd.
456+ *
457+ * This program is free software: you can redistribute it and/or modify it
458+ * under the terms of the GNU General Public License version 3, as published
459+ * by the Free Software Foundation.
460+ *
461+ * This program is distributed in the hope that it will be useful, but
462+ * WITHOUT ANY WARRANTY; without even the implied warranties of
463+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
464+ * PURPOSE. See the GNU General Public License for more details.
465+ *
466+ * You should have received a copy of the GNU General Public License along
467+ * with this program. If not, see <http://www.gnu.org/licenses/>.
468+ *
469+ * In addition, as a special exception, the copyright holders give
470+ * permission to link the code of portions of this program with the
471+ * OpenSSL library under certain conditions as described in each
472+ * individual source file, and distribute linked combinations
473+ * including the two.
474+ * You must obey the GNU General Public License in all respects
475+ * for all of the code used other than OpenSSL. If you modify
476+ * file(s) with this exception, you may extend this exception to your
477+ * version of the file(s), but you are not obligated to do so. If you
478+ * do not wish to do so, delete this exception statement from your
479+ * version. If you delete this exception statement from all source
480+ * files in the program, then also delete it here.
481+ */
482+
483+#include "highlights.h"
484+#include <iostream>
485+
486+namespace click
487+{
488+
489+Highlight::Highlight(const std::string& name)
490+ : name_(name)
491+{
492+}
493+
494+Highlight::Highlight(const std::string& name, const Packages& pkgs)
495+ : name_(name),
496+ packages_(pkgs)
497+{
498+}
499+
500+void Highlight::add_package(const Package& pkg)
501+{
502+ packages_.push_back(pkg);
503+}
504+
505+std::string Highlight::name() const
506+{
507+ return name_;
508+}
509+
510+Packages Highlight::packages() const
511+{
512+ return packages_;
513+}
514+
515+std::list<Highlight> Highlight::from_json_node(const Json::Value& node)
516+{
517+ std::list<Highlight> highlights;
518+
519+ for (uint i = 0; i < node.size(); i++)
520+ {
521+ auto const item = node[i];
522+ if (item.isObject() && item.isMember(Highlight::JsonKeys::name))
523+ {
524+ auto name = item[Highlight::JsonKeys::name].asString();
525+ auto pkgs = package_list_from_json_node(item);
526+ highlights.push_back(Highlight(name, pkgs));
527+ }
528+ }
529+
530+ return highlights;
531+}
532+
533+std::list<Highlight> Highlight::from_json_root_node(const Json::Value& root)
534+{
535+ if (root.isObject() && root.isMember(Highlight::JsonKeys::embedded))
536+ {
537+ auto const emb = root[Highlight::JsonKeys::embedded];
538+ if (emb.isObject() && emb.isMember(Highlight::JsonKeys::highlight))
539+ {
540+ auto const hl = emb[Highlight::JsonKeys::highlight];
541+ return from_json_node(hl);
542+ }
543+ }
544+
545+ return std::list<Highlight>();
546+}
547+
548+}
549
550=== added file 'libclickscope/click/highlights.h'
551--- libclickscope/click/highlights.h 1970-01-01 00:00:00 +0000
552+++ libclickscope/click/highlights.h 2014-06-18 18:08:01 +0000
553@@ -0,0 +1,72 @@
554+/*
555+ * Copyright (C) 2014 Canonical Ltd.
556+ *
557+ * This program is free software: you can redistribute it and/or modify it
558+ * under the terms of the GNU General Public License version 3, as published
559+ * by the Free Software Foundation.
560+ *
561+ * This program is distributed in the hope that it will be useful, but
562+ * WITHOUT ANY WARRANTY; without even the implied warranties of
563+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
564+ * PURPOSE. See the GNU General Public License for more details.
565+ *
566+ * You should have received a copy of the GNU General Public License along
567+ * with this program. If not, see <http://www.gnu.org/licenses/>.
568+ *
569+ * In addition, as a special exception, the copyright holders give
570+ * permission to link the code of portions of this program with the
571+ * OpenSSL library under certain conditions as described in each
572+ * individual source file, and distribute linked combinations
573+ * including the two.
574+ * You must obey the GNU General Public License in all respects
575+ * for all of the code used other than OpenSSL. If you modify
576+ * file(s) with this exception, you may extend this exception to your
577+ * version of the file(s), but you are not obligated to do so. If you
578+ * do not wish to do so, delete this exception statement from your
579+ * version. If you delete this exception statement from all source
580+ * files in the program, then also delete it here.
581+ */
582+
583+#ifndef CLICK_HIGHLIGHTS_H
584+#define CLICK_HIGHLIGHTS_H
585+
586+#include <string>
587+#include <list>
588+#include <json/json.h>
589+#include <click/package.h>
590+
591+namespace click
592+{
593+
594+class Highlight
595+{
596+public:
597+ struct JsonKeys
598+ {
599+ JsonKeys() = delete;
600+ constexpr static const char* name {"name"};
601+ constexpr static const char* embedded {"_embedded"};
602+ constexpr static const char* highlight {"clickindex:highlight"};
603+ };
604+
605+ Highlight(const std::string& name);
606+ Highlight(const std::string& name, const Packages& pkgs);
607+ void add_package(const Package& pkg);
608+
609+ std::string name() const;
610+ Packages packages() const;
611+
612+ static std::list<Highlight> from_json_root_node(const Json::Value& val);
613+
614+private:
615+ static std::list<Highlight> from_json_node(const Json::Value& val);
616+
617+ std::string name_;
618+ Packages packages_;
619+};
620+
621+typedef std::list<Highlight> HighlightList;
622+
623+}
624+
625+#endif
626
627=== modified file 'libclickscope/click/index.cpp'
628--- libclickscope/click/index.cpp 2014-06-12 21:05:25 +0000
629+++ libclickscope/click/index.cpp 2014-06-18 18:08:01 +0000
630@@ -88,11 +88,15 @@
631
632 }
633
634-std::string Index::build_index_query(const std::string& query)
635+std::string Index::build_index_query(const std::string& query, const std::string& department)
636 {
637 std::stringstream result;
638
639 result << query;
640+ if (!department.empty()) {
641+ result << ",department:" << department;
642+ }
643+
644 return result.str();
645 }
646
647@@ -110,10 +114,10 @@
648 };
649 }
650
651-click::web::Cancellable Index::search (const std::string& query, std::function<void(click::Packages)> callback)
652+click::web::Cancellable Index::search (const std::string& query, const std::string& department, std::function<void(click::Packages, click::DepartmentList)> callback)
653 {
654 click::web::CallParams params;
655- const std::string built_query(build_index_query(query));
656+ const std::string built_query(build_index_query(query, department));
657 params.add(click::QUERY_ARGNAME, built_query.c_str());
658 QSharedPointer<click::web::Response> response(client->call(
659 get_base_url() + click::SEARCH_PATH, "GET", false, build_headers(), "", params));
660@@ -123,22 +127,83 @@
661 Json::Value root;
662
663 click::Packages pl;
664+ click::DepartmentList depts;
665 if (reader.parse(reply.toUtf8().constData(), root)) {
666 pl = click::package_list_from_json_node(root);
667 qDebug() << "found packages:" << pl.size();
668+ depts = click::Department::from_json_root_node(root);
669 }
670- callback(pl);
671+ callback(pl, depts);
672 });
673 QObject::connect(response.data(), &click::web::Response::error, [=](QString /*description*/) {
674 qDebug() << "No packages found due to network error";
675 click::Packages pl;
676+ click::DepartmentList depts;
677 qDebug() << "calling callback";
678- callback(pl);
679+ callback(pl, depts);
680 qDebug() << " ...Done!";
681 });
682 return click::web::Cancellable(response);
683 }
684
685+click::web::Cancellable Index::bootstrap(std::function<void(const click::DepartmentList&, const click::HighlightList&, Error, int)> callback)
686+{
687+ click::web::CallParams params;
688+ QSharedPointer<click::web::Response> response(client->call(
689+ get_base_url() + click::BOOTSTRAP_PATH, "GET", false, build_headers(), "", params));
690+
691+ QObject::connect(response.data(), &click::web::Response::finished, [=](QString reply) {
692+ qDebug() << "bootstrap request finished";
693+ Json::Reader reader;
694+ Json::Value root;
695+
696+ click::DepartmentList depts;
697+ click::HighlightList highlights;
698+ if (reader.parse(reply.toUtf8().constData(), root)) {
699+ depts = Department::from_json_root_node(root);
700+ highlights = Highlight::from_json_root_node(root);
701+ }
702+ callback(depts, highlights, click::Index::Error::NoError, 0);
703+ });
704+ QObject::connect(response.data(), &click::web::Response::error, [=](QString /*description*/, int error_code) {
705+ qWarning() << "bootstrap call failed due to network error, code" << error_code;
706+ const click::DepartmentList depts;
707+ const click::HighlightList highlights;
708+ qDebug() << "bootstrap: calling callback";
709+ callback(depts, highlights, click::Index::Error::NetworkError, error_code);
710+ });
711+ return click::web::Cancellable(response);
712+}
713+
714+click::web::Cancellable Index::departments(const std::string& department_href, std::function<void(const DepartmentList&, const HighlightList&, Error)> callback)
715+{
716+ click::web::CallParams params;
717+ QSharedPointer<click::web::Response> response(client->call(
718+ department_href, "GET", false, build_headers(), "", params));
719+
720+ QObject::connect(response.data(), &click::web::Response::finished, [=](QString reply) {
721+ qDebug() << "departments request finished";
722+ Json::Reader reader;
723+ Json::Value root;
724+
725+ click::DepartmentList depts;
726+ click::HighlightList highlights;
727+ if (reader.parse(reply.toUtf8().constData(), root)) {
728+ depts = Department::from_json_root_node(root);
729+ highlights = Highlight::from_json_root_node(root);
730+ }
731+ callback(depts, highlights, click::Index::Error::NoError);
732+ });
733+ QObject::connect(response.data(), &click::web::Response::error, [=](QString /*description*/) {
734+ qWarning() << "departments call failed due to network error";
735+ const click::DepartmentList depts;
736+ const click::HighlightList highlights;
737+ qDebug() << "departments: calling callback";
738+ callback(depts, highlights, click::Index::Error::NetworkError);
739+ });
740+ return click::web::Cancellable(response);
741+}
742+
743 click::web::Cancellable Index::get_details (const std::string& package_name, std::function<void(PackageDetails, click::Index::Error)> callback)
744 {
745 QSharedPointer<click::web::Response> response = client->call
746
747=== modified file 'libclickscope/click/index.h'
748--- libclickscope/click/index.h 2014-06-12 21:05:25 +0000
749+++ libclickscope/click/index.h 2014-06-18 18:08:01 +0000
750@@ -38,6 +38,8 @@
751 #include <click/webclient.h>
752
753 #include "package.h"
754+#include <click/departments.h>
755+#include <click/highlights.h>
756
757
758 namespace click {
759@@ -47,6 +49,7 @@
760 const std::string SEARCH_BASE_URL_ENVVAR = "U1_SEARCH_BASE_URL";
761 const std::string SEARCH_BASE_URL = "https://search.apps.ubuntu.com/";
762 const std::string SEARCH_PATH = "api/v1/search";
763+const std::string BOOTSTRAP_PATH = "api/v1";
764 const std::string SUPPORTED_FRAMEWORKS = "framework:ubuntu-sdk-13.10";
765 const std::string QUERY_ARGNAME = "q";
766 const std::string ARCHITECTURE = "architecture:";
767@@ -64,15 +67,17 @@
768 protected:
769 QSharedPointer<web::Client> client;
770 QSharedPointer<Configuration> configuration;
771- virtual std::string build_index_query(const std::string& query);
772+ virtual std::string build_index_query(const std::string& query, const std::string& department);
773 virtual std::map<std::string, std::string> build_headers();
774
775 public:
776 enum class Error {NoError, CredentialsError, NetworkError};
777 Index(const QSharedPointer<click::web::Client>& client,
778 const QSharedPointer<Configuration> configuration=QSharedPointer<Configuration>(new Configuration()));
779- virtual click::web::Cancellable search (const std::string& query, std::function<void(Packages)> callback);
780+ virtual click::web::Cancellable search (const std::string& query, const std::string& department, std::function<void(Packages, DepartmentList)> callback);
781 virtual click::web::Cancellable get_details(const std::string& package_name, std::function<void(PackageDetails, Error)> callback);
782+ virtual click::web::Cancellable bootstrap(std::function<void(const DepartmentList&, const HighlightList&, Error, int)> callback);
783+ virtual click::web::Cancellable departments(const std::string& department_href, std::function<void(const DepartmentList&, const HighlightList&, Error)> callback);
784 virtual ~Index();
785
786 static std::string get_base_url ();
787
788=== modified file 'libclickscope/click/package.h'
789--- libclickscope/click/package.h 2014-06-13 22:42:02 +0000
790+++ libclickscope/click/package.h 2014-06-18 18:08:01 +0000
791@@ -34,6 +34,7 @@
792 #include <string>
793 #include <unordered_set>
794 #include <vector>
795+#include <functional>
796
797 #include <json/json.h>
798
799
800=== modified file 'libclickscope/click/preview.cpp'
801--- libclickscope/click/preview.cpp 2014-06-17 21:05:05 +0000
802+++ libclickscope/click/preview.cpp 2014-06-18 18:08:01 +0000
803@@ -57,6 +57,7 @@
804 const unity::scopes::ActionMetadata& metadata,
805 const QSharedPointer<click::web::Client>& client,
806 const QSharedPointer<click::network::AccessManager>& nam)
807+ : PreviewQueryBase(result, metadata)
808 {
809 strategy.reset(choose_strategy(result, metadata, client, nam));
810 }
811
812=== modified file 'libclickscope/click/scope_activation.cpp'
813--- libclickscope/click/scope_activation.cpp 2014-05-28 07:42:24 +0000
814+++ libclickscope/click/scope_activation.cpp 2014-06-18 18:08:01 +0000
815@@ -33,6 +33,11 @@
816 #include <click/qtbridge.h>
817 #include <unity/scopes/ActivationResponse.h>
818
819+click::ScopeActivation::ScopeActivation(const unity::scopes::Result& result, const unity::scopes::ActionMetadata& metadata)
820+ : unity::scopes::ActivationQueryBase(result, metadata)
821+{
822+}
823+
824 unity::scopes::ActivationResponse click::ScopeActivation::activate()
825 {
826 auto response = unity::scopes::ActivationResponse(status_);
827@@ -50,18 +55,19 @@
828 hints_[key] = value;
829 }
830
831-click::PerformUninstallAction::PerformUninstallAction(const unity::scopes::Result& result, const unity::scopes::ActivationResponse& response)
832- : result(result),
833+click::PerformUninstallAction::PerformUninstallAction(const unity::scopes::Result& result, const unity::scopes::ActionMetadata& metadata, const unity::scopes::ActivationResponse& response)
834+ : unity::scopes::ActivationQueryBase(result, metadata),
835 response(response)
836 {
837 }
838
839 unity::scopes::ActivationResponse click::PerformUninstallAction::activate()
840 {
841+ auto const res = result();
842 click::Package package;
843- package.title = result.title();
844- package.name = result["name"].get_string();
845- package.version = result["version"].get_string();
846+ package.title = res.title();
847+ package.name = res["name"].get_string();
848+ package.version = res["version"].get_string();
849 qt::core::world::enter_with_task([this, package] ()
850 {
851 click::PackageManager manager;
852
853=== modified file 'libclickscope/click/scope_activation.h'
854--- libclickscope/click/scope_activation.h 2014-05-28 07:42:24 +0000
855+++ libclickscope/click/scope_activation.h 2014-06-18 18:08:01 +0000
856@@ -40,11 +40,10 @@
857 class PerformUninstallAction: public unity::scopes::ActivationQueryBase
858 {
859 public:
860- PerformUninstallAction(const unity::scopes::Result& result, const unity::scopes::ActivationResponse& response);
861+ PerformUninstallAction(const unity::scopes::Result& result, const unity::scopes::ActionMetadata& metadata, const unity::scopes::ActivationResponse& response);
862 unity::scopes::ActivationResponse activate() override;
863
864 private:
865- unity::scopes::Result result;
866 unity::scopes::ActivationResponse response;
867 };
868
869@@ -53,6 +52,7 @@
870 unity::scopes::ActivationResponse activate() override;
871
872 public:
873+ ScopeActivation(const unity::scopes::Result& result, const unity::scopes::ActionMetadata& metadata);
874 void setStatus(unity::scopes::ActivationResponse::Status status);
875 void setHint(std::string key, unity::scopes::Variant value);
876
877
878=== modified file 'libclickscope/click/webclient.cpp'
879--- libclickscope/click/webclient.cpp 2014-05-23 18:45:01 +0000
880+++ libclickscope/click/webclient.cpp 2014-06-18 18:08:01 +0000
881@@ -176,7 +176,8 @@
882 {
883 auto message = reply->errorString() + QString(" (%1)").arg(network_error);
884 qWarning() << "Network error:" << message << "\n" << reply->readAll();
885- emit error(message);
886+ int error_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
887+ emit error(message, error_code);
888 }
889
890 void click::web::Response::abort()
891
892=== modified file 'libclickscope/click/webclient.h'
893--- libclickscope/click/webclient.h 2014-05-23 18:45:01 +0000
894+++ libclickscope/click/webclient.h 2014-06-18 18:08:01 +0000
895@@ -84,7 +84,7 @@
896
897 signals:
898 void finished(QByteArray result);
899- void error(QString description);
900+ void error(QString description, int error_code);
901
902 private:
903 QSharedPointer<click::network::Reply> reply;
904
905=== modified file 'libclickscope/tests/CMakeLists.txt'
906--- libclickscope/tests/CMakeLists.txt 2014-05-26 14:27:31 +0000
907+++ libclickscope/tests/CMakeLists.txt 2014-06-18 18:08:01 +0000
908@@ -28,6 +28,8 @@
909 test_reviews.cpp
910 test_smartconnect.cpp
911 test_webclient.cpp
912+ test_bootstrap.cpp
913+ test_departments.cpp
914
915 ${CMAKE_CURRENT_BINARY_DIR}/test_data.cpp
916 )
917
918=== modified file 'libclickscope/tests/fake_json.h'
919--- libclickscope/tests/fake_json.h 2014-06-13 23:18:41 +0000
920+++ libclickscope/tests/fake_json.h 2014-06-18 18:08:01 +0000
921@@ -150,6 +150,242 @@
922 }
923 )foo";
924
925+const std::string FAKE_JSON_BOOTSTRAP = R"(
926+ {
927+ "_embedded": {
928+ "clickindex:department": [
929+ {
930+ "has_children": false,
931+ "_links": {
932+ "self": {
933+ "href": "https://search.apps.staging.ubuntu.com/api/v1/departments/fake-subdepartment"}
934+ },
935+ "name": "Fake Subdepartment", "slug": "fake-subdepartment"}
936+ ],
937+ "clickindex:highlight": [
938+ {
939+ "_embedded": {
940+ "clickindex:package": [
941+ {
942+ "publisher": "Awesome Widget Company",
943+ "name": "org.example.awesomelauncher",
944+ "title": "Awesome Launcher",
945+ "price": 1.99,
946+ "_links": {
947+ "self": {
948+ "href": "https://search.apps.staging.ubuntu.com/api/v1/package/org.example.awesomelauncher"}
949+ },
950+ "icon": "http://example.org/media/org.example.awesomelauncher/icons/icon16.png"
951+ },
952+ {
953+ "publisher": "Awesome Widget Company",
954+ "name": "org.example.awesomewidget",
955+ "title": "Awesome Widget", "price": 1.99,
956+ "_links": {
957+ "self": {
958+ "href": "https://search.apps.staging.ubuntu.com/api/v1/package/org.example.awesomewidget"
959+ }
960+ },
961+ "icon": "http://example.org/media/org.example.awesomewidget/icons/icon16.png"}
962+ ]
963+ },
964+ "_links": {
965+ "self": {
966+ "href": "https://search.apps.staging.ubuntu.com/api/v1/highlights/top-apps"
967+ }
968+ },
969+ "name": "Top Apps", "slug": "top-apps"
970+ },
971+ {
972+ "_embedded": {
973+ "clickindex:package": [
974+ {
975+ "publisher": "Awesome Widget Company",
976+ "name": "org.example.awesomelauncher",
977+ "title": "Awesome Launcher",
978+ "price": 1.99,
979+ "_links": {
980+ "self": {
981+ "href": "https://search.apps.staging.ubuntu.com/api/v1/package/org.example.awesomelauncher"
982+ }
983+ },
984+ "icon": "http://example.org/media/org.example.awesomelauncher/icons/icon16.png"
985+ },
986+ {
987+ "publisher": "Awesome Widget Company",
988+ "name": "org.example.awesomewidget",
989+ "title": "Awesome Widget",
990+ "price": 1.99,
991+ "_links": {
992+ "self": {
993+ "href": "https://search.apps.staging.ubuntu.com/api/v1/package/org.example.awesomewidget"
994+ }
995+ },
996+ "icon": "http://example.org/media/org.example.awesomewidget/icons/icon16.png"
997+ }
998+ ]
999+ },
1000+ "_links": {
1001+ "self": {
1002+ "href": "https://search.apps.staging.ubuntu.com/api/v1/highlights/most-purchased"
1003+ }
1004+ },
1005+ "name": "Most Purchased",
1006+ "slug": "most-purchased"
1007+ },
1008+ {
1009+ "_embedded": {
1010+ "clickindex:package": [
1011+ {
1012+ "publisher": "Awesome Widget Company",
1013+ "name": "org.example.awesomelauncher",
1014+ "title": "Awesome Launcher",
1015+ "price": 1.99,
1016+ "_links": {
1017+ "self": {
1018+ "href": "https://search.apps.staging.ubuntu.com/api/v1/package/org.example.awesomelauncher"
1019+ }
1020+ },
1021+ "icon": "http://example.org/media/org.example.awesomelauncher/icons/icon16.png"
1022+ },
1023+ {
1024+ "publisher": "Awesome Widget Company",
1025+ "name": "org.example.awesomewidget",
1026+ "title": "Awesome Widget",
1027+ "price": 1.99,
1028+ "_links": {
1029+ "self": {
1030+ "href": "https://search.apps.staging.ubuntu.com/api/v1/package/org.example.awesomewidget"
1031+ }
1032+ },
1033+ "icon": "http://example.org/media/org.example.awesomewidget/icons/icon16.png"
1034+ }
1035+ ]
1036+ },
1037+ "_links": {
1038+ "self": {
1039+ "href": "https://search.apps.staging.ubuntu.com/api/v1/highlights/new-releases"
1040+ }
1041+ },
1042+ "name": "New Releases",
1043+ "slug": "new-releases"
1044+ }
1045+ ]
1046+ }, "has_children": true,
1047+ "_links": {
1048+ "curies": [
1049+ {
1050+ "href": "https://search.apps.staging.ubuntu.com/docs/v1/relations.html{#rel}",
1051+ "name": "clickindex", "templated": true
1052+ }
1053+ ],
1054+ "self": {
1055+ "href": "https://search.apps.staging.ubuntu.com/api/v1/departments/fake-department-with-subdepartments"
1056+ },
1057+ "collection": {
1058+ "href": "https://search.apps.staging.ubuntu.com/api/v1/departments"
1059+ }
1060+ },
1061+ "name": "Fake Department With Subdepartments",
1062+ "slug": "fake-department-with-subdepartments"
1063+ })";
1064+
1065+const std::string FAKE_JSON_DEPARTMENTS_ONLY = R"(
1066+ {
1067+ "_links": {
1068+ "self": {
1069+ "href": "https://search.apps.ubuntu.com/api/v1/departments"
1070+ },
1071+ "curies": [
1072+ {
1073+ "name": "clickindex",
1074+ "href": "https://search.apps.ubuntu.com/docs/v1/relations.html{#rel}",
1075+ "templated": true
1076+ }
1077+ ]
1078+ },
1079+ "_embedded": {
1080+ "clickindex:department": [
1081+ {
1082+ "name": "Games",
1083+ "_links": {
1084+ "self": {
1085+ "href": "https://search.apps.ubuntu.com/api/v1/departments/Games"
1086+ }
1087+ },
1088+ "_embedded": {
1089+ "clickindex:department": [
1090+ {
1091+ "name": "Board Games",
1092+ "_links": {
1093+ "self": {
1094+ "href": "https://search.apps.ubuntu.com/api/v1/departments/Games/Board+Games"
1095+ }
1096+ }
1097+ }
1098+ ]
1099+ }
1100+ },
1101+ {
1102+ "name": "Graphics",
1103+ "_links": {
1104+ "self": {
1105+ "href": "https://search.apps.ubuntu.com/api/v1/departments/Graphics"
1106+ }
1107+ },
1108+ "_embedded": {
1109+ "clickindex:department": [
1110+ {
1111+ "name": "Drawing",
1112+ "_links": {
1113+ "self": {
1114+ "href": "https://search.apps.ubuntu.com/api/v1/departments/Graphics/Drawing"
1115+ }
1116+ }
1117+ }
1118+ ]
1119+ }
1120+ },
1121+ {
1122+ "name": "Internet",
1123+ "_links": {
1124+ "self": {
1125+ "href": "https://search.apps.ubuntu.com/api/v1/departments/Internet"
1126+ }
1127+ },
1128+ "_embedded": {
1129+ "clickindex:department": [
1130+ {
1131+ "name": "Chat",
1132+ "_links": {
1133+ "self": {
1134+ "href": "https://search.apps.ubuntu.com/api/v1/departments/Internet/Chat"
1135+ }
1136+ }
1137+ },
1138+ {
1139+ "name": "Mail",
1140+ "_links": {
1141+ "self": {
1142+ "href": "https://search.apps.ubuntu.com/api/v1/departments/Internet/Mail"
1143+ }
1144+ }
1145+ },
1146+ {
1147+ "name": "Web Browsers",
1148+ "_links": {
1149+ "self": {
1150+ "href": "https://search.apps.ubuntu.com/api/v1/departments/Internet/Web+Browsers"
1151+ }
1152+ }
1153+ }
1154+ ]
1155+ }
1156+ }
1157+ ]
1158+ }
1159+})";
1160+
1161 const std::string FAKE_JSON_MANIFEST_REMOVABLE = R"foo(
1162 {
1163 "_removable": 1,
1164
1165=== modified file 'libclickscope/tests/mock_network_access_manager.h'
1166--- libclickscope/tests/mock_network_access_manager.h 2014-05-20 19:33:41 +0000
1167+++ libclickscope/tests/mock_network_access_manager.h 2014-06-18 18:08:01 +0000
1168@@ -48,6 +48,7 @@
1169 {
1170 // Set a default value for QByteArray-returning mocked methods.
1171 ::testing::DefaultValue<QByteArray>::Set(QByteArray(""));
1172+ ON_CALL(*this, attribute(::testing::_)).WillByDefault(::testing::Return(0));
1173 }
1174
1175 MOCK_METHOD0(abort, void());
1176
1177=== modified file 'libclickscope/tests/mock_webclient.h'
1178--- libclickscope/tests/mock_webclient.h 2014-05-23 18:45:01 +0000
1179+++ libclickscope/tests/mock_webclient.h 2014-06-18 18:08:01 +0000
1180@@ -86,7 +86,7 @@
1181 const click::web::CallParams& params));
1182 QSharedPointer<click::web::Response> call(
1183 const std::string& iri,
1184- const click::web::CallParams& params=click::web::CallParams()) {
1185+ const click::web::CallParams& params=click::web::CallParams()) override {
1186 return callImpl(iri, "GET", false,
1187 std::map<std::string, std::string>(), "", params);
1188 }
1189@@ -96,7 +96,7 @@
1190 bool sign = false,
1191 const std::map<std::string, std::string>& headers = std::map<std::string, std::string>(),
1192 const std::string& data = "",
1193- const click::web::CallParams& params=click::web::CallParams()) {
1194+ const click::web::CallParams& params=click::web::CallParams()) override {
1195 return callImpl(iri, method, sign, headers, data, params);
1196 }
1197 };
1198
1199=== added file 'libclickscope/tests/test_bootstrap.cpp'
1200--- libclickscope/tests/test_bootstrap.cpp 1970-01-01 00:00:00 +0000
1201+++ libclickscope/tests/test_bootstrap.cpp 2014-06-18 18:08:01 +0000
1202@@ -0,0 +1,73 @@
1203+/*
1204+ * Copyright (C) 2014 Canonical Ltd.
1205+ *
1206+ * This program is free software: you can redistribute it and/or modify it
1207+ * under the terms of the GNU General Public License version 3, as published
1208+ * by the Free Software Foundation.
1209+ *
1210+ * This program is distributed in the hope that it will be useful, but
1211+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1212+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1213+ * PURPOSE. See the GNU General Public License for more details.
1214+ *
1215+ * You should have received a copy of the GNU General Public License along
1216+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1217+ *
1218+ * In addition, as a special exception, the copyright holders give
1219+ * permission to link the code of portions of this program with the
1220+ * OpenSSL library under certain conditions as described in each
1221+ * individual source file, and distribute linked combinations
1222+ * including the two.
1223+ * You must obey the GNU General Public License in all respects
1224+ * for all of the code used other than OpenSSL. If you modify
1225+ * file(s) with this exception, you may extend this exception to your
1226+ * version of the file(s), but you are not obligated to do so. If you
1227+ * do not wish to do so, delete this exception statement from your
1228+ * version. If you delete this exception statement from all source
1229+ * files in the program, then also delete it here.
1230+ */
1231+
1232+#include <gtest/gtest.h>
1233+#include "fake_json.h"
1234+#include <json/reader.h>
1235+#include <json/value.h>
1236+#include <click/highlights.h>
1237+#include <click/departments.h>
1238+
1239+class BootstrapTest: public ::testing::Test
1240+{
1241+ protected:
1242+ void SetUp() override
1243+ {
1244+ }
1245+};
1246+
1247+TEST_F(BootstrapTest, testParsing)
1248+{
1249+ Json::Reader reader;
1250+ Json::Value root;
1251+
1252+ EXPECT_TRUE(reader.parse(FAKE_JSON_BOOTSTRAP, root));
1253+
1254+ {
1255+ auto highlights = click::Highlight::from_json_root_node(root);
1256+ EXPECT_EQ(3u, highlights.size());
1257+ auto it = highlights.begin();
1258+ EXPECT_EQ("Top Apps", it->name());
1259+ EXPECT_EQ(2u, it->packages().size());
1260+ ++it;
1261+ EXPECT_EQ("Most Purchased", it->name());
1262+ EXPECT_EQ(2u, it->packages().size());
1263+ ++it;
1264+ EXPECT_EQ("New Releases", it->name());
1265+ EXPECT_EQ(2u, it->packages().size());
1266+ }
1267+ {
1268+ auto depts = click::Department::from_json_root_node(root);
1269+ EXPECT_EQ(1u, depts.size());
1270+ auto it = depts.begin();
1271+ EXPECT_EQ("Fake Subdepartment", (*it)->name());
1272+ EXPECT_FALSE((*it)->has_children_flag());
1273+ EXPECT_EQ("https://search.apps.staging.ubuntu.com/api/v1/departments/fake-subdepartment", (*it)->href());
1274+ }
1275+}
1276
1277=== removed file 'libclickscope/tests/test_data.cpp'
1278=== added file 'libclickscope/tests/test_departments.cpp'
1279--- libclickscope/tests/test_departments.cpp 1970-01-01 00:00:00 +0000
1280+++ libclickscope/tests/test_departments.cpp 2014-06-18 18:08:01 +0000
1281@@ -0,0 +1,108 @@
1282+/*
1283+ * Copyright (C) 2014 Canonical Ltd.
1284+ *
1285+ * This program is free software: you can redistribute it and/or modify it
1286+ * under the terms of the GNU General Public License version 3, as published
1287+ * by the Free Software Foundation.
1288+ *
1289+ * This program is distributed in the hope that it will be useful, but
1290+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1291+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1292+ * PURPOSE. See the GNU General Public License for more details.
1293+ *
1294+ * You should have received a copy of the GNU General Public License along
1295+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1296+ *
1297+ * In addition, as a special exception, the copyright holders give
1298+ * permission to link the code of portions of this program with the
1299+ * OpenSSL library under certain conditions as described in each
1300+ * individual source file, and distribute linked combinations
1301+ * including the two.
1302+ * You must obey the GNU General Public License in all respects
1303+ * for all of the code used other than OpenSSL. If you modify
1304+ * file(s) with this exception, you may extend this exception to your
1305+ * version of the file(s), but you are not obligated to do so. If you
1306+ * do not wish to do so, delete this exception statement from your
1307+ * version. If you delete this exception statement from all source
1308+ * files in the program, then also delete it here.
1309+ */
1310+
1311+#include <gtest/gtest.h>
1312+#include "fake_json.h"
1313+#include <click/departments.h>
1314+#include <click/department-lookup.h>
1315+
1316+class DepartmentsTest : public ::testing::Test
1317+{
1318+ protected:
1319+ void SetUp() override
1320+ {
1321+ }
1322+};
1323+
1324+TEST_F(DepartmentsTest, testParsing)
1325+{
1326+ const std::string jsonstr(FAKE_JSON_DEPARTMENTS_ONLY);
1327+ auto depts = click::Department::from_json(jsonstr);
1328+ EXPECT_EQ(3u, depts.size());
1329+ auto it = depts.cbegin();
1330+ {
1331+ auto dep = *it;
1332+ EXPECT_EQ("Games", dep->id());
1333+ EXPECT_EQ("Games", dep->name());
1334+ EXPECT_FALSE(dep->has_children_flag());
1335+ auto subdepts = dep->sub_departments();
1336+ EXPECT_EQ(1u, subdepts.size());
1337+ auto sit = subdepts.cbegin();
1338+ EXPECT_EQ("Board Games", (*sit)->name());
1339+ }
1340+ {
1341+ ++it;
1342+ auto dep = *it;
1343+ EXPECT_EQ("Graphics", dep->id());
1344+ EXPECT_EQ("Graphics", dep->name());
1345+ EXPECT_FALSE(dep->has_children_flag());
1346+ auto subdepts = dep->sub_departments();
1347+ EXPECT_EQ(1u, subdepts.size());
1348+ auto sit = subdepts.cbegin();
1349+ EXPECT_EQ("Drawing", (*sit)->name());
1350+ }
1351+ {
1352+ ++it;
1353+ auto dep = *it;
1354+ EXPECT_EQ("Internet", dep->id());
1355+ EXPECT_EQ("Internet", dep->name());
1356+ EXPECT_FALSE(dep->has_children_flag());
1357+ auto subdepts = dep->sub_departments();
1358+ EXPECT_EQ(3u, subdepts.size());
1359+ auto sit = subdepts.cbegin();
1360+ auto subdep = *sit;
1361+ EXPECT_EQ("Chat", subdep->name());
1362+ subdep = *(++sit);
1363+ EXPECT_EQ("Mail", subdep->name());
1364+ subdep = *(++sit);
1365+ EXPECT_EQ("Web Browsers", subdep->name());
1366+ }
1367+}
1368+
1369+TEST_F(DepartmentsTest, testLookup)
1370+{
1371+ auto dep_games = std::make_shared<click::Department>("games", "Games", "", false);
1372+ auto dep_rpg = std::make_shared<click::Department>("rpg", "RPG", "", false);
1373+ auto dep_strategy = std::make_shared<click::Department>("strategy", "Strategy", "", false);
1374+ const std::list<click::Department::SPtr> departments {dep_rpg, dep_strategy};
1375+ dep_games->set_subdepartments(departments);
1376+
1377+ const std::list<click::Department::SPtr> root {dep_games};
1378+ click::DepartmentLookup lut;
1379+ lut.rebuild(root);
1380+
1381+ EXPECT_EQ(2u, lut.size());
1382+ EXPECT_EQ("games", lut.get_parent("strategy")->id());
1383+ EXPECT_EQ("games", lut.get_parent("rpg")->id());
1384+ EXPECT_EQ(nullptr, lut.get_parent("games"));
1385+
1386+ lut.rebuild(root);
1387+ EXPECT_EQ(2u, lut.size());
1388+}
1389+
1390
1391=== modified file 'libclickscope/tests/test_index.cpp'
1392--- libclickscope/tests/test_index.cpp 2014-06-12 21:05:25 +0000
1393+++ libclickscope/tests/test_index.cpp 2014-06-18 18:08:01 +0000
1394@@ -52,8 +52,8 @@
1395 click::Index(client, configuration)
1396 {
1397 }
1398- MOCK_METHOD1(build_index_query, std::string(const std::string&));
1399 MOCK_METHOD0(build_headers, std::map<std::string, std::string>());
1400+ MOCK_METHOD2(build_index_query, std::string(const std::string&, const std::string&));
1401 };
1402
1403 class MockConfiguration : public click::Configuration {
1404@@ -100,7 +100,7 @@
1405 .Times(1)
1406 .WillOnce(Return(response));
1407
1408- indexPtr->search("", [](click::Packages) {});
1409+ indexPtr->search("", "", [](click::Packages, click::DepartmentList) {});
1410 }
1411
1412 TEST_F(IndexTest, testSearchSendsBuiltQueryAsParam)
1413@@ -116,11 +116,11 @@
1414 .Times(1)
1415 .WillOnce(Return(response));
1416
1417- EXPECT_CALL(*indexPtr, build_index_query(FAKE_QUERY))
1418+ EXPECT_CALL(*indexPtr, build_index_query(FAKE_QUERY, ""))
1419 .Times(1)
1420 .WillOnce(Return(FAKE_BUILT_QUERY));
1421
1422- indexPtr->search(FAKE_QUERY, [](click::Packages) {});
1423+ indexPtr->search(FAKE_QUERY, "", [](click::Packages, click::DepartmentList) {});
1424 }
1425
1426 TEST_F(IndexTest, testSearchSendsRightPath)
1427@@ -133,7 +133,7 @@
1428 .Times(1)
1429 .WillOnce(Return(response));
1430
1431- indexPtr->search("", [](click::Packages) {});
1432+ indexPtr->search("", "", [](click::Packages, click::DepartmentList) {});
1433 }
1434
1435 TEST_F(IndexTest, testSearchCallbackIsCalled)
1436@@ -150,7 +150,7 @@
1437 .WillOnce(Return(response));
1438 EXPECT_CALL(*this, search_callback(_)).Times(1);
1439
1440- indexPtr->search("", [this](click::Packages packages){
1441+ indexPtr->search("", "", [this](click::Packages packages, click::DepartmentList){
1442 search_callback(packages);
1443 });
1444 response->replyFinished();
1445@@ -171,7 +171,7 @@
1446 click::Packages empty_package_list;
1447 EXPECT_CALL(*this, search_callback(empty_package_list)).Times(1);
1448
1449- indexPtr->search("", [this](click::Packages packages){
1450+ indexPtr->search("", "", [this](click::Packages packages, click::DepartmentList){
1451 search_callback(packages);
1452 });
1453 response->replyFinished();
1454@@ -200,7 +200,7 @@
1455 };
1456 EXPECT_CALL(*this, search_callback(single_package_list)).Times(1);
1457
1458- indexPtr->search("", [this](click::Packages packages){
1459+ indexPtr->search("", "", [this](click::Packages packages, click::DepartmentList){
1460 search_callback(packages);
1461 });
1462 response->replyFinished();
1463@@ -215,7 +215,7 @@
1464 .Times(1)
1465 .WillOnce(Return(response));
1466
1467- auto search_operation = indexPtr->search("", [](click::Packages) {});
1468+ auto search_operation = indexPtr->search("", "", [](click::Packages, click::DepartmentList) {});
1469 EXPECT_CALL(reply.instance, abort()).Times(1);
1470 search_operation.cancel();
1471 }
1472@@ -234,7 +234,7 @@
1473 .Times(1)
1474 .WillOnce(Return(response));
1475 EXPECT_CALL(reply.instance, errorString()).Times(1).WillOnce(Return("fake error"));
1476- indexPtr->search("", [this](click::Packages packages){
1477+ indexPtr->search("", "", [this](click::Packages packages, click::DepartmentList){
1478 search_callback(packages);
1479 });
1480
1481
1482=== modified file 'scope/clickapps/apps-query.cpp'
1483--- scope/clickapps/apps-query.cpp 2014-06-10 21:09:52 +0000
1484+++ scope/clickapps/apps-query.cpp 2014-06-18 18:08:01 +0000
1485@@ -128,25 +128,24 @@
1486
1487 struct click::Query::Private
1488 {
1489- Private(const unity::scopes::CannedQuery& query, click::Index& index, const scopes::SearchMetadata& metadata)
1490- : query(query),
1491- index(index),
1492+ Private(click::Index& index, const scopes::SearchMetadata& metadata)
1493+ : index(index),
1494 meta(metadata)
1495 {
1496 }
1497- unity::scopes::CannedQuery query;
1498 click::Index& index;
1499 scopes::SearchMetadata meta;
1500 };
1501
1502 click::Query::Query(unity::scopes::CannedQuery const& query, click::Index& index, scopes::SearchMetadata const& metadata)
1503- : impl(new Private(query, index, metadata))
1504+ : unity::scopes::SearchQueryBase(query, metadata),
1505+ impl(new Private(index, metadata))
1506 {
1507 }
1508
1509 void click::Query::cancelled()
1510 {
1511- qDebug() << "cancelling search of" << QString::fromStdString(impl->query.query_string());
1512+ qDebug() << "cancelling search of" << QString::fromStdString(query().query_string());
1513 }
1514
1515 click::Query::~Query()
1516@@ -171,10 +170,10 @@
1517 static const std::string title = _("Get more apps in Ubuntu store");
1518 auto name = title;
1519
1520- std::string query = impl->query.query_string();
1521- std::transform(query.begin(), query.end(), query.begin(), ::tolower);
1522+ std::string querystr = query().query_string();
1523+ std::transform(querystr.begin(), querystr.end(), querystr.begin(), ::tolower);
1524 std::transform(name.begin(), name.end(), name.begin(), ::tolower);
1525- if (query.empty() || name.find(query) != std::string::npos)
1526+ if (querystr.empty() || name.find(querystr) != std::string::npos)
1527 {
1528 scopes::CategoryRenderer rdr(CATEGORY_STORE);
1529 auto cat = searchReply->register_category("store", "", "", rdr);
1530@@ -196,13 +195,13 @@
1531
1532 void click::Query::run(scopes::SearchReplyProxy const& searchReply)
1533 {
1534- auto query = impl->query.query_string();
1535+ auto querystr = query().query_string();
1536 std::string categoryTemplate = CATEGORY_APPS_SEARCH;
1537- if (query.empty()) {
1538+ if (querystr.empty()) {
1539 categoryTemplate = CATEGORY_APPS_DISPLAY;
1540 }
1541 auto localResults = clickInterfaceInstance().find_installed_apps(
1542- query);
1543+ querystr);
1544
1545 push_local_results(
1546 searchReply,
1547
1548=== modified file 'scope/clickapps/apps-scope.cpp'
1549--- scope/clickapps/apps-scope.cpp 2014-06-12 14:26:26 +0000
1550+++ scope/clickapps/apps-scope.cpp 2014-06-18 18:08:01 +0000
1551@@ -54,13 +54,11 @@
1552 {
1553 }
1554
1555-int click::Scope::start(std::string const&, scopes::RegistryProxy const&)
1556+void click::Scope::start(std::string const&, scopes::RegistryProxy const&)
1557 {
1558 setlocale(LC_ALL, "");
1559 bindtextdomain(GETTEXT_PACKAGE, GETTEXT_LOCALEDIR);
1560 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
1561-
1562- return VERSION;
1563 }
1564
1565 void click::Scope::run()
1566@@ -91,14 +89,15 @@
1567 }
1568
1569
1570-unity::scopes::ActivationQueryBase::UPtr click::Scope::perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& /* widget_id */, std::string const& action_id)
1571+unity::scopes::ActivationQueryBase::UPtr click::Scope::perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata,
1572+ std::string const& /* widget_id */, std::string const& action_id)
1573 {
1574 if (action_id == click::Preview::Actions::CONFIRM_UNINSTALL) {
1575 const unity::scopes::CannedQuery cquery("clickscope");
1576- return scopes::ActivationQueryBase::UPtr(new PerformUninstallAction(result, unity::scopes::ActivationResponse(cquery)));
1577+ return scopes::ActivationQueryBase::UPtr(new PerformUninstallAction(result, metadata, unity::scopes::ActivationResponse(cquery)));
1578 }
1579
1580- auto activation = new ScopeActivation();
1581+ auto activation = new ScopeActivation(result, metadata);
1582 qDebug() << "perform_action called with action_id" << QString().fromStdString(action_id);
1583
1584 if (action_id == click::Preview::Actions::UNINSTALL_CLICK) {
1585
1586=== modified file 'scope/clickapps/apps-scope.h'
1587--- scope/clickapps/apps-scope.h 2014-05-27 06:57:52 +0000
1588+++ scope/clickapps/apps-scope.h 2014-06-18 18:08:01 +0000
1589@@ -49,14 +49,14 @@
1590 Scope();
1591 ~Scope();
1592
1593- virtual int start(std::string const&, scopes::RegistryProxy const&) override;
1594+ virtual void start(std::string const&, scopes::RegistryProxy const&) override;
1595
1596 virtual void run() override;
1597 virtual void stop() override;
1598
1599- virtual scopes::SearchQueryBase::UPtr search(scopes::CannedQuery const& q, scopes::SearchMetadata const&) override;
1600+ virtual scopes::SearchQueryBase::UPtr search(scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata) override;
1601 unity::scopes::PreviewQueryBase::UPtr preview(const unity::scopes::Result&,
1602- const unity::scopes::ActionMetadata&) override;
1603+ const unity::scopes::ActionMetadata& hints) override;
1604
1605 virtual unity::scopes::ActivationQueryBase::UPtr perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& widget_id, std::string const& action_id) override;
1606
1607
1608=== modified file 'scope/clickstore/store-query.cpp'
1609--- scope/clickstore/store-query.cpp 2014-06-13 23:18:41 +0000
1610+++ scope/clickstore/store-query.cpp 2014-06-18 18:08:01 +0000
1611@@ -30,6 +30,7 @@
1612 #include <click/application.h>
1613 #include <click/interface.h>
1614 #include "store-query.h"
1615+#include "store-scope.h"
1616 #include <click/qtbridge.h>
1617
1618 #include <click/key_file_locator.h>
1619@@ -37,6 +38,7 @@
1620 #include <unity/scopes/Annotation.h>
1621 #include <unity/scopes/CategoryRenderer.h>
1622 #include <unity/scopes/CategorisedResult.h>
1623+#include <unity/scopes/Department.h>
1624 #include <unity/scopes/CannedQuery.h>
1625 #include <unity/scopes/SearchReply.h>
1626 #include <unity/scopes/SearchMetadata.h>
1627@@ -93,20 +95,26 @@
1628
1629 struct click::Query::Private
1630 {
1631- Private(const unity::scopes::CannedQuery& query, click::Index& index, const scopes::SearchMetadata& metadata)
1632- : query(query),
1633- index(index),
1634+ Private(click::Index& index, click::DepartmentLookup& depts,
1635+ click::HighlightList& highlights, const scopes::SearchMetadata& metadata)
1636+ : index(index),
1637+ department_lookup(depts),
1638+ highlights(highlights),
1639 meta(metadata)
1640 {
1641 }
1642- unity::scopes::CannedQuery query;
1643 click::Index& index;
1644+ click::DepartmentLookup& department_lookup;
1645+ click::HighlightList& highlights;
1646 scopes::SearchMetadata meta;
1647 click::web::Cancellable search_operation;
1648 };
1649
1650-click::Query::Query(unity::scopes::CannedQuery const& query, click::Index& index, scopes::SearchMetadata const& metadata)
1651- : impl(new Private(query, index, metadata))
1652+click::Query::Query(unity::scopes::CannedQuery const& query, click::Index& index, click::DepartmentLookup& depts,
1653+ click::HighlightList& highlights,
1654+ scopes::SearchMetadata const& metadata)
1655+ : unity::scopes::SearchQueryBase(query, metadata),
1656+ impl(new Private(index, depts, highlights, metadata))
1657 {
1658 }
1659
1660@@ -117,7 +125,7 @@
1661
1662 void click::Query::cancelled()
1663 {
1664- qDebug() << "cancelling search of" << QString::fromStdString(impl->query.query_string());
1665+ qDebug() << "cancelling search of" << QString::fromStdString(query().query_string());
1666 impl->search_operation.cancel();
1667 }
1668
1669@@ -155,6 +163,166 @@
1670 });
1671 }
1672
1673+//
1674+// creates department menu with narrowed-down list of subdepartments of current department, as
1675+// returned by server call
1676+void click::Query::populate_departments(const click::DepartmentList& subdepts, const std::string& current_dep_id, unity::scopes::Department::SPtr &root)
1677+{
1678+ unity::scopes::DepartmentList departments;
1679+
1680+ // create a list of subdepartments of current department
1681+ foreach (auto d, subdepts)
1682+ {
1683+ unity::scopes::Department::SPtr department = unity::scopes::Department::create(d->id(), query(), d->name());
1684+ if (d->has_children_flag())
1685+ {
1686+ department->set_has_subdepartments();
1687+ }
1688+ departments.push_back(department);
1689+ }
1690+
1691+ if (current_dep_id != "")
1692+ {
1693+ auto curr_dpt = impl->department_lookup.get_department_info(current_dep_id);
1694+ if (curr_dpt != nullptr)
1695+ {
1696+ unity::scopes::Department::SPtr current = unity::scopes::Department::create(current_dep_id, query(), curr_dpt->name());
1697+ if (departments.size() > 0) // this may be a leaf department
1698+ {
1699+ current->set_subdepartments(departments);
1700+ }
1701+
1702+ auto parent_info = impl->department_lookup.get_parent(current_dep_id);
1703+ if (parent_info != nullptr)
1704+ {
1705+ root = unity::scopes::Department::create(parent_info->id(), query(), parent_info->name());
1706+ root->set_subdepartments({current});
1707+ return;
1708+ }
1709+ else
1710+ {
1711+ root = unity::scopes::Department::create("", query(), _("All departments"));
1712+ root->set_subdepartments({current});
1713+ return;
1714+ }
1715+ }
1716+ else
1717+ {
1718+ qWarning() << "Unknown department:" << QString::fromStdString(current_dep_id);
1719+ }
1720+ }
1721+
1722+ root = unity::scopes::Department::create("", query(), _("All departments"));
1723+ root->set_subdepartments(departments);
1724+}
1725+
1726+void click::Query::push_package(const scopes::SearchReplyProxy& searchReply, scopes::Category::SCPtr category, const PackageSet &installedPackages, const Package& pkg)
1727+{
1728+ qDebug() << "pushing result" << QString::fromStdString(pkg.name);
1729+ try {
1730+ scopes::CategorisedResult res(category);
1731+ res.set_title(pkg.title);
1732+ res.set_art(pkg.icon_url);
1733+ res.set_uri(pkg.url);
1734+ res[click::Query::ResultKeys::NAME] = pkg.name;
1735+ auto installed = installedPackages.find(pkg);
1736+ if (installed != installedPackages.end()) {
1737+ res[click::Query::ResultKeys::INSTALLED] = true;
1738+ res["subtitle"] = _("✔ INSTALLED");
1739+ res[click::Query::ResultKeys::VERSION] = installed->version;
1740+ } else {
1741+ res[click::Query::ResultKeys::INSTALLED] = false;
1742+ // TODO: get the real price from the webservice (upcoming branch)
1743+ res["subtitle"] = _("FREE");
1744+ }
1745+
1746+ this->push_result(searchReply, res);
1747+ } catch(const std::exception& e){
1748+ qDebug() << "PackageDetails::loadJson: Exception thrown while decoding JSON: " << e.what() ;
1749+ } catch(...){
1750+ qDebug() << "no reason to catch";
1751+ }
1752+}
1753+
1754+void click::Query::push_highlights(const scopes::SearchReplyProxy& searchReply, const HighlightList& highlights, const PackageSet &locallyInstalledApps)
1755+{
1756+ std::string categoryTemplate = CATEGORY_APPS_DISPLAY; //FIXME
1757+ scopes::CategoryRenderer renderer(categoryTemplate);
1758+
1759+ for (auto const& hl: highlights)
1760+ {
1761+ auto category = register_category(searchReply, hl.name(), hl.name(), "", renderer); //FIXME: highlight slug
1762+ for (auto const& pkg: hl.packages())
1763+ {
1764+ push_package(searchReply, category, locallyInstalledApps, pkg);
1765+ }
1766+ }
1767+ qDebug() << "Highlights pushed";
1768+}
1769+
1770+void click::Query::push_departments(const scopes::SearchReplyProxy& searchReply, const scopes::Department::SCPtr& root)
1771+{
1772+ if (root != nullptr)
1773+ {
1774+ try
1775+ {
1776+ qDebug() << "pushing departments";
1777+ searchReply->register_departments(root);
1778+ }
1779+ catch (const std::exception& e)
1780+ {
1781+ qWarning() << "Failed to register departments for query " << QString::fromStdString(query().query_string()) <<
1782+ ", current department " << QString::fromStdString(query().department_id()) << ": " << e.what();
1783+ }
1784+ }
1785+ else
1786+ {
1787+ qWarning() << "No departments data for query " << QString::fromStdString(query().query_string()) <<
1788+ "', current department " << QString::fromStdString(query().department_id());
1789+ }
1790+}
1791+
1792+//
1793+// push highlights and departments
1794+// use cached highlights for root department, otherwise run an async job for highlights of current department.
1795+void click::Query::add_highlights(scopes::SearchReplyProxy const& searchReply, const PackageSet& locallyInstalledApps)
1796+{
1797+ auto curdep = impl->department_lookup.get_department_info(query().department_id());
1798+ assert(curdep);
1799+ auto subdepts = curdep->sub_departments();
1800+ if (query().department_id() == "") // top-level departments
1801+ {
1802+ unity::scopes::Department::SPtr root;
1803+ populate_departments(subdepts, query().department_id(), root);
1804+ push_departments(searchReply, root);
1805+
1806+ qDebug() << "pushing cached highlights";
1807+ push_highlights(searchReply, impl->highlights, locallyInstalledApps);
1808+ this->finished(searchReply); //FIXME: this shouldn't be needed
1809+ }
1810+ else
1811+ {
1812+ qDebug() << "starting departments call for department" << QString::fromStdString(curdep->id()) << ", href" << QString::fromStdString(curdep->href());
1813+ impl->search_operation = impl->index.departments(curdep->href(), [this, locallyInstalledApps, searchReply](const DepartmentList& depts,
1814+ const HighlightList& highlights, Index::Error error)
1815+ {
1816+ if (error == click::Index::Error::NoError)
1817+ {
1818+ qDebug() << "departments call completed";
1819+ unity::scopes::Department::SPtr root;
1820+ populate_departments(depts, query().department_id(), root);
1821+ push_departments(searchReply, root);
1822+ push_highlights(searchReply, highlights, locallyInstalledApps);
1823+ }
1824+ else
1825+ {
1826+ qWarning() << "departments call failed";
1827+ }
1828+ this->finished(searchReply); //FIXME: this shouldn't be needed
1829+ });
1830+ }
1831+}
1832+
1833 void click::Query::add_available_apps(scopes::SearchReplyProxy const& searchReply,
1834 const PackageSet& installedPackages,
1835 const std::string& categoryTemplate)
1836@@ -162,12 +330,14 @@
1837 scopes::CategoryRenderer categoryRenderer(categoryTemplate);
1838 auto category = register_category(searchReply, "appstore", _("Available"), "", categoryRenderer);
1839
1840+ assert(searchReply);
1841+
1842 run_under_qt([=]()
1843 {
1844- auto search_cb = [this, searchReply, category, installedPackages](Packages packages) {
1845+ auto search_cb = [this, searchReply, category, installedPackages](Packages packages, DepartmentList) {
1846 qDebug("search callback");
1847
1848- // handle packages data
1849+ // handle packages data; FIXME: use push_package()
1850 foreach (auto p, packages) {
1851 qDebug() << "pushing result" << QString::fromStdString(p.name);
1852 try {
1853@@ -195,11 +365,58 @@
1854 }
1855 }
1856 qDebug() << "search completed";
1857- this->finished(searchReply);
1858- };
1859-
1860- qDebug() << "starting search of" << QString::fromStdString(impl->query.query_string());
1861- impl->search_operation = impl->index.search(impl->query.query_string(), search_cb);
1862+ this->finished(searchReply); //FIXME: this shouldn't be needed
1863+ };
1864+
1865+ // this is the case when we do bootstrap for the first time, or it failed last time
1866+ if (impl->department_lookup.size() == 0 && !click::Scope::use_old_api())
1867+ {
1868+ qDebug() << "performing bootstrap request";
1869+ impl->search_operation = impl->index.bootstrap([this, search_cb, searchReply, installedPackages](const DepartmentList& deps, const
1870+ HighlightList& highlights, click::Index::Error error, int error_code) {
1871+ if (error == click::Index::Error::NoError)
1872+ {
1873+ qDebug() << "bootstrap request completed";
1874+ auto root = std::make_shared<click::Department>("", "All Departments", "", true);
1875+ root->set_subdepartments(deps);
1876+ DepartmentList rdeps { root };
1877+ impl->department_lookup.rebuild(rdeps);
1878+ impl->highlights = highlights;
1879+ qDebug() << "Total number of departments:" << impl->department_lookup.size() << ", highlights:" << highlights.size();
1880+ }
1881+ else
1882+ {
1883+ qWarning() << "bootstrap request failed";
1884+ if (error_code == 405) // method not allowed
1885+ {
1886+ qDebug() << "bootstrap not available, using old API";
1887+ click::Scope::set_use_old_api();
1888+ }
1889+ }
1890+
1891+ if (query().query_string().empty() && !click::Scope::use_old_api())
1892+ {
1893+ add_highlights(searchReply, installedPackages);
1894+ }
1895+ else
1896+ {
1897+ qDebug() << "starting search of" << QString::fromStdString(query().query_string());
1898+ impl->search_operation = impl->index.search(query().query_string(), query().department_id(), search_cb);
1899+ }
1900+ });
1901+ }
1902+ else
1903+ {
1904+ if (query().query_string().empty() && !click::Scope::use_old_api())
1905+ {
1906+ add_highlights(searchReply, installedPackages);
1907+ }
1908+ else // normal search
1909+ {
1910+ qDebug() << "starting search of" << QString::fromStdString(query().query_string());
1911+ impl->search_operation = impl->index.search(query().query_string(), query().department_id(), search_cb);
1912+ }
1913+ }
1914 });
1915 }
1916
1917@@ -222,9 +439,9 @@
1918
1919 void click::Query::run(scopes::SearchReplyProxy const& searchReply)
1920 {
1921- auto query = impl->query.query_string();
1922+ auto q = query().query_string();
1923 std::string categoryTemplate = CATEGORY_APPS_SEARCH;
1924- if (query.empty()) {
1925+ if (q.empty()) {
1926 categoryTemplate = CATEGORY_APPS_DISPLAY;
1927 }
1928
1929
1930=== modified file 'scope/clickstore/store-query.h'
1931--- scope/clickstore/store-query.h 2014-06-16 14:09:21 +0000
1932+++ scope/clickstore/store-query.h 2014-06-18 18:08:01 +0000
1933@@ -32,10 +32,16 @@
1934
1935
1936 #include <unity/scopes/SearchQueryBase.h>
1937+#include <unity/scopes/Department.h>
1938
1939 namespace scopes = unity::scopes;
1940
1941 #include <QSharedPointer>
1942+#include <set>
1943+
1944+#include <click/department-lookup.h>
1945+#include <click/package.h>
1946+#include <click/highlights.h>
1947 #include <click/interface.h>
1948
1949 namespace click
1950@@ -43,6 +49,7 @@
1951
1952 class Application;
1953 class Index;
1954+class DepartmentLookup;
1955
1956 class Query : public scopes::SearchQueryBase
1957 {
1958@@ -69,7 +76,8 @@
1959 constexpr static const char* VERSION{"version"};
1960 };
1961
1962- Query(unity::scopes::CannedQuery const& query, click::Index& index, scopes::SearchMetadata const& metadata);
1963+ Query(unity::scopes::CannedQuery const& query, click::Index& index, click::DepartmentLookup& dept_lookup, click::HighlightList& highlights,
1964+ scopes::SearchMetadata const& metadata);
1965 virtual ~Query();
1966
1967 virtual void cancelled() override;
1968@@ -77,8 +85,10 @@
1969 virtual void run(scopes::SearchReplyProxy const& reply) override;
1970
1971 protected:
1972- virtual void add_available_apps(const scopes::SearchReplyProxy &searchReply,
1973- const PackageSet &installedPackages, const std::string &category);
1974+ virtual void populate_departments(const click::DepartmentList& depts, const std::string& current_department_id, unity::scopes::Department::SPtr &root);
1975+ virtual void push_departments(const scopes::SearchReplyProxy& searchReply, const scopes::Department::SCPtr& root);
1976+ virtual void add_highlights(scopes::SearchReplyProxy const& searchReply, const PackageSet& installedPackages);
1977+ virtual void add_available_apps(const scopes::SearchReplyProxy &searchReply, const PackageSet &installedPackages, const std::string &category);
1978 virtual click::Interface& clickInterfaceInstance();
1979 virtual PackageSet get_installed_packages();
1980 virtual bool push_result(const scopes::SearchReplyProxy &searchReply, scopes::CategorisedResult const& res);
1981@@ -88,6 +98,9 @@
1982 std::string const& title,
1983 std::string const& icon,
1984 scopes::CategoryRenderer const& renderer_template);
1985+ virtual void push_package(const scopes::SearchReplyProxy& searchReply, scopes::Category::SCPtr category, const PackageSet &locallyInstalledApps,
1986+ const click::Package& pkg);
1987+ virtual void push_highlights(const scopes::SearchReplyProxy& searchReply, const HighlightList& highlights, const PackageSet &locallyInstalledApps);
1988 virtual void run_under_qt(const std::function<void()> &task);
1989
1990 private:
1991
1992=== modified file 'scope/clickstore/store-scope.cpp'
1993--- scope/clickstore/store-scope.cpp 2014-06-17 21:32:44 +0000
1994+++ scope/clickstore/store-scope.cpp 2014-06-18 18:08:01 +0000
1995@@ -28,6 +28,7 @@
1996 */
1997
1998 #include <click/qtbridge.h>
1999+#include <click/department-lookup.h>
2000 #include "store-scope.h"
2001 #include "store-query.h"
2002 #include <click/preview.h>
2003@@ -42,27 +43,38 @@
2004
2005 #include <logging.h>
2006
2007+bool click::Scope::old_api = false;
2008
2009 click::Scope::Scope()
2010 {
2011 nam.reset(new click::network::AccessManager());
2012 client.reset(new click::web::Client(nam));
2013 index.reset(new click::Index(client));
2014+ depts.reset(new click::DepartmentLookup());
2015+ highlights.reset(new click::HighlightList());
2016 }
2017
2018 click::Scope::~Scope()
2019 {
2020 }
2021
2022-int click::Scope::start(std::string const&, scopes::RegistryProxy const&)
2023+void click::Scope::set_use_old_api()
2024+{
2025+ old_api = true;
2026+}
2027+
2028+bool click::Scope::use_old_api()
2029+{
2030+ return old_api;
2031+}
2032+
2033+void click::Scope::start(std::string const&, scopes::RegistryProxy const&)
2034 {
2035 setlocale(LC_ALL, "");
2036 // FIXME: This is wrong, but needed for json-cpp workaround.
2037 setlocale(LC_MONETARY, "C");
2038 bindtextdomain(GETTEXT_PACKAGE, GETTEXT_LOCALEDIR);
2039 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
2040-
2041- return VERSION;
2042 }
2043
2044 void click::Scope::run()
2045@@ -70,7 +82,6 @@
2046 static const int zero = 0;
2047 auto emptyCb = [this]()
2048 {
2049-
2050 };
2051
2052 qt::core::world::build_and_run(zero, nullptr, emptyCb);
2053@@ -83,7 +94,7 @@
2054
2055 scopes::SearchQueryBase::UPtr click::Scope::search(unity::scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata)
2056 {
2057- return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, metadata));
2058+ return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, *depts, *highlights, metadata));
2059 }
2060
2061
2062@@ -93,12 +104,21 @@
2063 return scopes::PreviewQueryBase::UPtr{new click::Preview(result, metadata, client, nam)};
2064 }
2065
2066+<<<<<<< TREE
2067 unity::scopes::ActivationQueryBase::UPtr click::Scope::perform_action(unity::scopes::Result const& /* result */, unity::scopes::ActionMetadata const& metadata,
2068 std::string const& widget_id, std::string const& _action_id)
2069+=======
2070+unity::scopes::ActivationQueryBase::UPtr click::Scope::perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& /* widget_id */, std::string const& action_id)
2071+>>>>>>> MERGE-SOURCE
2072 {
2073+<<<<<<< TREE
2074 std::string action_id = _action_id;
2075 auto activation = new ScopeActivation();
2076 qDebug() << "perform_action called with widget_id" << QString::fromStdString(widget_id) << "and action_id:" << QString::fromStdString(action_id);
2077+=======
2078+ auto activation = new ScopeActivation(result, metadata);
2079+ qDebug() << "perform_action called with action_id" << QString().fromStdString(action_id);
2080+>>>>>>> MERGE-SOURCE
2081
2082 // if the purchase is completed, do the install
2083 if (action_id == "purchaseCompleted") {
2084
2085=== modified file 'scope/clickstore/store-scope.h'
2086--- scope/clickstore/store-scope.h 2014-05-27 06:57:52 +0000
2087+++ scope/clickstore/store-scope.h 2014-06-18 18:08:01 +0000
2088@@ -30,6 +30,7 @@
2089 #ifndef CLICK_SCOPE_H
2090 #define CLICK_SCOPE_H
2091
2092+#include <memory>
2093 #include <click/network_access_manager.h>
2094 #include <click/webclient.h>
2095
2096@@ -43,29 +44,38 @@
2097
2098 namespace click
2099 {
2100+
2101+class DepartmentLookup;
2102+
2103 class Scope : public scopes::ScopeBase
2104 {
2105 public:
2106 Scope();
2107 ~Scope();
2108
2109- virtual int start(std::string const&, scopes::RegistryProxy const&) override;
2110+ virtual void start(std::string const&, scopes::RegistryProxy const&) override;
2111
2112 virtual void run() override;
2113 virtual void stop() override;
2114
2115- virtual scopes::SearchQueryBase::UPtr search(scopes::CannedQuery const& q, scopes::SearchMetadata const&) override;
2116+ virtual scopes::SearchQueryBase::UPtr search(scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata) override;
2117 unity::scopes::PreviewQueryBase::UPtr preview(const unity::scopes::Result&,
2118 const unity::scopes::ActionMetadata&) override;
2119
2120 virtual unity::scopes::ActivationQueryBase::UPtr perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& widget_id, std::string const& action_id) override;
2121
2122+ static void set_use_old_api();
2123+ static bool use_old_api();
2124+
2125 private:
2126 QSharedPointer<click::network::AccessManager> nam;
2127 QSharedPointer<click::web::Client> client;
2128 QSharedPointer<click::Index> index;
2129+ std::shared_ptr<click::DepartmentLookup> depts;
2130+ std::shared_ptr<click::HighlightList> highlights;
2131
2132 std::string installApplication(unity::scopes::Result const& result);
2133+ static bool old_api;
2134 };
2135 }
2136 #endif // CLICK_SCOPE_H
2137
2138=== modified file 'scope/tests/integration/webclient_integration.cpp'
2139--- scope/tests/integration/webclient_integration.cpp 2014-06-12 21:05:25 +0000
2140+++ scope/tests/integration/webclient_integration.cpp 2014-06-18 18:08:01 +0000
2141@@ -30,6 +30,7 @@
2142 #include <click/network_access_manager.h>
2143 #include <click/webclient.h>
2144 #include <click/index.h>
2145+#include <click/departments.h>
2146
2147 #include <QCoreApplication>
2148 #include <QDebug>
2149@@ -102,7 +103,8 @@
2150 new click::web::Client(namPtr));
2151 click::Index index(clientPtr);
2152 click::Packages packages;
2153- index.search("qr,architecture:armhf", [&, this](click::Packages found_packages){
2154+ index.search("qr,architecture:armhf", "", [&, this](click::Packages found_packages, click::DepartmentList){
2155+ //TODO departments
2156 packages = found_packages;
2157 Quit();
2158 });
2159
2160=== modified file 'scope/tests/test_query.cpp'
2161--- scope/tests/test_query.cpp 2014-06-12 22:17:42 +0000
2162+++ scope/tests/test_query.cpp 2014-06-18 18:08:01 +0000
2163@@ -45,6 +45,7 @@
2164 #include <unity/scopes/CannedQuery.h>
2165 #include <unity/scopes/ScopeBase.h>
2166 #include <unity/scopes/SearchReply.h>
2167+#include <unity/scopes/testing/MockSearchReply.h>
2168
2169 using namespace ::testing;
2170 using namespace click;
2171@@ -57,30 +58,45 @@
2172
2173 class MockIndex : public click::Index {
2174 click::Packages packages;
2175+ click::DepartmentList departments;
2176+ click::DepartmentList bootstrap_departments;
2177+ click::HighlightList bootstrap_highlights;
2178 public:
2179- MockIndex(click::Packages packages = click::Packages())
2180+ MockIndex(click::Packages packages = click::Packages(),
2181+ click::DepartmentList departments = click::DepartmentList(),
2182+ click::DepartmentList boot_departments = click::DepartmentList())
2183 : Index(QSharedPointer<click::web::Client>()),
2184- packages(packages)
2185- {
2186-
2187- }
2188-
2189- click::web::Cancellable search(const std::string &query, std::function<void (click::Packages)> callback) override
2190- {
2191- do_search(query, callback);
2192- callback(packages);
2193- return click::web::Cancellable();
2194- }
2195-
2196- MOCK_METHOD2(do_search,
2197- void(const std::string&,
2198- std::function<void(click::Packages)>));
2199+ packages(packages),
2200+ departments(departments),
2201+ bootstrap_departments(boot_departments)
2202+ {
2203+
2204+ }
2205+
2206+ click::web::Cancellable search(const std::string &query, const std::string& department, std::function<void (click::Packages, click::DepartmentList)> callback) override
2207+ {
2208+ do_search(query, department, callback);
2209+ callback(packages, departments);
2210+ return click::web::Cancellable();
2211+ }
2212+
2213+ click::web::Cancellable bootstrap(std::function<void(const click::DepartmentList&, const click::HighlightList&, Error, int)> callback) override
2214+ {
2215+ callback(bootstrap_departments, bootstrap_highlights, click::Index::Error::NoError, 0);
2216+ return click::web::Cancellable();
2217+ }
2218+
2219+ MOCK_METHOD3(do_search,
2220+ void(const std::string&, const std::string&,
2221+ std::function<void(click::Packages, click::DepartmentList)>));
2222 };
2223
2224 class MockQueryBase : public click::Query {
2225 public:
2226 MockQueryBase(const unity::scopes::CannedQuery& query, click::Index& index,
2227- scopes::SearchMetadata const& metadata) : click::Query(query, index, metadata)
2228+ click::DepartmentLookup& depts,
2229+ click::HighlightList& highlights,
2230+ scopes::SearchMetadata const& metadata) : click::Query(query, index, depts, highlights, metadata)
2231 {
2232
2233 }
2234@@ -94,7 +110,9 @@
2235 class MockQuery : public MockQueryBase {
2236 public:
2237 MockQuery(const unity::scopes::CannedQuery& query, click::Index& index,
2238- scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, metadata)
2239+ click::DepartmentLookup& depts,
2240+ click::HighlightList& highlights,
2241+ scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, highlights, metadata)
2242 {
2243
2244 }
2245@@ -118,7 +136,9 @@
2246 class MockQueryRun : public MockQueryBase {
2247 public:
2248 MockQueryRun(const unity::scopes::CannedQuery& query, click::Index& index,
2249- scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, metadata)
2250+ click::DepartmentLookup& depts,
2251+ click::HighlightList& highlights,
2252+ scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, highlights, metadata)
2253 {
2254
2255 }
2256@@ -147,12 +167,16 @@
2257 TEST(QueryTest, testAddAvailableAppsCallsClickIndex)
2258 {
2259 MockIndex mock_index;
2260+ click::DepartmentLookup dept_lookup;
2261+ click::HighlightList highlights;
2262 scopes::SearchMetadata metadata("en_EN", "phone");
2263 PackageSet no_installed_packages;
2264 const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
2265- MockQuery q(query, mock_index, metadata);
2266- EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)).Times(1);
2267- scopes::SearchReplyProxy reply;
2268+ MockQuery q(query, mock_index, dept_lookup, highlights, metadata);
2269+ EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _)).Times(1);
2270+
2271+ scopes::testing::MockSearchReply mock_reply;
2272+ scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
2273
2274 scopes::CategoryRenderer renderer("{}");
2275 auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
2276@@ -166,17 +190,21 @@
2277 {"name", "title", 0.0, "icon", "uri"}
2278 };
2279 MockIndex mock_index(packages);
2280+ click::DepartmentLookup dept_lookup;
2281+ click::HighlightList highlights;
2282 scopes::SearchMetadata metadata("en_EN", "phone");
2283 PackageSet no_installed_packages;
2284 const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
2285- MockQuery q(query, mock_index, metadata);
2286- EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _));
2287+ MockQuery q(query, mock_index, dept_lookup, highlights, metadata);
2288+ EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
2289
2290 scopes::CategoryRenderer renderer("{}");
2291 auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
2292 EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(ptrCat));
2293
2294- scopes::SearchReplyProxy reply;
2295+ scopes::testing::MockSearchReply mock_reply;
2296+ scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
2297+
2298 auto expected_title = packages.front().title;
2299 EXPECT_CALL(q, push_result(_, Property(&scopes::CategorisedResult::title, expected_title)));
2300 q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
2301@@ -188,17 +216,20 @@
2302 {"name", "title", 0.0, "icon", "uri"}
2303 };
2304 MockIndex mock_index(packages);
2305+ click::DepartmentLookup dept_lookup;
2306+ click::HighlightList highlights;
2307 scopes::SearchMetadata metadata("en_EN", "phone");
2308 PackageSet no_installed_packages;
2309 const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
2310- MockQuery q(query, mock_index, metadata);
2311- EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _));
2312+ MockQuery q(query, mock_index, dept_lookup, highlights, metadata);
2313+ EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
2314
2315 scopes::CategoryRenderer renderer("{}");
2316 auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
2317 EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(ptrCat));
2318
2319- scopes::SearchReplyProxy reply;
2320+ scopes::testing::MockSearchReply mock_reply;
2321+ scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
2322 EXPECT_CALL(q, finished(_));
2323 q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
2324 }
2325@@ -209,10 +240,12 @@
2326 {"name", "title", 0.0, "icon", "uri"}
2327 };
2328 MockIndex mock_index(packages);
2329+ click::DepartmentLookup dept_lookup;
2330+ click::HighlightList highlights;
2331 scopes::SearchMetadata metadata("en_EN", "phone");
2332 PackageSet no_installed_packages;
2333 const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
2334- MockQueryRun q(query, mock_index, metadata);
2335+ MockQueryRun q(query, mock_index, dept_lookup, highlights, metadata);
2336 auto reply = scopes::SearchReplyProxy();
2337 EXPECT_CALL(q, get_installed_packages()).WillOnce(Return(no_installed_packages));
2338 EXPECT_CALL(q, add_available_apps(reply, no_installed_packages, _));
2339@@ -234,15 +267,18 @@
2340 PackageSet one_installed_package {
2341 {"org.example.app2", "0.2"}
2342 };
2343+ click::DepartmentLookup dept_lookup;
2344+ click::HighlightList highlights;
2345 const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
2346- MockQuery q(query, mock_index, metadata);
2347- EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _));
2348+ MockQuery q(query, mock_index, dept_lookup, highlights, metadata);
2349+ EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
2350
2351 scopes::CategoryRenderer renderer("{}");
2352 auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
2353 EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(ptrCat));
2354
2355- scopes::SearchReplyProxy reply;
2356+ scopes::testing::MockSearchReply mock_reply;
2357+ scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
2358 auto expected_name1 = packages.front().name;
2359 EXPECT_CALL(q, push_result(_, HasPackageName(expected_name1)));
2360 auto expected_name2 = packages.back().name;
2361@@ -261,15 +297,18 @@
2362 PackageSet one_installed_package {
2363 {"org.example.app2", "0.2"}
2364 };
2365+ click::DepartmentLookup dept_lookup;
2366+ click::HighlightList highlights;
2367 const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
2368- MockQuery q(query, mock_index, metadata);
2369- EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _));
2370+ MockQuery q(query, mock_index, dept_lookup, highlights, metadata);
2371+ EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _, _));
2372
2373 scopes::CategoryRenderer renderer("{}");
2374 auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
2375 EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(ptrCat));
2376
2377- scopes::SearchReplyProxy reply;
2378+ scopes::testing::MockSearchReply mock_reply;
2379+ scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){});
2380 EXPECT_CALL(q, push_result(_, IsInstalled(true)));
2381 EXPECT_CALL(q, push_result(_, IsInstalled(false)));
2382 q.wrap_add_available_apps(reply, one_installed_package, FAKE_CATEGORY_TEMPLATE);
2383@@ -288,8 +327,10 @@
2384 };
2385 MockIndex mock_index(uninstalled_packages);
2386 scopes::SearchMetadata metadata("en_EN", "phone");
2387+ click::DepartmentLookup dept_lookup;
2388+ click::HighlightList highlights;
2389 const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, "");
2390- MockQuery q(query, mock_index, metadata);
2391+ MockQuery q(query, mock_index, dept_lookup, highlights, metadata);
2392 PackageSet installed_packages{{"package_1", "0.1"}};
2393
2394 FakeInterface fake_interface;

Subscribers

People subscribed via source and target branches

to all changes: