Merge lp:unity-scopes-api/staging into lp:unity-scopes-api

Proposed by Marcus Tomlinson
Status: Merged
Approved by: Paweł Stołowski
Approved revision: 324
Merged at revision: 367
Proposed branch: lp:unity-scopes-api/staging
Merge into: lp:unity-scopes-api
Diff against target: 2397 lines (+1285/-441)
31 files modified
CMakeLists.txt (+3/-3)
RELEASE_NOTES.md (+7/-0)
debian/VERSION (+1/-1)
debian/changelog (+22/-0)
debian/control.in (+1/-1)
doc/tutorial.dox (+96/-1)
include/unity/scopes/internal/JsonCppNode.h (+17/-10)
include/unity/scopes/internal/JsonNodeInterface.h (+2/-3)
include/unity/scopes/internal/JsonSettingsSchema.h (+1/-1)
include/unity/scopes/internal/gobj_memory.h (+212/-0)
scoperegistry/scoperegistry.cpp (+0/-1)
src/scopes/CategoryRenderer.cpp (+1/-1)
src/scopes/PreviewWidget.cpp (+9/-2)
src/scopes/internal/JsonCppNode.cpp (+283/-200)
src/scopes/internal/JsonSettingsSchema.cpp (+149/-162)
src/scopes/internal/Logger.cpp (+2/-2)
src/scopes/internal/RuntimeImpl.cpp (+1/-1)
src/scopes/internal/ScopeConfig.cpp (+0/-2)
src/scopes/internal/smartscopes/SmartScopesClient.cpp (+10/-0)
src/scopes/internal/zmq_middleware/StopPublisher.cpp (+1/-1)
src/scopes/testing/ScopeMetadataBuilder.cpp (+1/-3)
test/copyright/check_copyright.sh (+1/-7)
test/gtest/scopes/Registry/Registry_test.cpp (+0/-1)
test/gtest/scopes/Registry/scopes/testscopeA/testscopeA.ini.in (+0/-1)
test/gtest/scopes/internal/CMakeLists.txt (+1/-0)
test/gtest/scopes/internal/JsonNode/JsonNode_test.cpp (+153/-17)
test/gtest/scopes/internal/JsonSettingsSchema/JsonSettingsSchema_test.cpp (+37/-5)
test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp (+4/-4)
test/gtest/scopes/internal/gobj_ptr/CMakeLists.txt (+3/-0)
test/gtest/scopes/internal/gobj_ptr/gobj_ptr_test.cpp (+208/-0)
test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp (+59/-11)
To merge this branch: bzr merge lp:unity-scopes-api/staging
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Pending
Unity Team Pending
Review via email: mp+295415@code.launchpad.net

Commit message

