From 8ac8ca2cd9375cc3d9cdf7e50b9f07dad6c4ef8e Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 09:00:05 -0600 Subject: One test directory to rule them all --- tests/Makefile.am | 77 ++++ tests/applications/test.desktop | 2 + tests/indicator-messages-service-activate.build.sh | 3 + tests/indicator-messages-service-activate.c | 55 +++ tests/manual | 80 ++++ tests/test-client.py | 80 ++++ tests/test-gactionmuxer.cpp | 407 +++++++++++++++++++++ 7 files changed, 704 insertions(+) create mode 100644 tests/Makefile.am create mode 100644 tests/applications/test.desktop create mode 100644 tests/indicator-messages-service-activate.build.sh create mode 100644 tests/indicator-messages-service-activate.c create mode 100644 tests/manual create mode 100755 tests/test-client.py create mode 100644 tests/test-gactionmuxer.cpp (limited to 'tests') diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..b679615 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,77 @@ + +check_LIBRARIES = libgtest.a +check_PROGRAMS = test-gactionmuxer + +TESTS = $(check_PROGRAMS) + +AM_CPPFLAGS = $(GTEST_CPPFLAGS) \ + -I${top_srcdir}/src + +nodist_libgtest_a_SOURCES = \ + $(GTEST_SOURCE)/src/gtest-all.cc \ + $(GTEST_SOURCE)/src/gtest_main.cc +libgtest_a_CPPFLAGS = \ + $(GTEST_CPPFLAGS) -w \ + $(AM_CPPFLAGS) +libgtest_a_CXXFLAGS = \ + $(AM_CXXFLAGS) + + +test_gactionmuxer_SOURCES = \ + test-gactionmuxer.cpp + +test_gactionmuxer_CPPFLAGS = \ + $(APPLET_CFLAGS) \ + $(AM_CPPFLAGS) + +test_gactionmuxer_LDADD = \ + $(APPLET_LIBS) \ + libindicator-messages-service.la \ + libgtest.a + + +###################################### +# Lib containing code under test +###################################### + +noinst_LTLIBRARIES = \ + libindicator-messages-service.la + +libindicator_messages_service_la_SOURCES = \ + $(top_builddir)/common/indicator-messages-service.c \ + $(top_builddir)/common/indicator-messages-service.h \ + $(top_srcdir)/src/gactionmuxer.c \ + $(top_srcdir)/src/gactionmuxer.h + $(top_srcdir)/src/dbus-data.h + +libindicator_messages_service_ladir = \ + $(includedir)/libindicator-messages-service/ + +libindicator_messages_service_la_CFLAGS = \ + $(APPLET_CFLAGS) \ + $(COVERAGE_CFLAGS) \ + -I$(top_builddir)/src \ + -I$(top_builddir)/common \ + -Wall \ + -Wl,-Bsymbolic-functions \ + -Wl,-z,defs \ + -Wl,--as-needed \ + -Werror -Wno-error=deprecated-declarations \ + -DG_LOG_DOMAIN=\"Indicator-Messages\" + +libindicator_messages_service_la_LIBADD = \ + $(APPLET_LIBS) + +libindicator_messages_service_la_LDFLAGS = \ + $(COVERAGE_LDFLAGS) + +###################################### +# Test client with dbusmock +###################################### + +TESTS_ENVIRONMENT = \ + export LD_LIBRARY_PATH=$(top_builddir)/libmessaging-menu/.libs; \ + export GI_TYPELIB_PATH=$(top_builddir)/libmessaging-menu; \ + export XDG_DATA_DIRS=$(abs_srcdir); + +TESTS += test-client.py diff --git a/tests/applications/test.desktop b/tests/applications/test.desktop new file mode 100644 index 0000000..c2332b9 --- /dev/null +++ b/tests/applications/test.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Type=Application diff --git a/tests/indicator-messages-service-activate.build.sh b/tests/indicator-messages-service-activate.build.sh new file mode 100644 index 0000000..87a0316 --- /dev/null +++ b/tests/indicator-messages-service-activate.build.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +gcc -o indicator-messages-service-activate indicator-messages-service-activate.c `pkg-config --cflags --libs dbus-1 dbus-glib-1` diff --git a/tests/indicator-messages-service-activate.c b/tests/indicator-messages-service-activate.c new file mode 100644 index 0000000..f5a26b0 --- /dev/null +++ b/tests/indicator-messages-service-activate.c @@ -0,0 +1,55 @@ +/* +An indicator to show information that is in messaging applications +that the user is using. + +Copyright 2009 Canonical Ltd. + +Authors: + Ted Gould + +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 "../src/dbus-data.h" + +int +main (int argc, char ** argv) +{ +#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34 + g_type_init(); +#endif + + guint returnval = 0; + GError * error = NULL; + + DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL); + DBusGProxy * proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); + + g_debug("Activating service: %s", INDICATOR_MESSAGES_DBUS_NAME); + if (!org_freedesktop_DBus_start_service_by_name (proxy, INDICATOR_MESSAGES_DBUS_NAME, 0, &returnval, &error)) { + g_error("Unable to send message to DBus to start service: %s", error != NULL ? error->message : "(NULL error)" ); + g_error_free(error); + return 1; + } + + if (returnval != DBUS_START_REPLY_SUCCESS && returnval != DBUS_START_REPLY_ALREADY_RUNNING) { + g_error("Return value isn't indicative of success: %d", returnval); + return 1; + } + + return 0; +} + diff --git a/tests/manual b/tests/manual new file mode 100644 index 0000000..d638875 --- /dev/null +++ b/tests/manual @@ -0,0 +1,80 @@ + +Test-case indicator-messages/unity7-items-check +
+
Log in to a Unity 7 user session
+
Go to the panel and click on the Messages indicator
+
Ensure there are items in the menu
+
+ +Test-case indicator-messages/unity7-greeter-items-check +
+
Start a system and wait for the greeter or logout of the current user session
+
Go to the panel and click on the Messages indicator
+
Ensure there are items in the menu
+
+ +Test-case indicator-messages/unity8-items-check +
+
Login to a user session running Unity 8
+
Pull down the top panel until it sticks open
+
Navigate through the tabs until "Notifications" is shown
+
Incoming is at the top of the menu
+
The menu is populated with items
+
+ +Test-case indicator-messages/unity8-phone-symbolic-icon +
+
NOTE: Requires Unity8 and Telephony hardware
+
Login to a user session running Unity 8
+
Send an SMS to the device
+
Icon on the panel should change color signifying a new message
+
Verify the application icon in the menu item is monochromatic
+
On the right side of the item the application icon should have no color
+
+ +Test-case indicator-messages/unity8-embedded-greeter +
+
NOTE: Only works with embedded greeter, split greeter will require modifications to this test
+
NOTE: Only works on a device that can receive SMS messages
+
Ensure System Settings is set to "Show Messages on Greeter"
+
Send an SMS to the device
+
The notification icon should change color
+
There should be an entry in the messaging menu with the SMS message
+
The item should include the sender and the start of the message
+
Go to the greeter. This can be done by hitting the lock button twice.
+
Ensure the messaging menu has the message
+
The notification icon should have color
+
There should be an entry in the messaging menu with the SMS message
+
The item should include the sender and the start of the message
+
Clear the message in the greeter
+
The message should no longer be in the messaging menu
+
Disable System Settings value "Show Messages on Greeter"
+
Send an SMS to the device
+
The notification icon should change color
+
There should be an entry in the messaging menu with the SMS message
+
The item should include the sender and the start of the message
+
Go to the greeter. This can be done by hitting the lock button twice.
+
Ensure the messaging menu has the message, but it does not include the start of the message
+
The notification icon should have color
+
There should be an entry in the messaging menu with the SMS message
+
The item should include the sender but NOT the start of the message
+
Clear the message in the greeter
+
The message should no longer be in the messaging menu
+
+ +Test-case indicator-messages/push-message-twitter +
+
From a shell prompt send a simultated Twitter push notification
+
gdbus call --session --dest com.ubuntu.Postal --object-path /com/ubuntu/Postal/com_2eubuntu_2edeveloper_2ewebapps_2ewebapp_2dtwitter --method com.ubuntu.Postal.Post com.ubuntu.developer.webapps.webapp-twitter_webapp-twitter '"{\"message\": \"foobar\", \"notification\":{\"card\": {\"summary\": \"yes\", \"body\": \"hello\", \"popup\": true, \"persist\": true}}}"'
+
The messaging envelope on the panel should change to highlight a message
+
Open the messaging menu
+
The menu should contain an entry with the Twitter icon for the application
+
The title of the message should be 'yes'
+
The body of the message should be 'hello'
+
At the bottom of them menu there should be a 'Clear All' menu item
+
Clear the message using the 'Clear All' command
+
The Twitter message should disappear
+
The 'Clear All' item should disappear
+
The icon in the panel should return to its original state
+
+ diff --git a/tests/test-client.py b/tests/test-client.py new file mode 100755 index 0000000..0dbf868 --- /dev/null +++ b/tests/test-client.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +import unittest +import dbus +from dbus.mainloop.glib import DBusGMainLoop +import dbusmock +import subprocess +from gi.repository import GLib, Gio, MessagingMenu + +DBusGMainLoop(set_as_default=True) + +class MessagingMenuTest(dbusmock.DBusTestCase): + @classmethod + def setUpClass(klass): + klass.start_session_bus() + klass.bus = klass.get_dbus(False) + + def setUp(self): + name = 'com.canonical.indicator.messages' + obj_path = '/com/canonical/indicator/messages/service' + iface = 'com.canonical.indicator.messages.service' + + self.messaging_service = self.spawn_server(name, obj_path, iface, stdout=subprocess.PIPE) + self.mock = dbus.Interface(self.bus.get_object(name, obj_path), dbusmock.MOCK_IFACE) + self.mock.AddMethod('', 'RegisterApplication', 'so', '', '') + self.mock.AddMethod('', 'UnregisterApplication', 's', '', '') + self.mock.AddMethod('', 'ApplicationStoppedRunning', 's', '', '') + self.mock.AddMethod('', 'SetStatus', 'ss', '', '') + + self.loop = GLib.MainLoop() + + def tearDown(self): + self.messaging_service.terminate() + self.messaging_service.wait() + + def assertArgumentsEqual(self, args, *expected_args): + self.assertEqual(len(args), len(expected_args)) + for i in range(len(args)): + if expected_args[i]: + self.assertEqual(args[i], expected_args[i]) + + def assertMethodCalled(self, name, *expected_args): + # set a flag on timeout, assertions don't get bubbled up through c functions + self.timed_out = False + def timeout(): self.timed_out = True + timeout_id = GLib.timeout_add_seconds(10, timeout) + while 1: + calls = self.mock.GetMethodCalls(name) + if len(calls) > 0: + GLib.source_remove(timeout_id) + self.assertArgumentsEqual(calls[0][1], *expected_args) + break + GLib.MainContext.default().iteration(True) + if self.timed_out: + raise self.failureException('method %s was not called after 10 seconds' % name) + + def test_registration(self): + mmapp = MessagingMenu.App.new('test.desktop') + mmapp.register() + self.assertMethodCalled('RegisterApplication', 'test.desktop', None) + + mmapp.unregister() + self.assertMethodCalled('UnregisterApplication', 'test.desktop') + + # ApplicationStoppedRunning is called when the last ref on mmapp is dropped + # Since mmapp is the only thing holding on to a GDBusConnection, the + # connection might get freed before it sends the StoppedRunning + # message. Flush the connection to make sure it is sent. + bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) + bus.flush_sync(None) + del mmapp + self.assertMethodCalled('ApplicationStoppedRunning', 'test.desktop') + + def test_status(self): + mmapp = MessagingMenu.App.new('test.desktop') + mmapp.register() + mmapp.set_status(MessagingMenu.Status.AWAY) + self.assertMethodCalled('SetStatus', 'test.desktop', 'away') + +unittest.main(testRunner=unittest.TextTestRunner()) diff --git a/tests/test-gactionmuxer.cpp b/tests/test-gactionmuxer.cpp new file mode 100644 index 0000000..5c98c90 --- /dev/null +++ b/tests/test-gactionmuxer.cpp @@ -0,0 +1,407 @@ +/* +An indicator to show information that is in messaging applications +that the user is using. + +Copyright 2012 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 . +*/ + +#include +#include +#include + +extern "C" { +#include "gactionmuxer.h" +} + +static gboolean +strv_contains (gchar **str_array, + const gchar *str) +{ + gchar **it; + + for (it = str_array; *it; it++) { + if (!g_strcmp0 (*it, str)) + return TRUE; + } + + return FALSE; +} + +TEST(GActionMuxerTest, Sanity) { + GActionMuxer *muxer; + +#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34 + g_type_init (); +#endif + + g_test_expect_message ("Indicator-Messages", G_LOG_LEVEL_CRITICAL, "*G_IS_ACTION_MUXER*"); + g_action_muxer_insert (NULL, NULL, NULL); + g_test_assert_expected_messages (); + + g_test_expect_message ("Indicator-Messages", G_LOG_LEVEL_CRITICAL, "*G_IS_ACTION_MUXER*"); + g_action_muxer_remove (NULL, NULL); + g_test_assert_expected_messages (); + + muxer = g_action_muxer_new (); + + g_action_muxer_insert (muxer, NULL, NULL); + g_action_muxer_remove (muxer, NULL); + + g_test_expect_message ("Indicator-Messages", G_LOG_LEVEL_CRITICAL, "*NULL*"); + EXPECT_FALSE (g_action_group_has_action (G_ACTION_GROUP (muxer), NULL)); + g_test_assert_expected_messages (); + + g_test_expect_message ("Indicator-Messages", G_LOG_LEVEL_CRITICAL, "*NULL*"); + EXPECT_FALSE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), NULL)); + g_test_assert_expected_messages (); + + g_test_expect_message ("Indicator-Messages", G_LOG_LEVEL_CRITICAL, "*NULL*"); + EXPECT_FALSE (g_action_group_query_action (G_ACTION_GROUP (muxer), NULL, NULL, NULL, NULL, NULL, NULL)); + g_test_assert_expected_messages (); + + g_test_expect_message ("GLib-GIO", G_LOG_LEVEL_CRITICAL, "*NULL*"); + g_action_group_activate_action (G_ACTION_GROUP (muxer), NULL, NULL); + g_test_assert_expected_messages (); + + g_object_unref (muxer); +} + +TEST(GActionMuxerTest, Empty) { + GActionMuxer *muxer; + gchar **actions; + +#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34 + g_type_init (); +#endif + + muxer = g_action_muxer_new (); + + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (0, g_strv_length (actions)); + + g_strfreev (actions); + g_object_unref (muxer); +} + +TEST(GActionMuxerTest, AddAndRemove) { + const GActionEntry entries1[] = { { "one" }, { "two" }, { "three" } }; + const GActionEntry entries2[] = { { "gb" }, { "es" }, { "fr" } }; + const GActionEntry entries3[] = { { "foo" }, { "bar" } }; + GSimpleActionGroup *group1; + GSimpleActionGroup *group2; + GSimpleActionGroup *group3; + GActionMuxer *muxer; + gchar **actions; + +#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34 + g_type_init (); +#endif + + group1 = g_simple_action_group_new (); + g_action_map_add_action_entries (G_ACTION_MAP (group1), + entries1, + G_N_ELEMENTS (entries1), + NULL); + + group2 = g_simple_action_group_new (); + g_action_map_add_action_entries (G_ACTION_MAP (group2), + entries2, + G_N_ELEMENTS (entries2), + NULL); + + group3 = g_simple_action_group_new (); + g_action_map_add_action_entries (G_ACTION_MAP (group3), + entries3, + G_N_ELEMENTS (entries3), + NULL); + + muxer = g_action_muxer_new (); + g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group1)); + g_action_muxer_insert (muxer, "second", G_ACTION_GROUP (group2)); + g_action_muxer_insert (muxer, NULL, G_ACTION_GROUP (group3)); + + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_TRUE (g_action_group_has_action (G_ACTION_GROUP (muxer), "first.one")); + EXPECT_FALSE (g_action_group_has_action (G_ACTION_GROUP (muxer), "one")); + EXPECT_EQ (8, g_strv_length (actions)); + EXPECT_TRUE (strv_contains (actions, "first.one")); + EXPECT_TRUE (strv_contains (actions, "first.two")); + EXPECT_TRUE (strv_contains (actions, "first.three")); + EXPECT_TRUE (strv_contains (actions, "second.gb")); + EXPECT_TRUE (strv_contains (actions, "second.es")); + EXPECT_TRUE (strv_contains (actions, "second.fr")); + EXPECT_TRUE (strv_contains (actions, "foo")); + EXPECT_TRUE (strv_contains (actions, "bar")); + g_strfreev (actions); + + g_action_muxer_remove (muxer, NULL); + EXPECT_FALSE (g_action_group_has_action (G_ACTION_GROUP (muxer), "foo")); + EXPECT_TRUE (g_action_group_has_action (G_ACTION_GROUP (muxer), "first.one")); + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (6, g_strv_length (actions)); + EXPECT_FALSE (strv_contains (actions, "foo")); + EXPECT_TRUE (strv_contains (actions, "first.one")); + g_strfreev (actions); + + g_action_muxer_remove (muxer, "first"); + EXPECT_FALSE (g_action_group_has_action (G_ACTION_GROUP (muxer), "first.two")); + EXPECT_TRUE (g_action_group_has_action (G_ACTION_GROUP (muxer), "second.es")); + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (3, g_strv_length (actions)); + EXPECT_FALSE (strv_contains (actions, "first.two")); + EXPECT_TRUE (strv_contains (actions, "second.es")); + g_strfreev (actions); + + g_action_muxer_insert (muxer, "second", G_ACTION_GROUP (group2)); + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (3, g_strv_length (actions)); + g_strfreev (actions); + + g_action_muxer_insert (muxer, NULL, G_ACTION_GROUP (group3)); + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (5, g_strv_length (actions)); + g_strfreev (actions); + + g_object_unref (muxer); + g_object_unref (group1); + g_object_unref (group2); + g_object_unref (group3); +} + +static gboolean +g_variant_equal0 (gconstpointer one, + gconstpointer two) +{ + if (one == NULL) + return two == NULL; + else + return g_variant_equal (one, two); +} + +TEST(GActionMuxerTest, ActionAttributes) { + GSimpleActionGroup *group; + GSimpleAction *action; + GActionMuxer *muxer; + gboolean enabled[2]; + const GVariantType *param_type[2]; + const GVariantType *state_type[2]; + GVariant *state_hint[2]; + GVariant *state[2]; + +#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34 + g_type_init (); +#endif + + group = g_simple_action_group_new (); + action = g_simple_action_new ("one", G_VARIANT_TYPE_STRING); + g_action_map_add_action (G_ACTION_MAP(group), G_ACTION (action)); + + muxer = g_action_muxer_new (); + g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group)); + + /* test two of the convenience functions */ + EXPECT_TRUE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), "first.one")); + g_simple_action_set_enabled (action, FALSE); + EXPECT_FALSE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), "first.one")); + + EXPECT_STREQ ((gchar *) g_action_group_get_action_parameter_type (G_ACTION_GROUP (muxer), "first.one"), + (gchar *) G_VARIANT_TYPE_STRING); + + /* query_action */ + g_action_group_query_action (G_ACTION_GROUP (group), "one", + &enabled[0], ¶m_type[0], &state_type[0], &state_hint[0], &state[0]); + g_action_group_query_action (G_ACTION_GROUP (muxer), "first.one", + &enabled[1], ¶m_type[1], &state_type[1], &state_hint[1], &state[1]); + EXPECT_EQ (enabled[0], enabled[1]); + EXPECT_STREQ ((gchar *) param_type[0], (gchar *) param_type[1]); + EXPECT_STREQ ((gchar *) state_type[0], (gchar *) state_type[1]); + EXPECT_TRUE (g_variant_equal0 ((gconstpointer) state_hint[0], (gconstpointer) state_hint[1])); + EXPECT_TRUE (g_variant_equal0 ((gconstpointer) state[0], (gconstpointer) state[1])); + + g_object_unref (action); + g_object_unref (group); + g_object_unref (muxer); +} + +typedef struct { + gboolean signal_ran; + const gchar *name; +} TestSignalClosure; + +static void +action_added (GActionGroup *group, + gchar *action_name, + gpointer user_data) +{ + TestSignalClosure *c = (TestSignalClosure *)user_data; + EXPECT_STREQ (c->name, action_name); + c->signal_ran = TRUE; +} + +static void +action_enabled_changed (GActionGroup *group, + gchar *action_name, + gboolean enabled, + gpointer user_data) +{ + TestSignalClosure *c = (TestSignalClosure *)user_data; + EXPECT_EQ (enabled, FALSE); + c->signal_ran = TRUE; +} + +static void +action_state_changed (GActionGroup *group, + gchar *action_name, + GVariant *value, + gpointer user_data) +{ + TestSignalClosure *c = (TestSignalClosure *)user_data; + EXPECT_STREQ (g_variant_get_string (value, NULL), "off"); + c->signal_ran = TRUE; +} + +static void +action_removed (GActionGroup *group, + gchar *action_name, + gpointer user_data) +{ + TestSignalClosure *c = (TestSignalClosure *)user_data; + EXPECT_STREQ (c->name, action_name); + c->signal_ran = TRUE; +} + +TEST(GActionMuxerTest, Signals) { + GSimpleActionGroup *group; + GSimpleAction *action; + GActionMuxer *muxer; + TestSignalClosure closure; + + group = g_simple_action_group_new (); + + action = g_simple_action_new ("one", G_VARIANT_TYPE_STRING); + g_action_map_add_action (G_ACTION_MAP(group), G_ACTION (action)); + g_object_unref (action); + + muxer = g_action_muxer_new (); + + g_signal_connect (muxer, "action-added", + G_CALLBACK (action_added), (gpointer) &closure); + g_signal_connect (muxer, "action-enabled-changed", + G_CALLBACK (action_enabled_changed), (gpointer) &closure); + g_signal_connect (muxer, "action-state-changed", + G_CALLBACK (action_state_changed), (gpointer) &closure); + g_signal_connect (muxer, "action-removed", + G_CALLBACK (action_removed), (gpointer) &closure); + + /* add the group with "one" action and check whether the signal is emitted */ + closure.signal_ran = FALSE; + closure.name = "first.one"; + g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group)); + EXPECT_TRUE (closure.signal_ran); + + /* add a second action after the group was added to the muxer */ + closure.signal_ran = FALSE; + closure.name = "first.two"; + action = g_simple_action_new_stateful ("two", G_VARIANT_TYPE_STRING, + g_variant_new_string ("on")); + g_action_map_add_action (G_ACTION_MAP(group), G_ACTION (action)); + EXPECT_TRUE (closure.signal_ran); + + /* disable the action */ + closure.signal_ran = FALSE; + g_simple_action_set_enabled (action, FALSE); + EXPECT_TRUE (closure.signal_ran); + + /* change its state */ + closure.signal_ran = FALSE; + g_simple_action_set_state (action, g_variant_new_string ("off")); + EXPECT_TRUE (closure.signal_ran); + g_object_unref (action); + + /* remove the first action */ + closure.signal_ran = FALSE; + closure.name = "first.one"; + g_action_map_remove_action (G_ACTION_MAP(group), "one"); + EXPECT_TRUE (closure.signal_ran); + + /* remove the whole group, should be notified about "first.two" */ + closure.signal_ran = FALSE; + closure.name = "first.two"; + g_action_muxer_remove (muxer, "first"); + EXPECT_TRUE (closure.signal_ran); + + g_object_unref (group); + g_object_unref (muxer); +} + +static void +action_activated (GSimpleAction *simple, + GVariant *parameter, + gpointer user_data) +{ + gboolean *signal_ran = (gboolean *)user_data; + + EXPECT_STREQ (g_variant_get_string (parameter, NULL), "value"); + *signal_ran = TRUE; +} + +static void +action_change_state (GSimpleAction *simple, + GVariant *value, + gpointer user_data) +{ + gboolean *signal_ran = (gboolean *)user_data; + + EXPECT_STREQ (g_variant_get_string (value, NULL), "off"); + *signal_ran = TRUE; +} + +TEST(GActionMuxerTest, ActivateAction) { + GSimpleActionGroup *group; + GSimpleAction *action; + GActionMuxer *muxer; + gboolean signal_ran; + + group = g_simple_action_group_new (); + + action = g_simple_action_new ("one", G_VARIANT_TYPE_STRING); + g_action_map_add_action (G_ACTION_MAP(group), G_ACTION (action)); + g_signal_connect (action, "activate", + G_CALLBACK (action_activated), (gpointer) &signal_ran); + g_object_unref (action); + + action = g_simple_action_new_stateful ("two", NULL, + g_variant_new_string ("on")); + g_action_map_add_action (G_ACTION_MAP(group), G_ACTION (action)); + g_signal_connect (action, "change-state", + G_CALLBACK (action_change_state), (gpointer) &signal_ran); + g_object_unref (action); + + muxer = g_action_muxer_new (); + g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group)); + + signal_ran = FALSE; + g_action_group_activate_action (G_ACTION_GROUP (muxer), "first.one", + g_variant_new_string ("value")); + EXPECT_TRUE (signal_ran); + + signal_ran = FALSE; + g_action_group_change_action_state (G_ACTION_GROUP (muxer), "first.two", + g_variant_new_string ("off")); + EXPECT_TRUE (signal_ran); + + g_object_unref (group); + g_object_unref (muxer); +} -- cgit v1.2.3