diff options
-rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/libdbusmock-fixture.h | 9 | ||||
-rw-r--r-- | tests/test-notification-response.cpp | 144 | ||||
-rw-r--r-- | tests/test-notification.cpp | 100 |
4 files changed, 146 insertions, 108 deletions
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 14eab8f..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()) - g_main_iteration(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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Charles Kerr <charles.kerr@canonical.com> + */ + +#include <datetime/appointment.h> +#include <datetime/settings.h> +#include <datetime/snap.h> + +#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<GMainLoop*>(gloop)); + return G_SOURCE_REMOVE; + } +} + +/*** +**** +***/ + +TEST_F(NotificationFixture,Response) +{ + // create the world + make_interactive(); + auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME); + auto sb = std::make_shared<ayatana::indicator::notifications::DefaultSoundBuilder>(); + auto settings = std::make_shared<Settings>(); + 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<std::string> 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<std::string> 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<ayatana::indicator::notifications::Engine>(APP_NAME); - auto sb = std::make_shared<ayatana::indicator::notifications::DefaultSoundBuilder>(); - auto settings = std::make_shared<Settings>(); - 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<std::string> 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<std::string> 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; - } -} |