From 1eace0aeb116ca1a93a2bad1e25bfa5f8c50b1d8 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 2 Feb 2016 13:05:26 -0600 Subject: Move notifications tests into a new unit test. Extract notifications test fixture into a reusable header. --- tests/test-notification.cpp | 164 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 tests/test-notification.cpp (limited to 'tests/test-notification.cpp') diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp new file mode 100644 index 0000000..c1773e4 --- /dev/null +++ b/tests/test-notification.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2014-2016 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +#include +#include +#include + +#include "notification-fixture.h" + +/*** +**** +***/ + +using namespace ayatana::indicator::datetime; + +namespace +{ + static constexpr char const * APP_NAME {"indicator-datetime-service"}; + + gboolean quit_idle (gpointer gloop) + { + g_main_loop_quit(static_cast(gloop)); + return G_SOURCE_REMOVE; + }; +} + +/*** +**** +***/ + +TEST_F(NotificationFixture,Notification) +{ + // Feed different combinations of system settings, + // indicator-datetime settings, and event types, + // then see if notifications and haptic feedback behave as expected. + + auto settings = std::make_shared(); + auto ne = std::make_shared(APP_NAME); + auto sb = std::make_shared(); + auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; + + // combinatorial factor #1: event type + struct { + Appointment appt; + bool expected_notify_called; + bool expected_vibrate_called; + } test_appts[] = { + { appt, true, true }, + { ualarm, true, true } + }; + + // combinatorial factor #2: indicator-datetime's haptic mode + struct { + const char* haptic_mode; + bool expected_notify_called; + bool expected_vibrate_called; + } test_haptics[] = { + { "none", true, false }, + { "pulse", true, true } + }; + + // combinatorial factor #3: system settings' "other vibrations" enabled + struct { + bool other_vibrations; + bool expected_notify_called; + bool expected_vibrate_called; + } test_other_vibrations[] = { + { true, true, true }, + { false, true, false } + }; + + // combinatorial factor #4: system settings' notifications app blacklist + const std::set> blacklist_calendar { std::make_pair(std::string{"com.lomiri.calendar"}, std::string{"calendar-app"}) }; + const std::set> blacklist_empty; + struct { + std::set> muted_apps; // apps that should not trigger notifications + bool expected_notify_called; // do we expect the notification tho show? + bool expected_vibrate_called; // do we expect the phone to vibrate? + } test_muted_apps[] = { + { blacklist_calendar, false, false }, + { blacklist_empty, true, true } + }; + + for (const auto& test_appt : test_appts) + { + for (const auto& test_haptic : test_haptics) + { + for (const auto& test_vibes : test_other_vibrations) + { + for (const auto& test_muted : test_muted_apps) + { + auto snap = create_snap(ne, sb, settings); + + const bool expected_notify_called = test_appt.expected_notify_called + && test_vibes.expected_notify_called + && test_muted.expected_notify_called + && test_haptic.expected_notify_called; + + const bool expected_vibrate_called = test_appt.expected_vibrate_called + && test_vibes.expected_vibrate_called + && test_muted.expected_vibrate_called + && test_haptic.expected_vibrate_called; + + // clear out any previous iterations' noise + GError * error = nullptr; + dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error); + g_assert_no_error(error); + dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error); + g_assert_no_error(error); + + // set the properties to match the test case + settings->muted_apps.set(test_muted.muted_apps); + settings->alarm_haptic.set(test_haptic.haptic_mode); + dbus_test_dbus_mock_object_update_property(as_mock, + as_obj, + PROP_OTHER_VIBRATIONS, + g_variant_new_boolean(test_vibes.other_vibrations), + &error); + g_assert_no_error(error); + wait_msec(100); + + // run the test + (*snap)(appt, appt.alarms.front(), func, func); + wait_msec(100); + + // test that the notification was as expected + const bool notify_called = dbus_test_dbus_mock_object_check_method_call(notify_mock, + notify_obj, + METHOD_NOTIFY, + nullptr, + &error); + g_assert_no_error(error); + EXPECT_EQ(expected_notify_called, notify_called); + + // test that the vibration was as expected + const bool vibrate_called = dbus_test_dbus_mock_object_check_method_call(haptic_mock, + haptic_obj, + HAPTIC_METHOD_VIBRATE_PATTERN, + nullptr, + &error); + g_assert_no_error(error); + EXPECT_EQ(expected_vibrate_called, vibrate_called); + } + } + } + } +} + -- cgit v1.2.3 From 6b85df64a2639b133e1bbdf583f7f2ace992b178 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 3 Feb 2016 12:28:10 -0600 Subject: add notification title, icon checks to test-notification's battery of test combinations --- tests/test-notification.cpp | 57 +++++++++++++++++++++++++++++++++------------ tests/test-sound.cpp | 2 +- 2 files changed, 43 insertions(+), 16 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index c1773e4..5a2682e 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -58,11 +58,13 @@ TEST_F(NotificationFixture,Notification) // combinatorial factor #1: event type struct { Appointment appt; + const char* icon_name; + const char* prefix; bool expected_notify_called; bool expected_vibrate_called; } test_appts[] = { - { appt, true, true }, - { ualarm, true, true } + { appt, "reminder", "Event", true, true }, + { ualarm, "alarm-clock", "Alarm", true, true } }; // combinatorial factor #2: indicator-datetime's haptic mode @@ -90,11 +92,13 @@ TEST_F(NotificationFixture,Notification) const std::set> blacklist_empty; struct { std::set> muted_apps; // apps that should not trigger notifications - bool expected_notify_called; // do we expect the notification tho show? - bool expected_vibrate_called; // do we expect the phone to vibrate? + std::set expected_notify_called; // do we expect the notification to show? + std::set expected_vibrate_called; // do we expect the phone to vibrate? } test_muted_apps[] = { - { blacklist_calendar, false, false }, - { blacklist_empty, true, true } + { blacklist_empty, std::set{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT }, + std::set{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT } }, + { blacklist_calendar, std::set{ Appointment::Type::UBUNTU_ALARM }, + std::set{ Appointment::Type::UBUNTU_ALARM } } }; for (const auto& test_appt : test_appts) @@ -109,12 +113,12 @@ TEST_F(NotificationFixture,Notification) const bool expected_notify_called = test_appt.expected_notify_called && test_vibes.expected_notify_called - && test_muted.expected_notify_called + && (test_muted.expected_notify_called.count(test_appt.appt.type) > 0) && test_haptic.expected_notify_called; const bool expected_vibrate_called = test_appt.expected_vibrate_called && test_vibes.expected_vibrate_called - && test_muted.expected_vibrate_called + && (test_muted.expected_vibrate_called.count(test_appt.appt.type) > 0) && test_haptic.expected_vibrate_called; // clear out any previous iterations' noise @@ -136,17 +140,40 @@ TEST_F(NotificationFixture,Notification) wait_msec(100); // run the test - (*snap)(appt, appt.alarms.front(), func, func); + (*snap)(test_appt.appt, appt.alarms.front(), func, func); wait_msec(100); // test that the notification was as expected - const bool notify_called = dbus_test_dbus_mock_object_check_method_call(notify_mock, - notify_obj, - METHOD_NOTIFY, - nullptr, - &error); + guint num_notify_calls = 0; + const auto notify_calls = dbus_test_dbus_mock_object_get_method_calls(notify_mock, + notify_obj, + METHOD_NOTIFY, + &num_notify_calls, + &error); g_assert_no_error(error); - EXPECT_EQ(expected_notify_called, notify_called); + EXPECT_EQ((expected_notify_called?1:0), num_notify_calls); + if (num_notify_calls > 0) + { + // test that Notify was called with the app_name + const gchar* app_name {nullptr}; + g_variant_get_child(notify_calls[0].params, 0, "&s", &app_name); + ASSERT_STREQ(APP_NAME, app_name); + + // test that Notify was called with the type-appropriate icon + const gchar* icon_name {nullptr}; + g_variant_get_child(notify_calls[0].params, 2, "&s", &icon_name); + ASSERT_STREQ(test_appt.icon_name, icon_name); + + // test that the Notification title has the correct prefix + const gchar* title {nullptr}; + g_variant_get_child(notify_calls[0].params, 3, "&s", &title); + ASSERT_TRUE(g_str_has_prefix(title, test_appt.prefix)); + + // test that Notify was called with the appointment's body + const gchar* body {nullptr}; + g_variant_get_child(notify_calls[0].params, 4, "&s", &body); + ASSERT_STREQ(test_appt.appt.summary.c_str(), body); + } // test that the vibration was as expected const bool vibrate_called = dbus_test_dbus_mock_object_check_method_call(haptic_mock, diff --git a/tests/test-sound.cpp b/tests/test-sound.cpp index 8e55986..c2a8fb5 100644 --- a/tests/test-sound.cpp +++ b/tests/test-sound.cpp @@ -85,7 +85,7 @@ TEST_F(NotificationFixture, InteractiveDuration) // confirm that the icon passed to Notify was "alarm-clock" g_variant_get_child (params, 2, "&s", &str); - ASSERT_STREQ("alarm-clock", str); + ASSERT_STREQ("reminder", str); // confirm that the hints passed to Notify included a timeout matching duration_minutes int32_t i32; -- cgit v1.2.3 From 62f4861b11ba7e3c58c75cf574cc999e623b4247 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 10 Feb 2016 14:49:01 -0600 Subject: update notification tests to wait for the needed bus events instead of waiting for arbitrary time intervals --- tests/test-notification.cpp | 65 ++++++-- tests/test-snap.cpp | 396 -------------------------------------------- tests/test-sound.cpp | 100 ----------- 3 files changed, 48 insertions(+), 513 deletions(-) delete mode 100644 tests/test-snap.cpp (limited to 'tests/test-notification.cpp') diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index 5a2682e..a51267f 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -37,7 +37,18 @@ namespace { g_main_loop_quit(static_cast(gloop)); return G_SOURCE_REMOVE; - }; + } + + void on_dbus_signal(GDBusConnection* /*connection*/, + const gchar* /*sender_name*/, + const gchar* /*object_path*/, + const gchar* /*interface_name*/, + const gchar* /*signal_name*/, + GVariant* /*parameters*/, + gpointer gloop) + { + g_main_loop_quit(static_cast(gloop)); + } } /*** @@ -122,28 +133,58 @@ TEST_F(NotificationFixture,Notification) && test_haptic.expected_vibrate_called; // clear out any previous iterations' noise - GError * error = nullptr; + GError * error {}; dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error); - g_assert_no_error(error); dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error); g_assert_no_error(error); - // set the properties to match the test case + + // set test case properties: blacklist settings->muted_apps.set(test_muted.muted_apps); + + // set test case properties: haptic mode settings->alarm_haptic.set(test_haptic.haptic_mode); + + // set test case properties: other-vibrations flag + // (and wait for the PropertiesChanged signal so we know the dbusmock got it) + ASSERT_NAME_OWNED_EVENTUALLY(system_bus, AS_BUSNAME); + const auto subscription_id = g_dbus_connection_signal_subscribe(system_bus, + AS_BUSNAME, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + nullptr, /* object_path */ + "com.lomiri.touch.AccountsService.Sound", + G_DBUS_SIGNAL_FLAGS_NONE, + on_dbus_signal, + loop, + nullptr /*user_data_free_func*/); dbus_test_dbus_mock_object_update_property(as_mock, as_obj, PROP_OTHER_VIBRATIONS, g_variant_new_boolean(test_vibes.other_vibrations), &error); g_assert_no_error(error); - wait_msec(100); + g_main_loop_run(loop); + g_dbus_connection_signal_unsubscribe(system_bus, subscription_id); // run the test (*snap)(test_appt.appt, appt.alarms.front(), func, func); - wait_msec(100); - // test that the notification was as expected + // confirm that the notification was as expected + if (expected_notify_called) { + EXPECT_METHOD_CALLED_EVENTUALLY(notify_mock, notify_obj, METHOD_NOTIFY); + } else { + EXPECT_METHOD_NOT_CALLED_EVENTUALLY(notify_mock, notify_obj, METHOD_NOTIFY); + } + + // confirm that the vibration was as expected + if (expected_vibrate_called) { + EXPECT_METHOD_CALLED_EVENTUALLY(haptic_mock, haptic_obj, HAPTIC_METHOD_VIBRATE_PATTERN); + } else { + EXPECT_METHOD_NOT_CALLED_EVENTUALLY(haptic_mock, haptic_obj, HAPTIC_METHOD_VIBRATE_PATTERN); + } + + // confirm that the notification was as expected guint num_notify_calls = 0; const auto notify_calls = dbus_test_dbus_mock_object_get_method_calls(notify_mock, notify_obj, @@ -151,7 +192,6 @@ TEST_F(NotificationFixture,Notification) &num_notify_calls, &error); g_assert_no_error(error); - EXPECT_EQ((expected_notify_called?1:0), num_notify_calls); if (num_notify_calls > 0) { // test that Notify was called with the app_name @@ -174,15 +214,6 @@ TEST_F(NotificationFixture,Notification) g_variant_get_child(notify_calls[0].params, 4, "&s", &body); ASSERT_STREQ(test_appt.appt.summary.c_str(), body); } - - // test that the vibration was as expected - const bool vibrate_called = dbus_test_dbus_mock_object_check_method_call(haptic_mock, - haptic_obj, - HAPTIC_METHOD_VIBRATE_PATTERN, - nullptr, - &error); - g_assert_no_error(error); - EXPECT_EQ(expected_vibrate_called, vibrate_called); } } } diff --git a/tests/test-snap.cpp b/tests/test-snap.cpp deleted file mode 100644 index 2c53900..0000000 --- a/tests/test-snap.cpp +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright 2014 Canonical Ltd. - * - * Authors: - * Charles Kerr - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include -#include -#include - -#include -#include - -#include "notification-fixture.h" - -using namespace ayatana::indicator::datetime; - -namespace uin = ayatana::indicator::notifications; - -/*** -**** -***/ - -namespace -{ - static constexpr char const * APP_NAME {"ayatana-indicator-datetime-service"}; -} - -using namespace ayatana::indicator::datetime; - -/*** -**** -***/ - -namespace -{ - gboolean quit_idle (gpointer gloop) - { - g_main_loop_quit(static_cast(gloop)); - return G_SOURCE_REMOVE; - }; -} - -TEST_F(NotificationFixture, InteractiveDuration) -{ - static constexpr int duration_minutes = 120; - auto settings = std::make_shared(); - settings->alarm_duration.set(duration_minutes); - auto ne = std::make_shared(APP_NAME); - auto sb = std::make_shared(); - auto snap = create_snap(ne, sb, settings); - - make_interactive(); - - // call the Snap Decision - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; - (*snap)(appt, appt.alarms.front(), func, func); - - // confirm that Notify got called once - guint len = 0; - GError * error = nullptr; - const auto calls = dbus_test_dbus_mock_object_get_method_calls (notify_mock, - notify_obj, - METHOD_NOTIFY, - &len, - &error); - g_assert_no_error(error); - ASSERT_EQ(1, len); - - // confirm that the app_name passed to Notify was APP_NAME - const auto& params = calls[0].params; - ASSERT_EQ(8, g_variant_n_children(params)); - const char * str = nullptr; - g_variant_get_child (params, 0, "&s", &str); - ASSERT_STREQ(APP_NAME, str); - - // confirm that the icon passed to Notify was "alarm-clock" - g_variant_get_child (params, 2, "&s", &str); - ASSERT_STREQ("alarm-clock", str); - - // confirm that the hints passed to Notify included a timeout matching duration_minutes - int32_t i32; - bool b; - auto hints = g_variant_get_child_value (params, 6); - b = g_variant_lookup (hints, HINT_TIMEOUT, "i", &i32); - EXPECT_TRUE(b); - const auto duration = std::chrono::minutes(duration_minutes); - EXPECT_EQ(std::chrono::duration_cast(duration).count(), i32); - g_variant_unref(hints); - ne.reset(); -} - -/*** -**** -***/ - -TEST_F(NotificationFixture, InhibitSleep) -{ - auto settings = std::make_shared(); - auto ne = std::make_shared(APP_NAME); - auto sb = std::make_shared(); - auto snap = create_snap(ne, sb, settings); - - make_interactive(); - - // invoke the notification - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; - (*snap)(appt, appt.alarms.front(), func, func); - - wait_msec(1000); - - // confirm that sleep got inhibited - GError * error = nullptr; - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock, - powerd_obj, - POWERD_METHOD_REQUEST_SYS_STATE, - g_variant_new("(si)", APP_NAME, POWERD_SYS_STATE_ACTIVE), - &error)); - - // confirm that the screen got forced on - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (screen_mock, - screen_obj, - SCREEN_METHOD_KEEP_DISPLAY_ON, - nullptr, - &error)); - - // force-close the snap - wait_msec(100); - snap.reset(); - wait_msec(100); - - // confirm that sleep got uninhibted - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock, - powerd_obj, - POWERD_METHOD_CLEAR_SYS_STATE, - g_variant_new("(s)", POWERD_COOKIE), - &error)); - - // confirm that the screen's no longer forced on - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (screen_mock, - screen_obj, - SCREEN_METHOD_REMOVE_DISPLAY_ON_REQUEST, - g_variant_new("(i)", SCREEN_COOKIE), - &error)); - - g_assert_no_error (error); -} - -/*** -**** -***/ - -TEST_F(NotificationFixture, ForceScreen) -{ - auto settings = std::make_shared(); - auto ne = std::make_shared(APP_NAME); - auto sb = std::make_shared(); - auto snap = create_snap(ne, sb, settings); - - make_interactive(); - - // invoke the notification - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; - (*snap)(appt, appt.alarms.front(), func, func); - - wait_msec(1000); - - // confirm that sleep got inhibited - GError * error = nullptr; - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock, - powerd_obj, - POWERD_METHOD_REQUEST_SYS_STATE, - g_variant_new("(si)", APP_NAME, POWERD_SYS_STATE_ACTIVE), - &error)); - g_assert_no_error(error); - - // force-close the snap - wait_msec(100); - snap.reset(); - wait_msec(100); - - // confirm that sleep got uninhibted - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock, - powerd_obj, - POWERD_METHOD_CLEAR_SYS_STATE, - g_variant_new("(s)", POWERD_COOKIE), - &error)); - g_assert_no_error(error); -} - -/*** -**** -***/ - -/** - * A DefaultSoundBuilder wrapper which remembers the parameters of the last sound created. - */ -class TestSoundBuilder: public uin::SoundBuilder -{ -public: - TestSoundBuilder() =default; - ~TestSoundBuilder() =default; - - virtual std::shared_ptr create(const std::string& role, const std::string& uri, unsigned int volume, bool loop) override { - m_role = role; - m_uri = uri; - m_volume = volume; - m_loop = loop; - return m_impl.create(role, uri, volume, loop); - } - - const std::string& role() { return m_role; } - const std::string& uri() { return m_uri; } - unsigned int volume() { return m_volume; } - bool loop() { return m_loop; } - -private: - std::string m_role; - std::string m_uri; - unsigned int m_volume; - bool m_loop; - uin::DefaultSoundBuilder m_impl; -}; - -std::string path_to_uri(const std::string& path) -{ - auto file = g_file_new_for_path(path.c_str()); - auto uri_cstr = g_file_get_uri(file); - std::string uri = uri_cstr; - g_free(uri_cstr); - g_clear_pointer(&file, g_object_unref); - return uri; -} - -TEST_F(NotificationFixture,DefaultSounds) -{ - auto settings = std::make_shared(); - auto ne = std::make_shared(APP_NAME); - auto sb = std::make_shared(); - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; - - const struct { - Appointment appointment; - std::string expected_role; - std::string expected_uri; - } test_cases[] = { - { ualarm, "alarm", path_to_uri(ALARM_DEFAULT_SOUND) }, - { appt, "alert", path_to_uri(CALENDAR_DEFAULT_SOUND) } - }; - - auto snap = create_snap(ne, sb, settings); - - for(const auto& test_case : test_cases) - { - (*snap)(test_case.appointment, test_case.appointment.alarms.front(), func, func); - wait_msec(100); - EXPECT_EQ(test_case.expected_uri, sb->uri()); - EXPECT_EQ(test_case.expected_role, sb->role()); - } -} - -/*** -**** -***/ - -TEST_F(NotificationFixture,Notification) -{ - // Feed different combinations of system settings, - // indicator-datetime settings, and event types, - // then see if notifications and haptic feedback behave as expected. - - auto settings = std::make_shared(); - auto ne = std::make_shared(APP_NAME); - auto sb = std::make_shared(); - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; - - // combinatorial factor #1: event type - struct { - Appointment appt; - bool expected_notify_called; - bool expected_vibrate_called; - } test_appts[] = { - { appt, true, true }, - { ualarm, true, true } - }; - - // combinatorial factor #2: indicator-datetime's haptic mode - struct { - const char* haptic_mode; - bool expected_notify_called; - bool expected_vibrate_called; - } test_haptics[] = { - { "none", true, false }, - { "pulse", true, true } - }; - - // combinatorial factor #3: system settings' "other vibrations" enabled - struct { - bool other_vibrations; - bool expected_notify_called; - bool expected_vibrate_called; - } test_other_vibrations[] = { - { true, true, true }, - { false, true, false } - }; - - // combinatorial factor #4: system settings' notifications app blacklist - const std::set> blacklist_calendar { std::make_pair(std::string{"com.lomiri.calendar"}, std::string{"calendar-app"}) }; - const std::set> blacklist_empty; - struct { - std::set> muted_apps; // apps that should not trigger notifications - bool expected_notify_called; // do we expect the notification tho show? - bool expected_vibrate_called; // do we expect the phone to vibrate? - } test_muted_apps[] = { - { blacklist_calendar, false, false }, - { blacklist_empty, true, true } - }; - - for (const auto& test_appt : test_appts) - { - for (const auto& test_haptic : test_haptics) - { - for (const auto& test_vibes : test_other_vibrations) - { - for (const auto& test_muted : test_muted_apps) - { - auto snap = create_snap(ne, sb, settings); - - const bool expected_notify_called = test_appt.expected_notify_called - && test_vibes.expected_notify_called - && test_muted.expected_notify_called - && test_haptic.expected_notify_called; - - const bool expected_vibrate_called = test_appt.expected_vibrate_called - && test_vibes.expected_vibrate_called - && test_muted.expected_vibrate_called - && test_haptic.expected_vibrate_called; - - // clear out any previous iterations' noise - GError * error = nullptr; - dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error); - g_assert_no_error(error); - dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error); - g_assert_no_error(error); - - // set the properties to match the test case - settings->muted_apps.set(test_muted.muted_apps); - settings->alarm_haptic.set(test_haptic.haptic_mode); - dbus_test_dbus_mock_object_update_property(as_mock, - as_obj, - PROP_OTHER_VIBRATIONS, - g_variant_new_boolean(test_vibes.other_vibrations), - &error); - g_assert_no_error(error); - wait_msec(100); - - // run the test - (*snap)(appt, appt.alarms.front(), func, func); - wait_msec(100); - - // test that the notification was as expected - const bool notify_called = dbus_test_dbus_mock_object_check_method_call(notify_mock, - notify_obj, - METHOD_NOTIFY, - nullptr, - &error); - g_assert_no_error(error); - EXPECT_EQ(expected_notify_called, notify_called); - - // test that the vibration was as expected - const bool vibrate_called = dbus_test_dbus_mock_object_check_method_call(haptic_mock, - haptic_obj, - HAPTIC_METHOD_VIBRATE_PATTERN, - nullptr, - &error); - g_assert_no_error(error); - EXPECT_EQ(expected_vibrate_called, vibrate_called); - } - } - } - } -} diff --git a/tests/test-sound.cpp b/tests/test-sound.cpp index c2a8fb5..a222f39 100644 --- a/tests/test-sound.cpp +++ b/tests/test-sound.cpp @@ -103,104 +103,6 @@ TEST_F(NotificationFixture, InteractiveDuration) **** ***/ -TEST_F(NotificationFixture, InhibitSleep) -{ - auto settings = std::make_shared(); - auto ne = std::make_shared(APP_NAME); - auto sb = std::make_shared(); - auto snap = create_snap(ne, sb, settings); - - make_interactive(); - - // invoke the notification - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; - (*snap)(appt, appt.alarms.front(), func, func); - - wait_msec(1000); - - // confirm that sleep got inhibited - GError * error = nullptr; - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock, - powerd_obj, - POWERD_METHOD_REQUEST_SYS_STATE, - g_variant_new("(si)", APP_NAME, POWERD_SYS_STATE_ACTIVE), - &error)); - - // confirm that the screen got forced on - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (screen_mock, - screen_obj, - SCREEN_METHOD_KEEP_DISPLAY_ON, - nullptr, - &error)); - - // force-close the snap - wait_msec(100); - snap.reset(); - wait_msec(100); - - // confirm that sleep got uninhibted - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock, - powerd_obj, - POWERD_METHOD_CLEAR_SYS_STATE, - g_variant_new("(s)", POWERD_COOKIE), - &error)); - - // confirm that the screen's no longer forced on - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (screen_mock, - screen_obj, - SCREEN_METHOD_REMOVE_DISPLAY_ON_REQUEST, - g_variant_new("(i)", SCREEN_COOKIE), - &error)); - - g_assert_no_error (error); -} - -/*** -**** -***/ - -TEST_F(NotificationFixture, ForceScreen) -{ - auto settings = std::make_shared(); - auto ne = std::make_shared(APP_NAME); - auto sb = std::make_shared(); - auto snap = create_snap(ne, sb, settings); - - make_interactive(); - - // invoke the notification - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; - (*snap)(appt, appt.alarms.front(), func, func); - - wait_msec(1000); - - // confirm that sleep got inhibited - GError * error = nullptr; - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock, - powerd_obj, - POWERD_METHOD_REQUEST_SYS_STATE, - g_variant_new("(si)", APP_NAME, POWERD_SYS_STATE_ACTIVE), - &error)); - g_assert_no_error(error); - - // force-close the snap - wait_msec(100); - snap.reset(); - wait_msec(100); - - // confirm that sleep got uninhibted - EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock, - powerd_obj, - POWERD_METHOD_CLEAR_SYS_STATE, - g_variant_new("(s)", POWERD_COOKIE), - &error)); - g_assert_no_error(error); -} - -/*** -**** -***/ - /** * A DefaultSoundBuilder wrapper which remembers the parameters of the last sound created. */ @@ -258,11 +160,9 @@ TEST_F(NotificationFixture,DefaultSounds) }; auto snap = create_snap(ne, sb, settings); - for(const auto& test_case : test_cases) { (*snap)(test_case.appointment, test_case.appointment.alarms.front(), func, func); - wait_msec(100); EXPECT_EQ(test_case.expected_uri, sb->uri()); EXPECT_EQ(test_case.expected_role, sb->role()); } -- cgit v1.2.3 From 8a5815d92048f84581cc6802c1689f06c7df24f0 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 10 Feb 2016 20:49:07 -0600 Subject: in test-notifications we do need one wait() wart after all, because the Snap is building its impl proxies asynchronously and hasn't any public way of notifying when they're built --- tests/test-notification.cpp | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index a51267f..775d6d5 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -38,17 +38,6 @@ namespace g_main_loop_quit(static_cast(gloop)); return G_SOURCE_REMOVE; } - - void on_dbus_signal(GDBusConnection* /*connection*/, - const gchar* /*sender_name*/, - const gchar* /*object_path*/, - const gchar* /*interface_name*/, - const gchar* /*signal_name*/, - GVariant* /*parameters*/, - gpointer gloop) - { - g_main_loop_quit(static_cast(gloop)); - } } /*** @@ -147,25 +136,13 @@ TEST_F(NotificationFixture,Notification) // set test case properties: other-vibrations flag // (and wait for the PropertiesChanged signal so we know the dbusmock got it) - ASSERT_NAME_OWNED_EVENTUALLY(system_bus, AS_BUSNAME); - const auto subscription_id = g_dbus_connection_signal_subscribe(system_bus, - AS_BUSNAME, - "org.freedesktop.DBus.Properties", - "PropertiesChanged", - nullptr, /* object_path */ - "com.lomiri.touch.AccountsService.Sound", - G_DBUS_SIGNAL_FLAGS_NONE, - on_dbus_signal, - loop, - nullptr /*user_data_free_func*/); dbus_test_dbus_mock_object_update_property(as_mock, as_obj, PROP_OTHER_VIBRATIONS, g_variant_new_boolean(test_vibes.other_vibrations), &error); g_assert_no_error(error); - g_main_loop_run(loop); - g_dbus_connection_signal_unsubscribe(system_bus, subscription_id); + wait_msec(100); // run the test (*snap)(test_appt.appt, appt.alarms.front(), func, func); -- cgit v1.2.3 From 0fee0c157594ca750c3a253e984203cc3abe7cd5 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 10 Feb 2016 22:30:46 -0600 Subject: resolve some test timing issues by deferring Snap object creation until it's needed --- tests/test-notification.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index 775d6d5..4c11dca 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -109,8 +109,6 @@ TEST_F(NotificationFixture,Notification) { for (const auto& test_muted : test_muted_apps) { - auto snap = create_snap(ne, sb, settings); - const bool expected_notify_called = test_appt.expected_notify_called && test_vibes.expected_notify_called && (test_muted.expected_notify_called.count(test_appt.appt.type) > 0) @@ -121,13 +119,6 @@ TEST_F(NotificationFixture,Notification) && (test_muted.expected_vibrate_called.count(test_appt.appt.type) > 0) && test_haptic.expected_vibrate_called; - // clear out any previous iterations' noise - GError * error {}; - dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error); - dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error); - g_assert_no_error(error); - - // set test case properties: blacklist settings->muted_apps.set(test_muted.muted_apps); @@ -136,15 +127,22 @@ TEST_F(NotificationFixture,Notification) // set test case properties: other-vibrations flag // (and wait for the PropertiesChanged signal so we know the dbusmock got it) + GError * error {}; dbus_test_dbus_mock_object_update_property(as_mock, as_obj, PROP_OTHER_VIBRATIONS, g_variant_new_boolean(test_vibes.other_vibrations), &error); g_assert_no_error(error); - wait_msec(100); + + // wait for previous iterations' bus noise to finish and reset the counters + wait_msec(500); + dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error); + dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error); + g_assert_no_error(error); // run the test + auto snap = create_snap(ne, sb, settings); (*snap)(test_appt.appt, appt.alarms.front(), func, func); // confirm that the notification was as expected -- cgit v1.2.3 From bb7b522ef52b240718f33f37b577bacc4fea2db6 Mon Sep 17 00:00:00 2001 From: Renato Araujo Oliveira Filho Date: Mon, 18 Apr 2016 23:42:53 -0300 Subject: Post message on messaging menu if the notification get timeout. --- data/CMakeLists.txt | 7 +- data/ayatana-indicator-datetime.desktop.in | 1 + include/notifications/notifications.h | 11 ++- src/main.cpp | 5 +- src/notifications.cpp | 127 +++++++++++++++++++++++++++-- src/snap.cpp | 12 ++- tests/test-notification.cpp | 2 +- tests/test-sound.cpp | 2 +- 8 files changed, 154 insertions(+), 13 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index c460586..14d36b8 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -32,6 +32,7 @@ if (${SYSTEMD_FOUND}) # build it set (pkglibexecdir "${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") + set (messaging_menu_icon "${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/suru/actions/scalable/appointment.svg") configure_file ("${SYSTEMD_USER_FILE_IN}" "${SYSTEMD_USER_FILE}") # install it @@ -55,7 +56,11 @@ set (XDG_AUTOSTART_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/${XDG_AUTOSTART_NAME}.in set (pkglibexecdir "${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") configure_file ("${XDG_AUTOSTART_FILE_IN}" "${XDG_AUTOSTART_FILE}") -# install it +# install desktop file used by messaging-menu +install (FILES "${XDG_AUTOSTART_FILE}" + DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/applications/") + +# install XDG autostart install (FILES "${XDG_AUTOSTART_FILE}" DESTINATION "${XDG_AUTOSTART_DIR}") diff --git a/data/ayatana-indicator-datetime.desktop.in b/data/ayatana-indicator-datetime.desktop.in index 70df0d7..6d27166 100644 --- a/data/ayatana-indicator-datetime.desktop.in +++ b/data/ayatana-indicator-datetime.desktop.in @@ -6,3 +6,4 @@ OnlyShowIn=MATE;Unity;XFCE;Pantheon; NoDisplay=true StartupNotify=false Terminal=false +Icon=@messaging_menu_icon@ diff --git a/include/notifications/notifications.h b/include/notifications/notifications.h index 0de1e23..2bb6694 100644 --- a/include/notifications/notifications.h +++ b/include/notifications/notifications.h @@ -50,6 +50,8 @@ public: void set_icon_name (const std::string& icon_name); + void set_start_time(uint64_t time); + /* Set an interval, after which the notification will automatically be closed. If not set, the notification server's default timeout is used. */ @@ -62,19 +64,24 @@ public: static constexpr char const * HINT_NONSHAPED_ICON {"x-canonical-non-shaped-icon"}; static constexpr char const * HINT_AFFIRMATIVE_HINT {"x-canonical-private-affirmative-tint"}; static constexpr char const * HINT_REJECTION_TINT {"x-canonical-private-rejection-tint"}; + static constexpr char const * HINT_INTERACTIVE {"x-canonical-switch-to-application"}; /* Add an action button. This may fail if the Engine doesn't support actions. @see Engine::supports_actions() */ void add_action (const std::string& action, const std::string& label); - /** Sets the closed callback. This will be called exactly once. */ + /** Sets the closed callback. This will be called exactly once. After notification dissapear */ void set_closed_callback (std::function); + /** Sets the time-out callback. This will be called exactly once. */ + void set_missed_click_callback (std::function); + + private: friend class Engine; class Impl; - std::unique_ptr impl; + std::shared_ptr impl; }; /** diff --git a/src/main.cpp b/src/main.cpp index bb77c0e..f9a934a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -156,7 +156,10 @@ main(int /*argc*/, char** /*argv*/) auto on_snooze = [snooze_planner](const Appointment& appointment, const Alarm& alarm) { snooze_planner->add(appointment, alarm); }; - auto on_ok = [](const Appointment&, const Alarm&){}; + auto on_ok = [actions](const Appointment& app, const Alarm&){ + //TODO: add support for desktop + actions->phone_open_appointment(app, app.begin); + }; auto on_alarm_reached = [&engine, &snap, &on_snooze, &on_ok](const Appointment& appointment, const Alarm& alarm) { (*snap)(appointment, alarm, on_snooze, on_ok); engine->disable_ubuntu_alarm(appointment); diff --git a/src/notifications.cpp b/src/notifications.cpp index 051653d..2d22087 100644 --- a/src/notifications.cpp +++ b/src/notifications.cpp @@ -21,10 +21,18 @@ #include +#include +#include + + +#include + #include #include #include #include +#include + namespace ayatana { namespace indicator { @@ -45,9 +53,11 @@ public: std::string m_body; std::string m_icon_name; std::chrono::seconds m_duration; + gint64 m_start_time; std::set m_string_hints; std::vector> m_actions; std::function m_closed_callback; + std::function m_missed_click_callback; }; Builder::Builder(): @@ -101,6 +111,18 @@ Builder::set_closed_callback (std::function cb) impl->m_closed_callback.swap (cb); } +void +Builder::set_missed_click_callback (std::function cb) +{ + impl->m_missed_click_callback.swap (cb); +} + +void +Builder::set_start_time (uint64_t time) +{ + impl->m_start_time = time; +} + /*** **** ***/ @@ -110,23 +132,39 @@ class Engine::Impl struct notification_data { std::shared_ptr nn; - std::function closed_callback; + Builder::Impl data; + }; + + struct messaging_menu_data + { + std::shared_ptr mm; + std::function callback; }; public: Impl(const std::string& app_name): + m_messaging_app(messaging_menu_app_new(DATETIME_INDICATOR_DESKTOP_FILE), g_object_unref), m_app_name(app_name) { if (!notify_init(app_name.c_str())) g_critical("Unable to initialize libnotify!"); + + // messaging menu + GIcon *icon = g_themed_icon_new("calendar-app"); + + messaging_menu_app_register(m_messaging_app.get()); + messaging_menu_app_append_source(m_messaging_app.get(), m_app_name.c_str(), icon, "Calendar"); + g_object_unref(icon); } ~Impl() { close_all (); + remove_all (); notify_uninit (); + messaging_menu_app_unregister (m_messaging_app.get()); } const std::string& app_name() const @@ -217,7 +255,7 @@ public: notification_key_quark(), GINT_TO_POINTER(key)); - m_notifications[key] = { nn, info.m_closed_callback }; + m_notifications[key] = { nn, info }; g_signal_connect (nn.get(), "closed", G_CALLBACK(on_notification_closed), this); @@ -238,6 +276,59 @@ public: return ret; } + std::string post(const Builder::Impl& data) + { + uuid_t message_uuid; + uuid_generate(message_uuid); + + char message_id[37]; + uuid_unparse(message_uuid, message_id); + + GIcon *icon = g_themed_icon_new(data.m_icon_name.c_str()); + std::shared_ptr msg (messaging_menu_message_new(message_id, + icon, + data.m_title.c_str(), + nullptr, + data.m_body.c_str(), + data.m_start_time * 1000000), // secs -> microsecs + g_object_ref); + g_object_unref(icon); + if (msg) + { + m_messaging_messages[std::string(message_id)] = { msg, data.m_missed_click_callback }; + g_signal_connect(msg.get(), "activate", + G_CALLBACK(on_message_activated), this); + messaging_menu_app_append_message(m_messaging_app.get(), msg.get(), m_app_name.c_str(), false); + return message_id; + } else { + g_warning("Fail to create messaging menu message"); + } + return ""; + } + + void remove (const std::string &key) + { + auto it = m_messaging_messages.find(key); + if (it != m_messaging_messages.end()) + { + // tell the server to remove message + messaging_menu_app_remove_message(m_messaging_app.get(), it->second.mm.get()); + m_messaging_messages.erase(it); + } + } + + void remove_all () + { + // call remove() on all our keys + + std::set keys; + for (const auto& it : m_messaging_messages) + keys.insert (it.first); + + for (const std::string &key : keys) + remove (key); + } + private: const std::set& server_caps() const @@ -279,6 +370,22 @@ private: static_cast(gself)->remove_closed_notification(GPOINTER_TO_INT(gkey)); } + static void on_message_activated (MessagingMenuMessage *, + const char *actionId, + GVariant *, + gpointer gself) + { + auto self = static_cast(gself); + auto it = self->m_messaging_messages.find(actionId); + g_return_if_fail (it != self->m_messaging_messages.end()); + const auto& ndata = it->second; + + if (ndata.callback) + ndata.callback(); + + self->m_messaging_messages.erase(it); + } + void remove_closed_notification (int key) { auto it = m_notifications.find(key); @@ -286,16 +393,20 @@ private: const auto& ndata = it->second; auto nn = ndata.nn.get(); - if (ndata.closed_callback) + + if (ndata.data.m_closed_callback) { std::string action; - const GQuark q = notification_action_quark(); const gpointer p = g_object_get_qdata(G_OBJECT(nn), q); if (p != nullptr) action = static_cast(p); - ndata.closed_callback (action); + ndata.data.m_closed_callback (action); + // empty action means that the notification got timeout + // post a message on messaging menu + if (action.empty()) + post(ndata.data); } m_notifications.erase(it); @@ -305,6 +416,10 @@ private: **** ***/ + // messaging menu + std::shared_ptr m_messaging_app; + std::map m_messaging_messages; + const std::string m_app_name; // key-to-data @@ -315,6 +430,8 @@ private: mutable std::set m_lazy_caps; static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"}; + static constexpr char const * DATETIME_INDICATOR_DESKTOP_FILE {"indicator-datetime.desktop"}; + static constexpr char const * DATETIME_INDICATOR_SOURCE_ID {"indicator-datetime"}; }; /*** diff --git a/src/snap.cpp b/src/snap.cpp index 259592e..5c530be 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -122,8 +122,9 @@ public: const auto minutes = std::chrono::minutes(m_settings->alarm_duration.get()); ain::Builder b; b.set_body (appointment.summary); - b.set_icon_name (appointment.is_ubuntu_alarm() ? "alarm-clock" : "reminder"); + b.set_icon_name (appointment.is_ubuntu_alarm() ? "alarm-clock" : "appointment"); b.add_hint (ain::Builder::HINT_NONSHAPED_ICON); + b.set_start_time (appointment.begin.to_unix()); const char * timefmt; if (is_locale_12h()) { @@ -152,6 +153,9 @@ public: b.add_hint (ain::Builder::HINT_AFFIRMATIVE_HINT); b.add_action ("ok", _("OK")); b.add_action ("snooze", _("Snooze")); + } else { + b.add_hint (ain::Builder::HINT_INTERACTIVE); + b.add_action ("ok", _("OK")); } // add 'sound', 'haptic', and 'awake' objects to the capture so @@ -161,10 +165,14 @@ public: (const std::string& action){ if (action == "snooze") snooze(appointment, alarm); - else + else if (action == "ok") ok(appointment, alarm); }); + b.set_missed_click_callback([appointment, alarm, ok](){ + ok(appointment, alarm); + }); + const auto key = m_engine->show(b); if (key) m_notifications.insert (key); diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index 4c11dca..b951cee 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -63,7 +63,7 @@ TEST_F(NotificationFixture,Notification) bool expected_notify_called; bool expected_vibrate_called; } test_appts[] = { - { appt, "reminder", "Event", true, true }, + { appt, "appointment", "Event", true, true }, { ualarm, "alarm-clock", "Alarm", true, true } }; diff --git a/tests/test-sound.cpp b/tests/test-sound.cpp index a222f39..59c1a28 100644 --- a/tests/test-sound.cpp +++ b/tests/test-sound.cpp @@ -85,7 +85,7 @@ TEST_F(NotificationFixture, InteractiveDuration) // confirm that the icon passed to Notify was "alarm-clock" g_variant_get_child (params, 2, "&s", &str); - ASSERT_STREQ("reminder", str); + ASSERT_STREQ("appointment", str); // confirm that the hints passed to Notify included a timeout matching duration_minutes int32_t i32; -- cgit v1.2.3 From 04588f8bff4156dae76d8ef03d1bbd58fca9fdb7 Mon Sep 17 00:00:00 2001 From: Renato Araujo Oliveira Filho Date: Tue, 26 Apr 2016 21:43:03 -0300 Subject: Update notifications to use the new calendar icon. --- data/CMakeLists.txt | 2 +- src/snap.cpp | 2 +- tests/test-notification.cpp | 2 +- tests/test-sound.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 14d36b8..6bbc246 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -32,7 +32,7 @@ if (${SYSTEMD_FOUND}) # build it set (pkglibexecdir "${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") - set (messaging_menu_icon "${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/suru/actions/scalable/appointment.svg") + set (messaging_menu_icon "${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/suru/actions/scalable/calendar.svg") configure_file ("${SYSTEMD_USER_FILE_IN}" "${SYSTEMD_USER_FILE}") # install it diff --git a/src/snap.cpp b/src/snap.cpp index 217b6df..1e7dd5e 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -124,7 +124,7 @@ public: const auto minutes = std::chrono::minutes(m_settings->alarm_duration.get()); ain::Builder b; b.set_body (appointment.summary); - b.set_icon_name (appointment.is_ubuntu_alarm() ? "alarm-clock" : "appointment"); + b.set_icon_name (appointment.is_ubuntu_alarm() ? "alarm-clock" : "calendar"); b.add_hint (ain::Builder::HINT_NONSHAPED_ICON); b.set_start_time (appointment.begin.to_unix()); diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index b951cee..d660982 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -63,7 +63,7 @@ TEST_F(NotificationFixture,Notification) bool expected_notify_called; bool expected_vibrate_called; } test_appts[] = { - { appt, "appointment", "Event", true, true }, + { appt, "calendar", "Event", true, true }, { ualarm, "alarm-clock", "Alarm", true, true } }; diff --git a/tests/test-sound.cpp b/tests/test-sound.cpp index 469b085..013c388 100644 --- a/tests/test-sound.cpp +++ b/tests/test-sound.cpp @@ -85,7 +85,7 @@ TEST_F(NotificationFixture, InteractiveDuration) // confirm that the icon passed to Notify was "alarm-clock" g_variant_get_child (params, 2, "&s", &str); - ASSERT_STREQ("appointment", str); + ASSERT_STREQ("calendar", str); // confirm that the hints passed to Notify included a timeout matching duration_minutes int32_t i32; -- cgit v1.2.3 From 7ecfadf5eb61fe32332293ec6de2fe18bfedf0fa Mon Sep 17 00:00:00 2001 From: Renato Araujo Oliveira Filho Date: Wed, 27 Apr 2016 14:31:28 -0300 Subject: Only creates messaging menu if calendar app is instaled. Update tests. --- src/notifications.cpp | 22 +++++++++++++++++----- tests/test-notification.cpp | 2 +- tests/test-sound.cpp | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/src/notifications.cpp b/src/notifications.cpp index dc42534..9817686 100644 --- a/src/notifications.cpp +++ b/src/notifications.cpp @@ -150,14 +150,17 @@ class Engine::Impl public: Impl(const std::string& app_name): - m_messaging_app(messaging_menu_app_new(calendar_app_id().c_str()), g_object_unref), m_app_name(app_name) { if (!notify_init(app_name.c_str())) g_critical("Unable to initialize libnotify!"); // messaging menu - messaging_menu_app_register(m_messaging_app.get()); + auto app_id = calendar_app_id(); + if (!app_id.empty()) { + m_messaging_app.reset(messaging_menu_app_new(app_id.c_str()), g_object_unref); + messaging_menu_app_register(m_messaging_app.get()); + } } ~Impl() @@ -166,7 +169,8 @@ public: remove_all (); notify_uninit (); - messaging_menu_app_unregister (m_messaging_app.get()); + if (m_messaging_app) + messaging_menu_app_unregister (m_messaging_app.get()); } const std::string& app_name() const @@ -280,6 +284,9 @@ public: std::string post(const Builder::Impl& data) { + if (!m_messaging_app) { + return std::string(); + } uuid_t message_uuid; uuid_generate(message_uuid); @@ -439,9 +446,14 @@ private: { #ifdef HAS_LOMIRIAPPLAUNCH auto app_id = lomiri::app_launch::AppID::discover("com.lomiri.calendar"); - return std::string(app_id) + ".desktop"; + + if (!app_id.empty()) + return std::string(app_id) + ".desktop"; + else + return std::string(); + #else - return ""; + return std::string(); #endif } diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index d660982..d04cc8d 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -63,7 +63,7 @@ TEST_F(NotificationFixture,Notification) bool expected_notify_called; bool expected_vibrate_called; } test_appts[] = { - { appt, "calendar", "Event", true, true }, + { appt, "calendar-app", "Event", true, true }, { ualarm, "alarm-clock", "Alarm", true, true } }; diff --git a/tests/test-sound.cpp b/tests/test-sound.cpp index 013c388..0d80109 100644 --- a/tests/test-sound.cpp +++ b/tests/test-sound.cpp @@ -85,7 +85,7 @@ TEST_F(NotificationFixture, InteractiveDuration) // confirm that the icon passed to Notify was "alarm-clock" g_variant_get_child (params, 2, "&s", &str); - ASSERT_STREQ("calendar", str); + ASSERT_STREQ("calendar-app", str); // confirm that the hints passed to Notify included a timeout matching duration_minutes int32_t i32; -- cgit v1.2.3 From 8e58bff9438f67066f72a28cfdf7b421f3345d1e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sat, 14 May 2016 12:20:00 -0500 Subject: sync tests with previous commit's Snap::Response change --- tests/manual-test-snap.cpp | 17 ++++++++++------- tests/test-notification.cpp | 5 ++--- tests/test-sound.cpp | 8 ++++---- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/tests/manual-test-snap.cpp b/tests/manual-test-snap.cpp index a0f80f2..02cbb9f 100644 --- a/tests/manual-test-snap.cpp +++ b/tests/manual-test-snap.cpp @@ -74,12 +74,14 @@ int main(int argc, const char* argv[]) a.alarms.push_back(Alarm{"Alarm Text", "", a.begin}); auto loop = g_main_loop_new(nullptr, false); - auto on_snooze = [loop](const Appointment& appt, const Alarm&){ - g_message("You clicked 'Snooze' for appt url '%s'", appt.summary.c_str()); - g_idle_add(quit_idle, loop); - }; - auto on_ok = [loop](const Appointment&, const Alarm&){ - g_message("You clicked 'OK'"); + auto on_response = [loop](const Appointment& appt, const Alarm&, const Snap::Response& response){ + const char* str {""}; + switch(response) { + case Snap::Response::ShowApp: str = "show-app"; break; + case Snap::Response::Snooze: str = "snooze"; break; + case Snap::Response::None: str = "no-action"; break; + }; + g_message("You clicked '%s' for appt url '%s'", str, appt.summary.c_str()); g_idle_add(quit_idle, loop); }; @@ -92,8 +94,9 @@ int main(int argc, const char* argv[]) settings->alarm_volume.set(volume); auto notification_engine = std::make_shared("ayatana-indicator-datetime-service"); + auto sound_builder = std::make_shared(); Snap snap (notification_engine, settings); - snap(a, a.alarms.front(), on_snooze, on_ok); + snap(a, a.alarms.front(), on_response); g_main_loop_run(loop); g_main_loop_unref(loop); diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index d04cc8d..74a0b92 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -53,7 +53,7 @@ TEST_F(NotificationFixture,Notification) auto settings = std::make_shared(); auto ne = std::make_shared(APP_NAME); auto sb = std::make_shared(); - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; + auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);}; // combinatorial factor #1: event type struct { @@ -143,7 +143,7 @@ TEST_F(NotificationFixture,Notification) // run the test auto snap = create_snap(ne, sb, settings); - (*snap)(test_appt.appt, appt.alarms.front(), func, func); + (*snap)(test_appt.appt, appt.alarms.front(), func); // confirm that the notification was as expected if (expected_notify_called) { @@ -194,4 +194,3 @@ TEST_F(NotificationFixture,Notification) } } } - diff --git a/tests/test-sound.cpp b/tests/test-sound.cpp index 0d80109..9dbd212 100644 --- a/tests/test-sound.cpp +++ b/tests/test-sound.cpp @@ -62,8 +62,8 @@ TEST_F(NotificationFixture, InteractiveDuration) make_interactive(); // call the Snap Decision - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; - (*snap)(appt, appt.alarms.front(), func, func); + auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);}; + (*snap)(appt, appt.alarms.front(), func); // confirm that Notify got called once guint len = 0; @@ -148,7 +148,7 @@ TEST_F(NotificationFixture,DefaultSounds) auto settings = std::make_shared(); auto ne = std::make_shared(APP_NAME); auto sb = std::make_shared(); - auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);}; + auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);}; const struct { Appointment appointment; @@ -163,7 +163,7 @@ TEST_F(NotificationFixture,DefaultSounds) auto snap = create_snap(ne, sb, settings); for(const auto& test_case : test_cases) { - (*snap)(test_case.appointment, test_case.appointment.alarms.front(), func, func); + (*snap)(test_case.appointment, test_case.appointment.alarms.front(), func); EXPECT_EQ(test_case.expected_uri, sb->uri()); EXPECT_EQ(test_case.expected_role, sb->role()); } -- cgit v1.2.3 From b8df067a9fa8e5db5fcccc88de5be3071b64b3ec Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sat, 14 May 2016 12:22:10 -0500 Subject: add new tests to exercise the Snap::Response code --- tests/glib-fixture.h | 24 ++++++++++++ tests/test-notification.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) (limited to 'tests/test-notification.cpp') diff --git a/tests/glib-fixture.h b/tests/glib-fixture.h index efc8d17..eb2a8c5 100644 --- a/tests/glib-fixture.h +++ b/tests/glib-fixture.h @@ -20,6 +20,7 @@ #ifndef INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H #define INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H +#include #include // std::function #include #include // std::shared_ptr @@ -198,6 +199,29 @@ class GlibFixture : public ::testing::Test } GMainLoop * loop; + + using source_func = std::function; + + void idle_add(source_func&& func) + { + g_idle_add_full( + G_PRIORITY_DEFAULT_IDLE, + [](gpointer gf){return (*static_cast(gf))();}, + new std::function(func), + [](gpointer gf){delete static_cast(gf);} + ); + } + + void timeout_add(source_func&& func, std::chrono::milliseconds msec) + { + g_timeout_add_full( + G_PRIORITY_DEFAULT, + msec.count(), + [](gpointer gf){return (*static_cast(gf))();}, + new std::function(func), + [](gpointer gf){delete static_cast(gf);} + ); + } }; #endif /* INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H */ diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index 74a0b92..f31dcf2 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -194,3 +194,97 @@ TEST_F(NotificationFixture,Notification) } } } + + +TEST_F(NotificationFixture,Response) +{ + // create the world + make_interactive(); + auto ne = std::make_shared(APP_NAME); + auto sb = std::make_shared(); + auto settings = std::make_shared(); + int next_notification_id {FIRST_NOTIFY_ID}; + + // set a response callback that remembers what response we got + bool on_response_called {}; + Snap::Response response {}; + auto on_response = [this, &on_response_called, &response] + (const Appointment&, const Alarm&, const Snap::Response& r){ + on_response_called = true; + response = r; + g_idle_add(quit_idle, loop); + }; + + // our tests! + const struct { + Appointment appt; + std::vector expected_actions; + std::string action; + Snap::Response expected_response; + } tests[] = { + { appt, {"show-app"}, "show-app", Snap::Response::ShowApp }, + { ualarm, {"none", "snooze"}, "snooze", Snap::Response::Snooze }, + { ualarm, {"none", "snooze"}, "none", Snap::Response::None } + }; + + + // walk through the tests + for (const auto& test : tests) + { + // wait for previous iterations' bus noise to finish and reset the counters + GError* error {}; + wait_msec(500); + dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error); + g_assert_no_error(error); + on_response_called = false; + + // create a snap decision + auto snap = create_snap(ne, sb, settings); + (*snap)(test.appt, test.appt.alarms.front(), on_response); + + // wait for the notification to show up + EXPECT_METHOD_CALLED_EVENTUALLY(notify_mock, notify_obj, METHOD_NOTIFY); + + // test that Notify was called the right number of times + static constexpr int expected_num_notify_calls {1}; + guint num_notify_calls {}; + const auto notify_calls = dbus_test_dbus_mock_object_get_method_calls( + notify_mock, + notify_obj, + METHOD_NOTIFY, + &num_notify_calls, + &error); + g_assert_no_error(error); + EXPECT_EQ(expected_num_notify_calls, num_notify_calls); + + // test that Notify was called with the correct list of actions + if (num_notify_calls > 0) { + std::vector actions; + const gchar** as {nullptr}; + g_variant_get_child(notify_calls[0].params, 5, "^a&s", &as); + for (int i=0; as && as[i]; i+=2) // actions are in pairs of (name, i18n), skip the i18n + actions.push_back(as[i]); + EXPECT_EQ(test.expected_actions, actions); + } + + // make the notification mock tell the world that the user invoked an action + const auto notification_id {next_notification_id++}; + idle_add([this, notification_id, test](){ + GError* err {}; + dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "ActionInvoked", + G_VARIANT_TYPE("(us)"), + g_variant_new("(us)", guint(notification_id), test.action.c_str()), + &err); + dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "NotificationClosed", + G_VARIANT_TYPE("(uu)"), + g_variant_new("(uu)", guint(notification_id), guint(NOTIFICATION_CLOSED_DISMISSED)), + &err); + g_assert_no_error(err); + return G_SOURCE_REMOVE; + }); + + // confirm that the response callback got the right response + EXPECT_TRUE(wait_for([&on_response_called](){return on_response_called;})); + EXPECT_EQ(int(test.expected_response), int(response)) << "notification_id " << notification_id; + } +} -- cgit v1.2.3 From 8d384b89dfe9dc921047222623bf9036b6ab4282 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 16 May 2016 15:57:51 -0500 Subject: work around g++ 4.9.2 initializer list issue for vivid --- tests/test-notification.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test-notification.cpp') diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index f31dcf2..50d7b57 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -268,7 +268,7 @@ TEST_F(NotificationFixture,Response) } // make the notification mock tell the world that the user invoked an action - const auto notification_id {next_notification_id++}; + const auto notification_id = next_notification_id++; idle_add([this, notification_id, test](){ GError* err {}; dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "ActionInvoked", -- cgit v1.2.3 From 525a38eb600292ffb764f6b5de058f9ba6ddd2b8 Mon Sep 17 00:00:00 2001 From: Arthur Mello Date: Wed, 22 Jun 2016 15:37:55 -0300 Subject: Update indicator-datetime to work with the new notification settings --- include/datetime/settings-live.h | 12 ++-- include/datetime/settings-shared.h | 9 ++- include/datetime/settings.h | 6 +- src/settings-live.cpp | 115 ++++++++++++++++++++++--------------- src/snap.cpp | 45 ++++++++++----- tests/test-notification.cpp | 26 ++++----- tests/test-settings.cpp | 111 ++++++++++++++--------------------- 7 files changed, 173 insertions(+), 151 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/include/datetime/settings-live.h b/include/datetime/settings-live.h index 330b8e8..4aeaa9b 100644 --- a/include/datetime/settings-live.h +++ b/include/datetime/settings-live.h @@ -39,9 +39,9 @@ public: private: static void on_changed_ccid(GSettings*, gchar*, gpointer); - static void on_changed_cunh(GSettings*, gchar*, gpointer); + static void on_changed_cal_notification(GSettings*, gchar*, gpointer); void update_key_ccid(const std::string& key); - void update_key_cunh(const std::string& key); + void update_key_cal_notification(const std::string& key); void update_custom_time_format(); void update_locations(); @@ -62,10 +62,14 @@ private: void update_alarm_duration(); void update_alarm_haptic(); void update_snooze_duration(); - void update_muted_apps(); + void update_cal_notification_enabled(); + void update_cal_notification_sounds(); + void update_cal_notification_vibrations(); + void update_cal_notification_bubbles(); + void update_cal_notification_list(); GSettings* m_settings; - GSettings* m_settings_cunh; + GSettings* m_settings_cal_notification; // we've got a raw pointer here, so disable copying LiveSettings(const LiveSettings&) =delete; diff --git a/include/datetime/settings-shared.h b/include/datetime/settings-shared.h index f385e7a..236b8f1 100644 --- a/include/datetime/settings-shared.h +++ b/include/datetime/settings-shared.h @@ -51,7 +51,12 @@ TimeFormatMode; #define SETTINGS_ALARM_HAPTIC_S "alarm-haptic-feedback" #define SETTINGS_SNOOZE_DURATION_S "snooze-duration-minutes" -#define SETTINGS_CUNH_SCHEMA_ID "com.lomiri.notifications.hub" -#define SETTINGS_CUNH_BLACKLIST_S "blacklist" +#define SETTINGS_NOTIFY_SCHEMA_ID "com.lomiri.notifications.settings" +#define SETTINGS_NOTIFY_CALENDAR_PATH "/com/lomiri/NotificationSettings/com.lomiri.calendar/calendar/" +#define SETTINGS_NOTIFY_ENABLED_KEY "enable-notifications" +#define SETTINGS_NOTIFY_SOUNDS_KEY "use-sounds-notifications" +#define SETTINGS_NOTIFY_VIBRATIONS_KEY "use-vibrations-notifications" +#define SETTINGS_NOTIFY_BUBBLES_KEY "use-bubbles-notifications" +#define SETTINGS_NOTIFY_LIST_KEY "use-list-notifications" #endif // INDICATOR_DATETIME_SETTINGS_SHARED diff --git a/include/datetime/settings.h b/include/datetime/settings.h index d5e81c6..5ae00f6 100644 --- a/include/datetime/settings.h +++ b/include/datetime/settings.h @@ -61,7 +61,11 @@ public: core::Property alarm_volume; core::Property alarm_duration; core::Property snooze_duration; - core::Property>> muted_apps; + core::Property cal_notification_enabled; + core::Property cal_notification_sounds; + core::Property cal_notification_vibrations; + core::Property cal_notification_bubbles; + core::Property cal_notification_list; }; } // namespace datetime diff --git a/src/settings-live.cpp b/src/settings-live.cpp index 6504d7d..f908c05 100644 --- a/src/settings-live.cpp +++ b/src/settings-live.cpp @@ -34,7 +34,7 @@ namespace datetime { LiveSettings::~LiveSettings() { - g_clear_object(&m_settings_cunh); + g_clear_object(&m_settings_cal_notification); g_clear_object(&m_settings); } @@ -44,8 +44,8 @@ LiveSettings::LiveSettings(): m_settings(g_settings_new(SETTINGS_INTERFACE)) if (ayatana_common_utils_is_lomiri()) { - m_settings_cunh = g_settings_new(SETTINGS_CUNH_SCHEMA_ID); - g_signal_connect (m_settings_cunh, "changed", G_CALLBACK(on_changed_cunh), this); + m_settings_cal_notification = g_settings_new_with_path(SETTINGS_NOTIFY_SCHEMA_ID, SETTINGS_NOTIFY_CALENDAR_PATH); + g_signal_connect (m_settings_cal_notification, "changed", G_CALLBACK(on_changed_cal_notification), this); } // init the Properties from the GSettings backend @@ -68,7 +68,11 @@ LiveSettings::LiveSettings(): m_settings(g_settings_new(SETTINGS_INTERFACE)) update_alarm_duration(); update_alarm_haptic(); update_snooze_duration(); - update_muted_apps(); + update_cal_notification_enabled(); + update_cal_notification_sounds(); + update_cal_notification_vibrations(); + update_cal_notification_bubbles(); + update_cal_notification_list(); // now listen for clients to change the properties s.t. we can sync update GSettings @@ -76,20 +80,6 @@ LiveSettings::LiveSettings(): m_settings(g_settings_new(SETTINGS_INTERFACE)) g_settings_set_string(m_settings, SETTINGS_CUSTOM_TIME_FORMAT_S, value.c_str()); }); - if (ayatana_common_utils_is_lomiri()) - { - muted_apps.changed().connect([this](const std::set>& value){ - GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE("a(ss)")); - for(const auto& app : value){ - const std::string& pkgname {app.first}; - const std::string& appname {app.second}; - g_variant_builder_add(&builder, "(ss)", pkgname.c_str(), appname.c_str()); - } - g_settings_set_value(m_settings_cunh, SETTINGS_CUNH_BLACKLIST_S, g_variant_builder_end(&builder)); - }); - } - locations.changed().connect([this](const std::vector& value){ const int n = value.size(); gchar** strv = g_new0(gchar*, n+1); @@ -166,6 +156,26 @@ LiveSettings::LiveSettings(): m_settings(g_settings_new(SETTINGS_INTERFACE)) snooze_duration.changed().connect([this](unsigned int value){ g_settings_set_uint(m_settings, SETTINGS_SNOOZE_DURATION_S, value); }); + + cal_notification_enabled.changed().connect([this](bool value){ + g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_ENABLED_KEY, value); + }); + + cal_notification_sounds.changed().connect([this](bool value){ + g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_SOUNDS_KEY, value); + }); + + cal_notification_vibrations.changed().connect([this](bool value){ + g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_VIBRATIONS_KEY, value); + }); + + cal_notification_bubbles.changed().connect([this](bool value){ + g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_BUBBLES_KEY, value); + }); + + cal_notification_list.changed().connect([this](bool value){ + g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_LIST_KEY, value); + }); } /*** @@ -189,27 +199,6 @@ void LiveSettings::update_locations() locations.set(l); } -void LiveSettings::update_muted_apps() -{ - if (ayatana_common_utils_is_lomiri()) - { - std::set> apps; - - auto blacklist = g_settings_get_value(m_settings_cunh, SETTINGS_CUNH_BLACKLIST_S); - GVariantIter* iter {nullptr}; - g_variant_get (blacklist, "a(ss)", &iter); - gchar* pkgname; - gchar* appname; - while (g_variant_iter_loop (iter, "(ss)", &pkgname, &appname)) { - apps.insert(std::make_pair(pkgname,appname)); - } - g_variant_iter_free (iter); - g_clear_pointer(&blacklist, g_variant_unref); - - muted_apps.set(apps); - } -} - void LiveSettings::update_show_calendar() { const auto val = g_settings_get_boolean(m_settings, SETTINGS_SHOW_CALENDAR_S); @@ -308,21 +297,55 @@ void LiveSettings::update_snooze_duration() snooze_duration.set(g_settings_get_uint(m_settings, SETTINGS_SNOOZE_DURATION_S)); } +void LiveSettings::update_cal_notification_enabled() +{ + cal_notification_enabled.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_ENABLED_KEY)); +} + +void LiveSettings::update_cal_notification_sounds() +{ + cal_notification_sounds.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_SOUNDS_KEY)); +} + +void LiveSettings::update_cal_notification_vibrations() +{ + cal_notification_vibrations.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_VIBRATIONS_KEY)); +} + +void LiveSettings::update_cal_notification_bubbles() +{ + cal_notification_bubbles.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_BUBBLES_KEY)); +} + +void LiveSettings::update_cal_notification_list() +{ + cal_notification_list.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_LIST_KEY)); +} + /*** **** ***/ -void LiveSettings::on_changed_cunh(GSettings* /*settings*/, - gchar* key, - gpointer gself) +void LiveSettings::on_changed_cal_notification(GSettings* /*settings*/, + gchar* key, + gpointer gself) { - static_cast(gself)->update_key_cunh(key); + static_cast(gself)->update_key_cal_notification(key); } -void LiveSettings::update_key_cunh(const std::string& key) + +void LiveSettings::update_key_cal_notification(const std::string& key) { - if (key == SETTINGS_CUNH_BLACKLIST_S) - update_muted_apps(); + if (key == SETTINGS_NOTIFY_ENABLED_KEY) + update_cal_notification_enabled(); + else if (key == SETTINGS_NOTIFY_SOUNDS_KEY) + update_cal_notification_sounds(); + else if (key == SETTINGS_NOTIFY_VIBRATIONS_KEY) + update_cal_notification_vibrations(); + else if (key == SETTINGS_NOTIFY_BUBBLES_KEY) + update_cal_notification_bubbles(); + else if (key == SETTINGS_NOTIFY_LIST_KEY) + update_cal_notification_list(); } /*** diff --git a/src/snap.cpp b/src/snap.cpp index 51d04ae..1e71e7b 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -83,9 +83,9 @@ public: const Alarm& alarm, response_func on_response) { - // If calendar notifications are muted, don't show them - if (!appointment.is_ubuntu_alarm() && calendar_events_are_muted()) { - g_debug("Skipping muted calendar event '%s' notification", appointment.summary.c_str()); + // If calendar notifications are disabled, don't show them + if (!appointment.is_ubuntu_alarm() && !calendar_notifications_are_enabled()) { + g_debug("Skipping disabled calendar event '%s' notification", appointment.summary.c_str()); return; } @@ -96,13 +96,14 @@ public: const bool interactive = appointment.is_ubuntu_alarm() && m_engine->supports_actions(); // force the system to stay awake - auto awake = std::make_shared(m_engine->app_name()); + std::shared_ptr awake; + if (calendar_bubbles_enabled()) { + awake = std::make_shared(m_engine->app_name()); + } // calendar events are muted in silent mode; alarm clocks never are std::shared_ptr sound; - // FIXME: only play sounds for alarms for now, we should itegrate it with - // system settings to decide if we should play sounds for calendar notification or not - if (appointment.is_ubuntu_alarm()) { + if (appointment.is_ubuntu_alarm() || calendar_sounds_enabled()) { // create the sound. const auto role = appointment.is_ubuntu_alarm() ? "alarm" : "alert"; const auto uri = get_alarm_uri(appointment, alarm, m_settings); @@ -113,7 +114,7 @@ public: // create the haptic feedback... std::shared_ptr haptic; - if (should_vibrate()) { + if (should_vibrate() && calendar_vibrations_enabled()) { const auto haptic_mode = m_settings->alarm_haptic.get(); if (haptic_mode == "pulse") haptic = std::make_shared(ain::Haptic::MODE_PULSE, appointment.is_ubuntu_alarm()); @@ -189,15 +190,29 @@ public: private: - bool calendar_events_are_muted() const + bool calendar_notifications_are_enabled() const { - for(const auto& app : m_settings->muted_apps.get()) { - if (app.first == "com.ubuntu.calendar") { - return true; - } - } + return m_settings->cal_notification_enabled.get(); + } + + bool calendar_sounds_enabled() const + { + return m_settings->cal_notification_sounds.get(); + } - return false; + bool calendar_vibrations_enabled() const + { + return m_settings->cal_notification_vibrations.get(); + } + + bool calendar_bubbles_enabled() const + { + return m_settings->cal_notification_bubbles.get(); + } + + bool calendar_list_enabled() const + { + return m_settings->cal_notification_list.get(); } static void on_sound_proxy_ready(GObject* /*source_object*/, GAsyncResult* res, gpointer gself) diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index 50d7b57..b84c6f8 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -87,18 +87,16 @@ TEST_F(NotificationFixture,Notification) { false, true, false } }; - // combinatorial factor #4: system settings' notifications app blacklist - const std::set> blacklist_calendar { std::make_pair(std::string{"com.lomiri.calendar"}, std::string{"calendar-app"}) }; - const std::set> blacklist_empty; + // combinatorial factor #4: system settings' notifications disabled struct { - std::set> muted_apps; // apps that should not trigger notifications + bool cal_notification_enabled; // calendar app can trigger notifications std::set expected_notify_called; // do we expect the notification to show? std::set expected_vibrate_called; // do we expect the phone to vibrate? - } test_muted_apps[] = { - { blacklist_empty, std::set{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT }, - std::set{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT } }, - { blacklist_calendar, std::set{ Appointment::Type::UBUNTU_ALARM }, - std::set{ Appointment::Type::UBUNTU_ALARM } } + } test_cal_disabled[] = { + { true, std::set{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT }, + std::set{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT } }, + { false, std::set{ Appointment::Type::UBUNTU_ALARM }, + std::set{ Appointment::Type::UBUNTU_ALARM } } }; for (const auto& test_appt : test_appts) @@ -107,20 +105,20 @@ TEST_F(NotificationFixture,Notification) { for (const auto& test_vibes : test_other_vibrations) { - for (const auto& test_muted : test_muted_apps) + for (const auto& test_disabled : test_cal_disabled) { const bool expected_notify_called = test_appt.expected_notify_called && test_vibes.expected_notify_called - && (test_muted.expected_notify_called.count(test_appt.appt.type) > 0) + && (test_disabled.expected_notify_called.count(test_appt.appt.type) > 0) && test_haptic.expected_notify_called; const bool expected_vibrate_called = test_appt.expected_vibrate_called && test_vibes.expected_vibrate_called - && (test_muted.expected_vibrate_called.count(test_appt.appt.type) > 0) + && (test_disabled.expected_vibrate_called.count(test_appt.appt.type) > 0) && test_haptic.expected_vibrate_called; - // set test case properties: blacklist - settings->muted_apps.set(test_muted.muted_apps); + // set test case properties: cal_notification_enabled + settings->cal_notification_enabled.set(test_disabled.cal_notification_enabled); // set test case properties: haptic mode settings->alarm_haptic.set(test_haptic.haptic_mode); diff --git a/tests/test-settings.cpp b/tests/test-settings.cpp index d18b58a..d0ee369 100644 --- a/tests/test-settings.cpp +++ b/tests/test-settings.cpp @@ -43,7 +43,7 @@ protected: std::shared_ptr m_live; std::shared_ptr m_settings; GSettings * m_gsettings; - GSettings * m_gsettings_cunh; + GSettings * m_gsettings_cal_notification; void SetUp() override { @@ -53,7 +53,7 @@ protected: if (ayatana_common_utils_is_lomiri()) { - m_gsettings_cunh = g_settings_new(SETTINGS_CUNH_SCHEMA_ID); + m_gsettings_cal_notification = g_settings_new_with_path(SETTINGS_NOTIFY_SCHEMA_ID, SETTINGS_NOTIFY_CALENDAR_PATH); } m_live.reset(new LiveSettings); @@ -62,7 +62,7 @@ protected: void TearDown() override { - g_clear_object(&m_gsettings_cunh); + g_clear_object(&m_gsettings_cal_notification); g_clear_object(&m_gsettings); m_settings.reset(); m_live.reset(); @@ -70,62 +70,62 @@ protected: super::TearDown(); } - void TestBoolProperty(core::Property& property, const gchar* key) + void TestBoolProperty(GSettings* gsettings, core::Property& property, const gchar* key) { - EXPECT_EQ(g_settings_get_boolean(m_gsettings, key), property.get()); - g_settings_set_boolean(m_gsettings, key, false); + EXPECT_EQ(g_settings_get_boolean(gsettings, key), property.get()); + g_settings_set_boolean(gsettings, key, false); EXPECT_FALSE(property.get()); - g_settings_set_boolean(m_gsettings, key, true); + g_settings_set_boolean(gsettings, key, true); EXPECT_TRUE(property.get()); property.set(false); - EXPECT_FALSE(g_settings_get_boolean(m_gsettings, key)); + EXPECT_FALSE(g_settings_get_boolean(gsettings, key)); property.set(true); - EXPECT_TRUE(g_settings_get_boolean(m_gsettings, key)); + EXPECT_TRUE(g_settings_get_boolean(gsettings, key)); } - void TestStringProperty(core::Property& property, const gchar* key) + void TestStringProperty(GSettings* gsettings, core::Property& property, const gchar* key) { gchar* tmp; std::string str; - tmp = g_settings_get_string(m_gsettings, key); + tmp = g_settings_get_string(gsettings, key); EXPECT_EQ(tmp, property.get()); g_clear_pointer(&tmp, g_free); str = "a"; - g_settings_set_string(m_gsettings, key, str.c_str()); + g_settings_set_string(gsettings, key, str.c_str()); EXPECT_EQ(str, property.get()); str = "b"; - g_settings_set_string(m_gsettings, key, str.c_str()); + g_settings_set_string(gsettings, key, str.c_str()); EXPECT_EQ(str, property.get()); str = "a"; property.set(str); - tmp = g_settings_get_string(m_gsettings, key); + tmp = g_settings_get_string(gsettings, key); EXPECT_EQ(str, tmp); g_clear_pointer(&tmp, g_free); str = "b"; property.set(str); - tmp = g_settings_get_string(m_gsettings, key); + tmp = g_settings_get_string(gsettings, key); EXPECT_EQ(str, tmp); g_clear_pointer(&tmp, g_free); } - void TestUIntProperty(core::Property& property, const gchar* key) + void TestUIntProperty(GSettings* gsettings, core::Property& property, const gchar* key) { - EXPECT_EQ(g_settings_get_uint(m_gsettings, key), property.get()); + EXPECT_EQ(g_settings_get_uint(gsettings, key), property.get()); unsigned int expected_values[] = { 1, 2, 3 }; // modify GSettings and confirm that the new value is propagated for(const auto& expected_value : expected_values) { - g_settings_set_uint(m_gsettings, key, expected_value); + g_settings_set_uint(gsettings, key, expected_value); EXPECT_EQ(expected_value, property.get()); - EXPECT_EQ(expected_value, g_settings_get_uint(m_gsettings, key)); + EXPECT_EQ(expected_value, g_settings_get_uint(gsettings, key)); } // modify the property and confirm that the new value is propagated @@ -133,7 +133,7 @@ protected: { property.set(expected_value); EXPECT_EQ(expected_value, property.get()); - EXPECT_EQ(expected_value, g_settings_get_uint(m_gsettings, key)); + EXPECT_EQ(expected_value, g_settings_get_uint(gsettings, key)); } } }; @@ -149,31 +149,31 @@ TEST_F(SettingsFixture, HelloWorld) TEST_F(SettingsFixture, BoolProperties) { - TestBoolProperty(m_settings->show_seconds, SETTINGS_SHOW_SECONDS_S); - TestBoolProperty(m_settings->show_calendar, SETTINGS_SHOW_CALENDAR_S); - TestBoolProperty(m_settings->show_date, SETTINGS_SHOW_DATE_S); - TestBoolProperty(m_settings->show_day, SETTINGS_SHOW_DAY_S); - TestBoolProperty(m_settings->show_detected_location, SETTINGS_SHOW_DETECTED_S); - TestBoolProperty(m_settings->show_events, SETTINGS_SHOW_EVENTS_S); - TestBoolProperty(m_settings->show_locations, SETTINGS_SHOW_LOCATIONS_S); - TestBoolProperty(m_settings->show_week_numbers, SETTINGS_SHOW_WEEK_NUMBERS_S); - TestBoolProperty(m_settings->show_year, SETTINGS_SHOW_YEAR_S); + TestBoolProperty(m_gsettings, m_settings->show_seconds, SETTINGS_SHOW_SECONDS_S); + TestBoolProperty(m_gsettings, m_settings->show_calendar, SETTINGS_SHOW_CALENDAR_S); + TestBoolProperty(m_gsettings, m_settings->show_date, SETTINGS_SHOW_DATE_S); + TestBoolProperty(m_gsettings, m_settings->show_day, SETTINGS_SHOW_DAY_S); + TestBoolProperty(m_gsettings, m_settings->show_detected_location, SETTINGS_SHOW_DETECTED_S); + TestBoolProperty(m_gsettings, m_settings->show_events, SETTINGS_SHOW_EVENTS_S); + TestBoolProperty(m_gsettings, m_settings->show_locations, SETTINGS_SHOW_LOCATIONS_S); + TestBoolProperty(m_gsettings, m_settings->show_week_numbers, SETTINGS_SHOW_WEEK_NUMBERS_S); + TestBoolProperty(m_gsettings, m_settings->show_year, SETTINGS_SHOW_YEAR_S); } TEST_F(SettingsFixture, UIntProperties) { - TestUIntProperty(m_settings->alarm_duration, SETTINGS_ALARM_DURATION_S); - TestUIntProperty(m_settings->alarm_volume, SETTINGS_ALARM_VOLUME_S); - TestUIntProperty(m_settings->snooze_duration, SETTINGS_SNOOZE_DURATION_S); + TestUIntProperty(m_gsettings, m_settings->alarm_duration, SETTINGS_ALARM_DURATION_S); + TestUIntProperty(m_gsettings, m_settings->alarm_volume, SETTINGS_ALARM_VOLUME_S); + TestUIntProperty(m_gsettings, m_settings->snooze_duration, SETTINGS_SNOOZE_DURATION_S); } TEST_F(SettingsFixture, StringProperties) { - TestStringProperty(m_settings->custom_time_format, SETTINGS_CUSTOM_TIME_FORMAT_S); - TestStringProperty(m_settings->timezone_name, SETTINGS_TIMEZONE_NAME_S); - TestStringProperty(m_settings->alarm_sound, SETTINGS_ALARM_SOUND_S); - TestStringProperty(m_settings->calendar_sound, SETTINGS_CALENDAR_SOUND_S); - TestStringProperty(m_settings->alarm_haptic, SETTINGS_ALARM_HAPTIC_S); + TestStringProperty(m_gsettings, m_settings->custom_time_format, SETTINGS_CUSTOM_TIME_FORMAT_S); + TestStringProperty(m_gsettings, m_settings->timezone_name, SETTINGS_TIMEZONE_NAME_S); + TestStringProperty(m_gsettings, m_settings->alarm_sound, SETTINGS_ALARM_SOUND_S); + TestStringProperty(m_gsettings, m_settings->calendar_sound, SETTINGS_CALENDAR_SOUND_S); + TestStringProperty(m_gsettings, m_settings->alarm_haptic, SETTINGS_ALARM_HAPTIC_S); } TEST_F(SettingsFixture, TimeFormatMode) @@ -237,36 +237,9 @@ TEST_F(SettingsFixture, Locations) TEST_F(SettingsFixture, MutedApps) { - const auto key = SETTINGS_CUNH_BLACKLIST_S; - - struct { - std::string pkgname; - std::string appname; - } apps[] = { - { "", "lomiri-system-settings" }, - { "com.lomiri.calendar", "calendar" }, - { "com.lomiri.developer.webapps.webapp-facebook", "webapp-facebook" }, - { "com.lomiri.reminders", "reminders" } - }; - std::set> apps_set; - for (const auto& app : apps) - apps_set.insert(std::make_pair(app.pkgname, app.appname)); - - // test that changing Settings is reflected in the schema - m_settings->muted_apps.set(apps_set); - auto v = g_settings_get_value(m_gsettings_cunh, key); - auto str = g_variant_print(v, true); - EXPECT_STREQ("[('', 'lomiri-system-settings'), ('com.lomiri.calendar', 'calendar'), ('com.lomiri.developer.webapps.webapp-facebook', 'webapp-facebook'), ('com.lomiri.reminders', 'reminders')]", str); - g_clear_pointer(&str, g_free); - - // test that clearing the schema clears the settings - g_settings_reset(m_gsettings_cunh, key); - EXPECT_EQ(0, m_settings->muted_apps.get().size()); - - // test thst setting the schema updates the settings - g_settings_set_value(m_gsettings_cunh, key, v); - EXPECT_EQ(apps_set, m_settings->muted_apps.get()); - - // cleanup - g_clear_pointer(&v, g_variant_unref); + TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_enabled, SETTINGS_NOTIFY_ENABLED_KEY); + TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_sounds, SETTINGS_NOTIFY_SOUNDS_KEY); + TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_vibrations, SETTINGS_NOTIFY_VIBRATIONS_KEY); + TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_bubbles, SETTINGS_NOTIFY_BUBBLES_KEY); + TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_list, SETTINGS_NOTIFY_LIST_KEY); } -- cgit v1.2.3 From f3f17677a2718fb47cda50cd6c64c9650448ea2e Mon Sep 17 00:00:00 2001 From: Arthur Mello Date: Thu, 23 Jun 2016 16:04:50 -0300 Subject: Set calendar notification settings to true in case GSettings schema is not available Make sure calendar notification settings are correct during tests --- src/settings-live.cpp | 30 +++++++++++++++++++++++++----- tests/test-notification.cpp | 4 ++++ tests/test-sound.cpp | 12 ++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/src/settings-live.cpp b/src/settings-live.cpp index f908c05..39d8e18 100644 --- a/src/settings-live.cpp +++ b/src/settings-live.cpp @@ -299,27 +299,47 @@ void LiveSettings::update_snooze_duration() void LiveSettings::update_cal_notification_enabled() { - cal_notification_enabled.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_ENABLED_KEY)); + if (m_settings_cal_notification) { + cal_notification_enabled.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_ENABLED_KEY)); + } else { + cal_notification_enabled.set(true); + } } void LiveSettings::update_cal_notification_sounds() { - cal_notification_sounds.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_SOUNDS_KEY)); + if (m_settings_cal_notification) { + cal_notification_sounds.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_SOUNDS_KEY)); + } else { + cal_notification_sounds.set(true); + } } void LiveSettings::update_cal_notification_vibrations() { - cal_notification_vibrations.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_VIBRATIONS_KEY)); + if (m_settings_cal_notification) { + cal_notification_vibrations.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_VIBRATIONS_KEY)); + } else { + cal_notification_vibrations.set(true); + } } void LiveSettings::update_cal_notification_bubbles() { - cal_notification_bubbles.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_BUBBLES_KEY)); + if (m_settings_cal_notification) { + cal_notification_bubbles.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_BUBBLES_KEY)); + } else { + cal_notification_bubbles.set(true); + } } void LiveSettings::update_cal_notification_list() { - cal_notification_list.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_LIST_KEY)); + if (m_settings_cal_notification) { + cal_notification_list.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_LIST_KEY)); + } else { + cal_notification_list.set(true); + } } /*** diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index b84c6f8..58c0760 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -119,6 +119,10 @@ TEST_F(NotificationFixture,Notification) // set test case properties: cal_notification_enabled settings->cal_notification_enabled.set(test_disabled.cal_notification_enabled); + settings->cal_notification_sounds.set(test_disabled.cal_notification_enabled); + settings->cal_notification_vibrations.set(test_disabled.cal_notification_enabled); + settings->cal_notification_bubbles.set(test_disabled.cal_notification_enabled); + settings->cal_notification_list.set(test_disabled.cal_notification_enabled); // set test case properties: haptic mode settings->alarm_haptic.set(test_haptic.haptic_mode); diff --git a/tests/test-sound.cpp b/tests/test-sound.cpp index 9dbd212..f808db6 100644 --- a/tests/test-sound.cpp +++ b/tests/test-sound.cpp @@ -59,6 +59,12 @@ TEST_F(NotificationFixture, InteractiveDuration) auto sb = std::make_shared(); auto snap = create_snap(ne, sb, settings); + settings->cal_notification_enabled.set(true); + settings->cal_notification_sounds.set(true); + settings->cal_notification_vibrations.set(true); + settings->cal_notification_bubbles.set(true); + settings->cal_notification_list.set(true); + make_interactive(); // call the Snap Decision @@ -150,6 +156,12 @@ TEST_F(NotificationFixture,DefaultSounds) auto sb = std::make_shared(); auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);}; + settings->cal_notification_enabled.set(true); + settings->cal_notification_sounds.set(true); + settings->cal_notification_vibrations.set(true); + settings->cal_notification_bubbles.set(true); + settings->cal_notification_list.set(true); + const struct { Appointment appointment; std::string expected_role; -- cgit v1.2.3 From 686579f67c368512ac36267dd5bd13eff2a0abb5 Mon Sep 17 00:00:00 2001 From: Arthur Mello Date: Fri, 24 Jun 2016 09:26:06 -0300 Subject: Make sure that calendar settings do not affect alarm notifications --- src/snap.cpp | 6 +++--- tests/test-notification.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'tests/test-notification.cpp') diff --git a/src/snap.cpp b/src/snap.cpp index 1e71e7b..273f125 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -97,8 +97,8 @@ public: // force the system to stay awake std::shared_ptr awake; - if (calendar_bubbles_enabled()) { - awake = std::make_shared(m_engine->app_name()); + if (appointment.is_ubuntu_alarm() || calendar_bubbles_enabled()) { + awake = std::make_shared(m_engine->app_name()); } // calendar events are muted in silent mode; alarm clocks never are @@ -114,7 +114,7 @@ public: // create the haptic feedback... std::shared_ptr haptic; - if (should_vibrate() && calendar_vibrations_enabled()) { + if (should_vibrate() && (appointment.is_ubuntu_alarm() || calendar_vibrations_enabled())) { const auto haptic_mode = m_settings->alarm_haptic.get(); if (haptic_mode == "pulse") haptic = std::make_shared(ain::Haptic::MODE_PULSE, appointment.is_ubuntu_alarm()); diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index 58c0760..0db6ab9 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -230,6 +230,12 @@ TEST_F(NotificationFixture,Response) }; + settings->cal_notification_enabled.set(true); + settings->cal_notification_sounds.set(true); + settings->cal_notification_vibrations.set(true); + settings->cal_notification_bubbles.set(true); + settings->cal_notification_list.set(true); + // walk through the tests for (const auto& test : tests) { -- cgit v1.2.3 From 18ca4edc212f20c55d5859065dfc0579b3bfd8a0 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 4 Nov 2016 10:58:39 -0500 Subject: break test-notification into two separate test units --- tests/CMakeLists.txt | 1 + tests/libdbusmock-fixture.h | 9 +-- tests/test-notification-response.cpp | 144 +++++++++++++++++++++++++++++++++++ tests/test-notification.cpp | 100 ------------------------ 4 files changed, 146 insertions(+), 108 deletions(-) create mode 100644 tests/test-notification-response.cpp (limited to 'tests/test-notification.cpp') diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b7f60bb..3bc6777 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -50,6 +50,7 @@ add_test_by_name(test-datetime) if(HAVE_UT_ACCTSERVICE_SYSTEMSOUND_SETTINGS) add_test_by_name(test-sound) add_test_by_name(test-notification) +add_test_by_name(test-notification-response) endif() add_test_by_name(test-actions) add_test_by_name(test-alarm-queue) diff --git a/tests/libdbusmock-fixture.h b/tests/libdbusmock-fixture.h index ef42fbf..7301042 100644 --- a/tests/libdbusmock-fixture.h +++ b/tests/libdbusmock-fixture.h @@ -75,14 +75,7 @@ protected: // wait a little while for the scaffolding to shut down, // but don't block on it forever... - unsigned int cleartry = 0; - while (((system_bus != nullptr) || (session_bus != nullptr)) && (cleartry < 50)) - { - g_usleep(100000); - while (g_main_pending(nullptr)) - g_main_iteration(nullptr, true); - cleartry++; - } + wait_for([this](){return system_bus==nullptr && session_bus==nullptr;}, 5000); super::TearDown(); } diff --git a/tests/test-notification-response.cpp b/tests/test-notification-response.cpp new file mode 100644 index 0000000..fd40ed8 --- /dev/null +++ b/tests/test-notification-response.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2014-2016 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +#include +#include +#include + +#include "notification-fixture.h" + +/*** +**** +***/ + +using namespace ayatana::indicator::datetime; + +namespace +{ + static constexpr char const * APP_NAME {"indicator-datetime-service"}; + + gboolean quit_idle (gpointer gloop) + { + g_main_loop_quit(static_cast(gloop)); + return G_SOURCE_REMOVE; + } +} + +/*** +**** +***/ + +TEST_F(NotificationFixture,Response) +{ + // create the world + make_interactive(); + auto ne = std::make_shared(APP_NAME); + auto sb = std::make_shared(); + auto settings = std::make_shared(); + int next_notification_id {FIRST_NOTIFY_ID}; + + // set a response callback that remembers what response we got + bool on_response_called {}; + Snap::Response response {}; + auto on_response = [this, &on_response_called, &response] + (const Appointment&, const Alarm&, const Snap::Response& r){ + on_response_called = true; + response = r; + g_idle_add(quit_idle, loop); + }; + + // our tests! + const struct { + Appointment appt; + std::vector expected_actions; + std::string action; + Snap::Response expected_response; + } tests[] = { + { appt, {"show-app"}, "show-app", Snap::Response::ShowApp }, + { ualarm, {"none", "snooze"}, "snooze", Snap::Response::Snooze }, + { ualarm, {"none", "snooze"}, "none", Snap::Response::None } + }; + + + settings->cal_notification_enabled.set(true); + settings->cal_notification_sounds.set(true); + settings->cal_notification_vibrations.set(true); + settings->cal_notification_bubbles.set(true); + settings->cal_notification_list.set(true); + + // walk through the tests + for (const auto& test : tests) + { + // wait for previous iterations' bus noise to finish and reset the counters + GError* error {}; + wait_msec(500); + dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error); + g_assert_no_error(error); + on_response_called = false; + + // create a snap decision + auto snap = create_snap(ne, sb, settings); + (*snap)(test.appt, test.appt.alarms.front(), on_response); + + // wait for the notification to show up + EXPECT_METHOD_CALLED_EVENTUALLY(notify_mock, notify_obj, METHOD_NOTIFY); + + // test that Notify was called the right number of times + static constexpr int expected_num_notify_calls {1}; + guint num_notify_calls {}; + const auto notify_calls = dbus_test_dbus_mock_object_get_method_calls( + notify_mock, + notify_obj, + METHOD_NOTIFY, + &num_notify_calls, + &error); + g_assert_no_error(error); + EXPECT_EQ(expected_num_notify_calls, num_notify_calls); + + // test that Notify was called with the correct list of actions + if (num_notify_calls > 0) { + std::vector actions; + const gchar** as {nullptr}; + g_variant_get_child(notify_calls[0].params, 5, "^a&s", &as); + for (int i=0; as && as[i]; i+=2) // actions are in pairs of (name, i18n), skip the i18n + actions.push_back(as[i]); + EXPECT_EQ(test.expected_actions, actions); + } + + // make the notification mock tell the world that the user invoked an action + const auto notification_id = next_notification_id++; + idle_add([this, notification_id, test](){ + GError* err {}; + dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "ActionInvoked", + G_VARIANT_TYPE("(us)"), + g_variant_new("(us)", guint(notification_id), test.action.c_str()), + &err); + dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "NotificationClosed", + G_VARIANT_TYPE("(uu)"), + g_variant_new("(uu)", guint(notification_id), guint(NOTIFICATION_CLOSED_DISMISSED)), + &err); + g_assert_no_error(err); + return G_SOURCE_REMOVE; + }); + + // confirm that the response callback got the right response + EXPECT_TRUE(wait_for([&on_response_called](){return on_response_called;})); + EXPECT_EQ(int(test.expected_response), int(response)) << "notification_id " << notification_id; + } +} diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp index 0db6ab9..83a021f 100644 --- a/tests/test-notification.cpp +++ b/tests/test-notification.cpp @@ -196,103 +196,3 @@ TEST_F(NotificationFixture,Notification) } } } - - -TEST_F(NotificationFixture,Response) -{ - // create the world - make_interactive(); - auto ne = std::make_shared(APP_NAME); - auto sb = std::make_shared(); - auto settings = std::make_shared(); - int next_notification_id {FIRST_NOTIFY_ID}; - - // set a response callback that remembers what response we got - bool on_response_called {}; - Snap::Response response {}; - auto on_response = [this, &on_response_called, &response] - (const Appointment&, const Alarm&, const Snap::Response& r){ - on_response_called = true; - response = r; - g_idle_add(quit_idle, loop); - }; - - // our tests! - const struct { - Appointment appt; - std::vector expected_actions; - std::string action; - Snap::Response expected_response; - } tests[] = { - { appt, {"show-app"}, "show-app", Snap::Response::ShowApp }, - { ualarm, {"none", "snooze"}, "snooze", Snap::Response::Snooze }, - { ualarm, {"none", "snooze"}, "none", Snap::Response::None } - }; - - - settings->cal_notification_enabled.set(true); - settings->cal_notification_sounds.set(true); - settings->cal_notification_vibrations.set(true); - settings->cal_notification_bubbles.set(true); - settings->cal_notification_list.set(true); - - // walk through the tests - for (const auto& test : tests) - { - // wait for previous iterations' bus noise to finish and reset the counters - GError* error {}; - wait_msec(500); - dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error); - g_assert_no_error(error); - on_response_called = false; - - // create a snap decision - auto snap = create_snap(ne, sb, settings); - (*snap)(test.appt, test.appt.alarms.front(), on_response); - - // wait for the notification to show up - EXPECT_METHOD_CALLED_EVENTUALLY(notify_mock, notify_obj, METHOD_NOTIFY); - - // test that Notify was called the right number of times - static constexpr int expected_num_notify_calls {1}; - guint num_notify_calls {}; - const auto notify_calls = dbus_test_dbus_mock_object_get_method_calls( - notify_mock, - notify_obj, - METHOD_NOTIFY, - &num_notify_calls, - &error); - g_assert_no_error(error); - EXPECT_EQ(expected_num_notify_calls, num_notify_calls); - - // test that Notify was called with the correct list of actions - if (num_notify_calls > 0) { - std::vector actions; - const gchar** as {nullptr}; - g_variant_get_child(notify_calls[0].params, 5, "^a&s", &as); - for (int i=0; as && as[i]; i+=2) // actions are in pairs of (name, i18n), skip the i18n - actions.push_back(as[i]); - EXPECT_EQ(test.expected_actions, actions); - } - - // make the notification mock tell the world that the user invoked an action - const auto notification_id = next_notification_id++; - idle_add([this, notification_id, test](){ - GError* err {}; - dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "ActionInvoked", - G_VARIANT_TYPE("(us)"), - g_variant_new("(us)", guint(notification_id), test.action.c_str()), - &err); - dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "NotificationClosed", - G_VARIANT_TYPE("(uu)"), - g_variant_new("(uu)", guint(notification_id), guint(NOTIFICATION_CLOSED_DISMISSED)), - &err); - g_assert_no_error(err); - return G_SOURCE_REMOVE; - }); - - // confirm that the response callback got the right response - EXPECT_TRUE(wait_for([&on_response_called](){return on_response_called;})); - EXPECT_EQ(int(test.expected_response), int(response)) << "notification_id " << notification_id; - } -} -- cgit v1.2.3