aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/glib-fixture.h24
-rw-r--r--tests/test-notification.cpp94
2 files changed, 118 insertions, 0 deletions
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 <chrono>
#include <functional> // std::function
#include <map>
#include <memory> // std::shared_ptr
@@ -198,6 +199,29 @@ class GlibFixture : public ::testing::Test
}
GMainLoop * loop;
+
+ using source_func = std::function<gboolean()>;
+
+ void idle_add(source_func&& func)
+ {
+ g_idle_add_full(
+ G_PRIORITY_DEFAULT_IDLE,
+ [](gpointer gf){return (*static_cast<source_func*>(gf))();},
+ new std::function<gboolean()>(func),
+ [](gpointer gf){delete static_cast<source_func*>(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<source_func*>(gf))();},
+ new std::function<gboolean()>(func),
+ [](gpointer gf){delete static_cast<source_func*>(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<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 }
+ };
+
+
+ // 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;
+ }
+}