Merge lp:~aacid/unity/do_not_reuse_menus_on_order_change into lp:unity

Proposed by Albert Astals Cid
Status: Merged
Approved by: Marco Trevisan (Treviño)
Approved revision: no longer in the source branch.
Merged at revision: 2815
Proposed branch: lp:~aacid/unity/do_not_reuse_menus_on_order_change
Merge into: lp:unity
Diff against target: 662 lines (+471/-6)
11 files modified
UnityCore/DBusIndicators.cpp (+28/-5)
UnityCore/DBusIndicators.h (+4/-0)
UnityCore/Indicator.cpp (+15/-0)
UnityCore/Indicator.h (+1/-0)
tests/CMakeLists.txt (+4/-1)
tests/test_dbus_indicators.cpp (+99/-0)
tests/test_indicator.cpp (+3/-0)
tests/test_service_main.c (+4/-0)
tests/test_service_panel.c (+253/-0)
tests/test_service_panel.h (+46/-0)
tests/test_utils.h (+14/-0)
To merge this branch: bzr merge lp:~aacid/unity/do_not_reuse_menus_on_order_change
Reviewer Review Type Date Requested Status
Marco Trevisan (Treviño) Approve
Review via email: mp+128243@code.launchpad.net

Commit message

Do not reuse the menu entries if their order changes

Since the indicators api only have "add" and "remove" signals, if we reuse an entry that is not in the correct order it will case the menus or whatever this indicator represents to be in the wrong order

Description of the change

Do not reuse the menu entries if their order changes

Since the indicators api only have "add" and "remove" signals, if we reuse an entry that is not in the correct order it will case the menus or whatever this indicator represents to be in the wrong order

To post a comment you must log in.
Revision history for this message
Albert Astals Cid (aacid) wrote :

Working in a unittest

Revision history for this message
Albert Astals Cid (aacid) wrote :

Unit test added

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

112 + DBusIndicators(const std::string &dbus_name = "com.canonical.Unity.Panel.Service");

In unity we prefer to use this syntax instead:
  std::string const& dbus_name

8 -const std::string SERVICE_NAME("com.canonical.Unity.Panel.Service");

However, probably instead of adding an optional parameter, I would add another one (better if protected, so that you'll make accessible only in a test mock class) that takes the service name parameter.

91 + : connected(false), pimpl(new Impl(dbus_name, this))

Better two lines here.

115 + nux::Property<bool> connected;

Don't use a property here, for two reasons: a non-RO property like is this one, is meant to be editable, while you only use to store a value; also you don't really need that... Just add an IsConnected() (protected as well?) method that proxies gproxy_.IsConnected().

On the testing side, yes... That's what I meant: good! :)

However, on code side you can be more clean by using the TestDBusIndicators class: so, add in the constructor (or in a SetUp() function) the calls you're duplicating in the tests to initialize them, and the cleanup calls in a TearDown() method.

Also instead of using g_timeout, you can use glib::Timeout, since probably you won't able to use utils::WaitUntil

+ session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);

I guess that using a glib::DbusProxy would be better here.

182 === added file 'tests/test_dbusindicators.cpp'

I'd prefer it to be named test_dbus_indicators.cpp

PS: also cleanup the commented code in test.

review: Needs Fixing
Revision history for this message
Albert Astals Cid (aacid) wrote :

ok, all suggestions should be implemented if i did not miss something

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

331 + DBusIndicatorsTest* dbus_indicators;

Would be nice to have DBusIndicators::Ptr instead, so you don't need to worry about destruction (unless it must be done before unreffing the loop)

336 +TEST_F(TestDBusIndicators, TestConstruction)
337 +{
338 + SetUp();

357 + TearDown();
358 +}

No need to do this... GTest will do this automatically, so forget about setting-up and tearing-down once you've defined these testing::Test functions.

341 + auto timeout_check = [&] () -> bool
342 + {
343 + nChecks++;
344 + bool quit_loop = dbus_indicators->IsConnected() || nChecks > 99;
345 + if (quit_loop)
346 + g_main_loop_quit(loop_);
347 + return !quit_loop;
348 + };
349
350 + nChecks = 0;
351 + timeout.reset(new glib::Timeout(100, timeout_check));
352 +
353 + g_main_loop_run(loop_);

No need to repeat this for every test...

Just do it in the SetUp function, and probably instead of quitting the loop is enough to add an ASSERT there.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

108 + GVariant *CallSync(string const& method_name,
109 + GVariant* parameters,

Ah, please also add the * near to the typename (i.e. GVariant*) and, fix the parameters indentation.

Revision history for this message
Albert Astals Cid (aacid) wrote :

Second round of updates hope i did not miss anything :-)

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Thanks a lot for your changes (and patience), it looks very nice now! ;)

review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/1502/console reported an error when processing this lp:~aacid/unity/do_not_reuse_menus_on_order_change branch.
Not merging it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/DBusIndicators.cpp'
2--- UnityCore/DBusIndicators.cpp 2012-06-18 02:57:23 +0000
3+++ UnityCore/DBusIndicators.cpp 2012-10-08 14:36:19 +0000
4@@ -48,7 +48,7 @@
5 class DBusIndicators::Impl
6 {
7 public:
8- Impl(DBusIndicators* owner);
9+ Impl(std::string const& dbus_name, DBusIndicators* owner);
10
11 void CheckLocalService();
12 void RequestSyncAll();
13@@ -84,9 +84,9 @@
14
15
16 // Public Methods
17-DBusIndicators::Impl::Impl(DBusIndicators* owner)
18+DBusIndicators::Impl::Impl(std::string const& dbus_name, DBusIndicators* owner)
19 : owner_(owner)
20- , gproxy_(SERVICE_NAME, SERVICE_PATH, SERVICE_IFACE,
21+ , gproxy_(dbus_name, SERVICE_PATH, SERVICE_IFACE,
22 G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
23 {
24 gproxy_.Connect("ReSync", sigc::mem_fun(this, &DBusIndicators::Impl::OnReSync));
25@@ -276,6 +276,8 @@
26 return;
27
28 std::map<Indicator::Ptr, Indicator::Entries> indicators;
29+ int wantedIndex = 0;
30+ bool anyIndexDifferent = false;
31
32 g_variant_get(args, "(a(ssssbbusbbi))", &iter);
33 while (g_variant_iter_loop(iter, "(ssssbbusbbi)",
34@@ -305,7 +307,18 @@
35 // Null entries (entry_id == "") are empty indicators.
36 if (entry != "")
37 {
38- Entry::Ptr e = indicator->GetEntry(entry_id);
39+ Entry::Ptr e;
40+ if (!anyIndexDifferent)
41+ {
42+ // Indicators can only add or remove entries, so if
43+ // there is a index change we can't reuse the existing ones
44+ // after that index
45+ int existingEntryIndex = indicator->EntryIndex(entry_id);
46+ if (wantedIndex == existingEntryIndex)
47+ e = indicator->GetEntry(entry_id);
48+ else
49+ anyIndexDifferent = true;
50+ }
51
52 if (!e)
53 {
54@@ -321,6 +334,7 @@
55 }
56
57 entries.push_back(e);
58+ wantedIndex++;
59 }
60 }
61 g_variant_iter_free(iter);
62@@ -393,12 +407,21 @@
63 }
64
65 DBusIndicators::DBusIndicators()
66- : pimpl(new Impl(this))
67+ : pimpl(new Impl(SERVICE_NAME, this))
68+{}
69+
70+DBusIndicators::DBusIndicators(std::string const& dbus_name)
71+ : pimpl(new Impl(dbus_name, this))
72 {}
73
74 DBusIndicators::~DBusIndicators()
75 {}
76
77+bool DBusIndicators::IsConnected() const
78+{
79+ return pimpl->gproxy_.IsConnected();
80+}
81+
82 void DBusIndicators::SyncGeometries(std::string const& name,
83 EntryLocationMap const& locations)
84 {
85
86=== modified file 'UnityCore/DBusIndicators.h'
87--- UnityCore/DBusIndicators.h 2012-06-18 02:57:23 +0000
88+++ UnityCore/DBusIndicators.h 2012-10-08 14:36:19 +0000
89@@ -50,6 +50,10 @@
90 virtual void OnShowAppMenu(unsigned int xid, int x, int y,
91 unsigned int timestamp);
92
93+protected:
94+ DBusIndicators(std::string const& dbus_name);
95+ bool IsConnected() const;
96+
97 private:
98 class Impl;
99 std::unique_ptr<Impl> pimpl;
100
101=== modified file 'UnityCore/Indicator.cpp'
102--- UnityCore/Indicator.cpp 2012-08-08 06:57:43 +0000
103+++ UnityCore/Indicator.cpp 2012-10-08 14:36:19 +0000
104@@ -115,6 +115,21 @@
105 return Entry::Ptr();
106 }
107
108+int Indicator::EntryIndex(std::string const& entry_id) const
109+{
110+ int i = 0;
111+ for (auto entry : entries_)
112+ {
113+ if (entry->id() == entry_id)
114+ {
115+ return i;
116+ }
117+ ++i;
118+ }
119+
120+ return -1;
121+}
122+
123 void Indicator::OnEntryShowMenu(std::string const& entry_id, unsigned int xid,
124 int x, int y, unsigned int button, unsigned int timestamp)
125 {
126
127=== modified file 'UnityCore/Indicator.h'
128--- UnityCore/Indicator.h 2012-06-18 02:57:23 +0000
129+++ UnityCore/Indicator.h 2012-10-08 14:36:19 +0000
130@@ -48,6 +48,7 @@
131
132 void Sync(Entries const& new_entries);
133 Entry::Ptr GetEntry(std::string const& entry_id) const;
134+ int EntryIndex(std::string const& entry_id) const;
135 Entries GetEntries() const;
136
137 // Signals
138
139=== modified file 'tests/CMakeLists.txt'
140--- tests/CMakeLists.txt 2012-10-08 06:36:17 +0000
141+++ tests/CMakeLists.txt 2012-10-08 14:36:19 +0000
142@@ -110,7 +110,9 @@
143 test_service_lens.h
144 test_service_main.c
145 test_service_model.c
146- test_service_model.h)
147+ test_service_model.h
148+ test_service_panel.c
149+ test_service_panel.c)
150 target_link_libraries(test-gtest-service unity-shared ${LIBS})
151 add_dependencies (test-gtest-service unity-core-${UNITY_API_VERSION} gtest)
152
153@@ -194,6 +196,7 @@
154 test_utils.h
155 test_ratings_filter.cpp
156 test_results.cpp
157+ test_dbus_indicators.cpp
158 )
159 target_link_libraries(test-gtest-dbus gtest unity-shared ${LIBS})
160 add_test(UnityGTestDBus test-gtest-dbus)
161
162=== added file 'tests/test_dbus_indicators.cpp'
163--- tests/test_dbus_indicators.cpp 1970-01-01 00:00:00 +0000
164+++ tests/test_dbus_indicators.cpp 2012-10-08 14:36:19 +0000
165@@ -0,0 +1,99 @@
166+#include <gtest/gtest.h>
167+
168+#include <UnityCore/GLibDBusProxy.h>
169+#include <UnityCore/GLibSource.h>
170+#include <UnityCore/GLibWrapper.h>
171+#include <UnityCore/DBusIndicators.h>
172+
173+#include "test_utils.h"
174+
175+using namespace unity;
176+using namespace unity::indicator;
177+
178+namespace
179+{
180+
181+class DBusIndicatorsTest : public DBusIndicators
182+{
183+public:
184+ DBusIndicatorsTest() : DBusIndicators("com.canonical.Unity.Test")
185+ {
186+ }
187+
188+ bool HasIndicators() const
189+ {
190+ return !GetIndicators().empty();
191+ }
192+
193+ using DBusIndicators::IsConnected;
194+};
195+
196+class TestDBusIndicators : public ::testing::Test
197+{
198+public:
199+ void SetUp()
200+ {
201+ session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
202+ g_dbus_connection_set_exit_on_close(session, FALSE);
203+
204+ dbus_indicators.reset(new DBusIndicatorsTest ());
205+
206+ // wait until the dbus indicator has connected to the panel service
207+ Utils::WaitUntil(sigc::mem_fun(*dbus_indicators, &DBusIndicatorsTest::IsConnected));
208+ }
209+
210+ bool TriggerResync1Sent() const
211+ {
212+ GVariant *ret = CallPanelMethod("TriggerResync1Sent");
213+ return g_variant_get_boolean(g_variant_get_child_value(ret, 0));
214+ }
215+
216+ GVariant* CallPanelMethod(std::string const& name) const
217+ {
218+ return g_dbus_connection_call_sync(session,
219+ "com.canonical.Unity.Test",
220+ "/com/canonical/Unity/Panel/Service",
221+ "com.canonical.Unity.Panel.Service",
222+ name.c_str(),
223+ NULL,
224+ NULL,
225+ G_DBUS_CALL_FLAGS_NONE,
226+ -1,
227+ NULL,
228+ NULL);
229+ }
230+
231+ glib::Object<GDBusConnection> session;
232+ std::shared_ptr<DBusIndicatorsTest> dbus_indicators;
233+};
234+
235+TEST_F(TestDBusIndicators, TestConstruction)
236+{
237+ EXPECT_EQ(dbus_indicators->IsConnected(), true);
238+}
239+
240+TEST_F(TestDBusIndicators, TestSync)
241+{
242+ // wait until the dbus indicator gets any indicator from the panel service
243+ Utils::WaitUntil(sigc::mem_fun(*dbus_indicators, &DBusIndicatorsTest::HasIndicators));
244+
245+ EXPECT_EQ(dbus_indicators->GetIndicators().size(), 1);
246+ EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().size(), 2);
247+ EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().front()->id(), "test_entry_id");
248+ EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().back()->id(), "test_entry_id2");
249+
250+ // Tell the service to trigger a resync and to send the entries in the reverse order
251+ CallPanelMethod("TriggerResync1");
252+
253+ Utils::WaitUntil(sigc::mem_fun(this, &TestDBusIndicators::TriggerResync1Sent));
254+ // We know the resync has been sent, but it may have not been processed
255+ // so do one interation of the main loop more
256+ g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
257+
258+ EXPECT_EQ(dbus_indicators->GetIndicators().size(), 1);
259+ EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().size(), 2);
260+ EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().front()->id(), "test_entry_id2");
261+ EXPECT_EQ(dbus_indicators->GetIndicators().front()->GetEntries().back()->id(), "test_entry_id");
262+}
263+
264+}
265
266=== modified file 'tests/test_indicator.cpp'
267--- tests/test_indicator.cpp 2012-02-01 01:55:05 +0000
268+++ tests/test_indicator.cpp 2012-10-08 14:36:19 +0000
269@@ -35,6 +35,7 @@
270 EXPECT_EQ(indicator.name(), "indicator-test");
271 EXPECT_FALSE(indicator.IsAppmenu());
272 EXPECT_EQ(indicator.GetEntry("test-entry"), nullptr);
273+ EXPECT_EQ(indicator.EntryIndex("test-entry"), -1);
274 EXPECT_TRUE(indicator.GetEntries().empty());
275 }
276
277@@ -76,6 +77,7 @@
278 indicator.Sync(sync_data);
279 EXPECT_EQ(indicator.GetEntries().size(), 3);
280 EXPECT_EQ(indicator.GetEntry("test-entry-2"), entry2);
281+ EXPECT_EQ(indicator.EntryIndex("test-entry-2"), 1);
282 EXPECT_EQ(added.size(), 3);
283 EXPECT_EQ(added.front()->id(), "test-entry-1");
284 EXPECT_EQ(added.back()->id(), "test-entry-3");
285@@ -91,6 +93,7 @@
286 indicator.Sync(sync_data);
287 EXPECT_EQ(indicator.GetEntries().size(), 2);
288 EXPECT_EQ(indicator.GetEntry("test-entry-2"), nullptr);
289+ EXPECT_EQ(indicator.EntryIndex("test-entry-2"), -1);
290 EXPECT_EQ(added.size(), 0);
291 EXPECT_EQ(removed.size(), 1);
292 EXPECT_EQ(removed.front(), entry2->id());
293
294=== modified file 'tests/test_service_main.c'
295--- tests/test_service_main.c 2012-03-14 06:24:18 +0000
296+++ tests/test_service_main.c 2012-10-08 14:36:19 +0000
297@@ -3,6 +3,7 @@
298 #include "test_service_lens.h"
299 #include "test_service_model.h"
300 #include "test_service_hud.h"
301+#include "test_service_panel.h"
302 #include "test_service_gdbus_wrapper.h"
303
304 static void on_bus_aquired(GDBusConnection* conn, const gchar* name, gpointer null);
305@@ -37,6 +38,7 @@
306 static ServiceLens* lens_ = NULL;
307 static ServiceModel* model_ = NULL;
308 static ServiceHud* hud_ = NULL;
309+static ServicePanel* panel_ = NULL;
310 static ServiceGDBusWrapper* gdbus_wrapper_ = NULL;
311 gint
312 main(gint argc, gchar** argv)
313@@ -48,6 +50,7 @@
314 lens_ = service_lens_new();
315 model_ = service_model_new();
316 hud_ = service_hud_new();
317+ panel_ = service_panel_new();
318 gdbus_wrapper_ = service_gdbus_wrapper_new();
319
320 g_bus_own_name(G_BUS_TYPE_SESSION,
321@@ -65,6 +68,7 @@
322 //g_object_unref(lens_);
323 //g_object_unref(model_);
324 g_object_unref(hud_);
325+ g_object_unref(panel_);
326 g_dbus_node_info_unref(introspection_data);
327
328 return 0;
329
330=== added file 'tests/test_service_panel.c'
331--- tests/test_service_panel.c 1970-01-01 00:00:00 +0000
332+++ tests/test_service_panel.c 2012-10-08 14:36:19 +0000
333@@ -0,0 +1,253 @@
334+#include "test_service_panel.h"
335+#include <unity.h>
336+#include <gio/gio.h>
337+
338+static const char * panel_interface =
339+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
340+"<node name=\"/\">\n"
341+" <interface name=\"com.canonical.Unity.Panel.Service\">\n"
342+"\n"
343+"<!-- Begin of real methods/signals -->\n"
344+" <method name='Sync'>"
345+" <arg type='a(ssssbbusbbi)' name='state' direction='out'/>"
346+" </method>"
347+"\n"
348+" <signal name='ReSync'>"
349+" <arg type='s' name='indicator_id' />"
350+" </signal>"
351+"\n"
352+"<!-- Begin of test only methods/signals -->\n"
353+"\n"
354+" <method name='TriggerResync1' />"
355+"\n"
356+" <method name='TriggerResync1Sent'>"
357+" <arg type='b' name='sent' direction='out'/>"
358+" </method>"
359+"\n"
360+" </interface>\n"
361+"</node>\n"
362+;
363+static void bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data);
364+static void bus_method (GDBusConnection *connection,
365+ const gchar *sender,
366+ const gchar *object_path,
367+ const gchar *interface_name,
368+ const gchar *method_name,
369+ GVariant *parameters,
370+ GDBusMethodInvocation *invocation,
371+ gpointer user_data);
372+
373+G_DEFINE_TYPE(ServicePanel, service_panel, G_TYPE_OBJECT);
374+static GDBusNodeInfo * node_info = NULL;
375+static GDBusInterfaceInfo * iface_info = NULL;
376+static GDBusInterfaceVTable bus_vtable = {
377+ method_call: bus_method,
378+ get_property: NULL,
379+ set_property: NULL,
380+};
381+
382+struct _ServicePanelPrivate
383+{
384+ GDBusConnection * bus;
385+ GCancellable * bus_lookup;
386+ guint bus_registration;
387+ guint sig_emission_handle;
388+};
389+
390+static void
391+service_panel_dispose(GObject* object)
392+{
393+ ServicePanel* self = SERVICE_PANEL(object);
394+ if (self->priv->bus_lookup != NULL) {
395+ g_cancellable_cancel(self->priv->bus_lookup);
396+ g_object_unref(self->priv->bus_lookup);
397+ self->priv->bus_lookup = NULL;
398+ }
399+
400+ if (self->priv->bus_registration != 0) {
401+ g_dbus_connection_unregister_object(self->priv->bus, self->priv->bus_registration);
402+ self->priv->bus_registration = 0;
403+ }
404+
405+ if (self->priv->bus != NULL) {
406+ g_object_unref(self->priv->bus);
407+ self->priv->bus = NULL;
408+ }
409+
410+ if (self->priv->sig_emission_handle) {
411+ g_source_remove(self->priv->sig_emission_handle);
412+ self->priv->sig_emission_handle = 0;
413+ }
414+
415+}
416+
417+static void
418+service_panel_class_init(ServicePanelClass* klass)
419+{
420+ G_OBJECT_CLASS(klass)->dispose = service_panel_dispose;
421+ g_type_class_add_private (klass, sizeof (ServicePanelPrivate));
422+
423+ if (node_info == NULL)
424+ {
425+ GError * error = NULL;
426+
427+ node_info = g_dbus_node_info_new_for_xml(panel_interface, &error);
428+ if (error != NULL)
429+ {
430+ g_error("Unable to parse Panel interface: %s", error->message);
431+ g_error_free(error);
432+ }
433+ }
434+
435+ if (node_info != NULL && iface_info == NULL)
436+ {
437+ iface_info = g_dbus_node_info_lookup_interface(node_info,"com.canonical.Unity.Panel.Service");
438+ if (iface_info == NULL)
439+ {
440+ g_error("Unable to find interface 'com.canonical.Unity.Panel.Service'");
441+ }
442+ }
443+
444+}
445+
446+static void
447+service_panel_init(ServicePanel* self)
448+{
449+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SERVICE_TYPE_PANEL, ServicePanelPrivate);
450+ self->priv->bus = NULL;
451+ self->priv->bus_lookup = NULL;
452+ self->priv->bus_registration = 0;
453+
454+ self->priv->bus_lookup = g_cancellable_new();
455+ g_bus_get(G_BUS_TYPE_SESSION, self->priv->bus_lookup, bus_got_cb, self);
456+}
457+
458+ServicePanel*
459+service_panel_new()
460+{
461+ return g_object_new(SERVICE_TYPE_PANEL, NULL);
462+}
463+
464+static void
465+bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data)
466+{
467+ GError * error = NULL;
468+ ServicePanel * self = SERVICE_PANEL(user_data);
469+ GDBusConnection * bus;
470+
471+ bus = g_bus_get_finish(res, &error);
472+ if (error != NULL) {
473+ g_critical("Unable to get bus: %s", error->message);
474+ g_error_free(error);
475+ return;
476+ }
477+
478+ self->priv->bus = bus;
479+
480+ /* Register object */
481+ self->priv->bus_registration = g_dbus_connection_register_object(bus,
482+ /* path */ "/com/canonical/Unity/Panel/Service",
483+ /* interface */ iface_info,
484+ /* vtable */ &bus_vtable,
485+ /* userdata */ self,
486+ /* destroy */ NULL,
487+ /* error */ &error);
488+
489+ if (error != NULL) {
490+ g_critical ("Unable to create bus connection object, %s", error->message);
491+ g_error_free(error);
492+ return;
493+ }
494+
495+ return;
496+}
497+
498+static void
499+add_entry_id(GVariantBuilder *b)
500+{
501+ g_variant_builder_add (b, "(ssssbbusbbi)",
502+ "test_indicator_id",
503+ "test_entry_id",
504+ "test_entry_name_hint",
505+ "test_entry_label",
506+ TRUE, /* label sensitive */
507+ TRUE, /* label visible */
508+ 0, /* image type */
509+ "", /* image_data */
510+ TRUE, /* image sensitive */
511+ TRUE, /* image visible */
512+ 1 /* priority */);
513+}
514+
515+static void
516+add_entry_id_2(GVariantBuilder *b)
517+{
518+ g_variant_builder_add (b, "(ssssbbusbbi)",
519+ "test_indicator_id",
520+ "test_entry_id2",
521+ "test_entry_name_hint2",
522+ "test_entry_label2",
523+ TRUE, /* label sensitive */
524+ TRUE, /* label visible */
525+ 0, /* image type */
526+ "", /* image_data */
527+ TRUE, /* image sensitive */
528+ TRUE, /* image visible */
529+ 1 /* priority */);
530+}
531+
532+static int sync_return_mode = 0;
533+static int trigger_resync1_sent = FALSE;
534+
535+static void
536+bus_method (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data)
537+{
538+ if (g_strcmp0(method_name, "Sync") == 0)
539+ {
540+ GVariantBuilder b;
541+
542+ g_variant_builder_init (&b, G_VARIANT_TYPE ("(a(ssssbbusbbi))"));
543+ g_variant_builder_open (&b, G_VARIANT_TYPE ("a(ssssbbusbbi)"));
544+
545+ if (sync_return_mode == 0)
546+ {
547+ add_entry_id(&b);
548+ add_entry_id_2(&b);
549+ }
550+ else if (sync_return_mode == 1)
551+ {
552+ add_entry_id_2(&b);
553+ add_entry_id(&b);
554+ }
555+
556+ g_variant_builder_close (&b);
557+
558+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end (&b));
559+
560+ if (sync_return_mode == 1)
561+ {
562+ trigger_resync1_sent = TRUE;
563+ }
564+ }
565+ else if (g_strcmp0(method_name, "TriggerResync1") == 0)
566+ {
567+ sync_return_mode = 1;
568+ trigger_resync1_sent = FALSE;
569+
570+ g_dbus_method_invocation_return_value(invocation, NULL);
571+ GVariantBuilder ret_builder;
572+ g_variant_builder_init(&ret_builder, G_VARIANT_TYPE_TUPLE);
573+ g_variant_builder_add_value(&ret_builder, g_variant_new_string(""));
574+ g_dbus_connection_emit_signal (connection, NULL, "/com/canonical/Unity/Panel/Service", "com.canonical.Unity.Panel.Service", "ReSync", g_variant_builder_end(&ret_builder), NULL);
575+ }
576+ else if (g_strcmp0(method_name, "TriggerResync1Sent") == 0)
577+ {
578+ GVariantBuilder ret_builder;
579+ g_variant_builder_init(&ret_builder, G_VARIANT_TYPE ("(b)"));
580+ g_variant_builder_add_value (&ret_builder, g_variant_new_boolean(trigger_resync1_sent));
581+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end (&ret_builder));
582+ }
583+
584+ return;
585+}
586+
587
588=== added file 'tests/test_service_panel.h'
589--- tests/test_service_panel.h 1970-01-01 00:00:00 +0000
590+++ tests/test_service_panel.h 2012-10-08 14:36:19 +0000
591@@ -0,0 +1,46 @@
592+#ifndef _SERVICE_PANEL_H_
593+#define _SERVICE_PANEL_H_
594+
595+#include <glib-object.h>
596+G_BEGIN_DECLS
597+
598+#define SERVICE_TYPE_PANEL (service_panel_get_type ())
599+
600+#define SERVICE_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
601+ SERVICE_TYPE_PANEL, ServicePanel))
602+
603+#define SERVICE_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
604+ SERVICE_TYPE_PANEL, ServicePanelClass))
605+
606+#define SERVICE_IS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
607+ SERVICE_TYPE_PANEL))
608+
609+#define SERVICE_IS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
610+ SERVICE_TYPE_PANEL))
611+
612+#define ServicePanel_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
613+ SERVICE_TYPE_PANEL, ServicePanelClass))
614+
615+typedef struct _ServicePanel ServicePanel;
616+typedef struct _ServicePanelClass ServicePanelClass;
617+typedef struct _ServicePanelPrivate ServicePanelPrivate;
618+
619+struct _ServicePanel
620+{
621+ GObject parent;
622+
623+ ServicePanelPrivate *priv;
624+};
625+
626+struct _ServicePanelClass
627+{
628+ GObjectClass parent_class;
629+};
630+
631+GType service_panel_get_type(void) G_GNUC_CONST;
632+
633+ServicePanel* service_panel_new(void);
634+
635+G_END_DECLS
636+
637+#endif /* _SERVICE_PANEL_H_ */
638
639=== modified file 'tests/test_utils.h'
640--- tests/test_utils.h 2012-05-19 05:21:05 +0000
641+++ tests/test_utils.h 2012-10-08 14:36:19 +0000
642@@ -46,6 +46,20 @@
643 EXPECT_TRUE(success);
644 }
645
646+ static void WaitUntil(std::function<bool()> check_function, bool result = true, unsigned int max_wait = 10)
647+ {
648+ bool timeout_reached = false;
649+ guint32 timeout_id = ScheduleTimeout(&timeout_reached, max_wait * 1000);
650+
651+ while (!check_function() && !timeout_reached)
652+ g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
653+
654+ if (check_function())
655+ g_source_remove(timeout_id);
656+
657+ EXPECT_EQ(check_function(), result);
658+ }
659+
660 static guint32 ScheduleTimeout(bool* timeout_reached, unsigned int timeout_duration = 10)
661 {
662 return g_timeout_add(timeout_duration, TimeoutCallback, timeout_reached);