diff options
author | Ted Gould <ted@gould.cx> | 2014-03-04 15:40:28 -0600 |
---|---|---|
committer | Ted Gould <ted@gould.cx> | 2014-03-04 15:40:28 -0600 |
commit | e6fab6c96fe0e9414f214d47c8b762c8a435cc51 (patch) | |
tree | 25569bade0f178b7ce44205acb2e5c7ec82c8994 | |
parent | f06b9ff784c15e9e1c0ad0840299ed70b5616a74 (diff) | |
parent | e9f0b68ab8b9afec9466011b8a8bae3b202b4bf9 (diff) | |
download | ayatana-indicator-sound-e6fab6c96fe0e9414f214d47c8b762c8a435cc51.tar.gz ayatana-indicator-sound-e6fab6c96fe0e9414f214d47c8b762c8a435cc51.tar.bz2 ayatana-indicator-sound-e6fab6c96fe0e9414f214d47c8b762c8a435cc51.zip |
Update to the latest player
-rw-r--r-- | data/com.canonical.indicator.sound | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/media-player-list-greeter.vala | 12 | ||||
-rw-r--r-- | src/media-player-user.vala | 10 | ||||
-rw-r--r-- | src/service.vala | 11 | ||||
-rw-r--r-- | src/sound-menu.vala | 42 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 44 | ||||
-rw-r--r-- | tests/accounts-service-mock.h | 101 | ||||
-rw-r--r-- | tests/accounts-service-user.cc | 60 | ||||
-rw-r--r-- | tests/media-player-user.cc | 210 | ||||
-rw-r--r-- | tests/sound-menu.cc | 113 |
11 files changed, 530 insertions, 76 deletions
diff --git a/data/com.canonical.indicator.sound b/data/com.canonical.indicator.sound index ae5fd5d..7d9ab41 100644 --- a/data/com.canonical.indicator.sound +++ b/data/com.canonical.indicator.sound @@ -16,5 +16,5 @@ ObjectPath=/com/canonical/indicator/sound/desktop_greeter ObjectPath=/com/canonical/indicator/sound/desktop_greeter [phone_greeter] -ObjectPath=/com/canonical/indicator/sound/desktop_greeter +ObjectPath=/com/canonical/indicator/sound/phone_greeter diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 55c5fba..98bc7c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,7 +96,6 @@ vala_add(indicator-sound-service sound-menu.vala DEPENDS media-player - mpris2-interfaces ) vala_add(indicator-sound-service accounts-service-user.vala diff --git a/src/media-player-list-greeter.vala b/src/media-player-list-greeter.vala index 2f1962e..15e4c55 100644 --- a/src/media-player-list-greeter.vala +++ b/src/media-player-list-greeter.vala @@ -63,12 +63,15 @@ public class MediaPlayerListGreeter : MediaPlayerList { return; } + debug(@"Active user changed to: $active_user"); + var old_user = selected_user; /* Protect against a null user */ - if (active_user != "") { + if (active_user != "" && active_user[0] != '*') { selected_user = active_user; } else { + debug(@"Blocking active user change for '$active_user'"); selected_user = null; } @@ -78,12 +81,17 @@ public class MediaPlayerListGreeter : MediaPlayerList { if (old_user != null) { var old_player = players.lookup(old_user); + debug("Removing player for user: %s", old_user); player_removed(old_player); } if (selected_user != null) { var new_player = players.lookup(selected_user); - player_added(new_player); + + if (new_player != null) { + debug("Adding player for user: %s", selected_user); + player_added(new_player); + } } } diff --git a/src/media-player-user.vala b/src/media-player-user.vala index c48c39b..11678d5 100644 --- a/src/media-player-user.vala +++ b/src/media-player-user.vala @@ -69,9 +69,12 @@ public class MediaPlayerUser : MediaPlayer { properties_timeout = 0; properties_queued.@foreach((key, value) => { + debug("Notifying '%s' changed", key); this.notify_property(key); }); + properties_queued.remove_all(); + /* Remove source */ return false; } @@ -88,6 +91,7 @@ public class MediaPlayerUser : MediaPlayer { properties_queued.insert("icon", true); properties_queued.insert("state", true); properties_queued.insert("current-track", true); + properties_queued.insert("is-running", true); break; case "PlayerName": properties_queued.insert("name", true); @@ -126,8 +130,8 @@ public class MediaPlayerUser : MediaPlayer { } }); - /* Update all of them -- we've got a proxy! */ - queue_property_notification("Timestamp"); + debug("Notifying player is ready for user: %s", this.username); + this.notify_property("is-running"); } catch (Error e) { this.proxy = null; warning("Unable to get proxy to user '%s' sound settings: %s", username, e.message); @@ -195,7 +199,7 @@ public class MediaPlayerUser : MediaPlayer { /* If it's shown externally it's running */ public override bool is_running { get { return proxy_is_valid(); } } /* A bit weird. Not sure how we should handle this. */ - public override bool can_raise { get { return false; } } + public override bool can_raise { get { return true; } } /* Fill out the track based on the values in the proxy */ MediaPlayer.Track track_cache; diff --git a/src/service.vala b/src/service.vala index be0164d..ca00caa 100644 --- a/src/service.vala +++ b/src/service.vala @@ -35,7 +35,8 @@ public class IndicatorSound.Service: Object { this.actions.add_action (this.create_mic_volume_action ()); this.menus = new HashTable<string, SoundMenu> (str_hash, str_equal); - this.menus.insert ("desktop_greeter", new SoundMenu (null, SoundMenu.DisplayFlags.SHOW_MUTE)); + this.menus.insert ("desktop_greeter", new SoundMenu (null, SoundMenu.DisplayFlags.SHOW_MUTE | SoundMenu.DisplayFlags.DONT_SHOW_PLAYERS)); + this.menus.insert ("phone_greeter", new SoundMenu (null, SoundMenu.DisplayFlags.SHOW_MUTE | SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS)); this.menus.insert ("desktop", new SoundMenu ("indicator.desktop-settings", SoundMenu.DisplayFlags.SHOW_MUTE)); this.menus.insert ("phone", new SoundMenu ("indicator.phone-settings", SoundMenu.DisplayFlags.HIDE_INACTIVE_PLAYERS)); @@ -366,15 +367,15 @@ public class IndicatorSound.Service: Object { this.menus.@foreach ( (profile, menu) => menu.add_player (player)); SimpleAction action = new SimpleAction.stateful (player.id, null, this.action_state_for_player (player)); + action.set_enabled (player.can_raise); action.activate.connect ( () => { player.activate (); }); this.actions.add_action (action); var play_action = new SimpleAction.stateful ("play." + player.id, null, player.state); play_action.activate.connect ( () => player.play_pause () ); this.actions.add_action (play_action); - player.notify.connect ( (object, pspec) => { - if (pspec.name == "state") - play_action.set_state (player.state); + player.notify["state"].connect ( (object, pspec) => { + play_action.set_state (player.state); }); var next_action = new SimpleAction ("next." + player.id, null); @@ -401,6 +402,8 @@ public class IndicatorSound.Service: Object { this.actions.remove_action ("previous." + player.id); this.actions.remove_action ("play-playlist." + player.id); + player.notify.disconnect (this.eventually_update_player_actions); + this.menus.@foreach ( (profile, menu) => menu.remove_player (player)); this.update_preferred_players (); diff --git a/src/sound-menu.vala b/src/sound-menu.vala index 480e1cf..ebb7632 100644 --- a/src/sound-menu.vala +++ b/src/sound-menu.vala @@ -17,12 +17,13 @@ * Lars Uebernickel <lars.uebernickel@canonical.com> */ -class SoundMenu: Object +public class SoundMenu: Object { public enum DisplayFlags { NONE = 0, SHOW_MUTE = 1, - HIDE_INACTIVE_PLAYERS = 2 + HIDE_INACTIVE_PLAYERS = 2, + DONT_SHOW_PLAYERS = 4 } public SoundMenu (string? settings_action, DisplayFlags flags) { @@ -31,6 +32,8 @@ class SoundMenu: Object * it has a dynamic amount of player sections, one for each registered player. */ + this.no_players = ((flags & DisplayFlags.DONT_SHOW_PLAYERS) != 0); + this.volume_section = new Menu (); if ((flags & DisplayFlags.SHOW_MUTE) != 0) volume_section.append (_("Mute"), "indicator.mute"); @@ -87,6 +90,8 @@ class SoundMenu: Object } public void add_player (MediaPlayer player) { + if (this.no_players) + return; if (this.notify_handlers.contains (player)) return; @@ -95,12 +100,13 @@ class SoundMenu: Object this.update_playlists (player); var handler_id = player.notify["is-running"].connect ( () => { - if (this.hide_inactive) { - if (player.is_running) + if (player.is_running) + if (this.find_player_section(player) == -1) this.insert_player_section (player); - else + else + if (this.hide_inactive) this.remove_player_section (player); - } + this.update_playlists (player); }); this.notify_handlers.insert (player, handler_id); @@ -110,29 +116,43 @@ class SoundMenu: Object public void remove_player (MediaPlayer player) { this.remove_player_section (player); + + var id = this.notify_handlers.lookup(player); + if (id != 0) { + player.disconnect(id); + } + + player.playlists_changed.disconnect (this.update_playlists); + + /* this'll drop our ref to it */ this.notify_handlers.remove (player); } - Menu root; - Menu menu; + public Menu root; + public Menu menu; Menu volume_section; bool mic_volume_shown; bool settings_shown = false; bool hide_inactive; + bool no_players; HashTable<MediaPlayer, ulong> notify_handlers; /* returns the position in this.menu of the section that's associated with @player */ int find_player_section (MediaPlayer player) { + debug("Looking for player: %s", player.id); string action_name = @"indicator.$(player.id)"; - int n = this.menu.get_n_items () -1; - for (int i = 1; i < n; i++) { + int n = this.menu.get_n_items (); + for (int i = 0; i < n; i++) { var section = this.menu.get_item_link (i, Menu.LINK_SECTION); + if (section == null) continue; + string action; section.get_item_attribute (0, "action", "s", out action); if (action == action_name) return i; } + debug("Unable to find section for player: %s", player.id); return -1; } @@ -140,6 +160,8 @@ class SoundMenu: Object var section = new Menu (); Icon icon; + debug("Adding section for player: %s (%s)", player.id, player.is_running ? "running" : "not running"); + icon = player.icon; if (icon == null) icon = new ThemedIcon.with_default_fallbacks ("application-default-icon"); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1556fc7..9b0586a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -114,3 +114,47 @@ add_test(accounts-service-user-test-basic add_test(accounts-service-user-test-player accounts-service-user-test --gtest_filter=AccountsServiceUserTest.SetMediaPlayer ) + +########################### +# Sound Menu +########################### + +include_directories(${CMAKE_SOURCE_DIR}/src) +add_executable (sound-menu-test sound-menu.cc) +target_link_libraries ( + sound-menu-test + indicator-sound-service-lib + vala-mocks-lib + gtest + ${SOUNDSERVICE_LIBRARIES} + ${TEST_LIBRARIES} +) + +add_test(sound-menu-test sound-menu-test) + +########################### +# Accounts Service User +########################### + +include_directories(${CMAKE_SOURCE_DIR}/src) +add_executable (media-player-user-test media-player-user.cc) +target_link_libraries ( + media-player-user-test + indicator-sound-service-lib + vala-mocks-lib + gtest + ${SOUNDSERVICE_LIBRARIES} + ${TEST_LIBRARIES} +) + +# Split tests to work around libaccountservice sucking +add_test(media-player-user-test-basic + media-player-user-test --gtest_filter=MediaPlayerUserTest.BasicObject +) +add_test(media-player-user-test-dataset + media-player-user-test --gtest_filter=MediaPlayerUserTest.DataSet +) +add_test(media-player-user-test-timeout + media-player-user-test --gtest_filter=MediaPlayerUserTest.TimeoutTest +) + diff --git a/tests/accounts-service-mock.h b/tests/accounts-service-mock.h new file mode 100644 index 0000000..d4dae7e --- /dev/null +++ b/tests/accounts-service-mock.h @@ -0,0 +1,101 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Ted Gould <ted@canonical.com> + */ + +#include <libdbustest/dbus-test.h> + +class AccountsServiceMock +{ + DbusTestDbusMock * mock = nullptr; + DbusTestDbusMockObject * soundobj = nullptr; + DbusTestDbusMockObject * userobj = nullptr; + + public: + AccountsServiceMock () { + mock = dbus_test_dbus_mock_new("org.freedesktop.Accounts"); + + 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); + } + + ~AccountsServiceMock () { + g_debug("Destroying the Accounts Service Mock"); + g_clear_object(&mock); + } + + operator DbusTestTask* () { + return DBUS_TEST_TASK(mock); + } + + operator DbusTestDbusMock* () { + return mock; + } + + DbusTestDbusMockObject * get_sound () { + return soundobj; + } +}; diff --git a/tests/accounts-service-user.cc b/tests/accounts-service-user.cc index 522bec9..b39b546 100644 --- a/tests/accounts-service-user.cc +++ b/tests/accounts-service-user.cc @@ -22,6 +22,8 @@ #include <libdbustest/dbus-test.h> #include <act/act.h> +#include "accounts-service-mock.h" + extern "C" { #include "indicator-sound-service.h" #include "vala-mocks.h" @@ -41,61 +43,9 @@ class AccountsServiceUserTest : public ::testing::Test virtual void SetUp() { service = dbus_test_service_new(NULL); - mock = dbus_test_dbus_mock_new("org.freedesktop.Accounts"); - - 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); - - DbusTestDbusMockObject * 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); - - DbusTestDbusMockObject * 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); - - dbus_test_service_add_task(service, DBUS_TEST_TASK(mock)); + AccountsServiceMock service_mock; + + dbus_test_service_add_task(service, (DbusTestTask*)service_mock); dbus_test_service_start_tasks(service); g_setenv("DBUS_SYSTEM_BUS_ADDRESS", g_getenv("DBUS_SESSION_BUS_ADDRESS"), TRUE); diff --git a/tests/media-player-user.cc b/tests/media-player-user.cc new file mode 100644 index 0000000..2132e14 --- /dev/null +++ b/tests/media-player-user.cc @@ -0,0 +1,210 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Ted Gould <ted@canonical.com> + */ + +#include <gtest/gtest.h> +#include <gio/gio.h> +#include <libdbustest/dbus-test.h> + +#include "accounts-service-mock.h" + +extern "C" { +#include "indicator-sound-service.h" +} + +class MediaPlayerUserTest : public ::testing::Test +{ + + protected: + DbusTestService * service = NULL; + AccountsServiceMock service_mock; + + GDBusConnection * session = NULL; + GDBusConnection * system = NULL; + GDBusProxy * proxy = NULL; + + virtual void SetUp() { + service = dbus_test_service_new(NULL); + + + dbus_test_service_add_task(service, (DbusTestTask*)service_mock); + dbus_test_service_start_tasks(service); + + g_setenv("DBUS_SYSTEM_BUS_ADDRESS", g_getenv("DBUS_SESSION_BUS_ADDRESS"), TRUE); + + session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + ASSERT_NE(nullptr, session); + g_dbus_connection_set_exit_on_close(session, FALSE); + g_object_add_weak_pointer(G_OBJECT(session), (gpointer *)&session); + + system = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL); + ASSERT_NE(nullptr, system); + g_dbus_connection_set_exit_on_close(system, FALSE); + g_object_add_weak_pointer(G_OBJECT(system), (gpointer *)&system); + + proxy = g_dbus_proxy_new_sync(session, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.Accounts", + "/user", + "org.freedesktop.DBus.Properties", + NULL, NULL); + ASSERT_NE(nullptr, proxy); + } + + virtual void TearDown() { + g_clear_object(&proxy); + g_clear_object(&service); + + g_object_unref(session); + g_object_unref(system); + + #if 0 + /* Accounts Service keeps a bunch of references around so we + have to split the tests and can't check this :-( */ + unsigned int cleartry = 0; + while ((session != NULL || system != NULL) && cleartry < 100) { + loop(100); + cleartry++; + } + + ASSERT_EQ(nullptr, session); + ASSERT_EQ(nullptr, system); + #endif + } + + static gboolean timeout_cb (gpointer user_data) { + GMainLoop * loop = static_cast<GMainLoop *>(user_data); + g_main_loop_quit(loop); + return G_SOURCE_REMOVE; + } + + void loop (unsigned int ms) { + GMainLoop * loop = g_main_loop_new(NULL, FALSE); + g_timeout_add(ms, timeout_cb, loop); + g_main_loop_run(loop); + g_main_loop_unref(loop); + } + + void set_property (const gchar * name, GVariant * value) { + dbus_test_dbus_mock_object_update_property((DbusTestDbusMock *)service_mock, service_mock.get_sound(), name, value, NULL); + } +}; + +TEST_F(MediaPlayerUserTest, BasicObject) { + MediaPlayerUser * player = media_player_user_new("user"); + ASSERT_NE(nullptr, player); + + /* Protected, but no useful data */ + EXPECT_FALSE(media_player_get_is_running(MEDIA_PLAYER(player))); + EXPECT_TRUE(media_player_get_can_raise(MEDIA_PLAYER(player))); + EXPECT_STREQ("user", media_player_get_id(MEDIA_PLAYER(player))); + EXPECT_STREQ("", media_player_get_name(MEDIA_PLAYER(player))); + EXPECT_STREQ("", media_player_get_state(MEDIA_PLAYER(player))); + EXPECT_EQ(nullptr, media_player_get_icon(MEDIA_PLAYER(player))); + EXPECT_EQ(nullptr, media_player_get_current_track(MEDIA_PLAYER(player))); + + /* Get the proxy -- but no good data */ + loop(100); + + /* Ensure even with the proxy we don't have anything */ + EXPECT_FALSE(media_player_get_is_running(MEDIA_PLAYER(player))); + EXPECT_TRUE(media_player_get_can_raise(MEDIA_PLAYER(player))); + EXPECT_STREQ("user", media_player_get_id(MEDIA_PLAYER(player))); + EXPECT_STREQ("", media_player_get_name(MEDIA_PLAYER(player))); + EXPECT_STREQ("", media_player_get_state(MEDIA_PLAYER(player))); + EXPECT_EQ(nullptr, media_player_get_icon(MEDIA_PLAYER(player))); + EXPECT_EQ(nullptr, media_player_get_current_track(MEDIA_PLAYER(player))); + + g_clear_object(&player); +} + +TEST_F(MediaPlayerUserTest, DataSet) { + /* Put data into Acts */ + set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time())); + set_property("PlayerName", g_variant_new_string("The Player Formerly Known as Prince")); + GIcon * in_icon = g_themed_icon_new_with_default_fallbacks("foo-bar-fallback"); + set_property("PlayerIcon", g_variant_new_variant(g_icon_serialize(in_icon))); + set_property("State", g_variant_new_string("Chillin'")); + set_property("Title", g_variant_new_string("Dictator")); + set_property("Artist", g_variant_new_string("Bansky")); + set_property("Album", g_variant_new_string("Vinyl is dead")); + set_property("ArtUrl", g_variant_new_string("http://art.url")); + + /* Build our media player */ + MediaPlayerUser * player = media_player_user_new("user"); + ASSERT_NE(nullptr, player); + + /* Get the proxy -- and it's precious precious data -- oh, my, precious! */ + loop(100); + + /* Ensure even with the proxy we don't have anything */ + EXPECT_TRUE(media_player_get_is_running(MEDIA_PLAYER(player))); + EXPECT_TRUE(media_player_get_can_raise(MEDIA_PLAYER(player))); + EXPECT_STREQ("user", media_player_get_id(MEDIA_PLAYER(player))); + EXPECT_STREQ("The Player Formerly Known as Prince", media_player_get_name(MEDIA_PLAYER(player))); + EXPECT_STREQ("Chillin'", media_player_get_state(MEDIA_PLAYER(player))); + + GIcon * out_icon = media_player_get_icon(MEDIA_PLAYER(player)); + EXPECT_NE(nullptr, out_icon); + EXPECT_TRUE(g_icon_equal(in_icon, out_icon)); + g_clear_object(&out_icon); + + MediaPlayerTrack * track = media_player_get_current_track(MEDIA_PLAYER(player)); + EXPECT_NE(nullptr, track); + EXPECT_STREQ("Dictator", media_player_track_get_title(track)); + EXPECT_STREQ("Bansky", media_player_track_get_artist(track)); + EXPECT_STREQ("Vinyl is dead", media_player_track_get_album(track)); + EXPECT_STREQ("http://art.url", media_player_track_get_art_url(track)); + g_clear_object(&track); + + g_clear_object(&in_icon); + g_clear_object(&player); +} + +TEST_F(MediaPlayerUserTest, TimeoutTest) { + /* Put data into Acts -- but 15 minutes ago */ + set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time() - 15 * 60 * 1000 * 1000)); + set_property("PlayerName", g_variant_new_string("The Player Formerly Known as Prince")); + GIcon * in_icon = g_themed_icon_new_with_default_fallbacks("foo-bar-fallback"); + set_property("PlayerIcon", g_variant_new_variant(g_icon_serialize(in_icon))); + set_property("State", g_variant_new_string("Chillin'")); + set_property("Title", g_variant_new_string("Dictator")); + set_property("Artist", g_variant_new_string("Bansky")); + set_property("Album", g_variant_new_string("Vinyl is dead")); + set_property("ArtUrl", g_variant_new_string("http://art.url")); + + /* Build our media player */ + MediaPlayerUser * player = media_player_user_new("user"); + ASSERT_NE(nullptr, player); + + /* Get the proxy -- and the old data, so old, like forever */ + loop(100); + + /* Ensure that we show up as not running */ + EXPECT_FALSE(media_player_get_is_running(MEDIA_PLAYER(player))); + + /* Update to make running */ + set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time())); + loop(100); + + EXPECT_TRUE(media_player_get_is_running(MEDIA_PLAYER(player))); + + g_clear_object(&in_icon); + g_clear_object(&player); +} diff --git a/tests/sound-menu.cc b/tests/sound-menu.cc new file mode 100644 index 0000000..10c0cb9 --- /dev/null +++ b/tests/sound-menu.cc @@ -0,0 +1,113 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Ted Gould <ted@canonical.com> + */ + +#include <gtest/gtest.h> +#include <gio/gio.h> + +extern "C" { +#include "indicator-sound-service.h" +#include "vala-mocks.h" +} + +class SoundMenuTest : public ::testing::Test +{ + protected: + GTestDBus * bus = nullptr; + + virtual void SetUp() { + bus = g_test_dbus_new(G_TEST_DBUS_NONE); + g_test_dbus_up(bus); + } + + virtual void TearDown() { + g_test_dbus_down(bus); + g_clear_object(&bus); + } + + void verify_item_attribute (GMenuModel * mm, guint index, const gchar * name, GVariant * value) { + g_variant_ref_sink(value); + + gchar * variantstr = g_variant_print(value, TRUE); + g_debug("Expecting item %d to have a '%s' attribute: %s", index, name, variantstr); + + const GVariantType * type = g_variant_get_type(value); + GVariant * itemval = g_menu_model_get_item_attribute_value(mm, index, name, type); + + ASSERT_NE(nullptr, itemval); + EXPECT_TRUE(g_variant_equal(itemval, value)); + + g_variant_unref(value); + } +}; + +TEST_F(SoundMenuTest, BasicObject) { + SoundMenu * menu = sound_menu_new (nullptr, SOUND_MENU_DISPLAY_FLAGS_NONE); + + ASSERT_NE(nullptr, menu); + + g_clear_object(&menu); + return; +} + +TEST_F(SoundMenuTest, AddRemovePlayer) { + SoundMenu * menu = sound_menu_new (nullptr, SOUND_MENU_DISPLAY_FLAGS_NONE); + + MediaPlayerTrack * track = media_player_track_new("Artist", "Title", "Album", "http://art.url"); + + MediaPlayerMock * media = MEDIA_PLAYER_MOCK( + g_object_new(TYPE_MEDIA_PLAYER_MOCK, + "mock-id", "player-id", + "mock-name", "Test Player", + "mock-state", "Playing", + "mock-is-running", TRUE, + "mock-can-raise", FALSE, + "mock-current-track", track, + NULL) + ); + g_clear_object(&track); + + sound_menu_add_player(menu, MEDIA_PLAYER(media)); + + ASSERT_NE(nullptr, menu->menu); + EXPECT_EQ(2, g_menu_model_get_n_items(G_MENU_MODEL(menu->menu))); + + GMenuModel * section = g_menu_model_get_item_link(G_MENU_MODEL(menu->menu), 1, G_MENU_LINK_SECTION); + ASSERT_NE(nullptr, section); + EXPECT_EQ(2, g_menu_model_get_n_items(section)); /* No playlists, so two items */ + + /* Player display */ + verify_item_attribute(section, 0, "action", g_variant_new_string("indicator.player-id")); + verify_item_attribute(section, 0, "x-canonical-type", g_variant_new_string("com.canonical.unity.media-player")); + + /* Player control */ + verify_item_attribute(section, 1, "x-canonical-type", g_variant_new_string("com.canonical.unity.playback-item")); + verify_item_attribute(section, 1, "x-canonical-play-action", g_variant_new_string("indicator.play.player-id")); + verify_item_attribute(section, 1, "x-canonical-next-action", g_variant_new_string("indicator.next.player-id")); + verify_item_attribute(section, 1, "x-canonical-previous-action", g_variant_new_string("indicator.previous.player-id")); + + g_clear_object(§ion); + + sound_menu_remove_player(menu, MEDIA_PLAYER(media)); + + EXPECT_EQ(1, g_menu_model_get_n_items(G_MENU_MODEL(menu->menu))); + + g_clear_object(&media); + g_clear_object(&menu); + return; +} |