* Got rid of category header background, as per design (Bug #1446216).
* Re-enabled license/copyright test for xenial+.
* Removed libjson-cpp and replaced with json-glib based implementation (Bug #1360247).
* Fixed Yakkety build.

To post a comment you must log in.
lp:unity-scopes-api/staging updated
319. By Marcus Tomlinson

Sync changelog

320. By Marcus Tomlinson

Update changelog and RELEASE_NOTES.md

321. By Marcus Tomlinson

Bump version

322. By Marcus Tomlinson

Merge devel

323. By Marcus Tomlinson

Merged devel

324. By Paweł Stołowski

Merged devel changes

Revision history for this message
Robert Bruce Park (robru) wrote :

Changelog nitpick inline.

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 2016-03-31 23:48:56 +0000
3+++ CMakeLists.txt 2016-06-17 07:24:44 +0000
4@@ -66,11 +66,11 @@
5 pkg_check_modules(APPARMOR REQUIRED libapparmor REQUIRED)
6 pkg_check_modules(LTTNG_UST lttng-ust REQUIRED)
7 pkg_check_modules(LIBURCU_BP liburcu-bp REQUIRED)
8-pkg_check_modules(JSONCPP jsoncpp REQUIRED)
9 pkg_check_modules(LIBACCOUNTS libaccounts-glib REQUIRED)
10 pkg_check_modules(LIBSIGNON libsignon-glib REQUIRED)
11 pkg_check_modules(ZMQLIB libzmq REQUIRED)
12 pkg_check_modules(NET_CPP net-cpp>=1.2.0 REQUIRED)
13+pkg_check_modules(JSON_GLIB json-glib-1.0 REQUIRED)
14
15 find_library(ZMQPPLIB zmqpp)
16 if(NOT ZMQPPLIB)
17@@ -140,10 +140,10 @@
18 )
19
20 set(OTHER_INCLUDE_DIRS ${OTHER_INCLUDE_DIRS} ${UNITY_API_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
21- ${JSONCPP_INCLUDE_DIRS} ${PROCESS_CPP_INCLUDE_DIRS} ${APPARMOR_INCLUDE_DIRS}
22+ ${JSON_GLIB_INCLUDE_DIRS} ${PROCESS_CPP_INCLUDE_DIRS} ${APPARMOR_INCLUDE_DIRS}
23 ${LIBACCOUNTS_INCLUDE_DIRS} ${LIBSIGNON_INCLUDE_DIRS} ${NET_CPP_INCLUDE_DIRS})
24 set(OTHER_LIBS ${OTHER_LIBS} ${UNITY_API_LDFLAGS} ${APPARMOR_LDFLAGS} ${LIBACCOUNTS_LIBRARIES}
25- ${LIBSIGNON_LIBRARIES} ${Boost_LIBRARIES} ${JSONCPP_LDFLAGS} ${PROCESS_CPP_LDFLAGS}
26+ ${LIBSIGNON_LIBRARIES} ${Boost_LIBRARIES} ${JSON_GLIB_LDFLAGS} ${PROCESS_CPP_LDFLAGS}
27 ${ZMQPPLIB} ${ZMQLIB_LDFLAGS} ${CAPNPLIB} ${KJLIB} ${DLLIB} ${NET_CPP_LDFLAGS} pthread)
28
29 # Standard install paths
30
31=== modified file 'RELEASE_NOTES.md'
32--- RELEASE_NOTES.md 2016-04-11 07:58:52 +0000
33+++ RELEASE_NOTES.md 2016-06-17 07:24:44 +0000
34@@ -1,6 +1,13 @@
35 Release notes
36 =============
37
38+Changes in version 1.0.6
39+========================
40+ - Got rid of category header background, as per design (Bug #1446216).
41+ - Re-enabled license/copyright test for xenial+.
42+ - Removed libjson-cpp and replaced with json-glib based implementation (Bug #1360247).
43+ - Fixed Yakkety build.
44+
45 Changes in version 1.0.5
46 ========================
47 - Simplify debian/control munging.
48
49=== modified file 'debian/VERSION'
50--- debian/VERSION 2016-03-31 23:48:56 +0000
51+++ debian/VERSION 2016-06-17 07:24:44 +0000
52@@ -1,1 +1,1 @@
53-1.0.5
54+1.0.6
55
56=== modified file 'debian/changelog'
57--- debian/changelog 2016-04-13 09:51:48 +0000
58+++ debian/changelog 2016-06-17 07:24:44 +0000
59@@ -1,3 +1,25 @@
60+unity-scopes-api (1.0.6+16.10.20160520.3-0ubuntu2) UNRELEASED; urgency=medium
61+
62+ * Got rid of category header background, as per design (Bug #1446216).
63+ * Re-enabled license/copyright test for xenial+.
64+ * Removed libjson-cpp and replaced with json-glib based implementation (Bug #1360247).
65+ * Fixed Yakkety build.
66+
67+ -- Marcus Tomlinson <marcustomlinson@ubuntu> Mon, 23 May 2016 09:54:28 +0200
68+
69+unity-scopes-api (1.0.6+16.10.20160520.3-0ubuntu1) yakkety; urgency=medium
70+
71+ [ CI Train Bot ]
72+ * No-change rebuild.
73+
74+ -- Marcus Tomlinson <marcus.tomlinson@canonical.com> Fri, 20 May 2016 14:55:39 +0000
75+
76+unity-scopes-api (1.0.5+16.04.20160413.1-0ubuntu2) yakkety; urgency=medium
77+
78+ * No-change rebuild of latest xenial trunk against current archive.
79+
80+ -- Łukasz 'sil2100' Zemczak <lukasz.zemczak@ubuntu.com> Thu, 19 May 2016 19:19:30 +0200
81+
82 unity-scopes-api (1.0.5+16.04.20160413.1-0ubuntu1) xenial; urgency=medium
83
84 [ Marcus Tomlinson ]
85
86=== modified file 'debian/control.in'
87--- debian/control.in 2016-03-16 12:35:22 +0000
88+++ debian/control.in 2016-06-17 07:24:44 +0000
89@@ -21,7 +21,7 @@
90 libboost-thread-dev,
91 libcapnp-dev (>= 0.4.0),
92 libdbustest1-dev,
93- libjsoncpp-dev,
94+ libjson-glib-dev,
95 liblttng-ust-dev,
96 libnet-cpp-dev (>= 1.2.0),
97 libprocess-cpp-dev (>= 1.0.1),
98
99=== modified file 'doc/tutorial.dox'
100--- doc/tutorial.dox 2016-03-16 12:35:22 +0000
101+++ doc/tutorial.dox 2016-06-17 07:24:44 +0000
102@@ -636,6 +636,102 @@
103 call to your `activate()` method. Your implementation of `activate()` should follow the same guidelines as for
104 `perform_action()` (except that widget and action identifiers do not apply to result activation).
105
106+\paragraph resultaction Handling result action activation
107+
108+Search results can embed simple action buttons (icons) in their cards. When the user taps an action icon, the scope gets notified and can update
109+the affected result card to reflect the new state. A typical use case for this is to offer "social" actions, such as thumbs up/down buttons.
110+
111+The following snippet demonstrates how two actions can be added to a \link unity::scopes::CategorisedResult CategorisedResult\endlink:
112+
113+\code
114+CategorisedResult res(cat);
115+res.set_uri("myuri");
116+res.set_title("My Title");
117+
118+// Add result actions
119+VariantBuilder builder;
120+builder.add_tuple({
121+ {"id", Variant("thumbsup")},
122+ {"icon", Variant("thOff")},
123+ {"temporaryIcon", Variant("thOn")},
124+ {"label", Variant("I like it")},
125+});
126+builder.add_tuple({
127+ {"id", Variant("flag")},
128+ {"icon", Variant("flag")},
129+ {"temporaryIcon", Variant("flagOn")},
130+ {"label", Variant("Flag this result")},
131+});
132+res["social-actions"] = builder.end();
133+\endcode
134+
135+The attributes of result actions are as follows:
136+<ul>
137+<li>id - unique action identifier that will be reported to the scope.
138+<li>icon - the icon for the action button.
139+<li>temporaryIcon (optional) - defines an icon that will be shown immediately when the user taps the button, before the scope reacts to the action.
140+<li>label - the text shown next to the icon.
141+</ul>
142+
143+To respond to activation of result actions, your scope must implement
144+\link unity::scopes::ScopeBase::activate_result_action ScopeBase::activate_result_action\endlink:
145+
146+\code{.cpp}
147+class MyScope : public ScopeBase
148+{
149+ ...
150+ ActivationQueryBase::UPtr activate_result_action(Result const& result,
151+ ActionMetadata const& metadata,
152+ std::string const& action_id) override;
153+ ...
154+}
155+\endcode
156+
157+Like `search()` and `preview()`, `activate_result_action()` is a factory method. It must return an
158+instance that derives from \link unity::scopes::ActivationQueryBase ActivationQueryBase\endlink.
159+Your derived class must implement the \link unity::scopes::ActivationQueryBase::activate activate()\endlink method,
160+whose job it is to respond to the activation (that is, the user pressing action button). `activate` must return
161+an \link unity::scopes::ActivationResponse ActivationResponse\endlink, which tells the UI how it should
162+behave in response to the result action activation. For result actions the typical and recommended behavior is to update the card
163+for the result whose action was activated.
164+
165+For example, here is how to update the actions of an affected card in response to a "thumbsup" action, so that tapping the "thumbsup" action button replaces that
166+button with "thumbsdown":
167+
168+\code{.cpp}
169+class MyActivation : public ActivationQueryBase
170+{
171+ MyActivation(Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& action_id) :
172+ ActivationQueryBase(result, metadata, action_id)
173+ {
174+ }
175+
176+ virtual ActivationResponse activate() override
177+ {
178+ if (action_id() == "thumbsup")
179+ {
180+ // ... update backend data for 'thumbs up' action ...
181+
182+ // get the affect result and update it
183+ Result updatedRes(result());
184+ VariantBuilder builder;
185+ builder.add_tuple({
186+ {"id", Variant("thumbsdown")},
187+ {"icon", Variant("thOn")},
188+ {"temporaryIcon", Variant("thOff")},
189+ {"label", Variant("I don't like it")},
190+ });
191+ builder.add_tuple({ ... })
192+ updatedRes["social-actions"] = builder.end();
193+ return ActivationResponse(updatedRes);
194+ }
195+
196+ if (action_id() == "thumbsdown")
197+ ...
198+ }
199+};
200+\endcode
201+
202 \paragraph export Exporting a scope
203
204 Your scope must be compiled into a `.so` shared library and, to be successfully
205@@ -1430,7 +1526,6 @@
206 ForegroundColor = default text color (defaults to theme-provided foreground color)
207 BackgroundColor = color of scope background (default is transparent)
208 ShapeImages = whether to use Ubuntu-shape for all cards and artwork (defaults to true)
209- CategoryHeaderBackground = background scheme of the results categories
210 PreviewButtonColor = color of preview buttons (defaults to theme-provided color)
211 LogoOverlayColor = color for the overlay in scopes overview (defaults to semi-transparent black)
212 PageHeader.Logo = image containing scope's logo
213
214=== modified file 'include/unity/scopes/internal/JsonCppNode.h'
215--- include/unity/scopes/internal/JsonCppNode.h 2014-11-03 05:31:30 +0000
216+++ include/unity/scopes/internal/JsonCppNode.h 2016-06-17 07:24:44 +0000
217@@ -19,9 +19,15 @@
218 #pragma once
219
220 #include <unity/scopes/internal/JsonNodeInterface.h>
221-#include <jsoncpp/json/value.h>
222+
223+#include <unity/scopes/internal/gobj_memory.h>
224 #include <unity/scopes/Variant.h>
225
226+#pragma GCC diagnostic push
227+#pragma GCC diagnostic ignored "-Wold-style-cast"
228+#include <json-glib/json-glib.h>
229+#pragma GCC diagnostic pop
230+
231 namespace unity
232 {
233
234@@ -34,10 +40,11 @@
235 class JsonCppNode : public JsonNodeInterface
236 {
237 public:
238- explicit JsonCppNode(std::string const& json_string = "");
239- explicit JsonCppNode(const Json::Value& root);
240- explicit JsonCppNode(const Variant& var);
241- ~JsonCppNode();
242+ JsonCppNode();
243+ JsonCppNode(std::string const& json_string);
244+ explicit JsonCppNode(JsonNode* root);
245+ explicit JsonCppNode(Variant const& var);
246+ ~JsonCppNode() = default;
247
248 void clear() override;
249 void read_json(std::string const& json_string) override;
250@@ -49,8 +56,7 @@
251 NodeType type() const override;
252
253 std::string as_string() const override;
254- int as_int() const override;
255- unsigned int as_uint() const override;
256+ int64_t as_int() const override;
257 double as_double() const override;
258 bool as_bool() const override;
259
260@@ -61,9 +67,10 @@
261 JsonNodeInterface::SPtr get_node(unsigned int node_index) const override;
262
263 private:
264- static Json::Value from_variant(Variant const& var);
265- static Variant to_variant(Json::Value const &val);
266- Json::Value root_;
267+ void init_from_string(std::string const& jscon_string);
268+
269+ typedef std::unique_ptr<JsonNode, decltype(&json_node_free)> NodePtr;
270+ NodePtr root_;
271 };
272
273 } // namespace internal
274
275=== modified file 'include/unity/scopes/internal/JsonNodeInterface.h'
276--- include/unity/scopes/internal/JsonNodeInterface.h 2014-11-03 05:31:30 +0000
277+++ include/unity/scopes/internal/JsonNodeInterface.h 2016-06-17 07:24:44 +0000
278@@ -42,7 +42,7 @@
279
280 enum NodeType
281 {
282- Null, Array, Object, String, Int, UInt, Real, Bool
283+ Null, Array, Object, String, Int, Real, Bool
284 };
285
286 JsonNodeInterface() = default;
287@@ -58,8 +58,7 @@
288 virtual NodeType type() const = 0;
289
290 virtual std::string as_string() const = 0;
291- virtual int as_int() const = 0;
292- virtual unsigned int as_uint() const = 0;
293+ virtual int64_t as_int() const = 0;
294 virtual double as_double() const = 0;
295 virtual bool as_bool() const = 0;
296
297
298=== modified file 'include/unity/scopes/internal/JsonSettingsSchema.h'
299--- include/unity/scopes/internal/JsonSettingsSchema.h 2014-11-03 05:31:30 +0000
300+++ include/unity/scopes/internal/JsonSettingsSchema.h 2016-06-17 07:24:44 +0000
301@@ -49,7 +49,7 @@
302 void add_location_setting() override;
303
304 private:
305- JsonSettingsSchema(std::string const& ini_file);
306+ JsonSettingsSchema(std::string const& json_string);
307
308 JsonSettingsSchema();
309
310
311=== added file 'include/unity/scopes/internal/gobj_memory.h'
312--- include/unity/scopes/internal/gobj_memory.h 1970-01-01 00:00:00 +0000
313+++ include/unity/scopes/internal/gobj_memory.h 2016-06-17 07:24:44 +0000
314@@ -0,0 +1,212 @@
315+/*
316+ * Copyright (C) 2013 Canonical Ltd.
317+ *
318+ * This program is free software: you can redistribute it and/or modify
319+ * it under the terms of the GNU Lesser General Public License version 3 as
320+ * published by the Free Software Foundation.
321+ *
322+ * This program is distributed in the hope that it will be useful,
323+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
324+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
325+ * GNU Lesser General Public License for more details.
326+ *
327+ * You should have received a copy of the GNU Lesser General Public License
328+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
329+ *
330+ * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
331+ */
332+
333+#pragma once
334+
335+#include <stdexcept>
336+
337+#pragma GCC diagnostic push
338+#pragma GCC diagnostic ignored "-Wold-style-cast"
339+#pragma GCC diagnostic ignored "-Wcast-qual"
340+#include <glib-object.h>
341+
342+namespace unity
343+{
344+
345+namespace scopes
346+{
347+
348+namespace internal
349+{
350+
351+/**
352+ * This class is meant for automatically managing the lifetime of C objects derived
353+ * from gobject. Its API perfectly mirrors the API of unique_ptr except that you
354+ * can't define your own deleter function as it is always g_object_unref.
355+ *
356+ * API/ABI stability is not guaranteed. If you need to pass the object across an ABI
357+ * boundary, pass the plain gobject.
358+ *
359+ * This is how you would use gobj_ptr 99% of the time:
360+ *
361+ * gobj_ptr<GSomeType> o(g_some_type_new(...));
362+ *
363+ * More specifically, the object will decrement the gobject reference count
364+ * of the object it points to when it goes out of scope. It will never increment it.
365+ * Thus you should only assign to it when already holding a reference. gobj_ptr
366+ * will then take ownership of that particular reference.
367+ *
368+ * Floating gobjects can not be put in this container as they are meant to be put
369+ * into native gobject aware containers immediately upon construction. Trying to insert
370+ * a floating gobject into a gobj_ptr will throw an invalid_argument exception. To
371+ * prevent accidental memory leaks, the floating gobject is unreffed in this case.
372+ */
373+template <typename T>
374+class gobj_ptr final
375+{
376+private:
377+ T* u;
378+
379+ void validate_float(T* t)
380+ {
381+ if (t != nullptr && g_object_is_floating(G_OBJECT(t)))
382+ {
383+ // LCOV_EXCL_START // False negative from gcovr.
384+ throw std::invalid_argument("Tried to add a floating gobject into a gobj_ptr.");
385+ // LCOV_EXCL_STOP
386+ }
387+ }
388+
389+public:
390+ typedef T element_type;
391+ typedef T* pointer;
392+ typedef decltype(g_object_unref) deleter_type;
393+
394+ constexpr gobj_ptr() noexcept : u(nullptr)
395+ {
396+ }
397+ explicit gobj_ptr(T* t)
398+ : u(t)
399+ {
400+ // What should we do if validate throws? Unreffing unknown objs
401+ // is dodgy but not unreffing runs the risk of
402+ // memory leaks. Currently unrefs as u is destroyed
403+ // when this exception is thrown.
404+ validate_float(t);
405+ }
406+ constexpr gobj_ptr(std::nullptr_t) noexcept : u(nullptr){};
407+ gobj_ptr(gobj_ptr&& o) noexcept
408+ {
409+ u = o.u;
410+ o.u = nullptr;
411+ }
412+ gobj_ptr(const gobj_ptr& o)
413+ : u(nullptr)
414+ {
415+ *this = o;
416+ }
417+ gobj_ptr& operator=(const gobj_ptr& o)
418+ {
419+ if (o.u != nullptr)
420+ {
421+ g_object_ref(o.u);
422+ }
423+ reset(o.u);
424+ return *this;
425+ }
426+ ~gobj_ptr()
427+ {
428+ reset();
429+ }
430+
431+ deleter_type& get_deleter() noexcept
432+ {
433+ return g_object_unref;
434+ }
435+ deleter_type& get_deleter() const noexcept
436+ {
437+ return g_object_unref;
438+ }
439+
440+ void swap(gobj_ptr<T>& o) noexcept
441+ {
442+ T* tmp = u;
443+ u = o.u;
444+ o.u = tmp;
445+ }
446+ void reset(pointer p = pointer())
447+ {
448+ if (u != nullptr)
449+ {
450+ g_object_unref(G_OBJECT(u));
451+ u = nullptr;
452+ }
453+ // Same throw dilemma as in pointer constructor.
454+ u = p;
455+ validate_float(p);
456+ }
457+
458+ T* release() noexcept
459+ {
460+ T* r = u;
461+ u = nullptr;
462+ return r;
463+ }
464+ T* get() const noexcept
465+ {
466+ return u;
467+ }
468+
469+ T& operator*() const
470+ {
471+ return *u;
472+ }
473+ T* operator->() const noexcept
474+ {
475+ return u;
476+ }
477+ explicit operator bool() const noexcept
478+ {
479+ return u != nullptr;
480+ }
481+
482+ gobj_ptr& operator=(gobj_ptr&& o) noexcept
483+ {
484+ reset();
485+ u = o.u;
486+ o.u = nullptr;
487+ return *this;
488+ }
489+ gobj_ptr& operator=(std::nullptr_t) noexcept
490+ {
491+ reset();
492+ return *this;
493+ }
494+ bool operator==(const gobj_ptr<T>& o) const noexcept
495+ {
496+ return u == o.u;
497+ }
498+ bool operator!=(const gobj_ptr<T>& o) const noexcept
499+ {
500+ return u != o.u;
501+ }
502+ bool operator<(const gobj_ptr<T>& o) const noexcept
503+ {
504+ return u < o.u;
505+ }
506+ bool operator<=(const gobj_ptr<T>& o) const noexcept
507+ {
508+ return u <= o.u;
509+ }
510+ bool operator>(const gobj_ptr<T>& o) const noexcept
511+ {
512+ return u > o.u;
513+ }
514+ bool operator>=(const gobj_ptr<T>& o) const noexcept
515+ {
516+ return u >= o.u;
517+ }
518+};
519+
520+} // namespace internal
521+
522+} // namespace scopes
523+
524+} // namespace unity
525+
526+#pragma GCC diagnostic pop
527
528=== modified file 'scoperegistry/scoperegistry.cpp'
529--- scoperegistry/scoperegistry.cpp 2015-09-11 07:29:12 +0000
530+++ scoperegistry/scoperegistry.cpp 2016-06-17 07:24:44 +0000
531@@ -338,7 +338,6 @@
532 convert_relative_attribute(inner_map, "navigation-background", scope_dir);
533 app_attrs["page-header"] = Variant(inner_map);
534 }
535- convert_relative_attribute(app_attrs, "category-header-background", scope_dir);
536 mi->set_appearance_attributes(app_attrs);
537
538 mi->set_scope_directory(scope_dir.native());
539
540=== modified file 'src/scopes/CategoryRenderer.cpp'
541--- src/scopes/CategoryRenderer.cpp 2016-03-08 10:09:42 +0000
542+++ src/scopes/CategoryRenderer.cpp 2016-06-17 07:24:44 +0000
543@@ -66,7 +66,7 @@
544 \arg \c card-layout Specifies layout of the individual result cards; possible values: \c "vertical" (default), \c "horizontal"
545 \arg \c card-size Size of the result cards; possible values: \c "small", \c "medium" (default), \c "large"; when using <tt>"category-layout": "vertical-journal"</tt> any integer between 12 and 38
546 \arg \c overlay Overlay text data on top of the art; boolean, default false
547-\arg \c collapsed-rows Number of result rows displayed while the category is collapsed; possible values: any non-negative integer, where 0 fully expands the category (only affects grid and vertical journal)
548+\arg \c collapsed-rows Number of result rows displayed while the category is collapsed; possible values: any non-negative integer, where 0 fully expands the category (only affects grid)
549 \arg \c card-background Background color for the cards; string; URI in the format \verbatim color:///#rrggbb \endverbatim or \verbatim color:///color_name
550 \endverbatim or \verbatim gradient:///#rrggbb/#rrggbb \endverbatim or an image URI (will be stretched)
551 \arg \c quick-preview-type The type of media content represented by result cards, for use with inline playback; the only currently supported type is "audio".
552
553=== modified file 'src/scopes/PreviewWidget.cpp'
554--- src/scopes/PreviewWidget.cpp 2016-01-18 19:50:19 +0000
555+++ src/scopes/PreviewWidget.cpp 2016-06-17 07:24:44 +0000
556@@ -431,15 +431,18 @@
557 \subsection expandable expandable widget
558
559 The expandable widget is used to group several widgets into an expandable pane.
560+The expandable widget can be collapsed or uncollapsed. When it's uncollapsed then
561+all the contained widgets are shown. When collapsed, only the first few widgets determined
562+by collapsed-widgets attribute are shown.
563
564 List of attributes:
565 \arg \c title A string specifying the title
566-\arg \c collapsed-widgets Optional number of collapsed widgets (0 makes all of them visible)
567+\arg \c collapsed-widgets A number of widgets to show when the expandable widget is collapsed (optional).
568
569 \code
570 PreviewWidget expandable("exp", "expandable");
571 expandable.add_attribute_value("title", Variant("This is an expandable widget"));
572- expandable.add_attribute_value("collapsed-widgets", Variant(0));
573+ expandable.add_attribute_value("collapsed-widgets", Variant(2));
574
575 PreviewWidget w1("w1", "text");
576 w1.add_attribute_value("title", Variant("Subwidget 1"));
577@@ -447,8 +450,12 @@
578 PreviewWidget w2("w2", "text");
579 w2.add_attribute_value("title", Variant("Subwidget 2"));
580 w2.add_attribute_value("text", Variant("A text"));
581+ PreviewWidget w3("w3", "text");
582+ w3.add_attribute_value("title", Variant("Subwidget 3"));
583+ w3.add_attribute_value("text", Variant("A text"));
584 expandable.add_widget(w1);
585 expandable.add_widget(w2);
586+ expandable.add_widget(w3);
587 ...
588 \endcode
589
590
591=== modified file 'src/scopes/internal/JsonCppNode.cpp'
592--- src/scopes/internal/JsonCppNode.cpp 2015-11-02 05:08:08 +0000
593+++ src/scopes/internal/JsonCppNode.cpp 2016-06-17 07:24:44 +0000
594@@ -14,316 +14,399 @@
595 * along with this program. If not, see <http://www.gnu.org/licenses/>.
596 *
597 * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
598+ * Michi Henning <michi.henning@canonical.com>
599 */
600
601 #include <unity/scopes/internal/JsonCppNode.h>
602+
603 #include <unity/UnityExceptions.h>
604-#include <jsoncpp/json/reader.h>
605-#include <jsoncpp/json/writer.h>
606-#include <sstream>
607
608+using namespace std;
609 using namespace unity::scopes;
610 using namespace unity::scopes::internal;
611
612-JsonCppNode::JsonCppNode(std::string const& json_string)
613-{
614- if (!json_string.empty())
615- {
616- read_json(json_string);
617- }
618-}
619-
620-JsonCppNode::JsonCppNode(const Json::Value& root)
621- : root_(root)
622-{
623-}
624-
625-JsonCppNode::JsonCppNode(const Variant& var)
626-{
627- root_ = from_variant(var);
628-}
629-
630-JsonCppNode::~JsonCppNode()
631-{
632-}
633-
634-Json::Value JsonCppNode::from_variant(Variant const& var)
635-{
636+void JsonCppNode::init_from_string(string const& json_string)
637+{
638+ if (json_string.find_first_not_of(" \t\n") == std::string::npos)
639+ {
640+ throw unity::ResourceException("JsonCppNode(): empty string is not a valid JSON");
641+ }
642+
643+ gobj_ptr<JsonParser> parser(json_parser_new());
644+ GError *err = nullptr;
645+ if (!json_parser_load_from_data(parser.get(), json_string.c_str(), json_string.size(), &err))
646+ {
647+ string msg = string("JsonCppNode(); parse error: ") + err->message;
648+ g_error_free(err);
649+ throw unity::ResourceException(msg);
650+ }
651+ root_.reset(json_node_copy(json_parser_get_root(parser.get())));
652+}
653+
654+JsonCppNode::JsonCppNode()
655+ : root_(json_node_alloc(), json_node_free)
656+{
657+ json_node_init_null(root_.get());
658+}
659+
660+JsonCppNode::JsonCppNode(string const& json_string)
661+ : JsonCppNode()
662+{
663+ init_from_string(json_string);
664+}
665+
666+JsonCppNode::JsonCppNode(JsonNode* node)
667+ : root_(json_node_copy(node), json_node_free)
668+{
669+}
670+
671+namespace
672+{
673+
674+// Allocates a new node for each value. Caller is responsible for deallocating the root node.
675+
676+JsonNode* variant_to_node(Variant const& var)
677+{
678+ unique_ptr<JsonNode, decltype(&json_node_free)> node_guard(json_node_alloc(), json_node_free);
679+ auto node = node_guard.get();
680 switch (var.which())
681 {
682+ case Variant::Type::Null:
683+ json_node_init_null(node);
684+ break;
685+ case Variant::Type::Array:
686+ {
687+ unique_ptr<JsonArray, decltype(&json_array_unref)> array(json_array_new(), json_array_unref);
688+ for (auto const& v : var.get_array())
689+ {
690+ json_array_add_element(array.get(), variant_to_node(v));
691+ }
692+ json_node_init_array(node, array.get());
693+ break;
694+ }
695+ case Variant::Type::Dict:
696+ {
697+ unique_ptr<JsonObject, decltype(&json_object_unref)> object(json_object_new(), json_object_unref);
698+ for (auto const& v : var.get_dict())
699+ {
700+ json_object_set_member(object.get(), v.first.c_str(), variant_to_node(v.second));
701+ }
702+ json_node_set_object(node, object.get());
703+ break;
704+ }
705+ case Variant::Type::String:
706+ json_node_init_string(node, var.get_string().c_str());
707+ break;
708 case Variant::Type::Int:
709- return Json::Value(var.get_int());
710+ json_node_init_int(node, int64_t(var.get_int()));
711+ break;
712 case Variant::Type::Int64:
713- return Json::Value(static_cast<Json::Int64>(var.get_int64_t()));
714+ json_node_init_int(node, var.get_int64_t());
715+ break;
716+ case Variant::Type::Double:
717+ json_node_init_double(node, var.get_double());
718+ break;
719 case Variant::Type::Bool:
720- return Json::Value(var.get_bool());
721- case Variant::Type::String:
722- return Json::Value(var.get_string());
723- case Variant::Type::Double:
724- return Json::Value(var.get_double());
725- case Variant::Type::Dict:
726- {
727- Json::Value val(Json::ValueType::objectValue);
728- for (auto const& v: var.get_dict())
729- {
730- val[v.first] = from_variant(v.second);
731- }
732- return val;
733- }
734- case Variant::Type::Array:
735- {
736- Json::Value val(Json::ValueType::arrayValue);
737- for (auto const& v: var.get_array())
738- {
739- val.append(from_variant(v));
740- }
741- return val;
742- }
743- case Variant::Type::Null:
744- return Json::Value(Json::ValueType::nullValue);
745+ {
746+ json_node_init_boolean(node, var.get_bool());
747+ break;
748+ }
749 default:
750- {
751- std::ostringstream s;
752- s << "JsonCppNode::from_variant(): unsupported variant type ";
753- s << static_cast<int>(var.which());
754- throw unity::LogicException(s.str());
755- }
756+ {
757+ abort(); // LCOV_EXCL_LINE // Impossible
758+ }
759 }
760-}
761-
762-Variant JsonCppNode::to_variant(Json::Value const& value)
763-{
764- switch (value.type())
765+ return node_guard.release();
766+}
767+
768+} // namespace
769+
770+JsonCppNode::JsonCppNode(Variant const& var)
771+ : root_(variant_to_node(var), json_node_free)
772+{
773+}
774+
775+#pragma GCC diagnostic push
776+#pragma GCC diagnostic ignored "-Wold-style-cast"
777+
778+namespace
779+{
780+
781+Variant node_to_variant(JsonNode* node); // Mutual recursion, need forward declaration.
782+
783+extern "C"
784+void add_to_array(JsonArray* /* array */, guint /* index */, JsonNode* element_node, gpointer user_data)
785+{
786+ VariantArray* va = reinterpret_cast<VariantArray*>(user_data);
787+ va->push_back(node_to_variant(element_node));
788+}
789+
790+extern "C"
791+void add_to_map(JsonObject* /* object */, gchar const* member_name, JsonNode* member_node, gpointer user_data)
792+{
793+ VariantMap* vm = reinterpret_cast<VariantMap*>(user_data);
794+ (*vm)[member_name] = node_to_variant(member_node);
795+}
796+
797+Variant node_to_variant(JsonNode* node)
798+{
799+ switch (json_node_get_node_type(node))
800 {
801- case Json::ValueType::nullValue:
802+ case JSON_NODE_NULL:
803 return Variant::null();
804- case Json::ValueType::arrayValue:
805- {
806- VariantArray arr;
807- for (unsigned int i=0; i<value.size(); ++i)
808- {
809- arr.push_back(to_variant(value[i]));
810- }
811- return Variant(arr);
812- }
813- case Json::ValueType::objectValue:
814- {
815- VariantMap var;
816- for (auto const& m: value.getMemberNames())
817- {
818- var[m] = to_variant(value[m]);
819- }
820- return Variant(var);
821- }
822- case Json::ValueType::stringValue:
823- return Variant(value.asString());
824- case Json::ValueType::intValue:
825- case Json::ValueType::uintValue:
826- // this can throw std::runtime_error from jsoncpp if unsigned int to int conversion is not possible
827- if (value.isInt())
828- {
829- return Variant(value.asInt());
830- }
831- return Variant(static_cast<int64_t>(value.asInt64()));
832- case Json::ValueType::realValue:
833- return Variant(value.asDouble());
834- case Json::ValueType::booleanValue:
835- return Variant(value.asBool());
836+ case JSON_NODE_ARRAY:
837+ {
838+ VariantArray va;
839+ auto array = json_node_get_array(node);
840+ json_array_foreach_element(array, add_to_array, &va);
841+ return Variant(va);
842+ }
843+ case JSON_NODE_OBJECT:
844+ {
845+ VariantMap vm;
846+ auto object = json_node_get_object(node);
847+ json_object_foreach_member(object, add_to_map, &vm);
848+ return Variant(vm);
849+ }
850+ case JSON_NODE_VALUE:
851+ {
852+ switch (json_node_get_value_type(node))
853+ {
854+ case G_TYPE_STRING:
855+ return Variant(string(json_node_get_string(node)));
856+ case G_TYPE_INT64:
857+ {
858+ // HACK: If the value fits into a 32-bit int, return an Int
859+ // variant. Otherwise, return an Int64 variant.
860+ int64_t val64 = json_node_get_int(node);
861+ if (val64 < INT32_MIN || val64 > INT32_MAX)
862+ {
863+ return Variant(val64);
864+ }
865+ int32_t val32 = val64;
866+ return Variant(val32);
867+ }
868+ case G_TYPE_DOUBLE:
869+ return Variant(json_node_get_double(node));
870+ case G_TYPE_BOOLEAN:
871+ return Variant(bool(json_node_get_boolean(node)));
872+ default:
873+ abort(); // LCOV_EXCL_LINE // Impossible
874+ }
875+ }
876 default:
877- {
878- std::ostringstream s;
879- s << "JsonCppNode::to_variant(): unsupported json type ";
880- s << static_cast<int>(value.type());
881- throw unity::LogicException(s.str());
882- }
883+ abort(); // LCOV_EXCL_LINE // Impossible
884 }
885 }
886
887+} // namespace
888+
889 Variant JsonCppNode::to_variant() const
890 {
891- return to_variant(root_);
892+ return node_to_variant(root_.get());
893 }
894
895 void JsonCppNode::clear()
896 {
897- root_.clear();
898-}
899-
900-void JsonCppNode::read_json(std::string const& json_string)
901-{
902- Json::Reader reader;
903- clear();
904-
905- if (!reader.parse(json_string, root_))
906- {
907- throw unity::ResourceException("Failed to parse json string: " + reader.getFormattedErrorMessages());
908- }
909-}
910-
911-std::string JsonCppNode::to_json_string() const
912-{
913- Json::FastWriter writer;
914- return writer.write(root_);
915+ json_node_init_null(root_.get());
916+}
917+
918+void JsonCppNode::read_json(string const& json_string)
919+{
920+ init_from_string(json_string);
921+}
922+
923+string JsonCppNode::to_json_string() const
924+{
925+ gobj_ptr<JsonGenerator> generator(json_generator_new());
926+ json_generator_set_root(generator.get(), root_.get());
927+
928+ gsize len;
929+ unique_ptr<gchar, decltype(&g_free)> data(json_generator_to_data(generator.get(), &len), g_free);
930+ string result(data.get(), len);
931+ result += '\n';
932+ return result;
933 }
934
935 int JsonCppNode::size() const
936 {
937- return root_.size();
938-}
939-
940-std::vector<std::string> JsonCppNode::member_names() const
941-{
942- if (root_.type() != Json::objectValue)
943+ switch (json_node_get_node_type(root_.get()))
944+ {
945+ case JSON_NODE_ARRAY:
946+ {
947+ auto array = json_node_get_array(root_.get());
948+ return json_array_get_length(array);
949+ }
950+ case JSON_NODE_OBJECT:
951+ {
952+ auto object = json_node_get_object(root_.get());
953+ return json_object_get_size(object);
954+ }
955+ default:
956+ return 0;
957+ }
958+}
959+
960+namespace
961+{
962+
963+extern "C"
964+void add_name(JsonObject* /* object */, gchar const* member_name, JsonNode* /* member_node */, gpointer user_data)
965+{
966+ vector<string>* names = reinterpret_cast<vector<string>*>(user_data);
967+ names->push_back(member_name);
968+}
969+
970+}
971+
972+vector<string> JsonCppNode::member_names() const
973+{
974+ if (!JSON_NODE_HOLDS_OBJECT(root_.get()))
975 {
976 throw unity::LogicException("Root node is not an object");
977 }
978- return root_.getMemberNames();
979+
980+ vector<string> names;
981+ auto object = json_node_get_object(root_.get());
982+ json_object_foreach_member(object, add_name, &names);
983+ return names;
984 }
985
986 JsonNodeInterface::NodeType JsonCppNode::type() const
987 {
988- switch (root_.type())
989+ switch (json_node_get_node_type(root_.get()))
990 {
991- case Json::nullValue:
992+ case JSON_NODE_NULL:
993 return Null;
994- case Json::arrayValue:
995+ case JSON_NODE_ARRAY:
996 return Array;
997- case Json::objectValue:
998+ case JSON_NODE_OBJECT:
999 return Object;
1000- case Json::stringValue:
1001- return String;
1002- case Json::intValue:
1003- return Int;
1004- case Json::uintValue:
1005- return UInt;
1006- case Json::realValue:
1007- return Real;
1008- case Json::booleanValue:
1009- return Bool;
1010+ case JSON_NODE_VALUE:
1011+ {
1012+ switch (json_node_get_value_type(root_.get()))
1013+ {
1014+ case G_TYPE_STRING:
1015+ return String;
1016+ case G_TYPE_INT64:
1017+ return Int;
1018+ case G_TYPE_DOUBLE:
1019+ return Real;
1020+ case G_TYPE_BOOLEAN:
1021+ return Bool;
1022+ default:
1023+ abort(); // LCOV_EXCL_LINE // Impossible
1024+ }
1025+ }
1026 default:
1027- break;
1028+ abort(); // LCOV_EXCL_LINE // Impossible
1029 }
1030
1031- return Null;
1032+ abort(); // LCOV_EXCL_LINE
1033 }
1034
1035-std::string JsonCppNode::as_string() const
1036+string JsonCppNode::as_string() const
1037 {
1038- if (!root_.isConvertibleTo(Json::stringValue))
1039+ if (JSON_NODE_HOLDS_NULL(root_.get()))
1040+ {
1041+ return string();
1042+ }
1043+ if (!JSON_NODE_HOLDS_VALUE(root_.get()) || json_node_get_value_type(root_.get()) != G_TYPE_STRING)
1044 {
1045 throw unity::LogicException("Node does not contain a string value");
1046 }
1047
1048- return root_.asString();
1049+ return string(json_node_get_string(root_.get()));
1050 }
1051
1052-int JsonCppNode::as_int() const
1053+int64_t JsonCppNode::as_int() const
1054 {
1055- if (!root_.isConvertibleTo(Json::intValue))
1056+ if (!JSON_NODE_HOLDS_VALUE(root_.get()) || json_node_get_value_type(root_.get()) != G_TYPE_INT64)
1057 {
1058 throw unity::LogicException("Node does not contain an int value");
1059 }
1060
1061- return root_.asInt();
1062-}
1063-
1064-unsigned int JsonCppNode::as_uint() const
1065-{
1066- if (!root_.isConvertibleTo(Json::uintValue))
1067- {
1068- throw unity::LogicException("Node does not contain a unsigned int value");
1069- }
1070-
1071- return root_.asUInt();
1072+ return json_node_get_int(root_.get());
1073 }
1074
1075 double JsonCppNode::as_double() const
1076 {
1077- if (!root_.isConvertibleTo(Json::realValue))
1078+ if (!JSON_NODE_HOLDS_VALUE(root_.get()) || json_node_get_value_type(root_.get()) != G_TYPE_DOUBLE)
1079 {
1080 throw unity::LogicException("Node does not contain a double value");
1081 }
1082
1083- return root_.asDouble();
1084+ return json_node_get_double(root_.get());
1085 }
1086
1087 bool JsonCppNode::as_bool() const
1088 {
1089- if (!root_.isConvertibleTo(Json::booleanValue))
1090+ if (!JSON_NODE_HOLDS_VALUE(root_.get()) || json_node_get_value_type(root_.get()) != G_TYPE_BOOLEAN)
1091 {
1092 throw unity::LogicException("Node does not contain a bool value");
1093 }
1094
1095- return root_.asBool();
1096+ return json_node_get_boolean(root_.get());
1097 }
1098
1099-bool JsonCppNode::has_node(std::string const& node_name) const
1100+#pragma GCC diagnostic pop
1101+
1102+bool JsonCppNode::has_node(string const& node_name) const
1103 {
1104- if (!root_)
1105+ if (JSON_NODE_HOLDS_NULL(root_.get()))
1106 {
1107 throw unity::LogicException("Current node is empty");
1108 }
1109
1110- if (root_.type() != Json::objectValue)
1111+ if (!JSON_NODE_HOLDS_OBJECT(root_.get()))
1112 {
1113 throw unity::LogicException("Root node is not an object");
1114 }
1115
1116- return root_.isMember(node_name);
1117+ return json_object_has_member(json_node_get_object(root_.get()), node_name.c_str());
1118 }
1119
1120 JsonNodeInterface::SPtr JsonCppNode::get_node() const
1121 {
1122- if (!root_)
1123+ if (JSON_NODE_HOLDS_NULL(root_.get()))
1124 {
1125 throw unity::LogicException("Current node is empty");
1126 }
1127
1128- return std::make_shared<JsonCppNode>(root_);
1129+ return make_shared<JsonCppNode>(root_.get());
1130 }
1131
1132-JsonNodeInterface::SPtr JsonCppNode::get_node(std::string const& node_name) const
1133+JsonNodeInterface::SPtr JsonCppNode::get_node(string const& node_name) const
1134 {
1135- if (!root_)
1136- {
1137- throw unity::LogicException("Current node is empty");
1138- }
1139-
1140- if (root_.type() != Json::objectValue)
1141- {
1142- throw unity::LogicException("Root node is not an object");
1143- }
1144- if (!root_.isMember(node_name))
1145+ if (!has_node(node_name))
1146 {
1147 throw unity::LogicException("Node " + node_name + " does not exist");
1148 }
1149
1150- const Json::Value& value_node = root_[node_name];
1151- return std::make_shared<JsonCppNode>(value_node);
1152+ auto object = json_node_get_object(root_.get());
1153+ auto member = json_object_get_member(object, node_name.c_str());
1154+ return make_shared<JsonCppNode>(member);
1155 }
1156
1157 JsonNodeInterface::SPtr JsonCppNode::get_node(unsigned int node_index) const
1158 {
1159- if (!root_)
1160+ if (JSON_NODE_HOLDS_NULL(root_.get()))
1161 {
1162 throw unity::LogicException("Current node is empty");
1163 }
1164
1165- if (root_.type() != Json::arrayValue)
1166+ if (!JSON_NODE_HOLDS_ARRAY(root_.get()))
1167 {
1168 throw unity::LogicException("Root node is not an array");
1169 }
1170- else if (node_index >= root_.size())
1171- {
1172- throw unity::LogicException("Invalid array index");
1173- }
1174-
1175- const Json::Value& value_node = root_[node_index];
1176-
1177- if (!value_node)
1178- {
1179- throw unity::LogicException("Node " + std::to_string(node_index) + " does not exist");
1180- }
1181-
1182- return std::make_shared <JsonCppNode> (value_node);
1183+
1184+ auto array = json_node_get_array(root_.get());
1185+ auto size = json_array_get_length(array);
1186+ if (node_index >= size)
1187+ {
1188+ throw unity::LogicException("Invalid array index: " + to_string(node_index));
1189+ }
1190+
1191+ auto element = json_array_get_element(array, node_index);
1192+ return make_shared<JsonCppNode>(element);
1193 }
1194
1195=== modified file 'src/scopes/internal/JsonSettingsSchema.cpp'
1196--- src/scopes/internal/JsonSettingsSchema.cpp 2015-03-02 03:59:01 +0000
1197+++ src/scopes/internal/JsonSettingsSchema.cpp 2016-06-17 07:24:44 +0000
1198@@ -19,10 +19,10 @@
1199 #include <unity/scopes/internal/JsonSettingsSchema.h>
1200
1201 #include <unity/scopes/internal/DfltConfig.h>
1202+#include <unity/scopes/internal/JsonCppNode.h>
1203
1204 #include <boost/algorithm/string/predicate.hpp>
1205 #include <boost/filesystem.hpp>
1206-#include <jsoncpp/json/json.h>
1207 #include <unity/UnityExceptions.h>
1208
1209 #include <set>
1210@@ -52,7 +52,7 @@
1211 public:
1212 NONCOPYABLE(Setting);
1213
1214- Setting(Json::Value const& v);
1215+ Setting(Variant const& v);
1216 Setting(string const& id,
1217 string const& type,
1218 string const& display_name,
1219@@ -68,13 +68,13 @@
1220
1221 private:
1222
1223- Json::Value get_mandatory(Json::Value const& v, Json::StaticString const& key, Json::ValueType expected_type) const;
1224- void set_default_value(Json::Value const& v, Type expected_type);
1225- Variant get_bool_default(Json::Value const& v) const;
1226- Variant get_enum_default(Json::Value const& v);
1227- Variant get_double_default(Json::Value const& v) const;
1228- Variant get_string_default(Json::Value const& v) const;
1229- void set_enumerators(Json::Value const& v);
1230+ Variant get_mandatory(Variant const& v, string const& key, Variant::Type expected_type) const;
1231+ void set_default_value(Variant const& v, Type expected_type);
1232+ Variant get_bool_default(Variant const& v) const;
1233+ Variant get_enum_default(Variant const& v);
1234+ Variant get_double_default(Variant const& v) const;
1235+ Variant get_string_default(Variant const& v) const;
1236+ void set_enumerators(Variant const& v);
1237
1238 string id_;
1239 string type_;
1240@@ -90,32 +90,32 @@
1241 { "string", Setting::StringT },
1242 };
1243
1244-Setting::Setting(Json::Value const& v)
1245+Setting::Setting(Variant const& v)
1246 {
1247- assert(v.isObject());
1248-
1249- static auto const id_key = Json::StaticString("id");
1250- static auto const type_key = Json::StaticString("type");
1251- static auto const display_name_key = Json::StaticString("displayName");
1252-
1253- id_ = get_mandatory(v, id_key, Json::stringValue).asString();
1254+ assert(v.which() == Variant::Type::Dict);
1255+
1256+ static string const id_key = "id";
1257+ static string const type_key = "type";
1258+ static string const display_name_key = "displayName";
1259+
1260+ id_ = get_mandatory(v, id_key, Variant::Type::String).get_string();
1261 if (id_.empty())
1262 {
1263- throw ResourceException(string("JsonSettingsSchema(): invalid empty \"") + id_key.c_str() + "\" definition");
1264+ throw ResourceException(string("JsonSettingsSchema(): invalid empty \"") + id_key + "\" definition");
1265 }
1266
1267- auto v_type = get_mandatory(v, type_key, Json::stringValue);
1268- string type_string = v_type.asString();
1269+ auto v_type = get_mandatory(v, type_key, Variant::Type::String);
1270+ string type_string = v_type.get_string();
1271 auto const it = VALID_TYPES.find(type_string);
1272 if (it == VALID_TYPES.end())
1273 {
1274- throw ResourceException(string("JsonSettingsSchema(): invalid \"") + type_key.c_str() + "\" setting: \""
1275- + type_string + "\", " "id = \"" + id_ + "\"");
1276+ throw ResourceException(string("JsonSettingsSchema(): invalid \"") + type_key + "\" definition: \""
1277+ + type_string + "\", " "id = \"" + id_ + "\"");
1278 }
1279 type_ = it->first;
1280 set_default_value(v, it->second);
1281
1282- display_name_ = get_mandatory(v, display_name_key, Json::stringValue).asString();
1283+ display_name_ = get_mandatory(v, display_name_key, Variant::Type::String).get_string();
1284 }
1285
1286 Setting::Setting(string const& id,
1287@@ -131,11 +131,7 @@
1288 assert(!id.empty());
1289
1290 auto const it = VALID_TYPES.find(type);
1291- if (it == VALID_TYPES.end())
1292- {
1293- throw ResourceException(string("JsonSettingsSchema(): invalid \"type\" definition: \"")
1294- + type + "\", setting = \"" + id_ + "\"");
1295- }
1296+ assert(it != VALID_TYPES.end());
1297 type_ = it->first;
1298 }
1299
1300@@ -158,35 +154,33 @@
1301 return Variant(schema);
1302 }
1303
1304-Json::Value Setting::get_mandatory(Json::Value const& v,
1305- Json::StaticString const& key,
1306- Json::ValueType expected_type) const
1307+Variant Setting::get_mandatory(Variant const& v, string const& key, Variant::Type expected_type) const
1308 {
1309- assert(v.isObject());
1310- auto val = v[key];
1311- if (val.isNull())
1312+ assert(v.which() == Variant::Type::Dict);
1313+ auto val = v.get_dict()[key];
1314+ if (val.is_null())
1315 {
1316- throw ResourceException(string("JsonSettingsSchema(): missing \"") + key.c_str() + "\" definition"
1317- + (!id_.empty() ? ", id = \"" + id_ + "\"" : string()));
1318+ throw ResourceException(string("JsonSettingsSchema(): missing \"") + key + "\" definition"
1319+ + (!id_.empty() ? ", id = \"" + id_ + "\"" : string()));
1320 }
1321- if (val.type() != expected_type)
1322+ if (val.which() != expected_type)
1323 {
1324- throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + key.c_str() + "\" definition, "
1325- + "id = \"" + id_ + "\"");
1326+ throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + key
1327+ + "\" definition, " + "id = \"" + id_ + "\"");
1328 }
1329 return val;
1330 }
1331
1332-static auto const parameters_key = Json::StaticString("parameters");
1333+static string const parameters_key = "parameters";
1334
1335-void Setting::set_default_value(Json::Value const& v, Type expected_type)
1336+void Setting::set_default_value(Variant const& v, Type expected_type)
1337 {
1338- auto v_param = v[parameters_key];
1339- if (v_param.isNull())
1340+ auto v_param = v.get_dict()[parameters_key];
1341+ if (v_param.is_null())
1342 {
1343 return;
1344 }
1345- else if (!v_param.isObject())
1346+ else if (v_param.which() != Variant::Type::Dict)
1347 {
1348 throw ResourceException("JsonSettingsSchema(): expected value of type object for \"parameters\", id = \"" + id_ + "\"");
1349 }
1350@@ -219,124 +213,120 @@
1351 }
1352 }
1353
1354-static auto const dflt_key = Json::StaticString("defaultValue");
1355-
1356-Variant Setting::get_bool_default(Json::Value const& v) const
1357-{
1358- if (v.isNull()) // No "parameters" key
1359- {
1360- return Variant();
1361- }
1362- auto v_dflt = v[dflt_key];
1363- if (v_dflt.isNull())
1364- {
1365- return Variant(); // No "defaultValue" key
1366- }
1367- if (!v_dflt.isBool())
1368- {
1369- throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + dflt_key.c_str()
1370- + "\" definition, id = \"" + id_ + "\"");
1371- }
1372- return Variant(v_dflt.asBool());
1373-}
1374-
1375-Variant Setting::get_double_default(Json::Value const& v) const
1376-{
1377- if (v.isNull()) // No "parameters" key
1378- {
1379- return Variant();
1380- }
1381- auto v_dflt = v[dflt_key];
1382- if (v_dflt.isNull())
1383- {
1384- return Variant(); // No "defaultValue" key
1385- }
1386- if (!v_dflt.isNumeric())
1387- {
1388- throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + dflt_key.c_str()
1389- + "\" definition, id = \"" + id_ + "\"");
1390- }
1391- return Variant(v_dflt.asDouble());
1392-}
1393-
1394-Variant Setting::get_enum_default(Json::Value const& v)
1395-{
1396- assert(v.isObject());
1397-
1398- if (v.isNull()) // No "parameters" key
1399- {
1400- throw ResourceException(string("JsonSettingsSchema(): missing \"") + parameters_key.c_str()
1401- + "\" definition, id = \"" + id_ + "\"");
1402- }
1403- auto v_dflt = v[dflt_key];
1404- if (v_dflt.isNull())
1405- {
1406- return Variant(); // No "defaultValue" key
1407- }
1408- if (!v_dflt.isInt())
1409- {
1410- throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + dflt_key.c_str()
1411- + "\" definition, id = \"" + id_ + "\"");
1412- }
1413-
1414- static auto const values_key = Json::StaticString("values");
1415-
1416- auto v_vals = v[values_key];
1417- if (!v_vals.isArray())
1418- {
1419- throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + values_key.c_str()
1420- + "\" definition, id = \"" + id_ + "\"");
1421- }
1422- if (v_vals.size() < 1)
1423- {
1424- throw ResourceException(string("JsonSettingsSchema(): invalid empty \"") + values_key.c_str()
1425- + "\" definition, id = \"" + id_ + "\"");
1426+static string const dflt_key = "defaultValue";
1427+
1428+Variant Setting::get_bool_default(Variant const& v) const
1429+{
1430+ assert(!v.is_null());
1431+
1432+ auto v_dflt = v.get_dict()[dflt_key];
1433+ if (v_dflt.is_null())
1434+ {
1435+ return Variant(); // No "defaultValue" key
1436+ }
1437+ if (v_dflt.which() != Variant::Type::Bool)
1438+ {
1439+ throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + dflt_key
1440+ + "\" definition, id = \"" + id_ + "\"");
1441+ }
1442+ return v_dflt;
1443+}
1444+
1445+Variant Setting::get_double_default(Variant const& v) const
1446+{
1447+ assert(!v.is_null());
1448+
1449+ auto v_dflt = v.get_dict()[dflt_key];
1450+ if (v_dflt.is_null())
1451+ {
1452+ return Variant(); // No "defaultValue" key
1453+ }
1454+ switch (v_dflt.which())
1455+ {
1456+ case Variant::Type::Int:
1457+ return Variant(double(v_dflt.get_int()));
1458+ case Variant::Type::Int64:
1459+ return Variant(double(v_dflt.get_int64_t()));
1460+ case Variant::Type::Double:
1461+ return v_dflt;
1462+ default:
1463+ throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + dflt_key
1464+ + "\" definition, id = \"" + id_ + "\"");
1465+ }
1466+}
1467+
1468+Variant Setting::get_enum_default(Variant const& v)
1469+{
1470+ assert(v.which() == Variant::Type::Dict);
1471+
1472+ auto v_dflt = v.get_dict()[dflt_key];
1473+ if (v_dflt.is_null())
1474+ {
1475+ return Variant(); // No "defaultValue" key
1476+ }
1477+ if (v_dflt.which() != Variant::Type::Int)
1478+ {
1479+ throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + dflt_key
1480+ + "\" definition, id = \"" + id_ + "\"");
1481+ }
1482+
1483+ static string const values_key = "values";
1484+
1485+ auto v_vals = v.get_dict()[values_key];
1486+ if (v_vals.which() != Variant::Type::Array)
1487+ {
1488+ throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + values_key
1489+ + "\" definition, id = \"" + id_ + "\"");
1490+ }
1491+ if (v_vals.get_array().size() == 0)
1492+ {
1493+ throw ResourceException(string("JsonSettingsSchema(): invalid empty \"") + values_key
1494+ + "\" definition, id = \"" + id_ + "\"");
1495 }
1496
1497 set_enumerators(v_vals);
1498
1499- auto val = v_dflt.asInt();
1500- if (val < 0 || val >= static_cast<int>(v_vals.size()))
1501+ auto val = v_dflt.get_int();
1502+ if (val < 0 || val >= static_cast<int>(v_vals.get_array().size()))
1503 {
1504- throw ResourceException(string("JsonSettingsSchema(): \"") + dflt_key.c_str()
1505- + "\" out of range, id = \"" + id_ + "\"");
1506+ throw ResourceException(string("JsonSettingsSchema(): \"") + dflt_key
1507+ + "\" out of range, id = \"" + id_ + "\"");
1508 }
1509- return Variant(v_dflt.asInt());
1510+ return v_dflt;
1511 }
1512
1513-Variant Setting::get_string_default(Json::Value const& v) const
1514+Variant Setting::get_string_default(Variant const& v) const
1515 {
1516- if (v.isNull()) // No "parameters" key
1517- {
1518- return Variant();
1519- }
1520- auto v_dflt = v[dflt_key];
1521- if (v_dflt.isNull())
1522+ assert(!v.is_null());
1523+
1524+ auto v_dflt = v.get_dict()[dflt_key];
1525+ if (v_dflt.is_null())
1526 {
1527 return Variant(); // No "defaultValue" key
1528 }
1529- if (!v_dflt.isString())
1530+ if (v_dflt.which() != Variant::Type::String)
1531 {
1532- throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + dflt_key.c_str()
1533- + "\" definition, id = \"" + id_ + "\"");
1534+ throw ResourceException(string("JsonSettingsSchema(): invalid value type for \"") + dflt_key
1535+ + "\" definition, id = \"" + id_ + "\"");
1536 }
1537- return Variant(v_dflt.asString());
1538+ return v_dflt;
1539 }
1540
1541-void Setting::set_enumerators(Json::Value const& v)
1542+void Setting::set_enumerators(Variant const& v)
1543 {
1544- assert(v.isArray());
1545+ assert(v.which() == Variant::Type::Array);
1546
1547 set<string> enums_seen;
1548
1549- for (unsigned i = 0; i < v.size(); ++i)
1550+ VariantArray va = v.get_array();
1551+ for (unsigned i = 0; i < va.size(); ++i)
1552 {
1553- Json::Value enumerator = v[i];
1554- if (!enumerator.isString())
1555+ Variant enumerator = v.get_array()[i];
1556+ if (enumerator.which() != Variant::Type::String)
1557 {
1558 throw ResourceException(string("JsonSettingsSchema(): invalid enumerator type, id = \"") + id_ + "\"");
1559 }
1560- string enum_str = enumerator.asString();
1561+ string enum_str = enumerator.get_string();
1562 if (enum_str.empty())
1563 {
1564 throw ResourceException(string("JsonSettingsSchema(): invalid empty enumerator, id = \"") + id_ + "\"");
1565@@ -347,7 +337,7 @@
1566 + "\", id = \"" + id_ + "\"");
1567 }
1568 enums_seen.insert(enum_str);
1569- enumerators_.emplace_back(Variant(enum_str));
1570+ enumerators_.emplace_back(enumerator);
1571 }
1572 }
1573
1574@@ -367,39 +357,36 @@
1575 {
1576 try
1577 {
1578- Json::Value root;
1579- Json::Reader reader;
1580- if (!reader.parse(json_string, root))
1581- {
1582- throw ResourceException("JsonSettingsSchema(): cannot parse schema: " + reader.getFormattedErrorMessages());
1583- }
1584-
1585- if (!root.isArray())
1586- {
1587- root = root["settings"];
1588- }
1589- if (root.isNull())
1590- {
1591- throw ResourceException("JsonSettingsSchema(): missing \"settings\" definition");
1592- }
1593- if (!root.isArray())
1594- {
1595- throw ResourceException("JsonSettingsSchema(): value \"settings\" must be an array");
1596- }
1597+ JsonCppNode::SPtr root = make_shared<JsonCppNode>(json_string);
1598+
1599+ if (root->type() != JsonNodeInterface::Array)
1600+ {
1601+ if (root->type() != JsonNodeInterface::Object || !root->has_node("settings"))
1602+ {
1603+ throw ResourceException("JsonSettingsSchema(): missing \"settings\" definition");
1604+ }
1605+ root = root->get_node("settings");
1606+ if (root->type() != JsonNodeInterface::Array)
1607+ {
1608+ throw ResourceException("JsonSettingsSchema(): value \"settings\" must be an array");
1609+ }
1610+ }
1611+
1612 set<string> seen_settings;
1613- for (unsigned i = 0; i < root.size(); ++i)
1614+ for (int i = 0; i < root->size(); ++i)
1615 {
1616- Setting s(root[i]);
1617+ Setting s(root->get_node(i)->to_variant());
1618 if (starts_with(s.id(), "internal."))
1619 {
1620- throw ResourceException(string("JsonSettingsSchema(): invalid key \"") + s.id() + "\" prefixed with \"internal.\"");
1621+ throw ResourceException(string("JsonSettingsSchema(): invalid key \"") + s.id()
1622+ + "\" prefixed with \"internal.\"");
1623 }
1624 if (seen_settings.find(s.id()) != seen_settings.end())
1625 {
1626 throw ResourceException("JsonSettingsSchema(): duplicate definition, id = \"" + s.id() + "\"");
1627 }
1628+ seen_settings.insert(s.id());
1629 definitions_.push_back(s.to_schema_definition());
1630- seen_settings.insert(s.id());
1631 }
1632 }
1633 catch (ResourceException const&)
1634
1635=== modified file 'src/scopes/internal/Logger.cpp'
1636--- src/scopes/internal/Logger.cpp 2016-02-22 05:00:23 +0000
1637+++ src/scopes/internal/Logger.cpp 2016-06-17 07:24:44 +0000
1638@@ -41,10 +41,10 @@
1639 static array<string, 5> const severities = {{"INFO", "WARNING", "ERROR", "FATAL", "TRACE"}};
1640
1641 static array<pair<string, LoggerChannel>, int(LoggerChannel::LastChannelEnum_)> const channel_names =
1642-{
1643+{ {
1644 pair<string, LoggerChannel>{"", LoggerChannel::DefaultChannel},
1645 pair<string, LoggerChannel>{"IPC", LoggerChannel::IPC}
1646-};
1647+} };
1648
1649 } // namespace
1650
1651
1652=== modified file 'src/scopes/internal/RuntimeImpl.cpp'
1653--- src/scopes/internal/RuntimeImpl.cpp 2016-02-22 14:16:26 +0000
1654+++ src/scopes/internal/RuntimeImpl.cpp 2016-06-17 07:24:44 +0000
1655@@ -366,7 +366,7 @@
1656 string settings_schema = scope_dir.native() + "/" + scope_id_ + "-settings.ini";
1657
1658 boost::system::error_code ec;
1659- if (boost::filesystem::exists(settings_schema, ec))
1660+ if (boost::filesystem::exists(settings_schema, ec) && boost::filesystem::file_size(settings_schema) > 0)
1661 {
1662 shared_ptr<SettingsDB> db(SettingsDB::create_from_ini_file(settings_db, settings_schema));
1663 scope_base->p->set_settings_db(db);
1664
1665=== modified file 'src/scopes/internal/ScopeConfig.cpp'
1666--- src/scopes/internal/ScopeConfig.cpp 2015-07-17 09:03:33 +0000
1667+++ src/scopes/internal/ScopeConfig.cpp 2016-06-17 07:24:44 +0000
1668@@ -67,7 +67,6 @@
1669 const string fg_color_key = "ForegroundColor";
1670 const string bg_color_key = "BackgroundColor";
1671 const string shape_images_key = "ShapeImages";
1672- const string category_header_bg_key = "CategoryHeaderBackground";
1673 const string preview_button_color_key = "PreviewButtonColor";
1674 const string logo_overlay_color_key = "LogoOverlayColor";
1675 const string pageheader_logo_key = "PageHeader.Logo";
1676@@ -317,7 +316,6 @@
1677 fg_color_key,
1678 bg_color_key,
1679 shape_images_key,
1680- category_header_bg_key,
1681 preview_button_color_key,
1682 logo_overlay_color_key,
1683 pageheader_logo_key,
1684
1685=== modified file 'src/scopes/internal/smartscopes/SmartScopesClient.cpp'
1686--- src/scopes/internal/smartscopes/SmartScopesClient.cpp 2016-02-25 11:40:06 +0000
1687+++ src/scopes/internal/smartscopes/SmartScopesClient.cpp 2016-06-17 07:24:44 +0000
1688@@ -592,6 +592,11 @@
1689
1690 void SmartScopesClient::handle_line(std::string const& json, PreviewReplyHandler const& handler)
1691 {
1692+ if (json.empty())
1693+ {
1694+ return;
1695+ }
1696+
1697 JsonNodeInterface::SPtr root_node;
1698 JsonNodeInterface::SPtr child_node;
1699 {
1700@@ -640,6 +645,11 @@
1701
1702 void SmartScopesClient::handle_line(std::string const& json, SearchReplyHandler& handler)
1703 {
1704+ if (json.empty())
1705+ {
1706+ return;
1707+ }
1708+
1709 JsonNodeInterface::SPtr root_node;
1710 JsonNodeInterface::SPtr child_node;
1711
1712
1713=== modified file 'src/scopes/internal/zmq_middleware/StopPublisher.cpp'
1714--- src/scopes/internal/zmq_middleware/StopPublisher.cpp 2014-11-18 07:04:04 +0000
1715+++ src/scopes/internal/zmq_middleware/StopPublisher.cpp 2016-06-17 07:24:44 +0000
1716@@ -121,7 +121,7 @@
1717 s.set(zmqpp::socket_option::linger, 0);
1718 s.connect(endpoint_);
1719 s.subscribe("");
1720- return move(s);
1721+ return s;
1722 }
1723 }
1724 }
1725
1726=== modified file 'src/scopes/testing/ScopeMetadataBuilder.cpp'
1727--- src/scopes/testing/ScopeMetadataBuilder.cpp 2015-02-22 22:27:09 +0000
1728+++ src/scopes/testing/ScopeMetadataBuilder.cpp 2016-06-17 07:24:44 +0000
1729@@ -212,9 +212,7 @@
1730 if (p->is_aggregator)
1731 impl->set_is_aggregator(*p->is_aggregator);
1732
1733- return unity::scopes::internal::ScopeMetadataImpl::create(
1734- std::move(
1735- std::unique_ptr<internal::ScopeMetadataImpl>{impl}));
1736+ return unity::scopes::internal::ScopeMetadataImpl::create(std::unique_ptr<internal::ScopeMetadataImpl>{impl});
1737 }
1738
1739 /// @endcond
1740
1741=== modified file 'test/copyright/check_copyright.sh'
1742--- test/copyright/check_copyright.sh 2015-11-13 06:33:11 +0000
1743+++ test/copyright/check_copyright.sh 2016-06-17 07:24:44 +0000
1744@@ -31,13 +31,7 @@
1745 [ $# -lt 1 ] && usage
1746 [ $# -gt 2 ] && usage
1747
1748-# TODO: Temporary hack to work around broken licensecheck on xenial. Remove this once that is fixed.
1749-distro=$(lsb_release -c -s)
1750-[ "$distro" = "xenial" ] && {
1751- exit 0
1752-}
1753-
1754-ignore_pat="\\.sci$"
1755+ignore_pat="\\.sci$|.bzr|debian|tsan-suppress|valgrind-suppress|RELEASE_NOTES.md|partnerid|suppressions|README|_clang-format|TODO|CONFIGFILES|astyle-config|no_.*_cache|\\.txt$|\\.in$|\\.ini$|\\.xml$|\\.json$|\\.swp$|\\.gz$|\\.service$|\\.map$|\\.dox$|\\.html$|ParseArguments\\.cmake"
1756
1757 #
1758 # We don't use the -i option of licensecheck to add ignore_dir to the pattern because Jenkins creates directories
1759
1760=== modified file 'test/gtest/scopes/Registry/Registry_test.cpp'
1761--- test/gtest/scopes/Registry/Registry_test.cpp 2015-07-06 13:47:54 +0000
1762+++ test/gtest/scopes/Registry/Registry_test.cpp 2016-06-17 07:24:44 +0000
1763@@ -122,7 +122,6 @@
1764 EXPECT_EQ("fg_color", attrs["foreground-color"].get_string());
1765 EXPECT_EQ("bg_color", attrs["background-color"].get_string());
1766 EXPECT_TRUE(attrs["shape-images"].get_bool());
1767- EXPECT_EQ(TEST_SCOPE_A_PATH "/cat_header_bg_scheme", attrs["category-header-background"].get_string());
1768 EXPECT_EQ("preview_button_color", attrs["preview-button-color"].get_string());
1769 EXPECT_EQ("overlay_color", attrs["logo-overlay-color"].get_string());
1770 auto page_hdr = attrs["page-header"].get_dict();
1771
1772=== modified file 'test/gtest/scopes/Registry/scopes/testscopeA/testscopeA.ini.in'
1773--- test/gtest/scopes/Registry/scopes/testscopeA/testscopeA.ini.in 2014-12-03 09:25:10 +0000
1774+++ test/gtest/scopes/Registry/scopes/testscopeA/testscopeA.ini.in 2016-06-17 07:24:44 +0000
1775@@ -16,7 +16,6 @@
1776 ForegroundColor = fg_color
1777 BackgroundColor = bg_color
1778 ShapeImages = true
1779-CategoryHeaderBackground = cat_header_bg_scheme
1780 PreviewButtonColor = preview_button_color
1781 LogoOverlayColor = overlay_color
1782 PageHeader.Logo = some_url
1783
1784=== modified file 'test/gtest/scopes/internal/CMakeLists.txt'
1785--- test/gtest/scopes/internal/CMakeLists.txt 2016-02-22 00:19:46 +0000
1786+++ test/gtest/scopes/internal/CMakeLists.txt 2016-06-17 07:24:44 +0000
1787@@ -1,6 +1,7 @@
1788 add_subdirectory(CategoryRegistry)
1789 add_subdirectory(ConfigBase)
1790 add_subdirectory(DynamicLoader)
1791+add_subdirectory(gobj_ptr)
1792 add_subdirectory(IniSettingsSchema)
1793 add_subdirectory(JsonNode)
1794 add_subdirectory(JsonSettingsSchema)
1795
1796=== modified file 'test/gtest/scopes/internal/JsonNode/JsonNode_test.cpp'
1797--- test/gtest/scopes/internal/JsonNode/JsonNode_test.cpp 2015-11-02 03:42:05 +0000
1798+++ test/gtest/scopes/internal/JsonNode/JsonNode_test.cpp 2016-06-17 07:24:44 +0000
1799@@ -43,6 +43,35 @@
1800 JsonNodeInterface::SPtr root_node_;
1801 };
1802
1803+TEST_F(JsonNodeTest, basic)
1804+{
1805+ try
1806+ {
1807+ JsonCppNode node("");
1808+ FAIL();
1809+ }
1810+ catch (unity::ResourceException const&)
1811+ {
1812+ }
1813+
1814+ EXPECT_EQ(0, root_node_->size());
1815+ EXPECT_EQ(JsonNodeInterface::Null, root_node_->type());
1816+
1817+ auto json = root_node_->to_json_string();
1818+ EXPECT_EQ("null\n", json);
1819+
1820+ root_node_->read_json("42");
1821+ EXPECT_EQ(JsonNodeInterface::Int, root_node_->type());
1822+ auto n = root_node_->get_node();
1823+ EXPECT_EQ(42, n->as_int());
1824+
1825+ EXPECT_THROW(root_node_->read_json(""), unity::ResourceException);
1826+ EXPECT_THROW(root_node_->read_json(" "), unity::ResourceException);
1827+
1828+ root_node_->clear();
1829+ EXPECT_EQ(JsonNodeInterface::Null, root_node_->type());
1830+}
1831+
1832 TEST_F(JsonNodeTest, flat_values)
1833 {
1834 std::string json_string = R"({
1835@@ -170,23 +199,45 @@
1836
1837 TEST_F(JsonNodeTest, from_variant)
1838 {
1839- VariantArray va({Variant(1), Variant(2), Variant(true)});
1840- VariantMap vm;
1841- vm["foo"] = "bar";
1842- vm["baz"] = 1;
1843- vm["boo"] = 2.0f;
1844- vm["zee"] = true;
1845- vm["wee"] = Variant(va);
1846-
1847- Variant var(vm);
1848- JsonCppNode node(var);
1849- EXPECT_EQ("bar", node.get_node("foo")->as_string());
1850- EXPECT_EQ(1, node.get_node("baz")->as_int());
1851- EXPECT_TRUE(node.get_node("boo")->as_double() - 2.0f < 0.00001f);
1852- EXPECT_TRUE(node.get_node("zee")->as_bool());
1853- EXPECT_EQ(1, node.get_node("wee")->get_node(0)->as_int());
1854- EXPECT_EQ(2, node.get_node("wee")->get_node(1)->as_int());
1855- EXPECT_TRUE(node.get_node("wee")->get_node(2)->as_bool());
1856+ {
1857+ VariantArray va({Variant(1), Variant(2), Variant(true)});
1858+ VariantMap vm;
1859+ vm["foo"] = "bar";
1860+ vm["baz"] = 1;
1861+ vm["boo"] = 2.0f;
1862+ vm["zee"] = true;
1863+ vm["wee"] = Variant(va);
1864+
1865+ Variant var(vm);
1866+ JsonCppNode node(var);
1867+ EXPECT_EQ(JsonNodeInterface::Object, node.type());
1868+ EXPECT_EQ("bar", node.get_node("foo")->as_string());
1869+ EXPECT_EQ(JsonNodeInterface::String, node.get_node("foo")->type());
1870+ EXPECT_EQ(1, node.get_node("baz")->as_int());
1871+ EXPECT_EQ(JsonNodeInterface::Real, node.get_node("boo")->type());
1872+ EXPECT_TRUE(node.get_node("boo")->as_double() - 2.0f < 0.00001f);
1873+ EXPECT_EQ(JsonNodeInterface::Bool, node.get_node("zee")->type());
1874+ EXPECT_TRUE(node.get_node("zee")->as_bool());
1875+ EXPECT_EQ(JsonNodeInterface::Array, node.get_node("wee")->type());
1876+ EXPECT_EQ(1, node.get_node("wee")->get_node(0)->as_int());
1877+ EXPECT_EQ(2, node.get_node("wee")->get_node(1)->as_int());
1878+ EXPECT_TRUE(node.get_node("wee")->get_node(2)->as_bool());
1879+ }
1880+
1881+ {
1882+ Variant var(1);
1883+ JsonCppNode node(var);
1884+ EXPECT_EQ(1, node.to_variant().get_int());
1885+ }
1886+
1887+ {
1888+ Variant var(2147483648); // > 2^31 - 1
1889+ JsonCppNode node(var);
1890+ EXPECT_EQ(2147483648, node.to_variant().get_int64_t());
1891+ }
1892+
1893+ JsonCppNode null_node((Variant()));
1894+ EXPECT_EQ(JsonNodeInterface::Null, null_node.type());
1895 }
1896
1897 TEST_F(JsonNodeTest, to_variant)
1898@@ -206,4 +257,89 @@
1899 EXPECT_EQ("foo", arr[2].get_string());
1900 }
1901
1902+TEST_F(JsonNodeTest, exceptions)
1903+{
1904+ EXPECT_THROW(JsonCppNode("syntax error"), unity::ResourceException);
1905+
1906+ try
1907+ {
1908+ JsonCppNode().member_names();
1909+ FAIL();
1910+ }
1911+ catch (unity::LogicException const& e)
1912+ {
1913+ EXPECT_STREQ("unity::LogicException: Root node is not an object", e.what());
1914+ }
1915+
1916+ try
1917+ {
1918+ JsonCppNode().has_node("x");
1919+ FAIL();
1920+ }
1921+ catch (unity::LogicException const& e)
1922+ {
1923+ EXPECT_STREQ("unity::LogicException: Current node is empty", e.what());
1924+ }
1925+
1926+ try
1927+ {
1928+ JsonCppNode("42").as_string();
1929+ FAIL();
1930+ }
1931+ catch (unity::LogicException const& e)
1932+ {
1933+ EXPECT_STREQ("unity::LogicException: Node does not contain a string value", e.what());
1934+ }
1935+
1936+ try
1937+ {
1938+ JsonCppNode("true").as_double();
1939+ FAIL();
1940+ }
1941+ catch (unity::LogicException const& e)
1942+ {
1943+ EXPECT_STREQ("unity::LogicException: Node does not contain a double value", e.what());
1944+ }
1945+
1946+ try
1947+ {
1948+ JsonCppNode("true").as_int();
1949+ FAIL();
1950+ }
1951+ catch (unity::LogicException const& e)
1952+ {
1953+ EXPECT_STREQ("unity::LogicException: Node does not contain an int value", e.what());
1954+ }
1955+
1956+ try
1957+ {
1958+ JsonCppNode("3.14").as_bool();
1959+ FAIL();
1960+ }
1961+ catch (unity::LogicException const& e)
1962+ {
1963+ EXPECT_STREQ("unity::LogicException: Node does not contain a bool value", e.what());
1964+ }
1965+
1966+ try
1967+ {
1968+ JsonCppNode().get_node(25);
1969+ FAIL();
1970+ }
1971+ catch (unity::LogicException const& e)
1972+ {
1973+ EXPECT_STREQ("unity::LogicException: Current node is empty", e.what());
1974+ }
1975+
1976+ try
1977+ {
1978+ JsonCppNode().get_node();
1979+ FAIL();
1980+ }
1981+ catch (unity::LogicException const& e)
1982+ {
1983+ EXPECT_STREQ("unity::LogicException: Current node is empty", e.what());
1984+ }
1985+}
1986+
1987 } // namespace
1988
1989=== modified file 'test/gtest/scopes/internal/JsonSettingsSchema/JsonSettingsSchema_test.cpp'
1990--- test/gtest/scopes/internal/JsonSettingsSchema/JsonSettingsSchema_test.cpp 2015-01-13 11:44:33 +0000
1991+++ test/gtest/scopes/internal/JsonSettingsSchema/JsonSettingsSchema_test.cpp 2016-06-17 07:24:44 +0000
1992@@ -22,7 +22,6 @@
1993 #include <unity/util/FileIO.h>
1994
1995 #include <gtest/gtest.h>
1996-#include <jsoncpp/json/json.h>
1997
1998 using namespace unity;
1999 using namespace unity::scopes;
2000@@ -153,6 +152,41 @@
2001 EXPECT_EQ(Variant(), defs[10].get_dict()["defaultValue"]);
2002 }
2003
2004+TEST(JsonSettingsSchema, integer_sizes)
2005+{
2006+ char const* schema = R"delimiter(
2007+ {
2008+ "settings":
2009+ [
2010+ {
2011+ "id": "double_temp",
2012+ "displayName": "floating-point default",
2013+ "type": "number",
2014+ "parameters": {
2015+ "defaultValue": 3.14
2016+ }
2017+ },
2018+ {
2019+ "id": "too_old",
2020+ "displayName": "won't fit into 32 bits",
2021+ "type": "number",
2022+ "parameters": {
2023+ "defaultValue": 2147483648
2024+ }
2025+ }
2026+ ]
2027+ }
2028+ )delimiter";
2029+
2030+ auto s = JsonSettingsSchema::create(schema);
2031+
2032+ auto defs = s->definitions();
2033+ EXPECT_EQ(2, defs.size());
2034+
2035+ EXPECT_EQ(3.14, defs[0].get_dict()["defaultValue"].get_double());
2036+ EXPECT_EQ(2147483648, defs[1].get_dict()["defaultValue"].get_double());
2037+}
2038+
2039 TEST(JsonSettingsSchema, exceptions)
2040 {
2041 try
2042@@ -162,9 +196,7 @@
2043 }
2044 catch (ResourceException const& e)
2045 {
2046- EXPECT_STREQ("unity::ResourceException: JsonSettingsSchema(): cannot parse schema: * Line 1, Column 1\n"
2047- " Syntax error: value, object or array expected.\n",
2048- e.what());
2049+ EXPECT_STREQ("unity::ResourceException: JsonCppNode(): empty string is not a valid JSON", e.what());
2050 }
2051
2052 try
2053@@ -335,7 +367,7 @@
2054 }
2055 catch (ResourceException const& e)
2056 {
2057- EXPECT_STREQ("unity::ResourceException: JsonSettingsSchema(): invalid \"type\" setting: "
2058+ EXPECT_STREQ("unity::ResourceException: JsonSettingsSchema(): invalid \"type\" definition: "
2059 "\"no_such_type\", id = \"x\"",
2060 e.what());
2061 }
2062
2063=== modified file 'test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp'
2064--- test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp 2015-11-26 05:48:01 +0000
2065+++ test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp 2016-06-17 07:24:44 +0000
2066@@ -22,6 +22,7 @@
2067
2068 #include <unity/UnityExceptions.h>
2069
2070+#include <boost/algorithm/string.hpp>
2071 #include <boost/regex.hpp> // Use Boost implementation until http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631 is fixed.
2072 #include <gtest/gtest.h>
2073 #include <fcntl.h>
2074@@ -321,10 +322,9 @@
2075 }
2076 catch (ResourceException const& e)
2077 {
2078- EXPECT_STREQ("unity::ResourceException: SettingsDB::create_from_json_string(): cannot parse schema, db = unused:\n"
2079- " unity::ResourceException: JsonSettingsSchema(): cannot parse schema: * Line 1, Column 1\n"
2080- " Syntax error: value, object or array expected.\n",
2081- e.what());
2082+ EXPECT_TRUE(boost::starts_with(e.what(),
2083+ "unity::ResourceException: SettingsDB::create_from_json_string(): cannot parse "
2084+ "schema, db = unused:")) << e.what();
2085 }
2086
2087 try
2088
2089=== added directory 'test/gtest/scopes/internal/gobj_ptr'
2090=== added file 'test/gtest/scopes/internal/gobj_ptr/CMakeLists.txt'
2091--- test/gtest/scopes/internal/gobj_ptr/CMakeLists.txt 1970-01-01 00:00:00 +0000
2092+++ test/gtest/scopes/internal/gobj_ptr/CMakeLists.txt 2016-06-17 07:24:44 +0000
2093@@ -0,0 +1,3 @@
2094+add_executable(gobj_ptr_test gobj_ptr_test.cpp)
2095+target_link_libraries(gobj_ptr_test ${TESTLIBS})
2096+add_test(gobj_ptr gobj_ptr_test)
2097
2098=== added file 'test/gtest/scopes/internal/gobj_ptr/gobj_ptr_test.cpp'
2099--- test/gtest/scopes/internal/gobj_ptr/gobj_ptr_test.cpp 1970-01-01 00:00:00 +0000
2100+++ test/gtest/scopes/internal/gobj_ptr/gobj_ptr_test.cpp 2016-06-17 07:24:44 +0000
2101@@ -0,0 +1,208 @@
2102+/*
2103+ * Copyright (C) 2013 Canonical Ltd.
2104+ *
2105+ * This program is free software: you can redistribute it and/or modify
2106+ * it under the terms of the GNU Lesser General Public License version 3 as
2107+ * published by the Free Software Foundation.
2108+ *
2109+ * This program is distributed in the hope that it will be useful,
2110+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2111+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2112+ * GNU Lesser General Public License for more details.
2113+ *
2114+ * You should have received a copy of the GNU Lesser General Public License
2115+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2116+ *
2117+ * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
2118+ */
2119+
2120+#pragma GCC diagnostic push
2121+#pragma GCC diagnostic ignored "-Wold-style-cast"
2122+#pragma GCC diagnostic ignored "-Wcast-qual"
2123+
2124+#include <unity/scopes/internal/gobj_memory.h>
2125+#include <glib-object.h>
2126+#include <gtest/gtest.h>
2127+
2128+using namespace std;
2129+using namespace unity::scopes::internal;
2130+
2131+TEST(Gobj_ptr, trivial)
2132+{
2133+ gobj_ptr<GObject> basic(G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr)));
2134+ EXPECT_TRUE(bool(basic));
2135+ EXPECT_TRUE(G_IS_OBJECT(basic.get()));
2136+}
2137+
2138+TEST(Gobj_ptr, compare)
2139+{
2140+ GObject* o1 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2141+ GObject* o2 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2142+ if (o1 > o2)
2143+ {
2144+ std::swap(o1, o2);
2145+ }
2146+ ASSERT_TRUE(o1 < o2);
2147+ gobj_ptr<GObject> u1(o1);
2148+ gobj_ptr<GObject> u2(o2);
2149+
2150+ EXPECT_TRUE(!(u1 == nullptr));
2151+ EXPECT_TRUE(u1 != nullptr);
2152+ EXPECT_TRUE(u1 != u2);
2153+ EXPECT_TRUE(!(u1 == u2));
2154+ EXPECT_TRUE(u1 < u2);
2155+ EXPECT_TRUE(!(u2 < u1));
2156+ EXPECT_TRUE(!(u1 == u2));
2157+ EXPECT_TRUE(!(u2 == u1));
2158+ EXPECT_TRUE(u1 <= u2);
2159+ EXPECT_TRUE(!(u2 <= u1));
2160+}
2161+
2162+// This is its own thing due to need to avoid double release.
2163+
2164+TEST(Gobj_ptr, equality)
2165+{
2166+ GObject* o = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2167+ gobj_ptr<GObject> u1(o);
2168+ g_object_ref(o);
2169+ gobj_ptr<GObject> u2(o);
2170+ EXPECT_TRUE(u1 == u2);
2171+ EXPECT_TRUE(u2 == u1);
2172+ EXPECT_TRUE(!(u1 != u2));
2173+ EXPECT_TRUE(!(u2 != u1));
2174+}
2175+
2176+TEST(Gobj_ptr, release)
2177+{
2178+ GObject* o = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2179+ gobj_ptr<GObject> u(o);
2180+ EXPECT_TRUE(u != nullptr);
2181+ EXPECT_TRUE(u.get() != nullptr);
2182+ EXPECT_TRUE(o == u.release());
2183+ EXPECT_TRUE(!u);
2184+ EXPECT_TRUE(u.get() == nullptr);
2185+ g_object_unref(o);
2186+}
2187+
2188+TEST(Gobj_ptr, refcount)
2189+{
2190+ GObject* o = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2191+ EXPECT_EQ(1, o->ref_count);
2192+ g_object_ref(o);
2193+
2194+ {
2195+ EXPECT_EQ(2, o->ref_count);
2196+ gobj_ptr<GObject> u(o);
2197+ EXPECT_EQ(2, o->ref_count);
2198+ // Now it dies and refcount is reduced.
2199+ }
2200+
2201+ EXPECT_EQ(1, o->ref_count);
2202+ g_object_unref(o);
2203+}
2204+
2205+TEST(Gobj_ptr, copy)
2206+{
2207+ GObject* o = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2208+ gobj_ptr<GObject> u(o);
2209+ EXPECT_EQ(1, u->ref_count);
2210+ gobj_ptr<GObject> u2(u);
2211+ EXPECT_EQ(2, u->ref_count);
2212+ gobj_ptr<GObject> u3 = u2;
2213+ EXPECT_EQ(3, u->ref_count);
2214+ u3.reset();
2215+ u2.reset();
2216+ EXPECT_EQ(1, u->ref_count);
2217+}
2218+
2219+TEST(Gobj_ptr, swap)
2220+{
2221+ GObject* o1 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2222+ GObject* o2 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2223+ gobj_ptr<GObject> u1(o1);
2224+ gobj_ptr<GObject> u2(o2);
2225+
2226+ u1.swap(u2);
2227+ EXPECT_EQ(o2, u1.get());
2228+ EXPECT_EQ(o1, u2.get());
2229+
2230+ std::swap(u1, u2);
2231+ EXPECT_EQ(o1, u1.get());
2232+ EXPECT_EQ(o2, u2.get());
2233+}
2234+
2235+TEST(Gobj_ptr, floating)
2236+{
2237+ GObject* o = G_OBJECT(g_object_new(G_TYPE_INITIALLY_UNOWNED, nullptr));
2238+ try
2239+ {
2240+ gobj_ptr<GObject> u(o);
2241+ FAIL();
2242+ }
2243+ catch (const invalid_argument& c)
2244+ {
2245+ EXPECT_EQ("Tried to add a floating gobject into a gobj_ptr.", string(c.what()));
2246+ }
2247+ // Object accepted after sinking.
2248+ g_object_ref_sink(o);
2249+ gobj_ptr<GObject> u(o);
2250+}
2251+
2252+TEST(Gobj_ptr, move)
2253+{
2254+ GObject* o1 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2255+ GObject* o2 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2256+ g_object_ref(o1);
2257+ gobj_ptr<GObject> u1(o1);
2258+ gobj_ptr<GObject> u2(o2);
2259+ u1 = std::move(u2);
2260+ EXPECT_TRUE(u1.get() == o2);
2261+ EXPECT_TRUE(!u2);
2262+ EXPECT_TRUE(o1->ref_count == 1);
2263+ g_object_unref(o1);
2264+}
2265+
2266+TEST(Gobj_ptr, null)
2267+{
2268+ GObject* o1 = NULL;
2269+ GObject* o3 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2270+ gobj_ptr<GObject> u1(o1);
2271+ gobj_ptr<GObject> u2(nullptr);
2272+ gobj_ptr<GObject> u3(o3);
2273+
2274+ EXPECT_TRUE(!u1);
2275+ EXPECT_TRUE(!u2);
2276+ u3 = nullptr;
2277+ EXPECT_TRUE(!u3);
2278+}
2279+
2280+TEST(Gobj_ptr, reset)
2281+{
2282+ GObject* o1 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2283+ GObject* o2 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
2284+ gobj_ptr<GObject> u(o1);
2285+
2286+ u.reset(o2);
2287+ EXPECT_EQ(o2, u.get());
2288+ u.reset(nullptr);
2289+ EXPECT_TRUE(!u);
2290+}
2291+
2292+TEST(Gobj_ptr, sizeoftest)
2293+{
2294+ EXPECT_EQ(sizeof(GObject*), sizeof(gobj_ptr<GObject>));
2295+}
2296+
2297+TEST(Gobj_ptr, deleter)
2298+{
2299+ gobj_ptr<GObject> u1;
2300+ EXPECT_TRUE(g_object_unref == u1.get_deleter());
2301+}
2302+
2303+int main(int argc, char** argv)
2304+{
2305+ ::testing::InitGoogleTest(&argc, argv);
2306+ return RUN_ALL_TESTS();
2307+}
2308+
2309+#pragma GCC diagnostic pop
2310
2311=== modified file 'test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp'
2312--- test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp 2016-02-29 15:57:12 +0000
2313+++ test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp 2016-06-17 07:24:44 +0000
2314@@ -130,13 +130,41 @@
2315 EXPECT_EQ(nullptr, scopes[2].art);
2316 EXPECT_FALSE(scopes[2].invisible);
2317 EXPECT_EQ(nullptr, scopes[2].appearance);
2318- EXPECT_EQ("[{\"displayName\":\"Location\",\"id\":\"location\",\"parameters\":{\"defaultValue\":"
2319- "\"London\"},\"type\":\"string\"},{\"displayName\":\"Temperature Units\",\"id\":"
2320- "\"unitTemp\",\"parameters\":{\"defaultValue\":1,\"values\":[\"Celsius\",\"Fahrenheit"
2321- "\"]},\"type\":\"list\"},{\"displayName\":\"Age\",\"id\":\"age\",\"parameters\":{"
2322- "\"defaultValue\":23},\"type\":\"number\"},{\"displayName\":\"Enabled\",\"id\":"
2323- "\"enabled\",\"parameters\":{\"defaultValue\":true},\"type\":\"boolean\"}]\n",
2324- *scopes[2].settings);
2325+ {
2326+ JsonCppNode node(*scopes[2].settings);
2327+ Variant v = node.to_variant();
2328+
2329+ VariantMap vm = v.get_array()[0].get_dict();
2330+ EXPECT_EQ("Location", vm["displayName"].get_string());
2331+ EXPECT_EQ("location", vm["id"].get_string());
2332+ EXPECT_EQ("string", vm["type"].get_string());
2333+ VariantMap params = vm["parameters"].get_dict();
2334+ EXPECT_EQ("London", params["defaultValue"].get_string());
2335+
2336+ vm = v.get_array()[1].get_dict();
2337+ EXPECT_EQ("Temperature Units", vm["displayName"].get_string());
2338+ EXPECT_EQ("unitTemp", vm["id"].get_string());
2339+ EXPECT_EQ("list", vm["type"].get_string());
2340+ params = vm["parameters"].get_dict();
2341+ EXPECT_EQ(1, params["defaultValue"].get_int());
2342+ VariantArray choices = params["values"].get_array();
2343+ EXPECT_EQ("Celsius", choices[0].get_string());
2344+ EXPECT_EQ("Fahrenheit", choices[1].get_string());
2345+
2346+ vm = v.get_array()[2].get_dict();
2347+ EXPECT_EQ("Age", vm["displayName"].get_string());
2348+ EXPECT_EQ("age", vm["id"].get_string());
2349+ EXPECT_EQ("number", vm["type"].get_string());
2350+ params = vm["parameters"].get_dict();
2351+ EXPECT_EQ(23, params["defaultValue"].get_int());
2352+
2353+ vm = v.get_array()[3].get_dict();
2354+ EXPECT_EQ("Enabled", vm["displayName"].get_string());
2355+ EXPECT_EQ("enabled", vm["id"].get_string());
2356+ EXPECT_EQ("boolean", vm["type"].get_string());
2357+ params = vm["parameters"].get_dict();
2358+ EXPECT_TRUE(params["defaultValue"].get_bool());
2359+ }
2360 ASSERT_EQ(4, scopes[2].keywords.size());
2361 EXPECT_NE(scopes[2].keywords.end(), scopes[2].keywords.find("music"));
2362 EXPECT_NE(scopes[2].keywords.end(), scopes[2].keywords.find("video"));
2363@@ -392,10 +420,30 @@
2364 EXPECT_EQ("widget_id_C", columns[2][2][0]);
2365
2366 ASSERT_EQ(3u, widgets.size());
2367-
2368- EXPECT_EQ("{\"id\":\"widget_id_A\",\"text\":\"First widget.\",\"title\":\"Widget A\",\"type\":\"text\"}\n", widgets[0]);
2369- EXPECT_EQ("{\"id\":\"widget_id_B\",\"text\":\"Second widget.\",\"title\":\"Widget B\",\"type\":\"text\"}\n", widgets[1]);
2370- EXPECT_EQ("{\"id\":\"widget_id_C\",\"text\":\"Third widget.\",\"title\":\"Widget C\",\"type\":\"text\"}\n", widgets[2]);
2371+ {
2372+ auto json = widgets[0];
2373+ JsonCppNode node(json);
2374+ EXPECT_EQ("widget_id_A", node.get_node("id")->as_string());
2375+ EXPECT_EQ("First widget.", node.get_node("text")->as_string());
2376+ EXPECT_EQ("Widget A", node.get_node("title")->as_string());
2377+ EXPECT_EQ("text", node.get_node("type")->as_string());
2378+ }
2379+ {
2380+ auto json = widgets[1];
2381+ JsonCppNode node(json);
2382+ EXPECT_EQ("widget_id_B", node.get_node("id")->as_string());
2383+ EXPECT_EQ("Second widget.", node.get_node("text")->as_string());
2384+ EXPECT_EQ("Widget B", node.get_node("title")->as_string());
2385+ EXPECT_EQ("text", node.get_node("type")->as_string());
2386+ }
2387+ {
2388+ auto json = widgets[2];
2389+ JsonCppNode node(json);
2390+ EXPECT_EQ("widget_id_C", node.get_node("id")->as_string());
2391+ EXPECT_EQ("Third widget.", node.get_node("text")->as_string());
2392+ EXPECT_EQ("Widget C", node.get_node("title")->as_string());
2393+ EXPECT_EQ("text", node.get_node("type")->as_string());
2394+ }
2395 }
2396
2397 TEST_F(SmartScopesClientTest, consecutive_searches)

Subscribers

People subscribed via source and target branches

to all changes: