Merge lp:~charlesk/indicator-datetime/lp-1474078-notification-blacklist-apps into lp:indicator-datetime/15.10

Proposed by Charles Kerr on 2016-02-03
Status: Merged
Approved by: David Barth on 2016-02-17
Approved revision: 432
Merged at revision: 432
Proposed branch: lp:~charlesk/indicator-datetime/lp-1474078-notification-blacklist-apps
Merge into: lp:indicator-datetime/15.10
Prerequisite: lp:~charlesk/indicator-datetime/unified-eds-code
Diff against target: 1725 lines (+1075/-414)
12 files modified
debian/control (+3/-0)
include/datetime/settings-live.h (+6/-2)
include/datetime/settings-shared.h (+3/-0)
include/datetime/settings.h (+1/-0)
src/settings-live.cpp (+60/-10)
src/snap.cpp (+17/-0)
tests/CMakeLists.txt (+2/-1)
tests/notification-fixture.h (+382/-0)
tests/test-notification.cpp (+164/-0)
tests/test-settings.cpp (+40/-0)
tests/test-snap.cpp (+128/-401)
tests/test-sound.cpp (+269/-0)
To merge this branch: bzr merge lp:~charlesk/indicator-datetime/lp-1474078-notification-blacklist-apps
Reviewer Review Type Date Requested Status
David Barth Approve on 2016-02-08
Xavi Garcia 2016-02-03 Needs Information on 2016-02-05
PS Jenkins bot continuous-integration Approve on 2016-02-03
Review via email: mp+284927@code.launchpad.net

Commit Message

Don't show calendar notifications if the're blacklisted in system settings

Description of the Change

Add support for system-settings' blacklist of apps whose notifications should not be shown.

Original branch by David Barth's branch at <https://code.launchpad.net/~dbarth/indicator-datetime/mute-notifications/+merge/280708>. This branch moves the GSchema code into Settings, adds more tests, and stacks on top of <https://code.launchpad.net/~charlesk/indicator-datetime/unified-eds-code> so it should be dual landable

Code changes:
* in Settings, a new core::Property "muted_apps" listing blacklisted apps
* in LiveSettings, code to bind the com.ubuntu.notification.hub GSchema and muted_apps property together
* in Snap, code to skip calendar notifications if the calendar app is blacklisted
* in tests, refactor the Notification gtest fixture into a reusable header so that multiple test files can use it
* add new notification tests to check out what happens under different combinations of system settings, indicator settings, and appointment types

To post a comment you must log in.
David Barth (dbarth) wrote :

Switching silo 003 to using that new MP. Thanks Charles !

On Wed, Feb 3, 2016 at 5:44 PM, Charles Kerr <email address hidden>
wrote:

> The proposal to merge
> lp:~charlesk/indicator-datetime/lp-1474078-notification-blacklist-apps into
> lp:indicator-datetime has been updated.
>
> Description changed to:
>
> Add support for system-settings' blacklist of apps whose notifications
> should not be shown.
>
> Original branch by David Barth's branch at <
> https://code.launchpad.net/~dbarth/indicator-datetime/mute-notifications/+merge/280708>.
> This branch moves the GSchema code into Settings, adds more tests, and
> stacks on top of <
> https://code.launchpad.net/~charlesk/indicator-datetime/unified-eds-code>
> so it should be dual landable
>
> Code changes:
> * in Settings, a new core::Property "muted_apps" listing blacklisted apps
> * in LiveSettings, code to bind the com.ubuntu.notification.hub GSchema
> and muted_apps property together
> * in Snap, code to skip calendar notifications if the calendar app is
> blacklisted
> * in tests, refactor the Notification gtest fixture into a reusable header
> so that multiple test files can use it
> * add new notification tests to check out what happens under different
> combinations of system settings, indicator settings, and appointment types
>
> For more details, see:
>
> https://code.launchpad.net/~charlesk/indicator-datetime/lp-1474078-notification-blacklist-apps/+merge/284927
> --
> Your team Indicator Applet Developers is requested to review the proposed
> merge of
> lp:~charlesk/indicator-datetime/lp-1474078-notification-blacklist-apps into
> lp:indicator-datetime.
>

Xavi Garcia (xavi-garcia-mena) wrote :

Looks good to me.
I'm just curious about some sleeps in the tests... Are they really needed? could we "wait" in a different way that does not use sleep?

review: Needs Information
Charles Kerr (charlesk) wrote :

In the cases where we're testing that something happens, yes and I'll work today on fixing that.

There are a few edge cases where we're testing that something /doesn't/ happen, e.g. a combination of settings that causes a notification to be suppressed, and in those cases I think we need to keep the "wait" calls because there's no trigger when testing a negative.

David Barth (dbarth) wrote :

Tested in silo 003, +1 for me

review: Approve
Charles Kerr (charlesk) wrote :

Xavi, since the tests change further in my branch for bug #1440111, I've applied your suggested timing fixes in that branch, which is MPed in <https://code.launchpad.net/~charlesk/indicator-datetime/lp-1440111-friendlier-calendar-items/+merge/284956> and stacked on top of this branch in silo 19

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2016-02-03 16:38:36 +0000
3+++ debian/control 2016-02-03 16:38:36 +0000
4@@ -14,6 +14,8 @@
5 libedataserver1.2-dev (>= 3.5),
6 liburl-dispatcher1-dev,
7 libproperties-cpp-dev,
8+# for com.ubuntu.notifications.hub schema to pick up blacklist of apps that can't show notifications
9+ gsettings-ubuntu-schemas,
10 # for the test harness:
11 libgtest-dev,
12 libdbustest1-dev,
13@@ -39,6 +41,7 @@
14 Architecture: any
15 Depends: ${shlibs:Depends},
16 ${misc:Depends},
17+ gsettings-ubuntu-schemas,
18 systemd-services,
19 systemd-shim,
20 Recommends: indicator-applet | indicator-renderer,
21
22=== modified file 'include/datetime/settings-live.h'
23--- include/datetime/settings-live.h 2015-10-13 23:28:20 +0000
24+++ include/datetime/settings-live.h 2016-02-03 16:38:36 +0000
25@@ -38,8 +38,10 @@
26 virtual ~LiveSettings();
27
28 private:
29- static void on_changed(GSettings*, gchar*, gpointer);
30- void update_key(const std::string& key);
31+ static void on_changed_ccid(GSettings*, gchar*, gpointer);
32+ static void on_changed_cunh(GSettings*, gchar*, gpointer);
33+ void update_key_ccid(const std::string& key);
34+ void update_key_cunh(const std::string& key);
35
36 void update_custom_time_format();
37 void update_locations();
38@@ -61,8 +63,10 @@
39 void update_alarm_duration();
40 void update_alarm_haptic();
41 void update_snooze_duration();
42+ void update_muted_apps();
43
44 GSettings* m_settings;
45+ GSettings* m_settings_cunh;
46
47 // we've got a raw pointer here, so disable copying
48 LiveSettings(const LiveSettings&) =delete;
49
50=== modified file 'include/datetime/settings-shared.h'
51--- include/datetime/settings-shared.h 2015-10-13 23:28:20 +0000
52+++ include/datetime/settings-shared.h 2016-02-03 16:38:36 +0000
53@@ -52,4 +52,7 @@
54 #define SETTINGS_ALARM_HAPTIC_S "alarm-haptic-feedback"
55 #define SETTINGS_SNOOZE_DURATION_S "snooze-duration-minutes"
56
57+#define SETTINGS_CUNH_SCHEMA_ID "com.ubuntu.notifications.hub"
58+#define SETTINGS_CUNH_BLACKLIST_S "blacklist"
59+
60 #endif // INDICATOR_DATETIME_SETTINGS_SHARED
61
62=== modified file 'include/datetime/settings.h'
63--- include/datetime/settings.h 2015-10-13 23:28:20 +0000
64+++ include/datetime/settings.h 2016-02-03 16:38:36 +0000
65@@ -62,6 +62,7 @@
66 core::Property<unsigned int> alarm_volume;
67 core::Property<unsigned int> alarm_duration;
68 core::Property<unsigned int> snooze_duration;
69+ core::Property<std::set<std::pair<std::string,std::string>>> muted_apps;
70 };
71
72 } // namespace datetime
73
74=== modified file 'src/settings-live.cpp'
75--- src/settings-live.cpp 2015-10-13 23:28:20 +0000
76+++ src/settings-live.cpp 2016-02-03 16:38:36 +0000
77@@ -29,13 +29,16 @@
78
79 LiveSettings::~LiveSettings()
80 {
81+ g_clear_object(&m_settings_cunh);
82 g_clear_object(&m_settings);
83 }
84
85 LiveSettings::LiveSettings():
86- m_settings(g_settings_new(SETTINGS_INTERFACE))
87+ m_settings(g_settings_new(SETTINGS_INTERFACE)),
88+ m_settings_cunh(g_settings_new(SETTINGS_CUNH_SCHEMA_ID))
89 {
90- g_signal_connect (m_settings, "changed", G_CALLBACK(on_changed), this);
91+ g_signal_connect (m_settings, "changed", G_CALLBACK(on_changed_ccid), this);
92+ g_signal_connect (m_settings_cunh, "changed", G_CALLBACK(on_changed_cunh), this);
93
94 // init the Properties from the GSettings backend
95 update_custom_time_format();
96@@ -58,6 +61,7 @@
97 update_alarm_duration();
98 update_alarm_haptic();
99 update_snooze_duration();
100+ update_muted_apps();
101
102 // now listen for clients to change the properties s.t. we can sync update GSettings
103
104@@ -65,6 +69,17 @@
105 g_settings_set_string(m_settings, SETTINGS_CUSTOM_TIME_FORMAT_S, value.c_str());
106 });
107
108+ muted_apps.changed().connect([this](const std::set<std::pair<std::string,std::string>>& value){
109+ GVariantBuilder builder;
110+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a(ss)"));
111+ for(const auto& app : value){
112+ const auto& pkgname {app.first};
113+ const auto& appname {app.second};
114+ g_variant_builder_add(&builder, "(ss)", pkgname.c_str(), appname.c_str());
115+ }
116+ g_settings_set_value(m_settings_cunh, SETTINGS_CUNH_BLACKLIST_S, g_variant_builder_end(&builder));
117+ });
118+
119 locations.changed().connect([this](const std::vector<std::string>& value){
120 const int n = value.size();
121 gchar** strv = g_new0(gchar*, n+1);
122@@ -168,6 +183,24 @@
123 locations.set(l);
124 }
125
126+void LiveSettings::update_muted_apps()
127+{
128+ std::set<std::pair<std::string,std::string>> apps;
129+
130+ auto blacklist = g_settings_get_value(m_settings_cunh, SETTINGS_CUNH_BLACKLIST_S);
131+ GVariantIter* iter {nullptr};
132+ g_variant_get (blacklist, "a(ss)", &iter);
133+ gchar* pkgname;
134+ gchar* appname;
135+ while (g_variant_iter_loop (iter, "(ss)", &pkgname, &appname)) {
136+ apps.insert(std::make_pair(pkgname,appname));
137+ }
138+ g_variant_iter_free (iter);
139+ g_clear_pointer(&blacklist, g_variant_unref);
140+
141+ muted_apps.set(apps);
142+}
143+
144 void LiveSettings::update_show_calendar()
145 {
146 const auto val = g_settings_get_boolean(m_settings, SETTINGS_SHOW_CALENDAR_S);
147@@ -275,14 +308,31 @@
148 ****
149 ***/
150
151-void LiveSettings::on_changed(GSettings* /*settings*/,
152- gchar* key,
153- gpointer gself)
154-{
155- static_cast<LiveSettings*>(gself)->update_key(key);
156-}
157-
158-void LiveSettings::update_key(const std::string& key)
159+void LiveSettings::on_changed_cunh(GSettings* /*settings*/,
160+ gchar* key,
161+ gpointer gself)
162+{
163+ static_cast<LiveSettings*>(gself)->update_key_cunh(key);
164+}
165+
166+void LiveSettings::update_key_cunh(const std::string& key)
167+{
168+ if (key == SETTINGS_CUNH_BLACKLIST_S)
169+ update_muted_apps();
170+}
171+
172+/***
173+****
174+***/
175+
176+void LiveSettings::on_changed_ccid(GSettings* /*settings*/,
177+ gchar* key,
178+ gpointer gself)
179+{
180+ static_cast<LiveSettings*>(gself)->update_key_ccid(key);
181+}
182+
183+void LiveSettings::update_key_ccid(const std::string& key)
184 {
185 if (key == SETTINGS_SHOW_CLOCK_S)
186 update_show_clock();
187
188=== modified file 'src/snap.cpp'
189--- src/snap.cpp 2015-10-13 23:28:20 +0000
190+++ src/snap.cpp 2016-02-03 16:38:36 +0000
191@@ -85,6 +85,12 @@
192 appointment_func snooze,
193 appointment_func ok)
194 {
195+ // If calendar notifications are muted, don't show them
196+ if (!appointment.is_ubuntu_alarm() && calendar_events_are_muted()) {
197+ g_debug("Skipping muted calendar event '%s' notification", appointment.summary.c_str());
198+ return;
199+ }
200+
201 /* Alarms and calendar events are treated differently.
202 Alarms should require manual intervention to dismiss.
203 Calendar events are less urgent and shouldn't require manual
204@@ -160,6 +166,17 @@
205
206 private:
207
208+ bool calendar_events_are_muted() const
209+ {
210+ for(const auto& app : m_settings->muted_apps.get()) {
211+ if (app.first == "com.ubuntu.calendar") {
212+ return true;
213+ }
214+ }
215+
216+ return false;
217+ }
218+
219 static void on_sound_proxy_ready(GObject* /*source_object*/, GAsyncResult* res, gpointer gself)
220 {
221 GError * error;
222
223=== modified file 'tests/CMakeLists.txt'
224--- tests/CMakeLists.txt 2015-10-13 14:56:26 +0000
225+++ tests/CMakeLists.txt 2016-02-03 16:38:36 +0000
226@@ -47,7 +47,8 @@
227 target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
228 endfunction()
229 add_test_by_name(test-datetime)
230-add_test_by_name(test-snap)
231+add_test_by_name(test-sound)
232+add_test_by_name(test-notification)
233 add_test_by_name(test-actions)
234 add_test_by_name(test-alarm-queue)
235 add_test(NAME dear-reader-the-next-test-takes-60-seconds COMMAND true)
236
237=== added file 'tests/notification-fixture.h'
238--- tests/notification-fixture.h 1970-01-01 00:00:00 +0000
239+++ tests/notification-fixture.h 2016-02-03 16:38:36 +0000
240@@ -0,0 +1,382 @@
241+/*
242+ * Copyright 2014-2016 Canonical Ltd.
243+ *
244+ * This program is free software: you can redistribute it and/or modify it
245+ * under the terms of the GNU General Public License version 3, as published
246+ * by the Free Software Foundation.
247+ *
248+ * This program is distributed in the hope that it will be useful, but
249+ * WITHOUT ANY WARRANTY; without even the implied warranties of
250+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
251+ * PURPOSE. See the GNU General Public License for more details.
252+ *
253+ * You should have received a copy of the GNU General Public License along
254+ * with this program. If not, see <http://www.gnu.org/licenses/>.
255+ *
256+ * Authors:
257+ * Charles Kerr <charles.kerr@canonical.com>
258+ */
259+
260+#pragma once
261+
262+#include "glib-fixture.h"
263+
264+#include <datetime/appointment.h>
265+#include <datetime/dbus-shared.h>
266+#include <datetime/settings.h>
267+#include <datetime/snap.h>
268+
269+#include <notifications/dbus-shared.h>
270+#include <notifications/notifications.h>
271+
272+#include <libdbustest/dbus-test.h>
273+
274+#include <unistd.h> // getuid()
275+#include <sys/types.h> // getuid()
276+
277+/***
278+****
279+***/
280+
281+//using namespace unity::indicator::datetime;
282+
283+class NotificationFixture: public GlibFixture
284+{
285+private:
286+
287+ typedef GlibFixture super;
288+
289+ static constexpr char const * NOTIFY_BUSNAME {"org.freedesktop.Notifications"};
290+ static constexpr char const * NOTIFY_INTERFACE {"org.freedesktop.Notifications"};
291+ static constexpr char const * NOTIFY_PATH {"/org/freedesktop/Notifications"};
292+
293+ //namespace uin = unity::indicator::notifications;
294+
295+ //using namespace unity::indicator::datetime;
296+
297+protected:
298+
299+ static constexpr char const * HAPTIC_METHOD_VIBRATE_PATTERN {"VibratePattern"};
300+
301+ static constexpr int SCREEN_COOKIE {8675309};
302+ static constexpr char const * SCREEN_METHOD_KEEP_DISPLAY_ON {"keepDisplayOn"};
303+ static constexpr char const * SCREEN_METHOD_REMOVE_DISPLAY_ON_REQUEST {"removeDisplayOnRequest"};
304+
305+ static constexpr int POWERD_SYS_STATE_ACTIVE = 1;
306+ static constexpr char const * POWERD_COOKIE {"567-48-8307"};
307+ static constexpr char const * POWERD_METHOD_REQUEST_SYS_STATE {"requestSysState"};
308+ static constexpr char const * POWERD_METHOD_CLEAR_SYS_STATE {"clearSysState"};
309+
310+ static constexpr int FIRST_NOTIFY_ID {1000};
311+
312+ static constexpr int NOTIFICATION_CLOSED_EXPIRED {1};
313+ static constexpr int NOTIFICATION_CLOSED_DISMISSED {2};
314+ static constexpr int NOTIFICATION_CLOSED_API {3};
315+ static constexpr int NOTIFICATION_CLOSED_UNDEFINED {4};
316+
317+ static constexpr char const * METHOD_CLOSE {"CloseNotification"};
318+ static constexpr char const * METHOD_GET_CAPS {"GetCapabilities"};
319+ static constexpr char const * METHOD_GET_INFO {"GetServerInformation"};
320+ static constexpr char const * METHOD_NOTIFY {"Notify"};
321+
322+ static constexpr char const * SIGNAL_CLOSED {"NotificationClosed"};
323+
324+ static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"};
325+
326+ static constexpr char const * AS_BUSNAME {"org.freedesktop.Accounts"};
327+ static constexpr char const * AS_INTERFACE {"com.ubuntu.touch.AccountsService.Sound"};
328+ static constexpr char const * PROP_OTHER_VIBRATIONS {"OtherVibrate"};
329+ static constexpr char const * PROP_SILENT_MODE {"SilentMode"};
330+
331+ unity::indicator::datetime::Appointment appt;
332+ unity::indicator::datetime::Appointment ualarm;
333+ GDBusConnection * system_bus = nullptr;
334+ GDBusConnection * session_bus = nullptr;
335+ DbusTestService * service = nullptr;
336+ DbusTestDbusMock * as_mock = nullptr;
337+ DbusTestDbusMock * notify_mock = nullptr;
338+ DbusTestDbusMock * powerd_mock = nullptr;
339+ DbusTestDbusMock * screen_mock = nullptr;
340+ DbusTestDbusMock * haptic_mock = nullptr;
341+ DbusTestDbusMockObject * as_obj = nullptr;
342+ DbusTestDbusMockObject * notify_obj = nullptr;
343+ DbusTestDbusMockObject * powerd_obj = nullptr;
344+ DbusTestDbusMockObject * screen_obj = nullptr;
345+ DbusTestDbusMockObject * haptic_obj = nullptr;
346+
347+ void SetUp() override
348+ {
349+ GError * error = nullptr;
350+ char * str = nullptr;
351+
352+ super::SetUp();
353+
354+ // init an Appointment
355+ appt.color = "green";
356+ appt.summary = "Christmas";
357+ appt.uid = "D4B57D50247291478ED31DED17FF0A9838DED402";
358+ appt.type = unity::indicator::datetime::Appointment::EVENT;
359+ const auto christmas = unity::indicator::datetime::DateTime::Local(2015,12,25,0,0,0);
360+ appt.begin = christmas.start_of_day();
361+ appt.end = christmas.end_of_day();
362+ appt.alarms.push_back(unity::indicator::datetime::Alarm{"Ho Ho Ho!", "", appt.begin});
363+
364+ // init an Ubuntu Alarm
365+ ualarm.color = "red";
366+ ualarm.summary = "Wakeup";
367+ ualarm.uid = "E4B57D50247291478ED31DED17FF0A9838DED403";
368+ ualarm.type = unity::indicator::datetime::Appointment::UBUNTU_ALARM;
369+ const auto tomorrow = unity::indicator::datetime::DateTime::NowLocal().add_days(1);
370+ ualarm.begin = tomorrow;
371+ ualarm.end = tomorrow;
372+ ualarm.alarms.push_back(unity::indicator::datetime::Alarm{"It's Tomorrow!", "", appt.begin});
373+
374+ service = dbus_test_service_new(nullptr);
375+
376+ ///
377+ /// Add the AccountsService mock
378+ ///
379+
380+ as_mock = dbus_test_dbus_mock_new(AS_BUSNAME);
381+ auto as_path = g_strdup_printf("/org/freedesktop/Accounts/User%lu", (gulong)getuid());
382+ as_obj = dbus_test_dbus_mock_get_object(as_mock,
383+ as_path,
384+ AS_INTERFACE,
385+ &error);
386+ g_free(as_path);
387+ g_assert_no_error(error);
388+
389+ // PROP_SILENT_MODE
390+ dbus_test_dbus_mock_object_add_property(as_mock,
391+ as_obj,
392+ PROP_SILENT_MODE,
393+ G_VARIANT_TYPE_BOOLEAN,
394+ g_variant_new_boolean(false),
395+ &error);
396+ g_assert_no_error(error);
397+
398+ // PROP_OTHER_VIBRATIONS
399+ dbus_test_dbus_mock_object_add_property(as_mock,
400+ as_obj,
401+ PROP_OTHER_VIBRATIONS,
402+ G_VARIANT_TYPE_BOOLEAN,
403+ g_variant_new_boolean(true),
404+ &error);
405+ g_assert_no_error(error);
406+ dbus_test_service_add_task(service, DBUS_TEST_TASK(as_mock));
407+
408+ ///
409+ /// Add the Notifications mock
410+ ///
411+
412+ notify_mock = dbus_test_dbus_mock_new(NOTIFY_BUSNAME);
413+ notify_obj = dbus_test_dbus_mock_get_object(notify_mock,
414+ NOTIFY_PATH,
415+ NOTIFY_INTERFACE,
416+ &error);
417+ g_assert_no_error(error);
418+
419+ // METHOD_GET_INFO
420+ str = g_strdup("ret = ('mock-notify', 'test vendor', '1.0', '1.1')");
421+ dbus_test_dbus_mock_object_add_method(notify_mock,
422+ notify_obj,
423+ METHOD_GET_INFO,
424+ nullptr,
425+ G_VARIANT_TYPE("(ssss)"),
426+ str,
427+ &error);
428+ g_assert_no_error (error);
429+ g_free (str);
430+
431+ // METHOD_NOTIFY
432+ str = g_strdup_printf("try:\n"
433+ " self.NextNotifyId\n"
434+ "except AttributeError:\n"
435+ " self.NextNotifyId = %d\n"
436+ "ret = self.NextNotifyId\n"
437+ "self.NextNotifyId += 1\n",
438+ FIRST_NOTIFY_ID);
439+ dbus_test_dbus_mock_object_add_method(notify_mock,
440+ notify_obj,
441+ METHOD_NOTIFY,
442+ G_VARIANT_TYPE("(susssasa{sv}i)"),
443+ G_VARIANT_TYPE_UINT32,
444+ str,
445+ &error);
446+ g_assert_no_error (error);
447+ g_free (str);
448+
449+ // METHOD_CLOSE
450+ str = g_strdup_printf("self.EmitSignal('%s', '%s', 'uu', [ args[0], %d ])",
451+ NOTIFY_INTERFACE,
452+ SIGNAL_CLOSED,
453+ NOTIFICATION_CLOSED_API);
454+ dbus_test_dbus_mock_object_add_method(notify_mock,
455+ notify_obj,
456+ METHOD_CLOSE,
457+ G_VARIANT_TYPE("(u)"),
458+ nullptr,
459+ str,
460+ &error);
461+ g_assert_no_error (error);
462+ g_free (str);
463+
464+ dbus_test_service_add_task(service, DBUS_TEST_TASK(notify_mock));
465+
466+ ///
467+ /// Add the powerd mock
468+ ///
469+
470+ powerd_mock = dbus_test_dbus_mock_new(BUS_POWERD_NAME);
471+ powerd_obj = dbus_test_dbus_mock_get_object(powerd_mock,
472+ BUS_POWERD_PATH,
473+ BUS_POWERD_INTERFACE,
474+ &error);
475+ g_assert_no_error(error);
476+
477+ str = g_strdup_printf ("ret = '%s'", POWERD_COOKIE);
478+ dbus_test_dbus_mock_object_add_method(powerd_mock,
479+ powerd_obj,
480+ POWERD_METHOD_REQUEST_SYS_STATE,
481+ G_VARIANT_TYPE("(si)"),
482+ G_VARIANT_TYPE("(s)"),
483+ str,
484+ &error);
485+ g_assert_no_error (error);
486+ g_free (str);
487+
488+ dbus_test_dbus_mock_object_add_method(powerd_mock,
489+ powerd_obj,
490+ POWERD_METHOD_CLEAR_SYS_STATE,
491+ G_VARIANT_TYPE("(s)"),
492+ nullptr,
493+ "",
494+ &error);
495+ g_assert_no_error (error);
496+
497+ dbus_test_service_add_task(service, DBUS_TEST_TASK(powerd_mock));
498+
499+ ///
500+ /// Add the Screen mock
501+ ///
502+
503+ screen_mock = dbus_test_dbus_mock_new(BUS_SCREEN_NAME);
504+ screen_obj = dbus_test_dbus_mock_get_object(screen_mock,
505+ BUS_SCREEN_PATH,
506+ BUS_SCREEN_INTERFACE,
507+ &error);
508+ g_assert_no_error(error);
509+
510+ str = g_strdup_printf ("ret = %d", SCREEN_COOKIE);
511+ dbus_test_dbus_mock_object_add_method(screen_mock,
512+ screen_obj,
513+ SCREEN_METHOD_KEEP_DISPLAY_ON,
514+ nullptr,
515+ G_VARIANT_TYPE("(i)"),
516+ str,
517+ &error);
518+ g_assert_no_error (error);
519+ g_free (str);
520+
521+ dbus_test_dbus_mock_object_add_method(screen_mock,
522+ screen_obj,
523+ SCREEN_METHOD_REMOVE_DISPLAY_ON_REQUEST,
524+ G_VARIANT_TYPE("(i)"),
525+ nullptr,
526+ "",
527+ &error);
528+ g_assert_no_error (error);
529+ dbus_test_service_add_task(service, DBUS_TEST_TASK(screen_mock));
530+
531+ ///
532+ /// Add the haptic mock
533+ ///
534+
535+ haptic_mock = dbus_test_dbus_mock_new(BUS_HAPTIC_NAME);
536+ haptic_obj = dbus_test_dbus_mock_get_object(haptic_mock,
537+ BUS_HAPTIC_PATH,
538+ BUS_HAPTIC_INTERFACE,
539+ &error);
540+
541+ dbus_test_dbus_mock_object_add_method(haptic_mock,
542+ haptic_obj,
543+ HAPTIC_METHOD_VIBRATE_PATTERN,
544+ G_VARIANT_TYPE("(auu)"),
545+ nullptr,
546+ "",
547+ &error);
548+ g_assert_no_error (error);
549+ dbus_test_service_add_task(service, DBUS_TEST_TASK(haptic_mock));
550+
551+
552+ // start 'em up.
553+ // make the system bus work off the mock bus too, since that's
554+ // where the upower and screen are on the system bus...
555+
556+ dbus_test_service_start_tasks(service);
557+ g_setenv("DBUS_SYSTEM_BUS_ADDRESS", g_getenv("DBUS_SESSION_BUS_ADDRESS"), TRUE);
558+
559+ session_bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
560+ ASSERT_NE(nullptr, session_bus);
561+ g_dbus_connection_set_exit_on_close(session_bus, false);
562+ g_object_add_weak_pointer(G_OBJECT(session_bus), (gpointer *)&session_bus);
563+
564+ system_bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr);
565+ ASSERT_NE(nullptr, system_bus);
566+ g_dbus_connection_set_exit_on_close(system_bus, FALSE);
567+ g_object_add_weak_pointer(G_OBJECT(system_bus), (gpointer *)&system_bus);
568+ }
569+
570+ void TearDown() override
571+ {
572+ g_clear_object(&haptic_mock);
573+ g_clear_object(&screen_mock);
574+ g_clear_object(&powerd_mock);
575+ g_clear_object(&notify_mock);
576+ g_clear_object(&as_mock);
577+ g_clear_object(&service);
578+ g_object_unref(session_bus);
579+ g_object_unref(system_bus);
580+
581+ // wait a little while for the scaffolding to shut down,
582+ // but don't block on it forever...
583+ unsigned int cleartry = 0;
584+ while (((system_bus != nullptr) || (session_bus != nullptr)) && (cleartry < 50))
585+ {
586+ g_usleep(100000);
587+ while (g_main_pending())
588+ g_main_iteration(true);
589+ cleartry++;
590+ }
591+
592+ super::TearDown();
593+ }
594+
595+ void make_interactive()
596+ {
597+ // GetCapabilities returns an array containing 'actions',
598+ // so our snap decision will be interactive.
599+ // For this test, it means we should get a timeout Notify Hint
600+ // that matches duration_minutes
601+ GError * error = nullptr;
602+ dbus_test_dbus_mock_object_add_method(notify_mock,
603+ notify_obj,
604+ METHOD_GET_CAPS,
605+ nullptr,
606+ G_VARIANT_TYPE_STRING_ARRAY,
607+ "ret = ['actions', 'body']",
608+ &error);
609+ g_assert_no_error (error);
610+ }
611+
612+ std::shared_ptr<unity::indicator::datetime::Snap>
613+ create_snap(const std::shared_ptr<unity::indicator::notifications::Engine>& ne,
614+ const std::shared_ptr<unity::indicator::notifications::SoundBuilder>& sb,
615+ const std::shared_ptr<unity::indicator::datetime::Settings>& settings)
616+ {
617+ auto snap = std::make_shared<unity::indicator::datetime::Snap>(ne, sb, settings);
618+ wait_msec(100); // wait a moment for the Snap to finish its async dbus bootstrapping
619+ return snap;
620+ }
621+};
622+
623
624=== added file 'tests/test-notification.cpp'
625--- tests/test-notification.cpp 1970-01-01 00:00:00 +0000
626+++ tests/test-notification.cpp 2016-02-03 16:38:36 +0000
627@@ -0,0 +1,164 @@
628+/*
629+ * Copyright 2014-2016 Canonical Ltd.
630+ *
631+ * This program is free software: you can redistribute it and/or modify it
632+ * under the terms of the GNU General Public License version 3, as published
633+ * by the Free Software Foundation.
634+ *
635+ * This program is distributed in the hope that it will be useful, but
636+ * WITHOUT ANY WARRANTY; without even the implied warranties of
637+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
638+ * PURPOSE. See the GNU General Public License for more details.
639+ *
640+ * You should have received a copy of the GNU General Public License along
641+ * with this program. If not, see <http://www.gnu.org/licenses/>.
642+ *
643+ * Authors:
644+ * Charles Kerr <charles.kerr@canonical.com>
645+ */
646+
647+#include <datetime/appointment.h>
648+#include <datetime/settings.h>
649+#include <datetime/snap.h>
650+
651+#include "notification-fixture.h"
652+
653+/***
654+****
655+***/
656+
657+using namespace unity::indicator::datetime;
658+
659+namespace
660+{
661+ static constexpr char const * APP_NAME {"indicator-datetime-service"};
662+
663+ gboolean quit_idle (gpointer gloop)
664+ {
665+ g_main_loop_quit(static_cast<GMainLoop*>(gloop));
666+ return G_SOURCE_REMOVE;
667+ };
668+}
669+
670+/***
671+****
672+***/
673+
674+TEST_F(NotificationFixture,Notification)
675+{
676+ // Feed different combinations of system settings,
677+ // indicator-datetime settings, and event types,
678+ // then see if notifications and haptic feedback behave as expected.
679+
680+ auto settings = std::make_shared<Settings>();
681+ auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
682+ auto sb = std::make_shared<unity::indicator::notifications::DefaultSoundBuilder>();
683+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
684+
685+ // combinatorial factor #1: event type
686+ struct {
687+ Appointment appt;
688+ bool expected_notify_called;
689+ bool expected_vibrate_called;
690+ } test_appts[] = {
691+ { appt, true, true },
692+ { ualarm, true, true }
693+ };
694+
695+ // combinatorial factor #2: indicator-datetime's haptic mode
696+ struct {
697+ const char* haptic_mode;
698+ bool expected_notify_called;
699+ bool expected_vibrate_called;
700+ } test_haptics[] = {
701+ { "none", true, false },
702+ { "pulse", true, true }
703+ };
704+
705+ // combinatorial factor #3: system settings' "other vibrations" enabled
706+ struct {
707+ bool other_vibrations;
708+ bool expected_notify_called;
709+ bool expected_vibrate_called;
710+ } test_other_vibrations[] = {
711+ { true, true, true },
712+ { false, true, false }
713+ };
714+
715+ // combinatorial factor #4: system settings' notifications app blacklist
716+ const std::set<std::pair<std::string,std::string>> blacklist_calendar { std::make_pair(std::string{"com.ubuntu.calendar"}, std::string{"calendar-app"}) };
717+ const std::set<std::pair<std::string,std::string>> blacklist_empty;
718+ struct {
719+ std::set<std::pair<std::string,std::string>> muted_apps; // apps that should not trigger notifications
720+ bool expected_notify_called; // do we expect the notification tho show?
721+ bool expected_vibrate_called; // do we expect the phone to vibrate?
722+ } test_muted_apps[] = {
723+ { blacklist_calendar, false, false },
724+ { blacklist_empty, true, true }
725+ };
726+
727+ for (const auto& test_appt : test_appts)
728+ {
729+ for (const auto& test_haptic : test_haptics)
730+ {
731+ for (const auto& test_vibes : test_other_vibrations)
732+ {
733+ for (const auto& test_muted : test_muted_apps)
734+ {
735+ auto snap = create_snap(ne, sb, settings);
736+
737+ const bool expected_notify_called = test_appt.expected_notify_called
738+ && test_vibes.expected_notify_called
739+ && test_muted.expected_notify_called
740+ && test_haptic.expected_notify_called;
741+
742+ const bool expected_vibrate_called = test_appt.expected_vibrate_called
743+ && test_vibes.expected_vibrate_called
744+ && test_muted.expected_vibrate_called
745+ && test_haptic.expected_vibrate_called;
746+
747+ // clear out any previous iterations' noise
748+ GError * error = nullptr;
749+ dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error);
750+ g_assert_no_error(error);
751+ dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error);
752+ g_assert_no_error(error);
753+
754+ // set the properties to match the test case
755+ settings->muted_apps.set(test_muted.muted_apps);
756+ settings->alarm_haptic.set(test_haptic.haptic_mode);
757+ dbus_test_dbus_mock_object_update_property(as_mock,
758+ as_obj,
759+ PROP_OTHER_VIBRATIONS,
760+ g_variant_new_boolean(test_vibes.other_vibrations),
761+ &error);
762+ g_assert_no_error(error);
763+ wait_msec(100);
764+
765+ // run the test
766+ (*snap)(appt, appt.alarms.front(), func, func);
767+ wait_msec(100);
768+
769+ // test that the notification was as expected
770+ const bool notify_called = dbus_test_dbus_mock_object_check_method_call(notify_mock,
771+ notify_obj,
772+ METHOD_NOTIFY,
773+ nullptr,
774+ &error);
775+ g_assert_no_error(error);
776+ EXPECT_EQ(expected_notify_called, notify_called);
777+
778+ // test that the vibration was as expected
779+ const bool vibrate_called = dbus_test_dbus_mock_object_check_method_call(haptic_mock,
780+ haptic_obj,
781+ HAPTIC_METHOD_VIBRATE_PATTERN,
782+ nullptr,
783+ &error);
784+ g_assert_no_error(error);
785+ EXPECT_EQ(expected_vibrate_called, vibrate_called);
786+ }
787+ }
788+ }
789+ }
790+}
791+
792
793=== modified file 'tests/test-settings.cpp'
794--- tests/test-settings.cpp 2015-10-13 23:28:20 +0000
795+++ tests/test-settings.cpp 2016-02-03 16:38:36 +0000
796@@ -38,18 +38,22 @@
797 std::shared_ptr<LiveSettings> m_live;
798 std::shared_ptr<Settings> m_settings;
799 GSettings * m_gsettings;
800+ GSettings * m_gsettings_cunh;
801
802 void SetUp() override
803 {
804 super::SetUp();
805
806 m_gsettings = g_settings_new(SETTINGS_INTERFACE);
807+ m_gsettings_cunh = g_settings_new(SETTINGS_CUNH_SCHEMA_ID);
808+
809 m_live.reset(new LiveSettings);
810 m_settings = std::dynamic_pointer_cast<Settings>(m_live);
811 }
812
813 void TearDown() override
814 {
815+ g_clear_object(&m_gsettings_cunh);
816 g_clear_object(&m_gsettings);
817 m_settings.reset();
818 m_live.reset();
819@@ -222,3 +226,39 @@
820 g_strfreev(tmp);
821 EXPECT_EQ(bv, vtmp);
822 }
823+
824+TEST_F(SettingsFixture, MutedApps)
825+{
826+ const auto key = SETTINGS_CUNH_BLACKLIST_S;
827+
828+ struct {
829+ std::string pkgname;
830+ std::string appname;
831+ } apps[] = {
832+ { "", "ubuntu-system-settings" },
833+ { "com.ubuntu.calendar", "calendar" },
834+ { "com.ubuntu.developer.webapps.webapp-facebook", "webapp-facebook" },
835+ { "com.ubuntu.reminders", "reminders" }
836+ };
837+ std::set<std::pair<std::string,std::string>> apps_set;
838+ for (const auto& app : apps)
839+ apps_set.insert(std::make_pair(app.pkgname, app.appname));
840+
841+ // test that changing Settings is reflected in the schema
842+ m_settings->muted_apps.set(apps_set);
843+ auto v = g_settings_get_value(m_gsettings_cunh, key);
844+ auto str = g_variant_print(v, true);
845+ EXPECT_STREQ("[('', 'ubuntu-system-settings'), ('com.ubuntu.calendar', 'calendar'), ('com.ubuntu.developer.webapps.webapp-facebook', 'webapp-facebook'), ('com.ubuntu.reminders', 'reminders')]", str);
846+ g_clear_pointer(&str, g_free);
847+
848+ // test that clearing the schema clears the settings
849+ g_settings_reset(m_gsettings_cunh, key);
850+ EXPECT_EQ(0, m_settings->muted_apps.get().size());
851+
852+ // test thst setting the schema updates the settings
853+ g_settings_set_value(m_gsettings_cunh, key, v);
854+ EXPECT_EQ(apps_set, m_settings->muted_apps.get());
855+
856+ // cleanup
857+ g_clear_pointer(&v, g_variant_unref);
858+}
859
860=== modified file 'tests/test-snap.cpp'
861--- tests/test-snap.cpp 2015-10-14 03:32:39 +0000
862+++ tests/test-snap.cpp 2016-02-03 16:38:36 +0000
863@@ -25,19 +25,12 @@
864 #include <notifications/dbus-shared.h>
865 #include <notifications/notifications.h>
866
867-#include <libdbustest/dbus-test.h>
868-
869-#include <glib.h>
870-
871-#include <unistd.h> // getuid()
872-#include <sys/types.h> // getuid()
873+#include "notification-fixture.h"
874
875 using namespace unity::indicator::datetime;
876
877 namespace uin = unity::indicator::notifications;
878
879-#include "glib-fixture.h"
880-
881 /***
882 ****
883 ***/
884@@ -49,341 +42,6 @@
885
886 using namespace unity::indicator::datetime;
887
888-class SnapFixture: public GlibFixture
889-{
890-private:
891-
892- typedef GlibFixture super;
893-
894- static constexpr char const * NOTIFY_BUSNAME {"org.freedesktop.Notifications"};
895- static constexpr char const * NOTIFY_INTERFACE {"org.freedesktop.Notifications"};
896- static constexpr char const * NOTIFY_PATH {"/org/freedesktop/Notifications"};
897-
898-protected:
899-
900- static constexpr char const * HAPTIC_METHOD_VIBRATE_PATTERN {"VibratePattern"};
901-
902- static constexpr int SCREEN_COOKIE {8675309};
903- static constexpr char const * SCREEN_METHOD_KEEP_DISPLAY_ON {"keepDisplayOn"};
904- static constexpr char const * SCREEN_METHOD_REMOVE_DISPLAY_ON_REQUEST {"removeDisplayOnRequest"};
905-
906- static constexpr int POWERD_SYS_STATE_ACTIVE = 1;
907- static constexpr char const * POWERD_COOKIE {"567-48-8307"};
908- static constexpr char const * POWERD_METHOD_REQUEST_SYS_STATE {"requestSysState"};
909- static constexpr char const * POWERD_METHOD_CLEAR_SYS_STATE {"clearSysState"};
910-
911- static constexpr int FIRST_NOTIFY_ID {1000};
912-
913- static constexpr int NOTIFICATION_CLOSED_EXPIRED {1};
914- static constexpr int NOTIFICATION_CLOSED_DISMISSED {2};
915- static constexpr int NOTIFICATION_CLOSED_API {3};
916- static constexpr int NOTIFICATION_CLOSED_UNDEFINED {4};
917-
918- static constexpr char const * METHOD_CLOSE {"CloseNotification"};
919- static constexpr char const * METHOD_GET_CAPS {"GetCapabilities"};
920- static constexpr char const * METHOD_GET_INFO {"GetServerInformation"};
921- static constexpr char const * METHOD_NOTIFY {"Notify"};
922-
923- static constexpr char const * SIGNAL_CLOSED {"NotificationClosed"};
924-
925- static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"};
926-
927- static constexpr char const * AS_BUSNAME {"org.freedesktop.Accounts"};
928- static constexpr char const * AS_INTERFACE {"com.ubuntu.touch.AccountsService.Sound"};
929- static constexpr char const * PROP_OTHER_VIBRATIONS {"OtherVibrate"};
930- static constexpr char const * PROP_SILENT_MODE {"SilentMode"};
931-
932- Appointment appt;
933- Appointment ualarm;
934- GDBusConnection * system_bus = nullptr;
935- GDBusConnection * session_bus = nullptr;
936- DbusTestService * service = nullptr;
937- DbusTestDbusMock * as_mock = nullptr;
938- DbusTestDbusMock * notify_mock = nullptr;
939- DbusTestDbusMock * powerd_mock = nullptr;
940- DbusTestDbusMock * screen_mock = nullptr;
941- DbusTestDbusMock * haptic_mock = nullptr;
942- DbusTestDbusMockObject * as_obj = nullptr;
943- DbusTestDbusMockObject * notify_obj = nullptr;
944- DbusTestDbusMockObject * powerd_obj = nullptr;
945- DbusTestDbusMockObject * screen_obj = nullptr;
946- DbusTestDbusMockObject * haptic_obj = nullptr;
947-
948- void SetUp() override
949- {
950- GError * error = nullptr;
951- char * str = nullptr;
952-
953- super::SetUp();
954-
955- // init an Appointment
956- appt.color = "green";
957- appt.summary = "Christmas";
958- appt.uid = "D4B57D50247291478ED31DED17FF0A9838DED402";
959- appt.type = Appointment::EVENT;
960- const auto christmas = DateTime::Local(2015,12,25,0,0,0);
961- appt.begin = christmas.start_of_day();
962- appt.end = christmas.end_of_day();
963- appt.alarms.push_back(Alarm{"Ho Ho Ho!", "", appt.begin});
964-
965- // init an Ubuntu Alarm
966- ualarm.color = "red";
967- ualarm.summary = "Wakeup";
968- ualarm.uid = "E4B57D50247291478ED31DED17FF0A9838DED403";
969- ualarm.type = Appointment::UBUNTU_ALARM;
970- const auto tomorrow = DateTime::NowLocal().add_days(1);
971- ualarm.begin = tomorrow;
972- ualarm.end = tomorrow;
973- ualarm.alarms.push_back(Alarm{"It's Tomorrow!", "", appt.begin});
974-
975- service = dbus_test_service_new(nullptr);
976-
977- ///
978- /// Add the AccountsService mock
979- ///
980-
981- as_mock = dbus_test_dbus_mock_new(AS_BUSNAME);
982- auto as_path = g_strdup_printf("/org/freedesktop/Accounts/User%lu", (gulong)getuid());
983- as_obj = dbus_test_dbus_mock_get_object(as_mock,
984- as_path,
985- AS_INTERFACE,
986- &error);
987- g_free(as_path);
988- g_assert_no_error(error);
989-
990- // PROP_SILENT_MODE
991- dbus_test_dbus_mock_object_add_property(as_mock,
992- as_obj,
993- PROP_SILENT_MODE,
994- G_VARIANT_TYPE_BOOLEAN,
995- g_variant_new_boolean(false),
996- &error);
997- g_assert_no_error(error);
998-
999- // PROP_OTHER_VIBRATIONS
1000- dbus_test_dbus_mock_object_add_property(as_mock,
1001- as_obj,
1002- PROP_OTHER_VIBRATIONS,
1003- G_VARIANT_TYPE_BOOLEAN,
1004- g_variant_new_boolean(true),
1005- &error);
1006- g_assert_no_error(error);
1007- dbus_test_service_add_task(service, DBUS_TEST_TASK(as_mock));
1008-
1009- ///
1010- /// Add the Notifications mock
1011- ///
1012-
1013- notify_mock = dbus_test_dbus_mock_new(NOTIFY_BUSNAME);
1014- notify_obj = dbus_test_dbus_mock_get_object(notify_mock,
1015- NOTIFY_PATH,
1016- NOTIFY_INTERFACE,
1017- &error);
1018- g_assert_no_error(error);
1019-
1020- // METHOD_GET_INFO
1021- str = g_strdup("ret = ('mock-notify', 'test vendor', '1.0', '1.1')");
1022- dbus_test_dbus_mock_object_add_method(notify_mock,
1023- notify_obj,
1024- METHOD_GET_INFO,
1025- nullptr,
1026- G_VARIANT_TYPE("(ssss)"),
1027- str,
1028- &error);
1029- g_assert_no_error (error);
1030- g_free (str);
1031-
1032- // METHOD_NOTIFY
1033- str = g_strdup_printf("try:\n"
1034- " self.NextNotifyId\n"
1035- "except AttributeError:\n"
1036- " self.NextNotifyId = %d\n"
1037- "ret = self.NextNotifyId\n"
1038- "self.NextNotifyId += 1\n",
1039- FIRST_NOTIFY_ID);
1040- dbus_test_dbus_mock_object_add_method(notify_mock,
1041- notify_obj,
1042- METHOD_NOTIFY,
1043- G_VARIANT_TYPE("(susssasa{sv}i)"),
1044- G_VARIANT_TYPE_UINT32,
1045- str,
1046- &error);
1047- g_assert_no_error (error);
1048- g_free (str);
1049-
1050- // METHOD_CLOSE
1051- str = g_strdup_printf("self.EmitSignal('%s', '%s', 'uu', [ args[0], %d ])",
1052- NOTIFY_INTERFACE,
1053- SIGNAL_CLOSED,
1054- NOTIFICATION_CLOSED_API);
1055- dbus_test_dbus_mock_object_add_method(notify_mock,
1056- notify_obj,
1057- METHOD_CLOSE,
1058- G_VARIANT_TYPE("(u)"),
1059- nullptr,
1060- str,
1061- &error);
1062- g_assert_no_error (error);
1063- g_free (str);
1064-
1065- dbus_test_service_add_task(service, DBUS_TEST_TASK(notify_mock));
1066-
1067- ///
1068- /// Add the powerd mock
1069- ///
1070-
1071- powerd_mock = dbus_test_dbus_mock_new(BUS_POWERD_NAME);
1072- powerd_obj = dbus_test_dbus_mock_get_object(powerd_mock,
1073- BUS_POWERD_PATH,
1074- BUS_POWERD_INTERFACE,
1075- &error);
1076- g_assert_no_error(error);
1077-
1078- str = g_strdup_printf ("ret = '%s'", POWERD_COOKIE);
1079- dbus_test_dbus_mock_object_add_method(powerd_mock,
1080- powerd_obj,
1081- POWERD_METHOD_REQUEST_SYS_STATE,
1082- G_VARIANT_TYPE("(si)"),
1083- G_VARIANT_TYPE("(s)"),
1084- str,
1085- &error);
1086- g_assert_no_error (error);
1087- g_free (str);
1088-
1089- dbus_test_dbus_mock_object_add_method(powerd_mock,
1090- powerd_obj,
1091- POWERD_METHOD_CLEAR_SYS_STATE,
1092- G_VARIANT_TYPE("(s)"),
1093- nullptr,
1094- "",
1095- &error);
1096- g_assert_no_error (error);
1097-
1098- dbus_test_service_add_task(service, DBUS_TEST_TASK(powerd_mock));
1099-
1100- ///
1101- /// Add the Screen mock
1102- ///
1103-
1104- screen_mock = dbus_test_dbus_mock_new(BUS_SCREEN_NAME);
1105- screen_obj = dbus_test_dbus_mock_get_object(screen_mock,
1106- BUS_SCREEN_PATH,
1107- BUS_SCREEN_INTERFACE,
1108- &error);
1109- g_assert_no_error(error);
1110-
1111- str = g_strdup_printf ("ret = %d", SCREEN_COOKIE);
1112- dbus_test_dbus_mock_object_add_method(screen_mock,
1113- screen_obj,
1114- SCREEN_METHOD_KEEP_DISPLAY_ON,
1115- nullptr,
1116- G_VARIANT_TYPE("(i)"),
1117- str,
1118- &error);
1119- g_assert_no_error (error);
1120- g_free (str);
1121-
1122- dbus_test_dbus_mock_object_add_method(screen_mock,
1123- screen_obj,
1124- SCREEN_METHOD_REMOVE_DISPLAY_ON_REQUEST,
1125- G_VARIANT_TYPE("(i)"),
1126- nullptr,
1127- "",
1128- &error);
1129- g_assert_no_error (error);
1130- dbus_test_service_add_task(service, DBUS_TEST_TASK(screen_mock));
1131-
1132- ///
1133- /// Add the haptic mock
1134- ///
1135-
1136- haptic_mock = dbus_test_dbus_mock_new(BUS_HAPTIC_NAME);
1137- haptic_obj = dbus_test_dbus_mock_get_object(haptic_mock,
1138- BUS_HAPTIC_PATH,
1139- BUS_HAPTIC_INTERFACE,
1140- &error);
1141-
1142- dbus_test_dbus_mock_object_add_method(haptic_mock,
1143- haptic_obj,
1144- HAPTIC_METHOD_VIBRATE_PATTERN,
1145- G_VARIANT_TYPE("(auu)"),
1146- nullptr,
1147- "",
1148- &error);
1149- g_assert_no_error (error);
1150- dbus_test_service_add_task(service, DBUS_TEST_TASK(haptic_mock));
1151-
1152-
1153- // start 'em up.
1154- // make the system bus work off the mock bus too, since that's
1155- // where the upower and screen are on the system bus...
1156-
1157- dbus_test_service_start_tasks(service);
1158- g_setenv("DBUS_SYSTEM_BUS_ADDRESS", g_getenv("DBUS_SESSION_BUS_ADDRESS"), TRUE);
1159-
1160- session_bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
1161- ASSERT_NE(nullptr, session_bus);
1162- g_dbus_connection_set_exit_on_close(session_bus, false);
1163- g_object_add_weak_pointer(G_OBJECT(session_bus), (gpointer *)&session_bus);
1164-
1165- system_bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr);
1166- ASSERT_NE(nullptr, system_bus);
1167- g_dbus_connection_set_exit_on_close(system_bus, FALSE);
1168- g_object_add_weak_pointer(G_OBJECT(system_bus), (gpointer *)&system_bus);
1169- }
1170-
1171- void TearDown() override
1172- {
1173- g_clear_object(&haptic_mock);
1174- g_clear_object(&screen_mock);
1175- g_clear_object(&powerd_mock);
1176- g_clear_object(&notify_mock);
1177- g_clear_object(&as_mock);
1178- g_clear_object(&service);
1179- g_object_unref(session_bus);
1180- g_object_unref(system_bus);
1181-
1182- // wait a little while for the scaffolding to shut down,
1183- // but don't block on it forever...
1184- unsigned int cleartry = 0;
1185- while (((system_bus != nullptr) || (session_bus != nullptr)) && (cleartry < 50))
1186- {
1187- g_usleep(100000);
1188- while (g_main_pending())
1189- g_main_iteration(true);
1190- cleartry++;
1191- }
1192-
1193- super::TearDown();
1194- }
1195-
1196- void make_interactive()
1197- {
1198- // GetCapabilities returns an array containing 'actions',
1199- // so our snap decision will be interactive.
1200- // For this test, it means we should get a timeout Notify Hint
1201- // that matches duration_minutes
1202- GError * error = nullptr;
1203- dbus_test_dbus_mock_object_add_method(notify_mock,
1204- notify_obj,
1205- METHOD_GET_CAPS,
1206- nullptr,
1207- G_VARIANT_TYPE_STRING_ARRAY,
1208- "ret = ['actions', 'body']",
1209- &error);
1210- g_assert_no_error (error);
1211- }
1212-
1213- std::shared_ptr<Snap> create_snap(const std::shared_ptr<uin::Engine>& ne,
1214- const std::shared_ptr<uin::SoundBuilder>& sb,
1215- const std::shared_ptr<Settings>& settings)
1216- {
1217- auto snap = std::make_shared<Snap>(ne, sb, settings);
1218- wait_msec(100); // wait a moment for the Snap to finish its async dbus bootstrapping
1219- return snap;
1220- }
1221-};
1222-
1223 /***
1224 ****
1225 ***/
1226@@ -397,7 +55,7 @@
1227 };
1228 }
1229
1230-TEST_F(SnapFixture, InteractiveDuration)
1231+TEST_F(NotificationFixture, InteractiveDuration)
1232 {
1233 static constexpr int duration_minutes = 120;
1234 auto settings = std::make_shared<Settings>();
1235@@ -450,7 +108,7 @@
1236 ****
1237 ***/
1238
1239-TEST_F(SnapFixture, InhibitSleep)
1240+TEST_F(NotificationFixture, InhibitSleep)
1241 {
1242 auto settings = std::make_shared<Settings>();
1243 auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1244@@ -506,7 +164,7 @@
1245 ****
1246 ***/
1247
1248-TEST_F(SnapFixture, ForceScreen)
1249+TEST_F(NotificationFixture, ForceScreen)
1250 {
1251 auto settings = std::make_shared<Settings>();
1252 auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1253@@ -548,59 +206,6 @@
1254 ****
1255 ***/
1256
1257-TEST_F(SnapFixture,Vibrate)
1258-{
1259- auto settings = std::make_shared<Settings>();
1260- auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1261- auto sb = std::make_shared<unity::indicator::notifications::DefaultSoundBuilder>();
1262- auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
1263- GError * error = nullptr;
1264-
1265- struct {
1266- bool other_vibrations; // the com.ubuntu.touch.AccountsService.Sound "other vibrations" setting
1267- const char* haptic_mode; // supported values: "none", "pulse"
1268- bool expected_vibrate_called; // do we expect the phone to vibrate?
1269- } test_cases[] = {
1270- { false, "none", false },
1271- { true, "none", false },
1272- { false, "pulse", false },
1273- { true, "pulse", true }
1274- };
1275-
1276- auto snap = create_snap(ne, sb, settings);
1277-
1278- for(const auto& test_case : test_cases)
1279- {
1280- // clear out any previous iterations' noise
1281- dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error);
1282-
1283- // set the properties to match the test case
1284- settings->alarm_haptic.set(test_case.haptic_mode);
1285- dbus_test_dbus_mock_object_update_property(as_mock,
1286- as_obj,
1287- PROP_OTHER_VIBRATIONS,
1288- g_variant_new_boolean(test_case.other_vibrations),
1289- &error);
1290- g_assert_no_error(error);
1291- wait_msec(100);
1292-
1293- // run the test
1294- (*snap)(appt, appt.alarms.front(), func, func);
1295- wait_msec(100);
1296- const bool vibrate_called = dbus_test_dbus_mock_object_check_method_call(haptic_mock,
1297- haptic_obj,
1298- HAPTIC_METHOD_VIBRATE_PATTERN,
1299- nullptr,
1300- &error);
1301- g_assert_no_error(error);
1302- EXPECT_EQ(test_case.expected_vibrate_called, vibrate_called);
1303- }
1304-}
1305-
1306-/***
1307-****
1308-***/
1309-
1310 /**
1311 * A DefaultSoundBuilder wrapper which remembers the parameters of the last sound created.
1312 */
1313@@ -641,10 +246,10 @@
1314 return uri;
1315 }
1316
1317-TEST_F(SnapFixture,DefaultSounds)
1318+TEST_F(NotificationFixture,DefaultSounds)
1319 {
1320 auto settings = std::make_shared<Settings>();
1321- auto ne = std::make_shared<uin::Engine>(APP_NAME);
1322+ auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1323 auto sb = std::make_shared<TestSoundBuilder>();
1324 auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
1325
1326@@ -667,3 +272,125 @@
1327 EXPECT_EQ(test_case.expected_role, sb->role());
1328 }
1329 }
1330+
1331+/***
1332+****
1333+***/
1334+
1335+TEST_F(NotificationFixture,Notification)
1336+{
1337+ // Feed different combinations of system settings,
1338+ // indicator-datetime settings, and event types,
1339+ // then see if notifications and haptic feedback behave as expected.
1340+
1341+ auto settings = std::make_shared<Settings>();
1342+ auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1343+ auto sb = std::make_shared<unity::indicator::notifications::DefaultSoundBuilder>();
1344+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
1345+
1346+ // combinatorial factor #1: event type
1347+ struct {
1348+ Appointment appt;
1349+ bool expected_notify_called;
1350+ bool expected_vibrate_called;
1351+ } test_appts[] = {
1352+ { appt, true, true },
1353+ { ualarm, true, true }
1354+ };
1355+
1356+ // combinatorial factor #2: indicator-datetime's haptic mode
1357+ struct {
1358+ const char* haptic_mode;
1359+ bool expected_notify_called;
1360+ bool expected_vibrate_called;
1361+ } test_haptics[] = {
1362+ { "none", true, false },
1363+ { "pulse", true, true }
1364+ };
1365+
1366+ // combinatorial factor #3: system settings' "other vibrations" enabled
1367+ struct {
1368+ bool other_vibrations;
1369+ bool expected_notify_called;
1370+ bool expected_vibrate_called;
1371+ } test_other_vibrations[] = {
1372+ { true, true, true },
1373+ { false, true, false }
1374+ };
1375+
1376+ // combinatorial factor #4: system settings' notifications app blacklist
1377+ const std::set<std::pair<std::string,std::string>> blacklist_calendar { std::make_pair(std::string{"com.ubuntu.calendar"}, std::string{"calendar-app"}) };
1378+ const std::set<std::pair<std::string,std::string>> blacklist_empty;
1379+ struct {
1380+ std::set<std::pair<std::string,std::string>> muted_apps; // apps that should not trigger notifications
1381+ bool expected_notify_called; // do we expect the notification tho show?
1382+ bool expected_vibrate_called; // do we expect the phone to vibrate?
1383+ } test_muted_apps[] = {
1384+ { blacklist_calendar, false, false },
1385+ { blacklist_empty, true, true }
1386+ };
1387+
1388+ for (const auto& test_appt : test_appts)
1389+ {
1390+ for (const auto& test_haptic : test_haptics)
1391+ {
1392+ for (const auto& test_vibes : test_other_vibrations)
1393+ {
1394+ for (const auto& test_muted : test_muted_apps)
1395+ {
1396+ auto snap = create_snap(ne, sb, settings);
1397+
1398+ const bool expected_notify_called = test_appt.expected_notify_called
1399+ && test_vibes.expected_notify_called
1400+ && test_muted.expected_notify_called
1401+ && test_haptic.expected_notify_called;
1402+
1403+ const bool expected_vibrate_called = test_appt.expected_vibrate_called
1404+ && test_vibes.expected_vibrate_called
1405+ && test_muted.expected_vibrate_called
1406+ && test_haptic.expected_vibrate_called;
1407+
1408+ // clear out any previous iterations' noise
1409+ GError * error = nullptr;
1410+ dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error);
1411+ g_assert_no_error(error);
1412+ dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error);
1413+ g_assert_no_error(error);
1414+
1415+ // set the properties to match the test case
1416+ settings->muted_apps.set(test_muted.muted_apps);
1417+ settings->alarm_haptic.set(test_haptic.haptic_mode);
1418+ dbus_test_dbus_mock_object_update_property(as_mock,
1419+ as_obj,
1420+ PROP_OTHER_VIBRATIONS,
1421+ g_variant_new_boolean(test_vibes.other_vibrations),
1422+ &error);
1423+ g_assert_no_error(error);
1424+ wait_msec(100);
1425+
1426+ // run the test
1427+ (*snap)(appt, appt.alarms.front(), func, func);
1428+ wait_msec(100);
1429+
1430+ // test that the notification was as expected
1431+ const bool notify_called = dbus_test_dbus_mock_object_check_method_call(notify_mock,
1432+ notify_obj,
1433+ METHOD_NOTIFY,
1434+ nullptr,
1435+ &error);
1436+ g_assert_no_error(error);
1437+ EXPECT_EQ(expected_notify_called, notify_called);
1438+
1439+ // test that the vibration was as expected
1440+ const bool vibrate_called = dbus_test_dbus_mock_object_check_method_call(haptic_mock,
1441+ haptic_obj,
1442+ HAPTIC_METHOD_VIBRATE_PATTERN,
1443+ nullptr,
1444+ &error);
1445+ g_assert_no_error(error);
1446+ EXPECT_EQ(expected_vibrate_called, vibrate_called);
1447+ }
1448+ }
1449+ }
1450+ }
1451+}
1452
1453=== added file 'tests/test-sound.cpp'
1454--- tests/test-sound.cpp 1970-01-01 00:00:00 +0000
1455+++ tests/test-sound.cpp 2016-02-03 16:38:36 +0000
1456@@ -0,0 +1,269 @@
1457+/*
1458+ * Copyright 2014-2016 Canonical Ltd.
1459+ *
1460+ * This program is free software: you can redistribute it and/or modify it
1461+ * under the terms of the GNU General Public License version 3, as published
1462+ * by the Free Software Foundation.
1463+ *
1464+ * This program is distributed in the hope that it will be useful, but
1465+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1466+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1467+ * PURPOSE. See the GNU General Public License for more details.
1468+ *
1469+ * You should have received a copy of the GNU General Public License along
1470+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1471+ *
1472+ * Authors:
1473+ * Charles Kerr <charles.kerr@canonical.com>
1474+ */
1475+
1476+#include <datetime/appointment.h>
1477+#include <datetime/settings.h>
1478+#include <datetime/snap.h>
1479+
1480+#include "notification-fixture.h"
1481+
1482+using namespace unity::indicator::datetime;
1483+
1484+namespace uin = unity::indicator::notifications;
1485+
1486+/***
1487+****
1488+***/
1489+
1490+namespace
1491+{
1492+ static constexpr char const * APP_NAME {"indicator-datetime-service"};
1493+}
1494+
1495+
1496+namespace
1497+{
1498+ gboolean quit_idle (gpointer gloop)
1499+ {
1500+ g_main_loop_quit(static_cast<GMainLoop*>(gloop));
1501+ return G_SOURCE_REMOVE;
1502+ };
1503+}
1504+
1505+/***
1506+****
1507+***/
1508+
1509+TEST_F(NotificationFixture, InteractiveDuration)
1510+{
1511+ static constexpr int duration_minutes = 120;
1512+ auto settings = std::make_shared<Settings>();
1513+ settings->alarm_duration.set(duration_minutes);
1514+ auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1515+ auto sb = std::make_shared<unity::indicator::notifications::DefaultSoundBuilder>();
1516+ auto snap = create_snap(ne, sb, settings);
1517+
1518+ make_interactive();
1519+
1520+ // call the Snap Decision
1521+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
1522+ (*snap)(appt, appt.alarms.front(), func, func);
1523+
1524+ // confirm that Notify got called once
1525+ guint len = 0;
1526+ GError * error = nullptr;
1527+ const auto calls = dbus_test_dbus_mock_object_get_method_calls (notify_mock,
1528+ notify_obj,
1529+ METHOD_NOTIFY,
1530+ &len,
1531+ &error);
1532+ g_assert_no_error(error);
1533+ ASSERT_EQ(1, len);
1534+
1535+ // confirm that the app_name passed to Notify was APP_NAME
1536+ const auto& params = calls[0].params;
1537+ ASSERT_EQ(8, g_variant_n_children(params));
1538+ const char * str = nullptr;
1539+ g_variant_get_child (params, 0, "&s", &str);
1540+ ASSERT_STREQ(APP_NAME, str);
1541+
1542+ // confirm that the icon passed to Notify was "alarm-clock"
1543+ g_variant_get_child (params, 2, "&s", &str);
1544+ ASSERT_STREQ("alarm-clock", str);
1545+
1546+ // confirm that the hints passed to Notify included a timeout matching duration_minutes
1547+ int32_t i32;
1548+ bool b;
1549+ auto hints = g_variant_get_child_value (params, 6);
1550+ b = g_variant_lookup (hints, HINT_TIMEOUT, "i", &i32);
1551+ EXPECT_TRUE(b);
1552+ const auto duration = std::chrono::minutes(duration_minutes);
1553+ EXPECT_EQ(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(), i32);
1554+ g_variant_unref(hints);
1555+ ne.reset();
1556+}
1557+
1558+/***
1559+****
1560+***/
1561+
1562+TEST_F(NotificationFixture, InhibitSleep)
1563+{
1564+ auto settings = std::make_shared<Settings>();
1565+ auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1566+ auto sb = std::make_shared<unity::indicator::notifications::DefaultSoundBuilder>();
1567+ auto snap = create_snap(ne, sb, settings);
1568+
1569+ make_interactive();
1570+
1571+ // invoke the notification
1572+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
1573+ (*snap)(appt, appt.alarms.front(), func, func);
1574+
1575+ wait_msec(1000);
1576+
1577+ // confirm that sleep got inhibited
1578+ GError * error = nullptr;
1579+ EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock,
1580+ powerd_obj,
1581+ POWERD_METHOD_REQUEST_SYS_STATE,
1582+ g_variant_new("(si)", APP_NAME, POWERD_SYS_STATE_ACTIVE),
1583+ &error));
1584+
1585+ // confirm that the screen got forced on
1586+ EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (screen_mock,
1587+ screen_obj,
1588+ SCREEN_METHOD_KEEP_DISPLAY_ON,
1589+ nullptr,
1590+ &error));
1591+
1592+ // force-close the snap
1593+ wait_msec(100);
1594+ snap.reset();
1595+ wait_msec(100);
1596+
1597+ // confirm that sleep got uninhibted
1598+ EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock,
1599+ powerd_obj,
1600+ POWERD_METHOD_CLEAR_SYS_STATE,
1601+ g_variant_new("(s)", POWERD_COOKIE),
1602+ &error));
1603+
1604+ // confirm that the screen's no longer forced on
1605+ EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (screen_mock,
1606+ screen_obj,
1607+ SCREEN_METHOD_REMOVE_DISPLAY_ON_REQUEST,
1608+ g_variant_new("(i)", SCREEN_COOKIE),
1609+ &error));
1610+
1611+ g_assert_no_error (error);
1612+}
1613+
1614+/***
1615+****
1616+***/
1617+
1618+TEST_F(NotificationFixture, ForceScreen)
1619+{
1620+ auto settings = std::make_shared<Settings>();
1621+ auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1622+ auto sb = std::make_shared<unity::indicator::notifications::DefaultSoundBuilder>();
1623+ auto snap = create_snap(ne, sb, settings);
1624+
1625+ make_interactive();
1626+
1627+ // invoke the notification
1628+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
1629+ (*snap)(appt, appt.alarms.front(), func, func);
1630+
1631+ wait_msec(1000);
1632+
1633+ // confirm that sleep got inhibited
1634+ GError * error = nullptr;
1635+ EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock,
1636+ powerd_obj,
1637+ POWERD_METHOD_REQUEST_SYS_STATE,
1638+ g_variant_new("(si)", APP_NAME, POWERD_SYS_STATE_ACTIVE),
1639+ &error));
1640+ g_assert_no_error(error);
1641+
1642+ // force-close the snap
1643+ wait_msec(100);
1644+ snap.reset();
1645+ wait_msec(100);
1646+
1647+ // confirm that sleep got uninhibted
1648+ EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock,
1649+ powerd_obj,
1650+ POWERD_METHOD_CLEAR_SYS_STATE,
1651+ g_variant_new("(s)", POWERD_COOKIE),
1652+ &error));
1653+ g_assert_no_error(error);
1654+}
1655+
1656+/***
1657+****
1658+***/
1659+
1660+/**
1661+ * A DefaultSoundBuilder wrapper which remembers the parameters of the last sound created.
1662+ */
1663+class TestSoundBuilder: public uin::SoundBuilder
1664+{
1665+public:
1666+ TestSoundBuilder() =default;
1667+ ~TestSoundBuilder() =default;
1668+
1669+ virtual std::shared_ptr<uin::Sound> create(const std::string& role, const std::string& uri, unsigned int volume, bool loop) override {
1670+ m_role = role;
1671+ m_uri = uri;
1672+ m_volume = volume;
1673+ m_loop = loop;
1674+ return m_impl.create(role, uri, volume, loop);
1675+ }
1676+
1677+ const std::string& role() { return m_role; }
1678+ const std::string& uri() { return m_uri; }
1679+ unsigned int volume() { return m_volume; }
1680+ bool loop() { return m_loop; }
1681+
1682+private:
1683+ std::string m_role;
1684+ std::string m_uri;
1685+ unsigned int m_volume;
1686+ bool m_loop;
1687+ uin::DefaultSoundBuilder m_impl;
1688+};
1689+
1690+std::string path_to_uri(const std::string& path)
1691+{
1692+ auto file = g_file_new_for_path(path.c_str());
1693+ auto uri_cstr = g_file_get_uri(file);
1694+ std::string uri = uri_cstr;
1695+ g_free(uri_cstr);
1696+ g_clear_pointer(&file, g_object_unref);
1697+ return uri;
1698+}
1699+
1700+TEST_F(NotificationFixture,DefaultSounds)
1701+{
1702+ auto settings = std::make_shared<Settings>();
1703+ auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
1704+ auto sb = std::make_shared<TestSoundBuilder>();
1705+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
1706+
1707+ const struct {
1708+ Appointment appointment;
1709+ std::string expected_role;
1710+ std::string expected_uri;
1711+ } test_cases[] = {
1712+ { ualarm, "alarm", path_to_uri(ALARM_DEFAULT_SOUND) },
1713+ { appt, "alert", path_to_uri(CALENDAR_DEFAULT_SOUND) }
1714+ };
1715+
1716+ auto snap = create_snap(ne, sb, settings);
1717+
1718+ for(const auto& test_case : test_cases)
1719+ {
1720+ (*snap)(test_case.appointment, test_case.appointment.alarms.front(), func, func);
1721+ wait_msec(100);
1722+ EXPECT_EQ(test_case.expected_uri, sb->uri());
1723+ EXPECT_EQ(test_case.expected_role, sb->role());
1724+ }
1725+}

Subscribers

People subscribed via source and target branches