Merge lp:~alecu/unity-scope-click/missing-preview-fields into lp:unity-scope-click/devel

Proposed by Alejandro J. Cura
Status: Merged
Approved by: dobey
Approved revision: 363
Merged at revision: 369
Proposed branch: lp:~alecu/unity-scope-click/missing-preview-fields
Merge into: lp:unity-scope-click/devel
Diff against target: 854 lines (+516/-19)
15 files modified
libclickscope/click/CMakeLists.txt (+1/-0)
libclickscope/click/package.cpp (+39/-2)
libclickscope/click/package.h (+21/-0)
libclickscope/click/preview.cpp (+58/-5)
libclickscope/click/preview.h (+7/-1)
libclickscope/click/utils.cpp (+100/-0)
libclickscope/click/utils.h (+61/-0)
libclickscope/tests/CMakeLists.txt (+2/-2)
libclickscope/tests/fake_json.cpp (+12/-7)
libclickscope/tests/test_index.cpp (+36/-2)
libclickscope/tests/test_preview.cpp (+42/-0)
libclickscope/tests/test_utils.cpp (+133/-0)
po/POTFILES.in (+1/-0)
scope/clickapps/apps-scope.cpp (+2/-0)
scope/clickstore/store-scope.cpp (+1/-0)
To merge this branch: bzr merge lp:~alecu/unity-scope-click/missing-preview-fields
Reviewer Review Type Date Requested Status
dobey (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Diego Sarmentero (community) Approve
Review via email: mp+228242@code.launchpad.net

Commit message

Adds pending fields for the store preview.

To post a comment you must log in.
359. By Alejandro J. Cura

Minimize diff

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
360. By Alejandro J. Cura

Me4rged with tip of /devel

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Diego Sarmentero (diegosarmentero) wrote :

+1

review: Approve
Revision history for this message
dobey (dobey) wrote :

I'm a bit worried about the lack of translation in the size formatting code. For example, here is the glib code for formatting sizes: https://git.gnome.org/browse/glib/tree/glib/gutils.c#n2103

It looks like we're expecting boost to do some magic here, and just tack a 'b' or 'bytes' on the end (and 'b' is wrong there, since 'B' is the correct symbol for bytes, at least in US).

review: Needs Information
361. By Alejandro J. Cura

Disable the human-readable formatting of file sizes, as per review

Revision history for this message
dobey (dobey) :
review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
362. By Alejandro J. Cura

Use the human readable again, with more tests and fixes.

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

Oh, and you'll also need to add libclickscope/click/utils.cpp to po/POTFILES.in.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
363. By Alejandro J. Cura

Use dngettext instead of boost::locale::translate, added utils.cpp to POTFILES.in

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
dobey (dobey) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'libclickscope/click/CMakeLists.txt'
2--- libclickscope/click/CMakeLists.txt 2014-07-10 07:20:26 +0000
3+++ libclickscope/click/CMakeLists.txt 2014-07-25 22:06:29 +0000
4@@ -31,6 +31,7 @@
5 scope_activation.cpp
6 smartconnect.cpp
7 ubuntuone_credentials.cpp
8+ utils.cpp
9 webclient.cpp
10 )
11
12
13=== modified file 'libclickscope/click/package.cpp'
14--- libclickscope/click/package.cpp 2014-07-02 15:24:07 +0000
15+++ libclickscope/click/package.cpp 2014-07-25 22:06:29 +0000
16@@ -55,15 +55,22 @@
17 lhs.rating == rhs.rating &&
18 // TODO: keywords should be a list of strings
19 lhs.keywords == rhs.keywords &&
20+
21 lhs.terms_of_service == rhs.terms_of_service &&
22 lhs.license == rhs.license &&
23 lhs.publisher == rhs.publisher &&
24+ lhs.developer_name == rhs.developer_name &&
25+ lhs.company_name == rhs.company_name &&
26+ lhs.website == rhs.website &&
27+ lhs.support_url == rhs.support_url &&
28+
29 lhs.main_screenshot_url == rhs.main_screenshot_url &&
30- // TODO: more_screenshots_urls should be a list of strings
31 lhs.more_screenshots_urls == rhs.more_screenshots_urls &&
32- // TODO: binary_filesize should be a int/long
33 lhs.binary_filesize == rhs.binary_filesize &&
34 lhs.version == rhs.version &&
35+ lhs.date_published == rhs.date_published &&
36+ lhs.last_updated == rhs.last_updated &&
37+ lhs.changelog == rhs.changelog &&
38 lhs.framework == rhs.framework;
39 }
40
41@@ -172,6 +179,27 @@
42 if (root[JsonKeys::framework].isString())
43 details.framework = root[JsonKeys::framework].asString();
44
45+ if (root[JsonKeys::developer_name].isString())
46+ details.developer_name = root[JsonKeys::developer_name].asString();
47+
48+ if (root[JsonKeys::company_name].isString())
49+ details.company_name = root[JsonKeys::company_name].asString();
50+
51+ if (root[JsonKeys::website].isString())
52+ details.website = root[JsonKeys::website].asString();
53+
54+ if (root[JsonKeys::support_url].isString())
55+ details.support_url = root[JsonKeys::support_url].asString();
56+
57+ if (root[JsonKeys::date_published].isString())
58+ details.date_published.parse_iso8601(root[JsonKeys::date_published].asString());
59+
60+ if (root[JsonKeys::last_updated].isString())
61+ details.last_updated.parse_iso8601(root[JsonKeys::last_updated].asString());
62+
63+ if (root[JsonKeys::changelog].isString())
64+ details.changelog = root[JsonKeys::changelog].asString();
65+
66 } catch(const std::exception& e)
67 {
68 std::cerr << "PackageDetails::loadJson: Exception thrown while decoding JSON: " << e.what() << std::endl;
69@@ -221,10 +249,19 @@
70 << print_string_if_not_empty(details.terms_of_service) << ", "
71 << print_string_if_not_empty(details.license) << ", "
72 << print_string_if_not_empty(details.publisher) << ", "
73+ << print_string_if_not_empty(details.developer_name) << ", "
74+ << print_string_if_not_empty(details.company_name) << ", "
75+ << print_string_if_not_empty(details.website) << ", "
76+ << print_string_if_not_empty(details.support_url) << ", "
77+
78 << print_string_if_not_empty(details.main_screenshot_url) << ", "
79 << print_list_if_not_empty(details.more_screenshots_urls) << ", "
80 << details.binary_filesize << ", "
81 << print_string_if_not_empty(details.version) << ", "
82+ << print_string_if_not_empty(details.date_published.formatted()) << ", "
83+ << print_string_if_not_empty(details.last_updated.formatted()) << ", "
84+ << print_string_if_not_empty(details.changelog) << ", "
85+
86 << print_string_if_not_empty(details.framework)
87 << ")";
88
89
90=== modified file 'libclickscope/click/package.h'
91--- libclickscope/click/package.h 2014-07-02 15:24:07 +0000
92+++ libclickscope/click/package.h 2014-07-25 22:06:29 +0000
93@@ -38,6 +38,7 @@
94
95 #include <json/json.h>
96
97+#include <click/utils.h>
98
99 namespace json = Json;
100
101@@ -123,14 +124,24 @@
102 constexpr static const char* download_url{"download_url"};
103 constexpr static const char* rating{"rating"};
104 constexpr static const char* keywords{"keywords"};
105+
106 constexpr static const char* terms_of_service{"terms_of_service"};
107 constexpr static const char* license{"license"};
108 constexpr static const char* publisher{"publisher"};
109+ constexpr static const char* developer_name{"developer_name"};
110+ constexpr static const char* company_name{"company_name"};
111+ constexpr static const char* website{"website"};
112+ constexpr static const char* support_url{"support_url"};
113+
114 constexpr static const char* department{"department"};
115 constexpr static const char* main_screenshot_url{"screenshot_url"};
116 constexpr static const char* more_screenshot_urls{"screenshot_urls"};
117 constexpr static const char* binary_filesize{"binary_filesize"};
118 constexpr static const char* version{"version"};
119+ constexpr static const char* date_published{"date_published"};
120+ constexpr static const char* last_updated{"last_updated"};
121+ constexpr static const char* changelog{"changelog"};
122+
123 constexpr static const char* framework{"framework"};
124 };
125
126@@ -142,13 +153,23 @@
127 std::string download_url;
128 double rating;
129 std::string keywords;
130+
131 std::string terms_of_service;
132 std::string license;
133 std::string publisher;
134+ std::string developer_name;
135+ std::string company_name;
136+ std::string website;
137+ std::string support_url;
138+
139 std::string main_screenshot_url;
140 std::list<std::string> more_screenshots_urls;
141 json::Value::UInt64 binary_filesize;
142 std::string version;
143+ click::Date date_published;
144+ click::Date last_updated;
145+ std::string changelog;
146+
147 std::string framework;
148 std::string department;
149 };
150
151=== modified file 'libclickscope/click/preview.cpp'
152--- libclickscope/click/preview.cpp 2014-07-22 13:02:28 +0000
153+++ libclickscope/click/preview.cpp 2014-07-25 22:06:29 +0000
154@@ -35,6 +35,7 @@
155 #include <click/launcher.h>
156 #include <click/dbus_constants.h>
157 #include <click/departments-db.h>
158+#include <click/utils.h>
159
160 #include <boost/algorithm/string/replace.hpp>
161
162@@ -54,6 +55,10 @@
163
164 namespace click {
165
166+const std::string PreviewStrategy::INFO_LABEL = _("Info");
167+const std::string PreviewStrategy::UPDATES_LABEL = _("Updates");
168+const std::string PreviewStrategy::WHATS_NEW_LABEL = _("What's new");
169+
170 DepartmentUpdater::DepartmentUpdater(const std::shared_ptr<click::DepartmentsDb>& depts)
171 : depts(depts)
172 {
173@@ -198,6 +203,37 @@
174 submit_operation.cancel();
175 }
176
177+// TODO: replace this big string with a TABLE widget
178+std::string PreviewStrategy::build_other_metadata(const PackageDetails &details)
179+{
180+ std::stringstream b;
181+ b << _("Publisher/Creator") << ": " << details.publisher << std::endl;
182+ b << _("Seller") << ": " << details.company_name << std::endl;
183+ b << _("Website") << ": " << details.website << std::endl;
184+ b << _("Contact") << ": " << details.support_url << std::endl;
185+ b << _("License") << ": " << details.license << std::endl;
186+ return b.str();
187+}
188+
189+// TODO: replace this big string with a TABLE widget
190+std::string PreviewStrategy::build_updates_table(const PackageDetails& details)
191+{
192+ std::stringstream b;
193+ b << _("Version number") << ": " << details.version << std::endl;
194+ b << _("Last updated") << ": " << details.last_updated.formatted() << std::endl;
195+ b << _("First released") << ": " << details.date_published.formatted() << std::endl;
196+ b << _("Size") << ": " <<
197+ click::Formatter::human_readable_filesize(details.binary_filesize) << std::endl;
198+ return b.str();
199+}
200+
201+std::string PreviewStrategy::build_whats_new(const PackageDetails& details)
202+{
203+ std::stringstream b;
204+ b << _("Version") << ": " << details.version << std::endl;
205+ b << details.changelog;
206+ return b.str();
207+}
208
209 // TODO: error handling - once get_details provides errors, we can
210 // return them from populateDetails and check them in the calling code
211@@ -291,14 +327,27 @@
212 scopes::PreviewWidgetList PreviewStrategy::descriptionWidgets(const click::PackageDetails& details)
213 {
214 scopes::PreviewWidgetList widgets;
215- if (details.description.empty())
216+ if (!details.description.empty())
217 {
218- return widgets;
219+ scopes::PreviewWidget summary("summary", "text");
220+ summary.add_attribute_value("title", scopes::Variant(INFO_LABEL));
221+ summary.add_attribute_value("text", scopes::Variant(details.description));
222+ widgets.push_back(summary);
223 }
224
225- scopes::PreviewWidget summary("summary", "text");
226- summary.add_attribute_value("text", scopes::Variant(details.description));
227- widgets.push_back(summary);
228+ scopes::PreviewWidget other_metadata("other_metadata", "text");
229+ other_metadata.add_attribute_value("text", scopes::Variant(build_other_metadata(details)));
230+ widgets.push_back(other_metadata);
231+
232+ scopes::PreviewWidget updates("updates", "text");
233+ updates.add_attribute_value("title", scopes::Variant(UPDATES_LABEL));
234+ updates.add_attribute_value("text", scopes::Variant(build_updates_table(details)));
235+ widgets.push_back(updates);
236+
237+ scopes::PreviewWidget whats_new("whats_new", "text");
238+ whats_new.add_attribute_value("title", scopes::Variant(WHATS_NEW_LABEL));
239+ whats_new.add_attribute_value("text", scopes::Variant(build_whats_new(details)));
240+ widgets.push_back(whats_new);
241
242 return widgets;
243 }
244@@ -311,6 +360,10 @@
245 scopes::VariantBuilder builder;
246
247 if (reviewlist.size() > 0) {
248+ scopes::PreviewWidget title("reviews_title", "text");
249+ title.add_attribute_value("title", scopes::Variant(_("Reviews")));
250+ widgets.push_back(title);
251+
252 for (const auto& kv : reviewlist) {
253 builder.add_tuple({
254 {"rating", scopes::Variant(kv.rating)},
255
256=== modified file 'libclickscope/click/preview.h'
257--- libclickscope/click/preview.h 2014-07-22 13:02:28 +0000
258+++ libclickscope/click/preview.h 2014-07-25 22:06:29 +0000
259@@ -115,7 +115,9 @@
260
261 virtual void cancelled();
262 virtual void run(unity::scopes::PreviewReplyProxy const& reply) = 0;
263-
264+ static const std::string INFO_LABEL;
265+ static const std::string UPDATES_LABEL;
266+ static const std::string WHATS_NEW_LABEL;
267 protected:
268 virtual void populateDetails(std::function<void(const PackageDetails &)> details_callback,
269 std::function<void(const click::ReviewList&,
270@@ -134,6 +136,10 @@
271 virtual void pushPackagePreviewWidgets(const unity::scopes::PreviewReplyProxy &reply,
272 const PackageDetails& details,
273 const scopes::PreviewWidgetList& button_area_widgets);
274+ virtual std::string build_other_metadata(const PackageDetails& details);
275+ virtual std::string build_updates_table(const PackageDetails& details);
276+ virtual std::string build_whats_new(const PackageDetails& details);
277+
278 scopes::Result result;
279 QSharedPointer<click::web::Client> client;
280 QSharedPointer<click::Index> index;
281
282=== added file 'libclickscope/click/utils.cpp'
283--- libclickscope/click/utils.cpp 1970-01-01 00:00:00 +0000
284+++ libclickscope/click/utils.cpp 2014-07-25 22:06:29 +0000
285@@ -0,0 +1,100 @@
286+/*
287+ * Copyright (C) 2014 Canonical Ltd.
288+ *
289+ * This program is free software: you can redistribute it and/or modify it
290+ * under the terms of the GNU General Public License version 3, as published
291+ * by the Free Software Foundation.
292+ *
293+ * This program is distributed in the hope that it will be useful, but
294+ * WITHOUT ANY WARRANTY; without even the implied warranties of
295+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
296+ * PURPOSE. See the GNU General Public License for more details.
297+ *
298+ * You should have received a copy of the GNU General Public License along
299+ * with this program. If not, see <http://www.gnu.org/licenses/>.
300+ *
301+ * In addition, as a special exception, the copyright holders give
302+ * permission to link the code of portions of this program with the
303+ * OpenSSL library under certain conditions as described in each
304+ * individual source file, and distribute linked combinations
305+ * including the two.
306+ * You must obey the GNU General Public License in all respects
307+ * for all of the code used other than OpenSSL. If you modify
308+ * file(s) with this exception, you may extend this exception to your
309+ * version of the file(s), but you are not obligated to do so. If you
310+ * do not wish to do so, delete this exception statement from your
311+ * version. If you delete this exception statement from all source
312+ * files in the program, then also delete it here.
313+ */
314+
315+#include <sstream>
316+
317+#include <boost/date_time/posix_time/posix_time.hpp>
318+#include <boost/date_time/time_facet.hpp>
319+#include <boost/locale.hpp>
320+#include <boost/units/systems/si/io.hpp>
321+
322+#include <click/utils.h>
323+
324+struct byte_base_unit : boost::units::base_unit<byte_base_unit, boost::units::dimensionless_type, 3>
325+{
326+ static const char* name() { return("byte"); }
327+ static const char* symbol() { return("B"); }
328+};
329+
330+std::string click::Formatter::human_readable_filesize(long num_bytes)
331+{
332+ std::ostringstream s;
333+ std::cout.imbue(std::locale());
334+
335+ if (num_bytes > 1023) {
336+ s << boost::units::symbol_format << boost::units::binary_prefix;
337+ s << boost::locale::format("{1,num=fixed,precision=1}") % (num_bytes * byte_base_unit::unit_type());
338+ } else {
339+ std::string tpl(dngettext(GETTEXT_PACKAGE, "{1} byte", "{1} bytes", num_bytes));
340+ s << boost::locale::format(tpl) % num_bytes;
341+ }
342+ return s.str();
343+}
344+
345+using namespace boost::posix_time;
346+
347+time_input_facet* build_input_facet(std::stringstream& ss)
348+{
349+ time_input_facet* input_facet = new time_input_facet(1);
350+ input_facet->set_iso_extended_format();
351+ ss.imbue(std::locale(ss.getloc(), input_facet));
352+ return input_facet;
353+}
354+
355+void click::Date::setup_system_locale()
356+{
357+ boost::locale::generator gen;
358+ std::locale loc=gen("");
359+ std::locale::global(loc);
360+}
361+
362+void click::Date::parse_iso8601(std::string iso8601)
363+{
364+ static std::stringstream ss;
365+ static ptime epoch(boost::gregorian::date(1970,1,1));
366+ static time_input_facet* input_facet = NULL;
367+
368+ if (input_facet == NULL) {
369+ build_input_facet(ss);
370+ }
371+
372+ ptime time;
373+ ss.str(iso8601);
374+ ss >> time;
375+ ss.clear();
376+
377+ timestamp = (time - epoch).total_seconds();
378+}
379+
380+std::string click::Date::formatted() const
381+{
382+ std::stringstream s;
383+ s << boost::locale::as::date << timestamp;
384+ return s.str();
385+}
386
387=== added file 'libclickscope/click/utils.h'
388--- libclickscope/click/utils.h 1970-01-01 00:00:00 +0000
389+++ libclickscope/click/utils.h 2014-07-25 22:06:29 +0000
390@@ -0,0 +1,61 @@
391+/*
392+ * Copyright (C) 2014 Canonical Ltd.
393+ *
394+ * This program is free software: you can redistribute it and/or modify it
395+ * under the terms of the GNU General Public License version 3, as published
396+ * by the Free Software Foundation.
397+ *
398+ * This program is distributed in the hope that it will be useful, but
399+ * WITHOUT ANY WARRANTY; without even the implied warranties of
400+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
401+ * PURPOSE. See the GNU General Public License for more details.
402+ *
403+ * You should have received a copy of the GNU General Public License along
404+ * with this program. If not, see <http://www.gnu.org/licenses/>.
405+ *
406+ * In addition, as a special exception, the copyright holders give
407+ * permission to link the code of portions of this program with the
408+ * OpenSSL library under certain conditions as described in each
409+ * individual source file, and distribute linked combinations
410+ * including the two.
411+ * You must obey the GNU General Public License in all respects
412+ * for all of the code used other than OpenSSL. If you modify
413+ * file(s) with this exception, you may extend this exception to your
414+ * version of the file(s), but you are not obligated to do so. If you
415+ * do not wish to do so, delete this exception statement from your
416+ * version. If you delete this exception statement from all source
417+ * files in the program, then also delete it here.
418+ */
419+
420+#ifndef CLICK_UTILS_H
421+#define CLICK_UTILS_H
422+
423+#include <ctime>
424+#include <string>
425+
426+namespace click
427+{
428+
429+class Date
430+{
431+protected:
432+ std::time_t timestamp;
433+public:
434+ void parse_iso8601(std::string iso8601);
435+ std::string formatted() const;
436+ static void setup_system_locale();
437+ inline bool operator==(const Date& other) const
438+ {
439+ return timestamp == other.timestamp;
440+ }
441+};
442+
443+
444+class Formatter
445+{
446+public:
447+ static std::string human_readable_filesize(long num_bytes);
448+};
449+
450+} // namespace click
451+#endif // CLICK_UTILS_H
452
453=== modified file 'libclickscope/tests/CMakeLists.txt'
454--- libclickscope/tests/CMakeLists.txt 2014-07-23 14:53:10 +0000
455+++ libclickscope/tests/CMakeLists.txt 2014-07-25 22:06:29 +0000
456@@ -26,6 +26,7 @@
457 test_bootstrap.cpp
458 test_configuration.cpp
459 test_departments.cpp
460+ test_departments-db.cpp
461 test_download_manager.cpp
462 test_index.cpp
463 test_interface.cpp
464@@ -33,9 +34,8 @@
465 test_preview.cpp
466 test_reviews.cpp
467 test_smartconnect.cpp
468+ test_utils.cpp
469 test_webclient.cpp
470- test_departments.cpp
471- test_departments-db.cpp
472
473 ${CMAKE_CURRENT_BINARY_DIR}/test_data.cpp
474 )
475
476=== modified file 'libclickscope/tests/fake_json.cpp'
477--- libclickscope/tests/fake_json.cpp 2014-07-17 18:37:23 +0000
478+++ libclickscope/tests/fake_json.cpp 2014-07-25 22:06:29 +0000
479@@ -175,26 +175,31 @@
480 "download_url": "https://public.apps.staging.ubuntu.com/download/ar.com.beuno/wheather-touch/ar.com.beuno.wheather-touch-0.2",
481 "rating": 3.5,
482 "keywords": "these, are, key, words",
483+
484 "terms_of_service": "tos",
485 "license": "Proprietary",
486- "publisher": "Beuno",
487+ "publisher": "Fake Publisher",
488+ "developer_name": "Fake Developer",
489+ "company_name": "Fake Company",
490+ "website": "http://example.com",
491+ "support_url": "http://example.com/support",
492+
493 "screenshot_url": "sshot0",
494 "screenshot_urls": ["sshot1", "sshot2"],
495 "binary_filesize": 177582,
496 "version": "0.2",
497+ "date_published": "2013-11-04T00:40:24.686298Z",
498+ "last_updated": "2014-07-03T08:16:34.532525Z",
499+ "changelog": "This is the changelog",
500+
501 "framework": "None",
502-
503- "website": "",
504- "support_url": "http://beuno.com.ar",
505 "price": 1.99,
506 "license_key_path": "",
507 "click_version": "0.1",
508- "company_name": "",
509 "icon_urls": {
510 "64": "http://developer.staging.ubuntu.com/site_media/appmedia/2013/07/weather-icone-6797-64.png"
511 },
512- "requires_license_key": false,
513- "date_published": "2013-07-16T21:50:34.874000"
514+ "requires_license_key": false
515 }
516 )foo";
517
518
519=== modified file 'libclickscope/tests/test_index.cpp'
520--- libclickscope/tests/test_index.cpp 2014-07-02 15:24:07 +0000
521+++ libclickscope/tests/test_index.cpp 2014-07-25 22:06:29 +0000
522@@ -28,6 +28,7 @@
523 */
524
525 #include <click/index.h>
526+#include <click/utils.h>
527 #include <click/webclient.h>
528
529 #include <tests/mock_network_access_manager.h>
530@@ -322,6 +323,13 @@
531 indexPtr->get_details("", [this](click::PackageDetails details, click::Index::Error error){
532 details_callback(details, error);
533 });
534+
535+ click::Date published;
536+ published.parse_iso8601("2013-11-04T00:40:24.686298Z");
537+
538+ click::Date updated;
539+ updated.parse_iso8601("2014-07-03T08:16:34.532525Z");
540+
541 click::PackageDetails fake_details {
542 {
543 "ar.com.beuno.wheather-touch",
544@@ -335,13 +343,23 @@
545 "https://public.apps.staging.ubuntu.com/download/ar.com.beuno/wheather-touch/ar.com.beuno.wheather-touch-0.2",
546 3.5,
547 "these, are, key, words",
548+
549 "tos",
550 "Proprietary",
551- "Beuno",
552+ "Fake Publisher",
553+ "Fake Developer",
554+ "Fake Company",
555+ "http://example.com",
556+ "http://example.com/support",
557+
558 "sshot0",
559 {"sshot1", "sshot2"},
560 177582,
561 "0.2",
562+ published,
563+ updated,
564+ "This is the changelog",
565+
566 "None",
567 "tools"
568 };
569@@ -370,6 +388,12 @@
570 details_callback(details, error);
571 });
572
573+ click::Date published;
574+ published.parse_iso8601("2013-11-04T00:40:24.686298Z");
575+
576+ click::Date updated;
577+ updated.parse_iso8601("2014-07-03T08:16:34.532525Z");
578+
579 click::PackageDetails fake_details {
580 {
581 "ar.com.beuno.wheather-touch",
582@@ -383,13 +407,23 @@
583 "https://public.apps.staging.ubuntu.com/download/ar.com.beuno/wheather-touch/ar.com.beuno.wheather-touch-0.2",
584 3.5,
585 "these, are, key, words",
586+
587 "tos",
588 "Proprietary",
589- "Beuno",
590+ "Fake Publisher",
591+ "Fake Developer",
592+ "Fake Company",
593+ "http://example.com",
594+ "http://example.com/support",
595+
596 "sshot0",
597 {"sshot1", "sshot2"},
598 177582,
599 "0.2",
600+ published,
601+ updated,
602+ "This is the changelog",
603+
604 "None",
605 "tools"
606 };
607
608=== modified file 'libclickscope/tests/test_preview.cpp'
609--- libclickscope/tests/test_preview.cpp 2014-07-22 16:05:53 +0000
610+++ libclickscope/tests/test_preview.cpp 2014-07-25 22:06:29 +0000
611@@ -31,6 +31,7 @@
612
613 #include <gtest/gtest.h>
614 #include <click/preview.h>
615+#include <fake_json.h>
616
617 using namespace ::testing;
618 using namespace unity::scopes;
619@@ -57,6 +58,10 @@
620
621 }
622 using click::PreviewStrategy::screenshotsWidgets;
623+ using click::PreviewStrategy::descriptionWidgets;
624+ using click::PreviewStrategy::build_other_metadata;
625+ using click::PreviewStrategy::build_updates_table;
626+ using click::PreviewStrategy::build_whats_new;
627 };
628
629 class PreviewsBaseTest : public Test
630@@ -97,6 +102,43 @@
631 ASSERT_EQ(sources[2].get_string(), "sshot3");
632 }
633
634+class PreviewStrategyDescriptionTest : public PreviewStrategyTest
635+{
636+public:
637+ FakeResult result{vm};
638+ FakePreview preview{result};
639+ click::PackageDetails details;
640+ unity::scopes::PreviewWidgetList widgets;
641+
642+ PreviewStrategyDescriptionTest() : details(click::PackageDetails::from_json(FAKE_JSON_PACKAGE_DETAILS))
643+ {
644+ widgets = preview.descriptionWidgets(details);
645+
646+ }
647+ void assertWidgetAttribute(int n, std::string attribute_name, std::string expected_value)
648+ {
649+ ASSERT_GT(widgets.size(), n);
650+ auto widget = std::next(widgets.begin(), n);
651+ auto attributes = widget->attribute_values();
652+ ASSERT_EQ(expected_value, attributes[attribute_name].get_string());
653+ }
654+};
655+
656+TEST_F(PreviewStrategyDescriptionTest, testDescriptionWidgets)
657+{
658+ assertWidgetAttribute(0, "title", click::PreviewStrategy::INFO_LABEL);
659+ assertWidgetAttribute(0, "text", details.description);
660+
661+ assertWidgetAttribute(1, "text", preview.build_other_metadata(details));
662+
663+ assertWidgetAttribute(2, "title", click::PreviewStrategy::UPDATES_LABEL);
664+ assertWidgetAttribute(2, "text", preview.build_updates_table(details));
665+
666+ assertWidgetAttribute(3, "title", click::PreviewStrategy::WHATS_NEW_LABEL);
667+ assertWidgetAttribute(3, "text", preview.build_whats_new(details));
668+
669+}
670+
671 class FakePreviewStrategy : public click::PreviewStrategy
672 {
673 public:
674
675=== added file 'libclickscope/tests/test_utils.cpp'
676--- libclickscope/tests/test_utils.cpp 1970-01-01 00:00:00 +0000
677+++ libclickscope/tests/test_utils.cpp 2014-07-25 22:06:29 +0000
678@@ -0,0 +1,133 @@
679+/*
680+ * Copyright (C) 2014 Canonical Ltd.
681+ *
682+ * This program is free software: you can redistribute it and/or modify it
683+ * under the terms of the GNU General Public License version 3, as published
684+ * by the Free Software Foundation.
685+ *
686+ * This program is distributed in the hope that it will be useful, but
687+ * WITHOUT ANY WARRANTY; without even the implied warranties of
688+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
689+ * PURPOSE. See the GNU General Public License for more details.
690+ *
691+ * You should have received a copy of the GNU General Public License along
692+ * with this program. If not, see <http://www.gnu.org/licenses/>.
693+ *
694+ * In addition, as a special exception, the copyright holders give
695+ * permission to link the code of portions of this program with the
696+ * OpenSSL library under certain conditions as described in each
697+ * individual source file, and distribute linked combinations
698+ * including the two.
699+ * You must obey the GNU General Public License in all respects
700+ * for all of the code used other than OpenSSL. If you modify
701+ * file(s) with this exception, you may extend this exception to your
702+ * version of the file(s), but you are not obligated to do so. If you
703+ * do not wish to do so, delete this exception statement from your
704+ * version. If you delete this exception statement from all source
705+ * files in the program, then also delete it here.
706+ */
707+
708+#include <gtest/gtest.h>
709+#include <boost/locale.hpp>
710+#include <boost/locale/time_zone.hpp>
711+
712+#include <click/utils.h>
713+
714+using namespace ::testing;
715+
716+class UtilsTest : public Test
717+{
718+public:
719+ void SetUp()
720+ {
721+ // The tests assume they run always under the same environment
722+ setDefaultTimezone();
723+ setDefaultLocale();
724+ }
725+
726+ void setDefaultTimezone()
727+ {
728+ boost::locale::time_zone::global("UTC");
729+ }
730+
731+ void setDefaultLocale()
732+ {
733+ boost::locale::generator gen;
734+ std::locale::global(gen("C"));
735+ }
736+};
737+
738+TEST_F(UtilsTest, testHumanReadableZeroBytes)
739+{
740+ ASSERT_EQ(click::Formatter::human_readable_filesize(0), "0 bytes");
741+}
742+
743+TEST_F(UtilsTest, testHumanReadableOneByte)
744+{
745+ ASSERT_EQ(click::Formatter::human_readable_filesize(1), "1 byte");
746+}
747+
748+TEST_F(UtilsTest, testHumanReadableMoreBytes)
749+{
750+ ASSERT_EQ(click::Formatter::human_readable_filesize(102), "102 bytes");
751+}
752+
753+TEST_F(UtilsTest, testHumanReadableKilobytes)
754+{
755+ ASSERT_EQ(click::Formatter::human_readable_filesize(102*1024), "102.0 KiB");
756+}
757+
758+TEST_F(UtilsTest, testHumanReadableFractionalKilobytes)
759+{
760+ ASSERT_EQ(click::Formatter::human_readable_filesize(102*1024+512+1), "102.5 KiB");
761+}
762+
763+TEST_F(UtilsTest, testHumanReadableMegabytes)
764+{
765+ ASSERT_EQ(click::Formatter::human_readable_filesize(42*1024*1024), "42.0 MiB");
766+}
767+
768+TEST_F(UtilsTest, testHumanReadableFractionalMegabytes)
769+{
770+ ASSERT_EQ(click::Formatter::human_readable_filesize(42*1024*1024+512*1024+512), "42.5 MiB");
771+}
772+
773+class TestableDate : public click::Date
774+{
775+public:
776+ using click::Date::timestamp;
777+};
778+
779+TEST_F(UtilsTest, testDateParseIso8601)
780+{
781+ TestableDate d;
782+ d.parse_iso8601("1975-11-30T00:00:00Z");
783+ ASSERT_EQ(186537600, d.timestamp);
784+}
785+
786+TEST_F(UtilsTest, testDateFormatted)
787+{
788+ TestableDate d;
789+ d.timestamp = 186537600;
790+ ASSERT_EQ("Nov 30, 1975", d.formatted());
791+}
792+
793+TEST_F(UtilsTest, testAFewDatesFormatted)
794+{
795+ TestableDate d;
796+ d.parse_iso8601("2008-12-06T00:00:00Z");
797+ ASSERT_EQ("Dec 6, 2008", d.formatted());
798+ d.parse_iso8601("2013-12-16T00:00:00Z");
799+ ASSERT_EQ("Dec 16, 2013", d.formatted());
800+}
801+
802+TEST_F(UtilsTest, testDateComparesOk)
803+{
804+ TestableDate d1;
805+ d1.parse_iso8601("1975-11-30T00:00:00Z");
806+
807+ TestableDate d2;
808+ d2.timestamp = 186537600;
809+
810+ ASSERT_EQ(d1, d2);
811+}
812
813=== modified file 'po/POTFILES.in'
814--- po/POTFILES.in 2014-06-25 13:43:08 +0000
815+++ po/POTFILES.in 2014-07-25 22:06:29 +0000
816@@ -1,5 +1,6 @@
817 [type: gettext/ini] data/com.canonical.scopes.clickstore.ini.in.in
818 [type: gettext/ini] data/clickscope.ini.in.in
819 libclickscope/click/preview.cpp
820+libclickscope/click/utils.cpp
821 scope/clickapps/apps-query.cpp
822 scope/clickstore/store-query.cpp
823
824=== modified file 'scope/clickapps/apps-scope.cpp'
825--- scope/clickapps/apps-scope.cpp 2014-07-18 15:12:22 +0000
826+++ scope/clickapps/apps-scope.cpp 2014-07-25 22:06:29 +0000
827@@ -38,6 +38,7 @@
828 #include <click/key_file_locator.h>
829 #include <click/network_access_manager.h>
830 #include <click/click-i18n.h>
831+#include <click/utils.h>
832 #include <unity/scopes/CannedQuery.h>
833
834 #include "apps-scope.h"
835@@ -69,6 +70,7 @@
836 setlocale(LC_ALL, "");
837 bindtextdomain(GETTEXT_PACKAGE, GETTEXT_LOCALEDIR);
838 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
839+ click::Date::setup_system_locale();
840 }
841
842 void click::Scope::run()
843
844=== modified file 'scope/clickstore/store-scope.cpp'
845--- scope/clickstore/store-scope.cpp 2014-07-22 10:20:38 +0000
846+++ scope/clickstore/store-scope.cpp 2014-07-25 22:06:29 +0000
847@@ -75,6 +75,7 @@
848 setlocale(LC_MONETARY, "C");
849 bindtextdomain(GETTEXT_PACKAGE, GETTEXT_LOCALEDIR);
850 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
851+ click::Date::setup_system_locale();
852 }
853
854 void click::Scope::run()

Subscribers

People subscribed via source and target branches

to all changes: