diff options
author | Ted Gould <ted@gould.cx> | 2015-02-19 16:27:24 +0000 |
---|---|---|
committer | CI Train Bot <ci-train-bot@canonical.com> | 2015-02-19 16:27:24 +0000 |
commit | 14be74296b0bd81a797373c4c972916277d0428e (patch) | |
tree | 6833db57605bf225620214218a427fe0f0a4444b /tests | |
parent | 403caf562ba967342b78d5491229fe40cc908361 (diff) | |
parent | 18891aa50808f29365f763cc503e5dfa2e17ab17 (diff) | |
download | ayatana-indicator-sound-14be74296b0bd81a797373c4c972916277d0428e.tar.gz ayatana-indicator-sound-14be74296b0bd81a797373c4c972916277d0428e.tar.bz2 ayatana-indicator-sound-14be74296b0bd81a797373c4c972916277d0428e.zip |
Add notifications mock and tests
Approved by: Jussi Pakkanen, PS Jenkins bot
Diffstat (limited to 'tests')
-rw-r--r-- | tests/CMakeLists.txt | 26 | ||||
-rw-r--r-- | tests/gtest-gvariant.h | 110 | ||||
-rw-r--r-- | tests/indicator-test.cc | 6 | ||||
-rw-r--r-- | tests/media-player-list-mock.vala | 25 | ||||
-rw-r--r-- | tests/notifications-mock.h | 155 | ||||
-rw-r--r-- | tests/notifications-test.cc | 349 | ||||
-rw-r--r-- | tests/volume-control-mock.vala | 47 | ||||
-rw-r--r-- | tests/volume-control-test.cc | 4 |
8 files changed, 720 insertions, 2 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 38a76ae..6e30bf5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -65,6 +65,14 @@ vala_add(vala-mocks media-player-mock.vala ) +vala_add(vala-mocks + media-player-list-mock.vala +) + +vala_add(vala-mocks + volume-control-mock.vala +) + vala_finish(vala-mocks SOURCES vala_mocks_VALA_SOURCES @@ -184,6 +192,24 @@ target_link_libraries ( add_test(sound-menu-test sound-menu-test) ########################### +# Notification Test +########################### + +include_directories(${CMAKE_SOURCE_DIR}/src) +add_executable (notifications-test notifications-test.cc) +target_link_libraries ( + notifications-test + indicator-sound-service-lib + vala-mocks-lib + pulse-mock + gtest + ${SOUNDSERVICE_LIBRARIES} + ${TEST_LIBRARIES} +) + +add_test(notifications-test notifications-test) + +########################### # Accounts Service User ########################### diff --git a/tests/gtest-gvariant.h b/tests/gtest-gvariant.h new file mode 100644 index 0000000..38fde0f --- /dev/null +++ b/tests/gtest-gvariant.h @@ -0,0 +1,110 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Ted Gould <ted@canonical.com> + */ + +#include <gtest/gtest.h> +#include <gio/gio.h> + +namespace GTestGVariant { + +testing::AssertionResult expectVariantEqual (const gchar * expectStr, const gchar * haveStr, GVariant * expect, GVariant * have) +{ + if (expect == nullptr && have == nullptr) { + auto result = testing::AssertionSuccess(); + return result; + } + + if (expect == nullptr || have == nullptr) { + gchar * havePrint; + if (have == nullptr) { + havePrint = g_strdup("(nullptr)"); + } else { + havePrint = g_variant_print(have, TRUE); + } + + auto result = testing::AssertionFailure(); + result << + " Result: " << haveStr << std::endl << + " Value: " << havePrint << std::endl << + " Expected: " << expectStr << std::endl; + + g_free(havePrint); + return result; + } + + if (g_variant_equal(expect, have)) { + auto result = testing::AssertionSuccess(); + return result; + } else { + gchar * havePrint = g_variant_print(have, TRUE); + gchar * expectPrint = g_variant_print(expect, TRUE); + + auto result = testing::AssertionFailure(); + result << + " Result: " << haveStr << std::endl << + " Value: " << havePrint << std::endl << + " Expected: " << expectStr << std::endl << + " Expected: " << expectPrint << std::endl; + + g_free(havePrint); + g_free(expectPrint); + + return result; + } +} + +testing::AssertionResult expectVariantEqual (const gchar * expectStr, const gchar * haveStr, std::shared_ptr<GVariant> expect, std::shared_ptr<GVariant> have) +{ + return expectVariantEqual(expectStr, haveStr, expect.get(), have.get()); +} + +testing::AssertionResult expectVariantEqual (const gchar * expectStr, const gchar * haveStr, const char * expect, std::shared_ptr<GVariant> have) +{ + auto expectv = std::shared_ptr<GVariant>([expect] { + auto variant = g_variant_parse(nullptr, expect, nullptr, nullptr, nullptr); + if (variant != nullptr) + g_variant_ref_sink(variant); + return variant; + }(), + [](GVariant * variant) { + if (variant != nullptr) + g_variant_unref(variant); + }); + + return expectVariantEqual(expectStr, haveStr, expectv, have); +} + +testing::AssertionResult expectVariantEqual (const gchar * expectStr, const gchar * haveStr, const char * expect, GVariant * have) +{ + auto havep = std::shared_ptr<GVariant>([have] { + if (have != nullptr) + g_variant_ref_sink(have); + return have; + }(), + [](GVariant * variant) { + if (variant != nullptr) + g_variant_unref(variant); + }); + + return expectVariantEqual(expectStr, haveStr, expect, havep); +} + +}; // ns GTestGVariant + +#define EXPECT_GVARIANT_EQ(expect, have) \ + EXPECT_PRED_FORMAT2(GTestGVariant::expectVariantEqual, expect, have) diff --git a/tests/indicator-test.cc b/tests/indicator-test.cc index f7d0b2b..b41a1ab 100644 --- a/tests/indicator-test.cc +++ b/tests/indicator-test.cc @@ -22,6 +22,7 @@ #include "indicator-fixture.h" #include "accounts-service-mock.h" +#include "notifications-mock.h" class IndicatorTest : public IndicatorFixture { @@ -32,6 +33,7 @@ protected: } std::shared_ptr<AccountsServiceMock> as; + std::shared_ptr<NotificationsMock> notification; virtual void SetUp() override { @@ -45,12 +47,16 @@ protected: as = std::make_shared<AccountsServiceMock>(); addMock(*as); + notification = std::make_shared<NotificationsMock>(); + addMock(*notification); + IndicatorFixture::SetUp(); } virtual void TearDown() override { as.reset(); + notification.reset(); IndicatorFixture::TearDown(); } diff --git a/tests/media-player-list-mock.vala b/tests/media-player-list-mock.vala new file mode 100644 index 0000000..44a6ae6 --- /dev/null +++ b/tests/media-player-list-mock.vala @@ -0,0 +1,25 @@ +/* + * 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> + */ + +public class MediaPlayerListMock : MediaPlayerList { + public override MediaPlayerList.Iterator iterator () { return new MediaPlayerList.Iterator(); } + + public override void sync (string[] ids) { return; } +} + diff --git a/tests/notifications-mock.h b/tests/notifications-mock.h new file mode 100644 index 0000000..b0f3b74 --- /dev/null +++ b/tests/notifications-mock.h @@ -0,0 +1,155 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Ted Gould <ted@canonical.com> + */ + +#include <algorithm> +#include <map> +#include <memory> +#include <type_traits> + +#include <libdbustest/dbus-test.h> + +class NotificationsMock +{ + DbusTestDbusMock * mock = nullptr; + DbusTestDbusMockObject * baseobj = nullptr; + + public: + NotificationsMock (std::vector<std::string> capabilities = {"body", "body-markup", "icon-static", "image/svg+xml", "x-canonical-private-synchronous", "x-canonical-append", "x-canonical-private-icon-only", "x-canonical-truncation", "private-synchronous", "append", "private-icon-only", "truncation"}) { + mock = dbus_test_dbus_mock_new("org.freedesktop.Notifications"); + dbus_test_task_set_bus(DBUS_TEST_TASK(mock), DBUS_TEST_SERVICE_BUS_SESSION); + dbus_test_task_set_name(DBUS_TEST_TASK(mock), "Notify"); + + baseobj =dbus_test_dbus_mock_get_object(mock, "/org/freedesktop/Notifications", "org.freedesktop.Notifications", nullptr); + + std::string capspython("ret = "); + capspython += vector2py(capabilities); + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "GetCapabilities", nullptr, G_VARIANT_TYPE("as"), + capspython.c_str(), nullptr); + + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "GetServerInformation", nullptr, G_VARIANT_TYPE("(ssss)"), + "ret = ['notification-mock', 'Testing harness', '1.0', '1.1']", nullptr); + + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "Notify", G_VARIANT_TYPE("(susssasa{sv}i)"), G_VARIANT_TYPE("u"), + "ret = 10", nullptr); + + dbus_test_dbus_mock_object_add_method(mock, baseobj, + "CloseNotification", G_VARIANT_TYPE("u"), nullptr, + "", nullptr); + } + + ~NotificationsMock () { + g_debug("Destroying the Notifications Mock"); + g_clear_object(&mock); + } + + std::string vector2py (std::vector<std::string> vect) { + std::string retval("[ "); + + std::for_each(vect.begin(), vect.end() - 1, [&retval](std::string entry) { + retval += "'"; + retval += entry; + retval += "', "; + }); + + retval += "'"; + retval += *(vect.end() - 1); + retval += "']"; + + return retval; + } + + operator std::shared_ptr<DbusTestTask> () { + std::shared_ptr<DbusTestTask> retval(DBUS_TEST_TASK(g_object_ref(mock)), [](DbusTestTask * task) { g_clear_object(&task); }); + return retval; + } + + operator DbusTestTask* () { + return DBUS_TEST_TASK(mock); + } + + operator DbusTestDbusMock* () { + return mock; + } + + struct Notification { + std::string app_name; + unsigned int replace_id; + std::string app_icon; + std::string summary; + std::string body; + std::vector<std::string> actions; + std::map<std::string, std::shared_ptr<GVariant>> hints; + int timeout; + }; + + std::shared_ptr<GVariant> childGet (GVariant * tuple, gsize index) { + return std::shared_ptr<GVariant>(g_variant_get_child_value(tuple, index), + [](GVariant * v){ if (v != nullptr) g_variant_unref(v); }); + } + + std::vector<Notification> getNotifications (void) { + std::vector<Notification> notifications; + + unsigned int cnt, i; + auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, baseobj, "Notify", &cnt, nullptr); + + for (i = 0; i < cnt; i++) { + auto call = calls[i]; + Notification notification; + + notification.app_name = g_variant_get_string(childGet(call.params, 0).get(), nullptr); + notification.replace_id = g_variant_get_uint32(childGet(call.params, 1).get()); + notification.app_icon = g_variant_get_string(childGet(call.params, 2).get(), nullptr); + notification.summary = g_variant_get_string(childGet(call.params, 3).get(), nullptr); + notification.body = g_variant_get_string(childGet(call.params, 4).get(), nullptr); + notification.timeout = g_variant_get_int32(childGet(call.params, 7).get()); + + auto vactions = childGet(call.params, 5); + GVariantIter iactions = {0}; + g_variant_iter_init(&iactions, vactions.get()); + const gchar * action = nullptr; + while (g_variant_iter_loop(&iactions, "&s", &action)) { + std::string saction(action); + notification.actions.push_back(saction); + } + + auto vhints = childGet(call.params, 6); + GVariantIter ihints = {0}; + g_variant_iter_init(&ihints, vhints.get()); + const gchar * hint_key = nullptr; + GVariant * hint_value = nullptr; + while (g_variant_iter_loop(&ihints, "{&sv}", &hint_key, &hint_value)) { + std::string key(hint_key); + std::shared_ptr<GVariant> value(g_variant_ref(hint_value), [](GVariant * v){ if (v != nullptr) g_variant_unref(v); }); + notification.hints[key] = value; + } + + notifications.push_back(notification); + } + + return notifications; + } + + bool clearNotifications (void) { + return dbus_test_dbus_mock_object_clear_method_calls(mock, baseobj, nullptr); + } +}; diff --git a/tests/notifications-test.cc b/tests/notifications-test.cc new file mode 100644 index 0000000..79b6e8e --- /dev/null +++ b/tests/notifications-test.cc @@ -0,0 +1,349 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Ted Gould <ted@canonical.com> + */ + +#include <memory> + +#include <gtest/gtest.h> +#include <gio/gio.h> +#include <libdbustest/dbus-test.h> +#include <libnotify/notify.h> + +#include "notifications-mock.h" +#include "gtest-gvariant.h" + +extern "C" { +#include "indicator-sound-service.h" +#include "vala-mocks.h" +} + +class NotificationsTest : public ::testing::Test +{ + protected: + DbusTestService * service = NULL; + + GDBusConnection * session = NULL; + std::shared_ptr<NotificationsMock> notifications; + + virtual void SetUp() { + g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE); + g_setenv("GSETTINGS_BACKEND", "memory", TRUE); + + service = dbus_test_service_new(NULL); + dbus_test_service_set_bus(service, DBUS_TEST_SERVICE_BUS_SESSION); + + /* Useful for debugging test failures, not needed all the time (until it fails) */ + #if 0 + auto bustle = std::shared_ptr<DbusTestTask>([]() { + DbusTestTask * bustle = DBUS_TEST_TASK(dbus_test_bustle_new("notifications-test.bustle")); + dbus_test_task_set_name(bustle, "Bustle"); + dbus_test_task_set_bus(bustle, DBUS_TEST_SERVICE_BUS_SESSION); + return bustle; + }(), [](DbusTestTask * bustle) { + g_clear_object(&bustle); + }); + dbus_test_service_add_task(service, bustle.get()); + #endif + + notifications = std::make_shared<NotificationsMock>(); + + dbus_test_service_add_task(service, (DbusTestTask*)*notifications); + dbus_test_service_start_tasks(service); + + 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); + + /* This is done in main.c */ + notify_init("indicator-sound"); + } + + virtual void TearDown() { + if (notify_is_initted()) + notify_uninit(); + + notifications.reset(); + g_clear_object(&service); + + g_object_unref(session); + + unsigned int cleartry = 0; + while (session != NULL && cleartry < 100) { + loop(100); + cleartry++; + } + + ASSERT_EQ(nullptr, session); + } + + 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); + } + + static int unref_idle (gpointer user_data) { + g_variant_unref(static_cast<GVariant *>(user_data)); + return G_SOURCE_REMOVE; + } + + std::shared_ptr<MediaPlayerList> playerListMock () { + auto playerList = std::shared_ptr<MediaPlayerList>( + MEDIA_PLAYER_LIST(media_player_list_mock_new()), + [](MediaPlayerList * list) { + g_clear_object(&list); + }); + return playerList; + } + + std::shared_ptr<VolumeControl> volumeControlMock () { + auto volumeControl = std::shared_ptr<VolumeControl>( + VOLUME_CONTROL(volume_control_mock_new()), + [](VolumeControl * control){ + g_clear_object(&control); + }); + return volumeControl; + } + + std::shared_ptr<IndicatorSoundService> standardService (std::shared_ptr<VolumeControl> volumeControl, std::shared_ptr<MediaPlayerList> playerList) { + auto soundService = std::shared_ptr<IndicatorSoundService>( + indicator_sound_service_new(playerList.get(), volumeControl.get(), nullptr), + [](IndicatorSoundService * service){ + g_clear_object(&service); + }); + + return soundService; + } +}; + +TEST_F(NotificationsTest, BasicObject) { + auto soundService = standardService(volumeControlMock(), playerListMock()); + + /* Give some time settle */ + loop(50); + + /* Auto free */ +} + +TEST_F(NotificationsTest, VolumeChanges) { + auto volumeControl = volumeControlMock(); + auto soundService = standardService(volumeControl, playerListMock()); + + /* Set a volume */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.50); + loop(50); + auto notev = notifications->getNotifications(); + ASSERT_EQ(1, notev.size()); + EXPECT_EQ("indicator-sound", notev[0].app_name); + EXPECT_EQ("Volume", notev[0].summary); + EXPECT_EQ(0, notev[0].actions.size()); + EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-private-synchronous"]); + EXPECT_GVARIANT_EQ("@i 50", notev[0].hints["value"]); + + /* Set a different volume */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.60); + loop(50); + notev = notifications->getNotifications(); + ASSERT_EQ(1, notev.size()); + EXPECT_GVARIANT_EQ("@i 60", notev[0].hints["value"]); + + /* Set the same volume */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.60); + loop(50); + notev = notifications->getNotifications(); + ASSERT_EQ(0, notev.size()); + + /* Change just a little */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.60001); + loop(50); + notev = notifications->getNotifications(); + ASSERT_EQ(0, notev.size()); +} + +TEST_F(NotificationsTest, StreamChanges) { + auto volumeControl = volumeControlMock(); + auto soundService = standardService(volumeControl, playerListMock()); + + /* Set a volume */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.5); + loop(50); + auto notev = notifications->getNotifications(); + ASSERT_EQ(1, notev.size()); + + /* Change Streams, no volume change */ + notifications->clearNotifications(); + volume_control_mock_set_mock_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), "alarm"); + volume_control_set_volume(volumeControl.get(), 0.5); + loop(50); + notev = notifications->getNotifications(); + EXPECT_EQ(0, notev.size()); + + /* Change Streams, volume change */ + notifications->clearNotifications(); + volume_control_mock_set_mock_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), "alert"); + volume_control_set_volume(volumeControl.get(), 0.60); + loop(50); + notev = notifications->getNotifications(); + EXPECT_EQ(0, notev.size()); + + /* Change Streams, no volume change, volume up */ + notifications->clearNotifications(); + volume_control_mock_set_mock_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), "multimedia"); + volume_control_set_volume(volumeControl.get(), 0.60); + loop(50); + volume_control_set_volume(volumeControl.get(), 0.65); + notev = notifications->getNotifications(); + EXPECT_EQ(1, notev.size()); + EXPECT_GVARIANT_EQ("@i 65", notev[0].hints["value"]); +} + +TEST_F(NotificationsTest, IconTesting) { + auto volumeControl = volumeControlMock(); + auto soundService = standardService(volumeControl, playerListMock()); + + /* Set an initial volume */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.5); + loop(50); + auto notev = notifications->getNotifications(); + ASSERT_EQ(1, notev.size()); + + /* Generate a set of notifications */ + notifications->clearNotifications(); + for (float i = 0.0; i < 1.01; i += 0.1) { + volume_control_set_volume(volumeControl.get(), i); + } + + loop(50); + notev = notifications->getNotifications(); + ASSERT_EQ(11, notev.size()); + + EXPECT_EQ("audio-volume-muted", notev[0].app_icon); + EXPECT_EQ("audio-volume-low", notev[1].app_icon); + EXPECT_EQ("audio-volume-low", notev[2].app_icon); + EXPECT_EQ("audio-volume-medium", notev[3].app_icon); + EXPECT_EQ("audio-volume-medium", notev[4].app_icon); + EXPECT_EQ("audio-volume-medium", notev[5].app_icon); + EXPECT_EQ("audio-volume-medium", notev[6].app_icon); + EXPECT_EQ("audio-volume-high", notev[7].app_icon); + EXPECT_EQ("audio-volume-high", notev[8].app_icon); + EXPECT_EQ("audio-volume-high", notev[9].app_icon); + EXPECT_EQ("audio-volume-high", notev[10].app_icon); +} + +TEST_F(NotificationsTest, ServerRestart) { + auto volumeControl = volumeControlMock(); + auto soundService = standardService(volumeControl, playerListMock()); + + /* Set a volume */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.50); + loop(50); + auto notev = notifications->getNotifications(); + ASSERT_EQ(1, notev.size()); + + /* Restart server without sync notifications */ + notifications->clearNotifications(); + dbus_test_service_remove_task(service, (DbusTestTask*)*notifications); + notifications.reset(); + + loop(50); + + notifications = std::make_shared<NotificationsMock>(std::vector<std::string>({"body", "body-markup", "icon-static"})); + dbus_test_service_add_task(service, (DbusTestTask*)*notifications); + dbus_test_task_run((DbusTestTask*)*notifications); + + /* Change the volume */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.60); + loop(50); + notev = notifications->getNotifications(); + ASSERT_EQ(0, notev.size()); + + /* Put a good server back */ + dbus_test_service_remove_task(service, (DbusTestTask*)*notifications); + notifications.reset(); + + loop(50); + + notifications = std::make_shared<NotificationsMock>(); + dbus_test_service_add_task(service, (DbusTestTask*)*notifications); + dbus_test_task_run((DbusTestTask*)*notifications); + + /* Change the volume again */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.70); + loop(50); + notev = notifications->getNotifications(); + ASSERT_EQ(1, notev.size()); +} + +TEST_F(NotificationsTest, HighVolume) { + auto volumeControl = volumeControlMock(); + auto soundService = standardService(volumeControl, playerListMock()); + + /* Set a volume */ + notifications->clearNotifications(); + volume_control_set_volume(volumeControl.get(), 0.50); + loop(50); + auto notev = notifications->getNotifications(); + ASSERT_EQ(1, notev.size()); + EXPECT_EQ("Volume", notev[0].summary); + EXPECT_EQ("", notev[0].body); + EXPECT_GVARIANT_EQ("@s 'false'", notev[0].hints["x-canonical-value-bar-tint"]); + + /* Set high volume with volume change */ + notifications->clearNotifications(); + volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), TRUE); + volume_control_set_volume(volumeControl.get(), 0.90); + loop(50); + notev = notifications->getNotifications(); + ASSERT_LT(0, notev.size()); /* This passes with one or two since it would just be an update to the first if a second was sent */ + EXPECT_EQ("Volume", notev[0].summary); + EXPECT_EQ("High volume", notev[0].body); + EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]); + + /* Move it back */ + volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), FALSE); + volume_control_set_volume(volumeControl.get(), 0.50); + loop(50); + + /* Set high volume without level change */ + /* NOTE: This can happen if headphones are plugged in */ + notifications->clearNotifications(); + volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), TRUE); + loop(50); + notev = notifications->getNotifications(); + ASSERT_EQ(1, notev.size()); + EXPECT_EQ("Volume", notev[0].summary); + EXPECT_EQ("High volume", notev[0].body); + EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]); +} diff --git a/tests/volume-control-mock.vala b/tests/volume-control-mock.vala new file mode 100644 index 0000000..4b846bf --- /dev/null +++ b/tests/volume-control-mock.vala @@ -0,0 +1,47 @@ +/* + * -*- Mode:Vala; indent-tabs-mode:t; tab-width:4; encoding:utf8 -*- + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Ted Gould <ted@canonical.com> + */ + +public class VolumeControlMock : VolumeControl +{ + public string mock_stream { get; set; default = "multimedia"; } + public override string stream { get { return mock_stream; } } + public override bool ready { get; set; } + public override bool active_mic { get; set; } + public bool mock_high_volume { get; set; } + public override bool high_volume { get { return mock_high_volume; } } + public bool mock_mute { get; set; } + public override bool mute { get { return mock_mute; } } + public bool mock_is_playing { get; set; } + public override bool is_playing { get { return mock_is_playing; } } + public override double volume { get; set; } + public override double mic_volume { get; set; } + + public override void set_mute (bool mute) { + + } + + public VolumeControlMock() { + ready = true; + this.notify["mock-stream"].connect(() => this.notify_property("stream")); + this.notify["mock-high-volume"].connect(() => this.notify_property("high-volume")); + this.notify["mock-mute"].connect(() => this.notify_property("mute")); + this.notify["mock-is-playing"].connect(() => this.notify_property("is-playing")); + } +} diff --git a/tests/volume-control-test.cc b/tests/volume-control-test.cc index 9970241..41e1886 100644 --- a/tests/volume-control-test.cc +++ b/tests/volume-control-test.cc @@ -71,13 +71,13 @@ class VolumeControlTest : public ::testing::Test }; TEST_F(VolumeControlTest, BasicObject) { - VolumeControl * control = volume_control_new(); + VolumeControlPulse * control = volume_control_pulse_new(); /* Setup the PA backend */ loop(100); /* Ready */ - EXPECT_TRUE(volume_control_get_ready(control)); + EXPECT_TRUE(volume_control_get_ready(VOLUME_CONTROL(control))); g_clear_object(&control); } |