From dbd3db2c833f9b02fb8e399551e977cf950cf559 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 08:58:29 -0600 Subject: Moving the manual tests into the same directory --- test/manual | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/manual | 80 ------------------------------------------------------------ 2 files changed, 80 insertions(+), 80 deletions(-) create mode 100644 test/manual delete mode 100644 tests/manual diff --git a/test/manual b/test/manual new file mode 100644 index 0000000..d638875 --- /dev/null +++ b/test/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/manual b/tests/manual deleted file mode 100644 index d638875..0000000 --- a/tests/manual +++ /dev/null @@ -1,80 +0,0 @@ - -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
-
- -- cgit v1.2.3 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 --- Makefile.am | 4 +- configure.ac | 2 +- test/Makefile.am | 77 ---- test/applications/test.desktop | 2 - test/indicator-messages-service-activate.build.sh | 3 - test/indicator-messages-service-activate.c | 55 --- test/manual | 80 ---- test/test-client.py | 80 ---- test/test-gactionmuxer.cpp | 407 --------------------- 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 +++++++++++++++++++++ 16 files changed, 707 insertions(+), 707 deletions(-) delete mode 100644 test/Makefile.am delete mode 100644 test/applications/test.desktop delete mode 100644 test/indicator-messages-service-activate.build.sh delete mode 100644 test/indicator-messages-service-activate.c delete mode 100644 test/manual delete mode 100755 test/test-client.py delete mode 100644 test/test-gactionmuxer.cpp 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 diff --git a/Makefile.am b/Makefile.am index f8141a8..fe247b6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,10 +12,10 @@ endif if BUILD_TESTS SUBDIRS += \ - test + tests # build src first -test: src +tests: src endif diff --git a/configure.ac b/configure.ac index 8550030..4190606 100644 --- a/configure.ac +++ b/configure.ac @@ -172,7 +172,7 @@ data/icons/scalable/status/Makefile data/icons/scalable/categories/Makefile data/upstart/Makefile po/Makefile.in -test/Makefile +tests/Makefile libmessaging-menu/Makefile libmessaging-menu/messaging-menu.pc doc/Makefile diff --git a/test/Makefile.am b/test/Makefile.am deleted file mode 100644 index b679615..0000000 --- a/test/Makefile.am +++ /dev/null @@ -1,77 +0,0 @@ - -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/test/applications/test.desktop b/test/applications/test.desktop deleted file mode 100644 index c2332b9..0000000 --- a/test/applications/test.desktop +++ /dev/null @@ -1,2 +0,0 @@ -[Desktop Entry] -Type=Application diff --git a/test/indicator-messages-service-activate.build.sh b/test/indicator-messages-service-activate.build.sh deleted file mode 100644 index 87a0316..0000000 --- a/test/indicator-messages-service-activate.build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/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/test/indicator-messages-service-activate.c b/test/indicator-messages-service-activate.c deleted file mode 100644 index f5a26b0..0000000 --- a/test/indicator-messages-service-activate.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -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/test/manual b/test/manual deleted file mode 100644 index d638875..0000000 --- a/test/manual +++ /dev/null @@ -1,80 +0,0 @@ - -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/test/test-client.py b/test/test-client.py deleted file mode 100755 index 0dbf868..0000000 --- a/test/test-client.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/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/test/test-gactionmuxer.cpp b/test/test-gactionmuxer.cpp deleted file mode 100644 index 5c98c90..0000000 --- a/test/test-gactionmuxer.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/* -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); -} 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 From e906c4b452d4ca394e327b2ccaa3a3d4083e1a08 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 09:21:47 -0600 Subject: Pulling stuff from indicator-sound --- tests/Makefile.am | 26 +++ tests/indicator-fixture.h | 524 ++++++++++++++++++++++++++++++++++++++++++++++ tests/indicator-test.cpp | 53 +++++ 3 files changed, 603 insertions(+) create mode 100644 tests/indicator-fixture.h create mode 100644 tests/indicator-test.cpp diff --git a/tests/Makefile.am b/tests/Makefile.am index b679615..1980de3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,6 +7,10 @@ TESTS = $(check_PROGRAMS) AM_CPPFLAGS = $(GTEST_CPPFLAGS) \ -I${top_srcdir}/src +###################################### +# Google Test +###################################### + nodist_libgtest_a_SOURCES = \ $(GTEST_SOURCE)/src/gtest-all.cc \ $(GTEST_SOURCE)/src/gtest_main.cc @@ -16,6 +20,9 @@ libgtest_a_CPPFLAGS = \ libgtest_a_CXXFLAGS = \ $(AM_CXXFLAGS) +###################################### +# GActionMixer +###################################### test_gactionmuxer_SOURCES = \ test-gactionmuxer.cpp @@ -29,6 +36,25 @@ test_gactionmuxer_LDADD = \ libindicator-messages-service.la \ libgtest.a +###################################### +# Indicator Test +###################################### + +indicator_test_SOURCES = \ + indicator-test.cpp + +indicator_test_CPPFLAGS = \ + -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(top_bindir)/service/indicator-messages-service\"" \ + -std=c++11 \ + $(APPLET_CFLAGS) \ + $(AM_CPPFLAGS) + +indicator_test_LDADD = \ + $(APPLET_LIBS) \ + libgtest.a + +TESTS += indicator-test +check_PROGRAMS += indicator-test ###################################### # Lib containing code under test diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h new file mode 100644 index 0000000..e725a50 --- /dev/null +++ b/tests/indicator-fixture.h @@ -0,0 +1,524 @@ +/* + * Copyright © 2014 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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: + * Ted Gould + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +class IndicatorFixture : public ::testing::Test +{ + private: + std::string _indicatorPath; + std::string _indicatorAddress; + std::vector> _mocks; + protected: + std::chrono::milliseconds _eventuallyTime; + + private: + class PerRunData { + public: + /* We're private in the fixture but other than that we don't care, + we don't leak out. This object's purpose isn't to hide data it is + to make the lifecycle of the items more clear. */ + std::shared_ptr _menu; + std::shared_ptr _actions; + DbusTestService * _session_service; + DbusTestService * _system_service; + DbusTestTask * _test_indicator; + DbusTestTask * _test_dummy; + GDBusConnection * _session; + GDBusConnection * _system; + + PerRunData (const std::string& indicatorPath, const std::string& indicatorAddress, std::vector>& mocks) + : _menu(nullptr) + , _session(nullptr) + { + _session_service = dbus_test_service_new(nullptr); + dbus_test_service_set_bus(_session_service, DBUS_TEST_SERVICE_BUS_SESSION); + + _system_service = dbus_test_service_new(nullptr); + dbus_test_service_set_bus(_system_service, DBUS_TEST_SERVICE_BUS_SYSTEM); + + _test_indicator = DBUS_TEST_TASK(dbus_test_process_new(indicatorPath.c_str())); + dbus_test_task_set_name(_test_indicator, "Indicator"); + dbus_test_service_add_task(_session_service, _test_indicator); + + _test_dummy = dbus_test_task_new(); + dbus_test_task_set_wait_for(_test_dummy, indicatorAddress.c_str()); + dbus_test_task_set_name(_test_dummy, "Dummy"); + dbus_test_service_add_task(_session_service, _test_dummy); + + std::for_each(mocks.begin(), mocks.end(), [this](std::shared_ptr task) { + if (dbus_test_task_get_bus(task.get()) == DBUS_TEST_SERVICE_BUS_SYSTEM) { + dbus_test_service_add_task(_system_service, task.get()); + } else { + dbus_test_service_add_task(_session_service, task.get()); + } + }); + + g_debug("Starting System Bus"); + dbus_test_service_start_tasks(_system_service); + _system = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr); + g_dbus_connection_set_exit_on_close(_system, FALSE); + + g_debug("Starting Session Bus"); + dbus_test_service_start_tasks(_session_service); + _session = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr); + g_dbus_connection_set_exit_on_close(_session, FALSE); + } + + virtual ~PerRunData (void) { + _menu.reset(); + _actions.reset(); + + /* D-Bus Test Stuff */ + g_clear_object(&_test_dummy); + g_clear_object(&_test_indicator); + g_clear_object(&_session_service); + g_clear_object(&_system_service); + + /* Wait for D-Bus session bus to go */ + if (!g_dbus_connection_is_closed(_session)) { + g_dbus_connection_close_sync(_session, nullptr, nullptr); + } + g_clear_object(&_session); + + if (!g_dbus_connection_is_closed(_system)) { + g_dbus_connection_close_sync(_system, nullptr, nullptr); + } + g_clear_object(&_system); + } + }; + + std::shared_ptr run; + + public: + virtual ~IndicatorFixture() = default; + + IndicatorFixture (const std::string& path, + const std::string& addr) + : _indicatorPath(path) + , _indicatorAddress(addr) + , _eventuallyTime(std::chrono::seconds(5)) + { + }; + + + protected: + virtual void SetUp() override + { + run = std::make_shared(_indicatorPath, _indicatorAddress, _mocks); + + _mocks.clear(); + } + + virtual void TearDown() override + { + run.reset(); + } + + void addMock (std::shared_ptr mock) + { + _mocks.push_back(mock); + } + + std::shared_ptr buildBustleMock (const std::string& filename, DbusTestServiceBus bus = DBUS_TEST_SERVICE_BUS_BOTH) + { + return std::shared_ptr([filename, bus]() { + DbusTestTask * bustle = DBUS_TEST_TASK(dbus_test_bustle_new(filename.c_str())); + dbus_test_task_set_name(bustle, "Bustle"); + dbus_test_task_set_bus(bustle, bus); + return bustle; + }(), [](DbusTestTask * bustle) { + g_clear_object(&bustle); + }); + } + + private: + void waitForCore (GObject * obj, const gchar * signalname) { + auto loop = g_main_loop_new(nullptr, FALSE); + + /* Our two exit criteria */ + gulong signal = g_signal_connect_swapped(obj, signalname, G_CALLBACK(g_main_loop_quit), loop); + guint timer = g_timeout_add_seconds(5, [](gpointer user_data) -> gboolean { + g_warning("Menu Timeout"); + g_main_loop_quit((GMainLoop *)user_data); + return G_SOURCE_CONTINUE; + }, loop); + + /* Wait for sync */ + g_main_loop_run(loop); + + /* Clean up */ + g_source_remove(timer); + g_signal_handler_disconnect(obj, signal); + + g_main_loop_unref(loop); + } + + void menuWaitForItems (const std::shared_ptr& menu) { + auto count = g_menu_model_get_n_items(menu.get()); + + if (count != 0) + return; + + waitForCore(G_OBJECT(menu.get()), "items-changed"); + } + + void agWaitForActions (const std::shared_ptr& group) { + auto list = std::shared_ptr( + g_action_group_list_actions(group.get()), + [](gchar ** list) { + g_strfreev(list); + }); + + if (g_strv_length(list.get()) != 0) { + return; + } + + waitForCore(G_OBJECT(group.get()), "action-added"); + } + + testing::AssertionResult expectEventually (std::function &testfunc) { + auto loop = std::shared_ptr(g_main_loop_new(nullptr, FALSE), [](GMainLoop * loop) { if (loop != nullptr) g_main_loop_unref(loop); }); + + std::promise retpromise; + auto retfuture = retpromise.get_future(); + auto start = std::chrono::steady_clock::now(); + + /* The core of the idle function as an object so we can use the C++-isms + of attaching the variables and make this code reasonably readable */ + std::function idlefunc = [&loop, &retpromise, &testfunc, &start, this]() -> void { + auto result = testfunc(); + + if (result == false && _eventuallyTime > (std::chrono::steady_clock::now() - start)) { + return; + } + + retpromise.set_value(result); + g_main_loop_quit(loop.get()); + }; + + auto idlesrc = g_idle_add([](gpointer data) -> gboolean { + auto func = reinterpret_cast *>(data); + (*func)(); + return G_SOURCE_CONTINUE; + }, &idlefunc); + + g_main_loop_run(loop.get()); + g_source_remove(idlesrc); + + return retfuture.get(); + } + + protected: + void setMenu (const std::string& path) { + run->_menu.reset(); + + g_debug("Getting Menu: %s:%s", _indicatorAddress.c_str(), path.c_str()); + run->_menu = std::shared_ptr(G_MENU_MODEL(g_dbus_menu_model_get(run->_session, _indicatorAddress.c_str(), path.c_str())), [](GMenuModel * modelptr) { + g_clear_object(&modelptr); + }); + + menuWaitForItems(run->_menu); + } + + void setActions (const std::string& path) { + run->_actions.reset(); + + run->_actions = std::shared_ptr(G_ACTION_GROUP(g_dbus_action_group_get(run->_session, _indicatorAddress.c_str(), path.c_str())), [](GActionGroup * groupptr) { + g_clear_object(&groupptr); + }); + + agWaitForActions(run->_actions); + } + + testing::AssertionResult expectActionExists (const gchar * nameStr, const std::string& name) { + bool hasit = g_action_group_has_action(run->_actions.get(), name.c_str()); + + if (!hasit) { + auto result = testing::AssertionFailure(); + result << + " Action: " << nameStr << std::endl << + " Expected: " << "Exists" << std::endl << + " Actual: " << "No action found" << std::endl; + + return result; + } + + auto result = testing::AssertionSuccess(); + return result; + } + + template testing::AssertionResult expectEventuallyActionStateExists (Args&& ... args) { + std::function func = [&]() { + return expectActionStateExists(std::forward(args)...); + }; + return expectEventually(func); + } + + testing::AssertionResult expectActionStateType (const char * nameStr, const char * typeStr, const std::string& name, const GVariantType * type) { + auto atype = g_action_group_get_action_state_type(run->_actions.get(), name.c_str()); + bool same = false; + + if (atype != nullptr) { + same = g_variant_type_equal(atype, type); + } + + if (!same) { + auto result = testing::AssertionFailure(); + result << + " Action: " << nameStr << std::endl << + " Expected: " << typeStr << std::endl << + " Actual: " << g_variant_type_peek_string(atype) << std::endl; + + return result; + } + + auto result = testing::AssertionSuccess(); + return result; + } + + template testing::AssertionResult expectEventuallyActionStateType (Args&& ... args) { + std::function func = [&]() { + return expectActionStateType(std::forward(args)...); + }; + return expectEventually(func); + } + + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, GVariant * value) { + auto varref = std::shared_ptr(g_variant_ref_sink(value), [](GVariant * varptr) { + if (varptr != nullptr) + g_variant_unref(varptr); + }); + auto aval = std::shared_ptr(g_action_group_get_action_state(run->_actions.get(), name.c_str()), [] (GVariant * varptr) { + if (varptr != nullptr) + g_variant_unref(varptr); + }); + bool match = false; + + if (aval != nullptr) { + match = g_variant_equal(aval.get(), varref.get()); + } + + if (!match) { + gchar * attstr = nullptr; + + if (aval != nullptr) { + attstr = g_variant_print(aval.get(), TRUE); + } else { + attstr = g_strdup("nullptr"); + } + + auto result = testing::AssertionFailure(); + result << + " Action: " << nameStr << std::endl << + " Expected: " << valueStr << std::endl << + " Actual: " << attstr << std::endl; + + g_free(attstr); + + return result; + } else { + auto result = testing::AssertionSuccess(); + return result; + } + } + + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, bool value) { + GVariant * var = g_variant_new_boolean(value); + return expectActionStateIs(nameStr, valueStr, name, var); + } + + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, std::string value) { + GVariant * var = g_variant_new_string(value.c_str()); + return expectActionStateIs(nameStr, valueStr, name, var); + } + + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, const char * value) { + GVariant * var = g_variant_new_string(value); + return expectActionStateIs(nameStr, valueStr, name, var); + } + + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, double value) { + GVariant * var = g_variant_new_double(value); + return expectActionStateIs(nameStr, valueStr, name, var); + } + + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, float value) { + GVariant * var = g_variant_new_double(value); + return expectActionStateIs(nameStr, valueStr, name, var); + } + + template testing::AssertionResult expectEventuallyActionStateIs (Args&& ... args) { + std::function func = [&]() { + return expectActionStateIs(std::forward(args)...); + }; + return expectEventually(func); + } + + + private: + std::shared_ptr getMenuAttributeVal (int location, std::shared_ptr& menu, const std::string& attribute, std::shared_ptr& value) { + if (!(location < g_menu_model_get_n_items(menu.get()))) { + return nullptr; + } + + if (location >= g_menu_model_get_n_items(menu.get())) + return nullptr; + + auto menuval = std::shared_ptr(g_menu_model_get_item_attribute_value(menu.get(), location, attribute.c_str(), g_variant_get_type(value.get())), [](GVariant * varptr) { + if (varptr != nullptr) + g_variant_unref(varptr); + }); + + return menuval; + } + + std::shared_ptr getMenuAttributeRecurse (std::vector::const_iterator menuLocation, std::vector::const_iterator menuEnd, const std::string& attribute, std::shared_ptr& value, std::shared_ptr& menu) { + if (menuLocation == menuEnd) + return nullptr; + + if (menuLocation + 1 == menuEnd) + return getMenuAttributeVal(*menuLocation, menu, attribute, value); + + auto clearfunc = [](GMenuModel * modelptr) { + g_clear_object(&modelptr); + }; + + auto submenu = std::shared_ptr(g_menu_model_get_item_link(menu.get(), *menuLocation, G_MENU_LINK_SUBMENU), clearfunc); + + if (submenu == nullptr) + submenu = std::shared_ptr(g_menu_model_get_item_link(menu.get(), *menuLocation, G_MENU_LINK_SECTION), clearfunc); + + if (submenu == nullptr) + return nullptr; + + menuWaitForItems(submenu); + + return getMenuAttributeRecurse(menuLocation + 1, menuEnd, attribute, value, submenu); + } + + protected: + testing::AssertionResult expectMenuAttribute (const char * menuLocationStr, const char * attributeStr, const char * valueStr, const std::vector menuLocation, const std::string& attribute, GVariant * value) { + auto varref = std::shared_ptr(g_variant_ref_sink(value), [](GVariant * varptr) { + if (varptr != nullptr) + g_variant_unref(varptr); + }); + + auto attrib = getMenuAttributeRecurse(menuLocation.cbegin(), menuLocation.cend(), attribute, varref, run->_menu); + bool same = false; + + if (attrib != nullptr && varref != nullptr) { + same = g_variant_equal(attrib.get(), varref.get()); + } + + if (!same) { + gchar * attstr = nullptr; + + if (attrib != nullptr) { + attstr = g_variant_print(attrib.get(), TRUE); + } else { + attstr = g_strdup("nullptr"); + } + + auto result = testing::AssertionFailure(); + result << + " Menu: " << menuLocationStr << std::endl << + " Attribute: " << attributeStr << std::endl << + " Expected: " << valueStr << std::endl << + " Actual: " << attstr << std::endl; + + g_free(attstr); + + return result; + } else { + auto result = testing::AssertionSuccess(); + return result; + } + } + + testing::AssertionResult expectMenuAttribute (const char * menuLocationStr, const char * attributeStr, const char * valueStr, const std::vector menuLocation, const std::string& attribute, bool value) { + GVariant * var = g_variant_new_boolean(value); + return expectMenuAttribute(menuLocationStr, attributeStr, valueStr, menuLocation, attribute, var); + } + + testing::AssertionResult expectMenuAttribute (const char * menuLocationStr, const char * attributeStr, const char * valueStr, const std::vector menuLocation, const std::string& attribute, std::string value) { + GVariant * var = g_variant_new_string(value.c_str()); + return expectMenuAttribute(menuLocationStr, attributeStr, valueStr, menuLocation, attribute, var); + } + + testing::AssertionResult expectMenuAttribute (const char * menuLocationStr, const char * attributeStr, const char * valueStr, const std::vector menuLocation, const std::string& attribute, const char * value) { + GVariant * var = g_variant_new_string(value); + return expectMenuAttribute(menuLocationStr, attributeStr, valueStr, menuLocation, attribute, var); + } + + template testing::AssertionResult expectEventuallyMenuAttribute (Args&& ... args) { + std::function func = [&]() { + return expectMenuAttribute(std::forward(args)...); + }; + return expectEventually(func); + } +}; + +/* Menu Attrib */ +#define ASSERT_MENU_ATTRIB(menu, attrib, value) \ + ASSERT_PRED_FORMAT3(IndicatorFixture::expectMenuAttribute, menu, attrib, value) + +#define EXPECT_MENU_ATTRIB(menu, attrib, value) \ + EXPECT_PRED_FORMAT3(IndicatorFixture::expectMenuAttribute, menu, attrib, value) + +#define EXPECT_EVENTUALLY_MENU_ATTRIB(menu, attrib, value) \ + EXPECT_PRED_FORMAT3(IndicatorFixture::expectEventuallyMenuAttribute, menu, attrib, value) + +/* Action Exists */ +#define ASSERT_ACTION_EXISTS(action) \ + ASSERT_PRED_FORMAT1(IndicatorFixture::expectActionExists, action) + +#define EXPECT_ACTION_EXISTS(action) \ + EXPECT_PRED_FORMAT1(IndicatorFixture::expectActionExists, action) + +#define EXPECT_EVENTUALLY_ACTION_EXISTS(action) \ + EXPECT_PRED_FORMAT1(IndicatorFixture::expectEventuallyActionExists, action) + +/* Action State */ +#define ASSERT_ACTION_STATE(action, value) \ + ASSERT_PRED_FORMAT2(IndicatorFixture::expectActionStateIs, action, value) + +#define EXPECT_ACTION_STATE(action, value) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectActionStateIs, action, value) + +#define EXPECT_EVENTUALLY_ACTION_STATE(action, value) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyActionStateIs, action, value) + +/* Action State Type */ +#define ASSERT_ACTION_STATE_TYPE(action, type) \ + ASSERT_PRED_FORMAT2(IndicatorFixture::expectActionStateType, action, type) + +#define EXPECT_ACTION_STATE_TYPE(action, type) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectActionStateType, action, type) + +#define EXPECT_EVENTUALLY_ACTION_STATE_TYPE(action, type) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyActionStateType, action, type) diff --git a/tests/indicator-test.cpp b/tests/indicator-test.cpp new file mode 100644 index 0000000..1aef466 --- /dev/null +++ b/tests/indicator-test.cpp @@ -0,0 +1,53 @@ +/* + * Copyright © 2015 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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: + * Ted Gould + */ + +#include +#include + +#include "indicator-fixture.h" + +class IndicatorTest : public IndicatorFixture +{ +protected: + IndicatorTest (void) : + IndicatorFixture(INDICATOR_MESSAGES_SERVICE_BINARY, "com.canonical.indicator.messages") + { + } + + virtual void SetUp() override + { + g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE); + g_setenv("GSETTINGS_BACKEND", "memory", TRUE); + + IndicatorFixture::SetUp(); + } + + virtual void TearDown() override + { + IndicatorFixture::TearDown(); + } + +}; + + +TEST_F(IndicatorTest, PhoneMenu) { + setMenu("/com/canonical/indicator/messages/phone"); + +} + -- cgit v1.2.3 From b540111644608c4873b0075b96a7cfbc127501ee Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 09:44:27 -0600 Subject: Adding in libdbustest --- configure.ac | 2 ++ debian/control | 1 + tests/Makefile.am | 2 ++ 3 files changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index 4190606..b9c8800 100644 --- a/configure.ac +++ b/configure.ac @@ -48,6 +48,8 @@ PKG_CHECK_MODULES(APPLET, gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION PKG_CHECK_MODULES(GIO, gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION) +PKG_CHECK_MODULES(DBUSTEST, dbustest-1) + AC_SUBST(APPLET_CFLAGS) AC_SUBST(APPLET_LIBS) diff --git a/debian/control b/debian/control index 5cdba7d..eccb874 100644 --- a/debian/control +++ b/debian/control @@ -11,6 +11,7 @@ Build-Depends: debhelper (>= 9), gtk-doc-tools, intltool, libaccountsservice-dev, + libdbustest1-dev, libgirepository1.0-dev (>= 0.9.12), libgtest-dev, python3-dbusmock, diff --git a/tests/Makefile.am b/tests/Makefile.am index 1980de3..7d433ba 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -47,10 +47,12 @@ indicator_test_CPPFLAGS = \ -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(top_bindir)/service/indicator-messages-service\"" \ -std=c++11 \ $(APPLET_CFLAGS) \ + $(DBUSTEST_CFLAGS) \ $(AM_CPPFLAGS) indicator_test_LDADD = \ $(APPLET_LIBS) \ + $(DBUSTEST_LIBS) \ libgtest.a TESTS += indicator-test -- cgit v1.2.3 From 23e18e9e09fadbd1cf590a7d69d69c753e974c9d Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 14:05:25 -0600 Subject: Linking and building, oh my --- po/POTFILES.in | 1 - tests/Makefile.am | 12 +++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 6cb028f..4cb6565 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,5 +1,4 @@ [encoding: UTF-8] -test/indicator-messages-service-activate.c src/im-phone-menu.c src/messages-service.c src/im-desktop-menu.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 7d433ba..ca03f56 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ -check_LIBRARIES = libgtest.a +check_LTLIBRARIES = libgtest.la check_PROGRAMS = test-gactionmuxer TESTS = $(check_PROGRAMS) @@ -11,13 +11,13 @@ AM_CPPFLAGS = $(GTEST_CPPFLAGS) \ # Google Test ###################################### -nodist_libgtest_a_SOURCES = \ +nodist_libgtest_la_SOURCES = \ $(GTEST_SOURCE)/src/gtest-all.cc \ $(GTEST_SOURCE)/src/gtest_main.cc -libgtest_a_CPPFLAGS = \ +libgtest_la_CPPFLAGS = \ $(GTEST_CPPFLAGS) -w \ $(AM_CPPFLAGS) -libgtest_a_CXXFLAGS = \ +libgtest_la_CXXFLAGS = \ $(AM_CXXFLAGS) ###################################### @@ -45,6 +45,7 @@ indicator_test_SOURCES = \ indicator_test_CPPFLAGS = \ -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(top_bindir)/service/indicator-messages-service\"" \ + -DSCHEMA_DIR="\"$(bindir)/gsettings-schemas-compiled/\"" \ -std=c++11 \ $(APPLET_CFLAGS) \ $(DBUSTEST_CFLAGS) \ @@ -53,7 +54,8 @@ indicator_test_CPPFLAGS = \ indicator_test_LDADD = \ $(APPLET_LIBS) \ $(DBUSTEST_LIBS) \ - libgtest.a + libgtest.la \ + -lc -lpthread TESTS += indicator-test check_PROGRAMS += indicator-test -- cgit v1.2.3 From 31fccc96b4f29a018b9c097e267313bc6b103a5e Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 14:28:07 -0600 Subject: Get some schemas in there --- tests/Makefile.am | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index ca03f56..74d7eef 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,5 @@ +CLEANFILES= check_LTLIBRARIES = libgtest.la check_PROGRAMS = test-gactionmuxer @@ -34,7 +35,7 @@ test_gactionmuxer_CPPFLAGS = \ test_gactionmuxer_LDADD = \ $(APPLET_LIBS) \ libindicator-messages-service.la \ - libgtest.a + libgtest.la ###################################### # Indicator Test @@ -44,8 +45,8 @@ indicator_test_SOURCES = \ indicator-test.cpp indicator_test_CPPFLAGS = \ - -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(top_bindir)/service/indicator-messages-service\"" \ - -DSCHEMA_DIR="\"$(bindir)/gsettings-schemas-compiled/\"" \ + -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(top_builddir)/service/indicator-messages-service\"" \ + -DSCHEMA_DIR="\"$(builddir)/gsettings-schemas-compiled/\"" \ -std=c++11 \ $(APPLET_CFLAGS) \ $(DBUSTEST_CFLAGS) \ @@ -57,6 +58,16 @@ indicator_test_LDADD = \ libgtest.la \ -lc -lpthread +indicator-test.cpp: schemas-compiled.stamp + +schemas-compiled.stamp: $(top_srcdir)/data/*gschema.xml + rm -rf $(builddir)/gsettings-schemas-compiled + mkdir -p $(builddir)/gsettings-schemas-compiled + cp -f $(top_srcdir)/data/*gschema.xml $(builddir)/gsettings-schemas-compiled + `pkg-config gio-2.0 --variable glib_compile_schemas` $(builddir)/gsettings-schemas-compiled + touch schemas-compiled.stamp + +CLEANFILES += schemas-compiled.stamp TESTS += indicator-test check_PROGRAMS += indicator-test @@ -71,7 +82,7 @@ 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/gactionmuxer.h \ $(top_srcdir)/src/dbus-data.h libindicator_messages_service_ladir = \ -- cgit v1.2.3 From bb83669a1a1cdf3cc4949a13a6b6977b336cd178 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 14:40:32 -0600 Subject: Get the paths right --- tests/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 74d7eef..ee0b9d7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -45,8 +45,8 @@ indicator_test_SOURCES = \ indicator-test.cpp indicator_test_CPPFLAGS = \ - -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(top_builddir)/service/indicator-messages-service\"" \ - -DSCHEMA_DIR="\"$(builddir)/gsettings-schemas-compiled/\"" \ + -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(abs_top_builddir)/src/indicator-messages-service\"" \ + -DSCHEMA_DIR="\"$(abs_builddir)/gsettings-schemas-compiled/\"" \ -std=c++11 \ $(APPLET_CFLAGS) \ $(DBUSTEST_CFLAGS) \ -- cgit v1.2.3 From 4bef5575c83bd34e467c4aa043e9bec221354feb Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 16:19:41 -0600 Subject: Bringing in AS mock and getting a base test of the root action going --- tests/accounts-service-mock.h | 122 ++++++++++++++++++++++++++++++++++++++++++ tests/indicator-fixture.h | 4 +- tests/indicator-test.cpp | 16 +++++- 3 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 tests/accounts-service-mock.h diff --git a/tests/accounts-service-mock.h b/tests/accounts-service-mock.h new file mode 100644 index 0000000..1d0c1fe --- /dev/null +++ b/tests/accounts-service-mock.h @@ -0,0 +1,122 @@ +/* + * Copyright © 2014 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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: + * Ted Gould + */ + +#include +#include + +class AccountsServiceMock +{ + DbusTestDbusMock * mock = nullptr; + DbusTestDbusMockObject * soundobj = nullptr; + DbusTestDbusMockObject * userobj = nullptr; + DbusTestDbusMockObject * syssoundobj = nullptr; + + public: + AccountsServiceMock () { + mock = dbus_test_dbus_mock_new("org.freedesktop.Accounts"); + + dbus_test_task_set_bus(DBUS_TEST_TASK(mock), DBUS_TEST_SERVICE_BUS_SYSTEM); + + DbusTestDbusMockObject * baseobj = dbus_test_dbus_mock_get_object(mock, "/org/freedesktop/Accounts", "org.freedesktop.Accounts", NULL); + + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "CacheUser", G_VARIANT_TYPE_STRING, G_VARIANT_TYPE_OBJECT_PATH, + "ret = dbus.ObjectPath('/user')\n", NULL); + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "FindUserById", G_VARIANT_TYPE_INT64, G_VARIANT_TYPE_OBJECT_PATH, + "ret = dbus.ObjectPath('/user')\n", NULL); + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "FindUserByName", G_VARIANT_TYPE_STRING, G_VARIANT_TYPE_OBJECT_PATH, + "ret = dbus.ObjectPath('/user')\n", NULL); + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "ListCachedUsers", NULL, G_VARIANT_TYPE_OBJECT_PATH_ARRAY, + "ret = [ dbus.ObjectPath('/user') ]\n", NULL); + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "UncacheUser", G_VARIANT_TYPE_STRING, NULL, + "", NULL); + + userobj = dbus_test_dbus_mock_get_object(mock, "/user", "org.freedesktop.Accounts.User", NULL); + dbus_test_dbus_mock_object_add_property(mock, userobj, + "UserName", G_VARIANT_TYPE_STRING, + g_variant_new_string(g_get_user_name()), NULL); + + soundobj = dbus_test_dbus_mock_get_object(mock, "/user", "com.canonical.indicator.sound.AccountsService", NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "Timestamp", G_VARIANT_TYPE_UINT64, + g_variant_new_uint64(0), NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "PlayerName", G_VARIANT_TYPE_STRING, + g_variant_new_string(""), NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "PlayerIcon", G_VARIANT_TYPE_VARIANT, + g_variant_new_variant(g_variant_new_string("")), NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "Running", G_VARIANT_TYPE_BOOLEAN, + g_variant_new_boolean(FALSE), NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "State", G_VARIANT_TYPE_STRING, + g_variant_new_string(""), NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "Title", G_VARIANT_TYPE_STRING, + g_variant_new_string(""), NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "Artist", G_VARIANT_TYPE_STRING, + g_variant_new_string(""), NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "Album", G_VARIANT_TYPE_STRING, + g_variant_new_string(""), NULL); + dbus_test_dbus_mock_object_add_property(mock, soundobj, + "ArtUrl", G_VARIANT_TYPE_STRING, + g_variant_new_string(""), NULL); + + syssoundobj = dbus_test_dbus_mock_get_object(mock, "/user", "com.ubuntu.touch.AccountsService.Sound", NULL); + dbus_test_dbus_mock_object_add_property(mock, syssoundobj, + "SilentMode", G_VARIANT_TYPE_BOOLEAN, + g_variant_new_boolean(FALSE), NULL); + } + + ~AccountsServiceMock () { + g_debug("Destroying the Accounts Service Mock"); + g_clear_object(&mock); + } + + void setSilentMode (bool modeValue) { + dbus_test_dbus_mock_object_update_property(mock, syssoundobj, + "SilentMode", g_variant_new_boolean(modeValue ? TRUE : FALSE), + NULL); + } + + operator std::shared_ptr () { + return std::shared_ptr( + DBUS_TEST_TASK(g_object_ref(mock)), + [](DbusTestTask * task) { g_clear_object(&task); }); + } + + operator DbusTestTask* () { + return DBUS_TEST_TASK(mock); + } + + operator DbusTestDbusMock* () { + return mock; + } + + DbusTestDbusMockObject * get_sound () { + return soundobj; + } +}; diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h index e725a50..aa191ae 100644 --- a/tests/indicator-fixture.h +++ b/tests/indicator-fixture.h @@ -272,9 +272,9 @@ class IndicatorFixture : public ::testing::Test return result; } - template testing::AssertionResult expectEventuallyActionStateExists (Args&& ... args) { + template testing::AssertionResult expectEventuallyActionExists (Args&& ... args) { std::function func = [&]() { - return expectActionStateExists(std::forward(args)...); + return expectActionExists(std::forward(args)...); }; return expectEventually(func); } diff --git a/tests/indicator-test.cpp b/tests/indicator-test.cpp index 1aef466..3a5ef6d 100644 --- a/tests/indicator-test.cpp +++ b/tests/indicator-test.cpp @@ -21,6 +21,7 @@ #include #include "indicator-fixture.h" +#include "accounts-service-mock.h" class IndicatorTest : public IndicatorFixture { @@ -30,24 +31,35 @@ protected: { } + std::shared_ptr as; + virtual void SetUp() override { g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE); g_setenv("GSETTINGS_BACKEND", "memory", TRUE); + as = std::make_shared(); + addMock(*as); + IndicatorFixture::SetUp(); } virtual void TearDown() override { + as.reset(); + IndicatorFixture::TearDown(); } }; -TEST_F(IndicatorTest, PhoneMenu) { - setMenu("/com/canonical/indicator/messages/phone"); +TEST_F(IndicatorTest, RootAction) { + setActions("/com/canonical/indicator/messages"); + + EXPECT_EVENTUALLY_ACTION_EXISTS("messages"); + EXPECT_ACTION_STATE_TYPE("messages", G_VARIANT_TYPE("a{sv}")); + EXPECT_ACTION_STATE("messages", g_variant_new_parsed("{'icon': <('themed', <['indicator-messages-offline', 'indicator-messages', 'indicator']>)>, 'title': <'Notifications'>, 'accessible-desc': <'Messages'>, 'visible': }")); } -- cgit v1.2.3 From df3f745d94c5bd0c5c0c2eaf85ed63a438981e3d Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 17:18:22 -0600 Subject: Adding some messaging menu properties to the AS mock --- tests/accounts-service-mock.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/accounts-service-mock.h b/tests/accounts-service-mock.h index 1d0c1fe..301fcd4 100644 --- a/tests/accounts-service-mock.h +++ b/tests/accounts-service-mock.h @@ -26,6 +26,7 @@ class AccountsServiceMock DbusTestDbusMockObject * soundobj = nullptr; DbusTestDbusMockObject * userobj = nullptr; DbusTestDbusMockObject * syssoundobj = nullptr; + DbusTestDbusMockObject * privacyobj = nullptr; public: AccountsServiceMock () { @@ -55,6 +56,9 @@ class AccountsServiceMock dbus_test_dbus_mock_object_add_property(mock, userobj, "UserName", G_VARIANT_TYPE_STRING, g_variant_new_string(g_get_user_name()), NULL); + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "SetXHasMessages", G_VARIANT_TYPE_BOOLEAN, nullptr, + "", NULL); soundobj = dbus_test_dbus_mock_get_object(mock, "/user", "com.canonical.indicator.sound.AccountsService", NULL); dbus_test_dbus_mock_object_add_property(mock, soundobj, @@ -89,6 +93,14 @@ class AccountsServiceMock dbus_test_dbus_mock_object_add_property(mock, syssoundobj, "SilentMode", G_VARIANT_TYPE_BOOLEAN, g_variant_new_boolean(FALSE), NULL); + + privacyobj = dbus_test_dbus_mock_get_object(mock, "/user", "com.ubuntu.touch.AccountsService.SecurityPrivacy", NULL); + dbus_test_dbus_mock_object_add_property(mock, privacyobj, + "MessagesWelcomeScreen", G_VARIANT_TYPE_BOOLEAN, + g_variant_new_boolean(true), NULL); + dbus_test_dbus_mock_object_add_property(mock, privacyobj, + "StatsWelcomeScreen", G_VARIANT_TYPE_BOOLEAN, + g_variant_new_boolean(true), NULL); } ~AccountsServiceMock () { -- cgit v1.2.3 From 474099ef1d4010fa918da698707b644cbc3fe5da Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 21:46:30 -0600 Subject: A test that puts a message in the menu --- Makefile.am | 2 +- tests/Makefile.am | 3 +++ tests/applications/test.desktop | 3 +++ tests/indicator-test.cpp | 25 ++++++++++++++++++++++++- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index fe247b6..a48804e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,7 @@ SUBDIRS += \ tests # build src first -tests: src +tests: src libmessaging-menu endif diff --git a/tests/Makefile.am b/tests/Makefile.am index ee0b9d7..6dabf89 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -47,6 +47,8 @@ indicator_test_SOURCES = \ indicator_test_CPPFLAGS = \ -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(abs_top_builddir)/src/indicator-messages-service\"" \ -DSCHEMA_DIR="\"$(abs_builddir)/gsettings-schemas-compiled/\"" \ + -DXDG_DATA_DIRS="\"$(abs_srcdir)/\"" \ + -I$(top_srcdir)/libmessaging-menu \ -std=c++11 \ $(APPLET_CFLAGS) \ $(DBUSTEST_CFLAGS) \ @@ -55,6 +57,7 @@ indicator_test_CPPFLAGS = \ indicator_test_LDADD = \ $(APPLET_LIBS) \ $(DBUSTEST_LIBS) \ + $(top_builddir)/libmessaging-menu/libmessaging-menu.la \ libgtest.la \ -lc -lpthread diff --git a/tests/applications/test.desktop b/tests/applications/test.desktop index c2332b9..63ccb6b 100644 --- a/tests/applications/test.desktop +++ b/tests/applications/test.desktop @@ -1,2 +1,5 @@ [Desktop Entry] Type=Application +Name=Test +Exec=test +Icon=test-app diff --git a/tests/indicator-test.cpp b/tests/indicator-test.cpp index 3a5ef6d..afb55d0 100644 --- a/tests/indicator-test.cpp +++ b/tests/indicator-test.cpp @@ -23,6 +23,9 @@ #include "indicator-fixture.h" #include "accounts-service-mock.h" +#include "messaging-menu-app.h" +#include "messaging-menu-message.h" + class IndicatorTest : public IndicatorFixture { protected: @@ -38,6 +41,8 @@ protected: g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE); g_setenv("GSETTINGS_BACKEND", "memory", TRUE); + g_setenv("XDG_DATA_DIRS", XDG_DATA_DIRS, TRUE); + as = std::make_shared(); addMock(*as); @@ -60,6 +65,24 @@ TEST_F(IndicatorTest, RootAction) { EXPECT_EVENTUALLY_ACTION_EXISTS("messages"); EXPECT_ACTION_STATE_TYPE("messages", G_VARIANT_TYPE("a{sv}")); EXPECT_ACTION_STATE("messages", g_variant_new_parsed("{'icon': <('themed', <['indicator-messages-offline', 'indicator-messages', 'indicator']>)>, 'title': <'Notifications'>, 'accessible-desc': <'Messages'>, 'visible': }")); - } +TEST_F(IndicatorTest, SingleMessage) { + setActions("/com/canonical/indicator/messages"); + + auto app = std::shared_ptr(messaging_menu_app_new("test.desktop"), [](MessagingMenuApp * app) { g_clear_object(&app); }); + ASSERT_NE(nullptr, app); + messaging_menu_app_register(app.get()); + + auto msg = std::shared_ptr(messaging_menu_message_new( + "test-id", + nullptr, /* no icon */ + "Test Title", + "A subtitle too", + "You only like me for my body", + 0), [](MessagingMenuMessage * msg) { g_clear_object(&msg); }); + messaging_menu_app_append_message(app.get(), msg.get(), nullptr, FALSE); + + EXPECT_EVENTUALLY_ACTION_EXISTS("test.launch"); + +} -- cgit v1.2.3 From e4b55aa627bba56186b8df30cbd9f27177cfe1ad Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Fri, 6 Mar 2015 22:21:09 -0600 Subject: Check the message's menu --- tests/indicator-test.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/indicator-test.cpp b/tests/indicator-test.cpp index afb55d0..2a711f0 100644 --- a/tests/indicator-test.cpp +++ b/tests/indicator-test.cpp @@ -74,8 +74,10 @@ TEST_F(IndicatorTest, SingleMessage) { ASSERT_NE(nullptr, app); messaging_menu_app_register(app.get()); + EXPECT_EVENTUALLY_ACTION_EXISTS("test.launch"); + auto msg = std::shared_ptr(messaging_menu_message_new( - "test-id", + "testid", nullptr, /* no icon */ "Test Title", "A subtitle too", @@ -83,6 +85,12 @@ TEST_F(IndicatorTest, SingleMessage) { 0), [](MessagingMenuMessage * msg) { g_clear_object(&msg); }); messaging_menu_app_append_message(app.get(), msg.get(), nullptr, FALSE); - EXPECT_EVENTUALLY_ACTION_EXISTS("test.launch"); + EXPECT_EVENTUALLY_ACTION_EXISTS("test.msg.testid"); + + setMenu("/com/canonical/indicator/messages/phone"); + EXPECT_EVENTUALLY_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-type", "com.canonical.indicator.messages.messageitem"); + EXPECT_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-message-id", "testid"); + EXPECT_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-subtitle", "A subtitle too"); + EXPECT_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-text", "You only like me for my body"); } -- cgit v1.2.3 From f6776a30db54d274d1918df5f5bacf41e1945530 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 9 Mar 2015 11:21:24 -0500 Subject: Add checking for the activation parameter type --- tests/indicator-fixture.h | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h index aa191ae..0747842 100644 --- a/tests/indicator-fixture.h +++ b/tests/indicator-fixture.h @@ -292,7 +292,7 @@ class IndicatorFixture : public ::testing::Test result << " Action: " << nameStr << std::endl << " Expected: " << typeStr << std::endl << - " Actual: " << g_variant_type_peek_string(atype) << std::endl; + " Actual: " << (atype == nullptr ? "(null)" : g_variant_type_peek_string(atype)) << std::endl; return result; } @@ -308,6 +308,35 @@ class IndicatorFixture : public ::testing::Test return expectEventually(func); } + testing::AssertionResult expectActionActivationType (const char * nameStr, const char * typeStr, const std::string& name, const GVariantType * type) { + auto atype = g_action_group_get_action_parameter_type(run->_actions.get(), name.c_str()); + bool same = false; + + if (atype != nullptr) { + same = g_variant_type_equal(atype, type); + } + + if (!same) { + auto result = testing::AssertionFailure(); + result << + " Action: " << nameStr << std::endl << + " Expected: " << typeStr << std::endl << + " Actual: " << (atype == nullptr ? "(null)" : g_variant_type_peek_string(atype)) << std::endl; + + return result; + } + + auto result = testing::AssertionSuccess(); + return result; + } + + template testing::AssertionResult expectEventuallyActionActivationType (Args&& ... args) { + std::function func = [&]() { + return expectActionActivationType(std::forward(args)...); + }; + return expectEventually(func); + } + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, GVariant * value) { auto varref = std::shared_ptr(g_variant_ref_sink(value), [](GVariant * varptr) { if (varptr != nullptr) @@ -522,3 +551,14 @@ class IndicatorFixture : public ::testing::Test #define EXPECT_EVENTUALLY_ACTION_STATE_TYPE(action, type) \ EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyActionStateType, action, type) + +/* Action Activation Type */ +#define ASSERT_ACTION_ACTIVATION_TYPE(action, type) \ + ASSERT_PRED_FORMAT2(IndicatorFixture::expectActionActivationType, action, type) + +#define EXPECT_ACTION_ACTIVATION_TYPE(action, type) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectActionActivationType, action, type) + +#define EXPECT_EVENTUALLY_ACTION_ACTIVATION_TYPE(action, type) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyActionActivationType, action, type) + -- cgit v1.2.3 From 0bfd7482c9af44928e884340f4d06e2162933337 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 9 Mar 2015 11:28:23 -0500 Subject: This commit might be evil --- tests/indicator-fixture.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h index 0747842..d5aa570 100644 --- a/tests/indicator-fixture.h +++ b/tests/indicator-fixture.h @@ -510,6 +510,22 @@ class IndicatorFixture : public ::testing::Test }; return expectEventually(func); } + + /* Eventually Helpers */ + #define _EVENTUALLY_HELPER(oper) \ + template testing::AssertionResult expectEventually##oper (Args&& ... args) { \ + std::function func = [&]() { \ + return testing::internal::CmpHelper##oper(std::forward(args)...); \ + }; \ + return expectEventually(func); \ + } + + _EVENTUALLY_HELPER(EQ); + _EVENTUALLY_HELPER(NE); + _EVENTUALLY_HELPER(LT); + _EVENTUALLY_HELPER(GT); + _EVENTUALLY_HELPER(STREQ); + _EVENTUALLY_HELPER(STRNE); }; /* Menu Attrib */ @@ -562,3 +578,22 @@ class IndicatorFixture : public ::testing::Test #define EXPECT_EVENTUALLY_ACTION_ACTIVATION_TYPE(action, type) \ EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyActionActivationType, action, type) +/* Helpers */ + +#define EXPECT_EVENTUALLY_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyEQ, expected, actual) + +#define EXPECT_EVENTUALLY_NE(expected, actual) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyNE, expected, actual) + +#define EXPECT_EVENTUALLY_LT(expected, actual) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyLT, expected, actual) + +#define EXPECT_EVENTUALLY_GT(expected, actual) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyGT, expected, actual) + +#define EXPECT_EVENTUALLY_STREQ(expected, actual) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallySTREQ, expected, actual) + +#define EXPECT_EVENTUALLY_STRNE(expected, actual) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallySTRNE, expected, actual) -- cgit v1.2.3 From 414740248af49364c7fce1d0dcf4baa65dca7608 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 9 Mar 2015 14:14:38 -0500 Subject: Add code to activate an action --- tests/indicator-fixture.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h index d5aa570..a1ca3e2 100644 --- a/tests/indicator-fixture.h +++ b/tests/indicator-fixture.h @@ -255,6 +255,21 @@ class IndicatorFixture : public ::testing::Test agWaitForActions(run->_actions); } + void activateAction (const std::string &name, std::shared_ptr ¶meter) { + g_action_group_activate_action(run->_actions.get(), name.c_str(), parameter.get()); + } + + void activateAction (const std::string &name, GVariant * parameter = nullptr) { + std::shared_ptr param; + + if (parameter != nullptr) + param = std::shared_ptr(g_variant_ref_sink(parameter), [](GVariant * var) { + g_variant_unref(var); + }); + + return activateAction(name, param); + } + testing::AssertionResult expectActionExists (const gchar * nameStr, const std::string& name) { bool hasit = g_action_group_has_action(run->_actions.get(), name.c_str()); @@ -526,6 +541,8 @@ class IndicatorFixture : public ::testing::Test _EVENTUALLY_HELPER(GT); _EVENTUALLY_HELPER(STREQ); _EVENTUALLY_HELPER(STRNE); + + #undef _EVENTUALLY_HELPER }; /* Menu Attrib */ -- cgit v1.2.3 From 9c16722dc9a6799d600a86fea48f3a3c71da895f Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 9 Mar 2015 14:20:14 -0500 Subject: Add enabled testing --- tests/indicator-fixture.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h index a1ca3e2..273d8ed 100644 --- a/tests/indicator-fixture.h +++ b/tests/indicator-fixture.h @@ -294,6 +294,30 @@ class IndicatorFixture : public ::testing::Test return expectEventually(func); } + testing::AssertionResult expectActionEnabled (const char * nameStr, const char * typeStr, const std::string& name, bool enabled) { + auto aenabled = g_action_group_get_action_enabled(run->_actions.get(), name.c_str()); + + if (enabled != aenabled) { + auto result = testing::AssertionFailure(); + result << + " Action: " << nameStr << std::endl << + " Expected: " << enabled << std::endl << + " Actual: " << aenabled << std::endl; + + return result; + } + + auto result = testing::AssertionSuccess(); + return result; + } + + template testing::AssertionResult expectEventuallyActionEnabled (Args&& ... args) { + std::function func = [&]() { + return expectActionEnabled(std::forward(args)...); + }; + return expectEventually(func); + } + testing::AssertionResult expectActionStateType (const char * nameStr, const char * typeStr, const std::string& name, const GVariantType * type) { auto atype = g_action_group_get_action_state_type(run->_actions.get(), name.c_str()); bool same = false; @@ -565,6 +589,16 @@ class IndicatorFixture : public ::testing::Test #define EXPECT_EVENTUALLY_ACTION_EXISTS(action) \ EXPECT_PRED_FORMAT1(IndicatorFixture::expectEventuallyActionExists, action) +/* Action Enabled */ +#define ASSERT_ACTION_ENABLED(action, state) \ + ASSERT_PRED_FORMAT2(IndicatorFixture::expectActionEnabled, action, state) + +#define EXPECT_ACTION_ENABLED(action, state) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectActionEnabled, action, state) + +#define EXPECT_EVENTUALLY_ACTION_ENABLED(action, state) \ + EXPECT_PRED_FORMAT2(IndicatorFixture::expectEventuallyActionEnabled, action, state) + /* Action State */ #define ASSERT_ACTION_STATE(action, value) \ ASSERT_PRED_FORMAT2(IndicatorFixture::expectActionStateIs, action, value) -- cgit v1.2.3 From 3bd0c14d33d444f02f3a35961fafa11d866b1b0d Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 9 Mar 2015 14:20:27 -0500 Subject: Added a test for message replying --- tests/indicator-test.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/indicator-test.cpp b/tests/indicator-test.cpp index 2a711f0..d8c79df 100644 --- a/tests/indicator-test.cpp +++ b/tests/indicator-test.cpp @@ -90,7 +90,57 @@ TEST_F(IndicatorTest, SingleMessage) { setMenu("/com/canonical/indicator/messages/phone"); EXPECT_EVENTUALLY_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-type", "com.canonical.indicator.messages.messageitem"); + EXPECT_MENU_ATTRIB(std::vector({0, 0, 0}), "label", "Test Title"); EXPECT_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-message-id", "testid"); EXPECT_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-subtitle", "A subtitle too"); EXPECT_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-text", "You only like me for my body"); } + +static void +messageReplyActivate (GObject * obj, gchar * name, GVariant * value, gpointer user_data) { + std::string * res = reinterpret_cast(user_data); + *res = g_variant_get_string(value, nullptr); +} + +TEST_F(IndicatorTest, MessageReply) { + setActions("/com/canonical/indicator/messages"); + + auto app = std::shared_ptr(messaging_menu_app_new("test.desktop"), [](MessagingMenuApp * app) { g_clear_object(&app); }); + ASSERT_NE(nullptr, app); + messaging_menu_app_register(app.get()); + + EXPECT_EVENTUALLY_ACTION_EXISTS("test.launch"); + + auto msg = std::shared_ptr(messaging_menu_message_new( + "messageid", + nullptr, /* no icon */ + "Reply Message", + "A message to reply to", + "In-app replies are for wimps, reply here to save yourself time and be cool.", + 0), [](MessagingMenuMessage * msg) { g_clear_object(&msg); }); + messaging_menu_message_add_action(msg.get(), + "replyid", + "Reply", + G_VARIANT_TYPE_STRING, + nullptr); + messaging_menu_app_append_message(app.get(), msg.get(), nullptr, FALSE); + + EXPECT_EVENTUALLY_ACTION_EXISTS("test.msg.messageid"); + EXPECT_EVENTUALLY_ACTION_EXISTS("test.msg-actions.messageid.replyid"); + EXPECT_ACTION_ACTIVATION_TYPE("test.msg-actions.messageid.replyid", G_VARIANT_TYPE_STRING); + + EXPECT_ACTION_ENABLED("remove-all", true); + + setMenu("/com/canonical/indicator/messages/phone"); + + EXPECT_EVENTUALLY_MENU_ATTRIB(std::vector({0, 0, 0}), "x-canonical-type", "com.canonical.indicator.messages.messageitem"); + + std::string activateResponse; + g_signal_connect(msg.get(), "activate", G_CALLBACK(messageReplyActivate), &activateResponse); + + activateAction("test.msg-actions.messageid.replyid", g_variant_new_string("Reply to me")); + + EXPECT_EVENTUALLY_EQ("Reply to me", activateResponse); + + EXPECT_EVENTUALLY_ACTION_ENABLED("remove-all", false); +} -- cgit v1.2.3 From ace149bd9c1218a5533d1f68d0ed760381552a47 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 9 Mar 2015 16:53:27 -0500 Subject: Add a shared pointer action state function --- tests/indicator-fixture.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h index 273d8ed..2455107 100644 --- a/tests/indicator-fixture.h +++ b/tests/indicator-fixture.h @@ -376,11 +376,7 @@ class IndicatorFixture : public ::testing::Test return expectEventually(func); } - testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, GVariant * value) { - auto varref = std::shared_ptr(g_variant_ref_sink(value), [](GVariant * varptr) { - if (varptr != nullptr) - g_variant_unref(varptr); - }); + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, std::shared_ptr varref) { auto aval = std::shared_ptr(g_action_group_get_action_state(run->_actions.get(), name.c_str()), [] (GVariant * varptr) { if (varptr != nullptr) g_variant_unref(varptr); @@ -415,6 +411,14 @@ class IndicatorFixture : public ::testing::Test } } + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, GVariant * value) { + auto varref = std::shared_ptr(g_variant_ref_sink(value), [](GVariant * varptr) { + if (varptr != nullptr) + g_variant_unref(varptr); + }); + return expectActionStateIs(nameStr, valueStr, name, varref); + } + testing::AssertionResult expectActionStateIs (const char * nameStr, const char * valueStr, const std::string& name, bool value) { GVariant * var = g_variant_new_boolean(value); return expectActionStateIs(nameStr, valueStr, name, var); -- cgit v1.2.3 From 56801d13e16f29542f620c1e0e7f249d52705b09 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 9 Mar 2015 17:06:43 -0500 Subject: Adding a test to ensure an action doesn't exist --- tests/indicator-fixture.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h index 2455107..75a49cd 100644 --- a/tests/indicator-fixture.h +++ b/tests/indicator-fixture.h @@ -294,6 +294,30 @@ class IndicatorFixture : public ::testing::Test return expectEventually(func); } + testing::AssertionResult expectActionDoesNotExist (const gchar * nameStr, const std::string& name) { + bool hasit = g_action_group_has_action(run->_actions.get(), name.c_str()); + + if (hasit) { + auto result = testing::AssertionFailure(); + result << + " Action: " << nameStr << std::endl << + " Expected: " << "No action found" << std::endl << + " Actual: " << "Exists" << std::endl; + + return result; + } + + auto result = testing::AssertionSuccess(); + return result; + } + + template testing::AssertionResult expectEventuallyActionDoesNotExist (Args&& ... args) { + std::function func = [&]() { + return expectActionDoesNotExist(std::forward(args)...); + }; + return expectEventually(func); + } + testing::AssertionResult expectActionEnabled (const char * nameStr, const char * typeStr, const std::string& name, bool enabled) { auto aenabled = g_action_group_get_action_enabled(run->_actions.get(), name.c_str()); @@ -593,6 +617,16 @@ class IndicatorFixture : public ::testing::Test #define EXPECT_EVENTUALLY_ACTION_EXISTS(action) \ EXPECT_PRED_FORMAT1(IndicatorFixture::expectEventuallyActionExists, action) +/* Action Does Not Exist */ +#define ASSERT_ACTION_DOES_NOT_EXIST(action) \ + ASSERT_PRED_FORMAT1(IndicatorFixture::expectActionDoesNotExist, action) + +#define EXPECT_ACTION_DOES_NOT_EXIST(action) \ + EXPECT_PRED_FORMAT1(IndicatorFixture::expectActionDoesNotExist, action) + +#define EXPECT_EVENTUALLY_ACTION_DOES_NOT_EXIST(action) \ + EXPECT_PRED_FORMAT1(IndicatorFixture::expectEventuallyActionDoesNotExist, action) + /* Action Enabled */ #define ASSERT_ACTION_ENABLED(action, state) \ ASSERT_PRED_FORMAT2(IndicatorFixture::expectActionEnabled, action, state) -- cgit v1.2.3 From 54ae3da705f9babeec8f2bf5c220d533eef425cc Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Mon, 9 Mar 2015 17:07:03 -0500 Subject: Test the messaging menu changing color on and off --- tests/applications/test2.desktop | 5 ++++ tests/indicator-test.cpp | 63 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/applications/test2.desktop diff --git a/tests/applications/test2.desktop b/tests/applications/test2.desktop new file mode 100644 index 0000000..63ccb6b --- /dev/null +++ b/tests/applications/test2.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Type=Application +Name=Test +Exec=test +Icon=test-app diff --git a/tests/indicator-test.cpp b/tests/indicator-test.cpp index d8c79df..8f87191 100644 --- a/tests/indicator-test.cpp +++ b/tests/indicator-test.cpp @@ -144,3 +144,66 @@ TEST_F(IndicatorTest, MessageReply) { EXPECT_EVENTUALLY_ACTION_ENABLED("remove-all", false); } + +TEST_F(IndicatorTest, IconNotification) { + auto normalicon = std::shared_ptr(g_variant_ref_sink(g_variant_new_parsed("{'icon': <('themed', <['indicator-messages-offline', 'indicator-messages', 'indicator']>)>, 'title': <'Notifications'>, 'accessible-desc': <'Messages'>, 'visible': }")), [](GVariant *var) {if (var != nullptr) g_variant_unref(var); }); + auto blueicon = std::shared_ptr(g_variant_ref_sink(g_variant_new_parsed("{'icon': <('themed', <['indicator-messages-new-offline', 'indicator-messages-new', 'indicator-messages', 'indicator']>)>, 'title': <'Notifications'>, 'accessible-desc': <'New Messages'>, 'visible': }")), [](GVariant *var) {if (var != nullptr) g_variant_unref(var); }); + + setActions("/com/canonical/indicator/messages"); + + auto app = std::shared_ptr(messaging_menu_app_new("test.desktop"), [](MessagingMenuApp * app) { g_clear_object(&app); }); + ASSERT_NE(nullptr, app); + messaging_menu_app_register(app.get()); + + EXPECT_EVENTUALLY_ACTION_EXISTS("test.launch"); + + EXPECT_ACTION_STATE("messages", normalicon); + + auto app2 = std::shared_ptr(messaging_menu_app_new("test2.desktop"), [](MessagingMenuApp * app) { g_clear_object(&app); }); + ASSERT_NE(nullptr, app2); + messaging_menu_app_register(app2.get()); + + EXPECT_EVENTUALLY_ACTION_EXISTS("test2.launch"); + + messaging_menu_app_append_source_with_count(app2.get(), + "countsource", + nullptr, + "Count Source", + 500); + messaging_menu_app_draw_attention(app2.get(), "countsource"); + + EXPECT_EVENTUALLY_ACTION_STATE("messages", blueicon); + + auto msg = std::shared_ptr(messaging_menu_message_new( + "messageid", + nullptr, /* no icon */ + "Message", + "A secret message", + "asdfa;lkweraoweprijas;dvlknasvdoiewur;aslkd", + 0), [](MessagingMenuMessage * msg) { g_clear_object(&msg); }); + messaging_menu_message_set_draws_attention(msg.get(), true); + messaging_menu_app_append_message(app.get(), msg.get(), nullptr, FALSE); + + EXPECT_EVENTUALLY_ACTION_EXISTS("test.msg.messageid"); + EXPECT_ACTION_STATE("messages", blueicon); + + messaging_menu_app_unregister(app2.get()); + app2.reset(); + + EXPECT_EVENTUALLY_ACTION_DOES_NOT_EXIST("test2.msg.countsource"); + EXPECT_ACTION_STATE("messages", blueicon); + + messaging_menu_app_remove_message(app.get(), msg.get()); + + EXPECT_EVENTUALLY_ACTION_STATE("messages", normalicon); + EXPECT_ACTION_ENABLED("remove-all", false); + + messaging_menu_app_append_message(app.get(), msg.get(), nullptr, FALSE); + + EXPECT_EVENTUALLY_ACTION_STATE("messages", blueicon); + EXPECT_ACTION_ENABLED("remove-all", true); + + activateAction("remove-all"); + + EXPECT_EVENTUALLY_ACTION_STATE("messages", normalicon); +} -- cgit v1.2.3 From cb7a4808f31fa347d39f7fd7f9a1687e45fd9196 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 10 Mar 2015 15:07:49 -0500 Subject: Making the schema compilation directory into its own variable --- tests/Makefile.am | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 6dabf89..bd559fd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -41,12 +41,14 @@ test_gactionmuxer_LDADD = \ # Indicator Test ###################################### +SCHEMA_COMPILED_DIR="$(abs_builddir)/gsettings-schemas-compiled/" + indicator_test_SOURCES = \ indicator-test.cpp indicator_test_CPPFLAGS = \ -DINDICATOR_MESSAGES_SERVICE_BINARY="\"$(abs_top_builddir)/src/indicator-messages-service\"" \ - -DSCHEMA_DIR="\"$(abs_builddir)/gsettings-schemas-compiled/\"" \ + -DSCHEMA_DIR="\"$(SCHEMA_COMPILED_DIR)\"" \ -DXDG_DATA_DIRS="\"$(abs_srcdir)/\"" \ -I$(top_srcdir)/libmessaging-menu \ -std=c++11 \ @@ -64,11 +66,11 @@ indicator_test_LDADD = \ indicator-test.cpp: schemas-compiled.stamp schemas-compiled.stamp: $(top_srcdir)/data/*gschema.xml - rm -rf $(builddir)/gsettings-schemas-compiled - mkdir -p $(builddir)/gsettings-schemas-compiled - cp -f $(top_srcdir)/data/*gschema.xml $(builddir)/gsettings-schemas-compiled - `pkg-config gio-2.0 --variable glib_compile_schemas` $(builddir)/gsettings-schemas-compiled - touch schemas-compiled.stamp + @rm -rf $(SCHEMA_COMPILED_DIR) + @mkdir -p $(SCHEMA_COMPILED_DIR) + @cp -f $(top_srcdir)/data/*gschema.xml $(SCHEMA_COMPILED_DIR) + @`pkg-config gio-2.0 --variable glib_compile_schemas` $(SCHEMA_COMPILED_DIR) + @touch schemas-compiled.stamp CLEANFILES += schemas-compiled.stamp TESTS += indicator-test -- cgit v1.2.3 From a3f4a0b948bb282ca016206becb290d0e7656f80 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 10 Mar 2015 16:13:05 -0500 Subject: Remove useless for_each call --- tests/indicator-fixture.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/indicator-fixture.h b/tests/indicator-fixture.h index 75a49cd..e2c4316 100644 --- a/tests/indicator-fixture.h +++ b/tests/indicator-fixture.h @@ -70,13 +70,13 @@ class IndicatorFixture : public ::testing::Test dbus_test_task_set_name(_test_dummy, "Dummy"); dbus_test_service_add_task(_session_service, _test_dummy); - std::for_each(mocks.begin(), mocks.end(), [this](std::shared_ptr task) { + for(auto task : mocks) { if (dbus_test_task_get_bus(task.get()) == DBUS_TEST_SERVICE_BUS_SYSTEM) { dbus_test_service_add_task(_system_service, task.get()); } else { dbus_test_service_add_task(_session_service, task.get()); } - }); + } g_debug("Starting System Bus"); dbus_test_service_start_tasks(_system_service); -- cgit v1.2.3 From 5133bf06e0398d43861ac0d2b19ca9bc9a03ec1e Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 10 Mar 2015 16:18:02 -0500 Subject: Pedantic use of auto --- tests/indicator-test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/indicator-test.cpp b/tests/indicator-test.cpp index 8f87191..0991db5 100644 --- a/tests/indicator-test.cpp +++ b/tests/indicator-test.cpp @@ -98,7 +98,7 @@ TEST_F(IndicatorTest, SingleMessage) { static void messageReplyActivate (GObject * obj, gchar * name, GVariant * value, gpointer user_data) { - std::string * res = reinterpret_cast(user_data); + auto res = reinterpret_cast(user_data); *res = g_variant_get_string(value, nullptr); } -- cgit v1.2.3