aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Gould <ted@gould.cx>2014-03-04 15:40:28 -0600
committerTed Gould <ted@gould.cx>2014-03-04 15:40:28 -0600
commite6fab6c96fe0e9414f214d47c8b762c8a435cc51 (patch)
tree25569bade0f178b7ce44205acb2e5c7ec82c8994
parentf06b9ff784c15e9e1c0ad0840299ed70b5616a74 (diff)
parente9f0b68ab8b9afec9466011b8a8bae3b202b4bf9 (diff)
downloadayatana-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.sound2
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/media-player-list-greeter.vala12
-rw-r--r--src/media-player-user.vala10
-rw-r--r--src/service.vala11
-rw-r--r--src/sound-menu.vala42
-rw-r--r--tests/CMakeLists.txt44
-rw-r--r--tests/accounts-service-mock.h101
-rw-r--r--tests/accounts-service-user.cc60
-rw-r--r--tests/media-player-user.cc210
-rw-r--r--tests/sound-menu.cc113
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(&section);
+
+ 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;
+}