37
37
class NotificationsTest : public ::testing::Test
40
DbusTestService * service = NULL;
42
GDBusConnection * session = NULL;
43
std::shared_ptr<NotificationsMock> notifications;
45
virtual void SetUp() {
46
g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
47
g_setenv("GSETTINGS_BACKEND", "memory", TRUE);
49
service = dbus_test_service_new(NULL);
50
dbus_test_service_set_bus(service, DBUS_TEST_SERVICE_BUS_SESSION);
52
/* Useful for debugging test failures, not needed all the time (until it fails) */
54
auto bustle = std::shared_ptr<DbusTestTask>([]() {
55
DbusTestTask * bustle = DBUS_TEST_TASK(dbus_test_bustle_new("notifications-test.bustle"));
56
dbus_test_task_set_name(bustle, "Bustle");
57
dbus_test_task_set_bus(bustle, DBUS_TEST_SERVICE_BUS_SESSION);
59
}(), [](DbusTestTask * bustle) {
60
g_clear_object(&bustle);
62
dbus_test_service_add_task(service, bustle.get());
65
notifications = std::make_shared<NotificationsMock>();
67
dbus_test_service_add_task(service, (DbusTestTask*)*notifications);
68
dbus_test_service_start_tasks(service);
70
session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
71
ASSERT_NE(nullptr, session);
72
g_dbus_connection_set_exit_on_close(session, FALSE);
73
g_object_add_weak_pointer(G_OBJECT(session), (gpointer *)&session);
75
/* This is done in main.c */
76
notify_init("indicator-sound");
79
virtual void TearDown() {
80
if (notify_is_initted())
83
notifications.reset();
84
g_clear_object(&service);
86
g_object_unref(session);
88
unsigned int cleartry = 0;
89
while (session != NULL && cleartry < 100) {
94
ASSERT_EQ(nullptr, session);
97
static gboolean timeout_cb (gpointer user_data) {
98
GMainLoop * loop = static_cast<GMainLoop *>(user_data);
99
g_main_loop_quit(loop);
100
return G_SOURCE_REMOVE;
103
void loop (unsigned int ms) {
104
GMainLoop * loop = g_main_loop_new(NULL, FALSE);
105
g_timeout_add(ms, timeout_cb, loop);
106
g_main_loop_run(loop);
107
g_main_loop_unref(loop);
110
void loop_until(const std::function<bool()>& test, unsigned int max_ms=50, unsigned int test_interval_ms=10) {
112
// g_timeout's callback only allows a single pointer,
113
// so use a temporary stack struct to wedge everything into one pointer
114
struct CallbackData {
115
const std::function<bool()>& test;
116
const gint64 deadline;
117
GMainLoop* loop = g_main_loop_new(nullptr, false);
118
CallbackData (const std::function<bool()>& f, unsigned int max_ms):
120
deadline{g_get_monotonic_time() + (max_ms*1000)} {}
121
~CallbackData() {g_main_loop_unref(loop);}
122
} data(test, max_ms);
124
// tell the timer to stop looping on success or deadline
125
auto timerfunc = [](gpointer gdata) -> gboolean {
126
auto& data = *static_cast<CallbackData*>(gdata);
127
if (!data.test() && (g_get_monotonic_time() < data.deadline))
128
return G_SOURCE_CONTINUE;
129
g_main_loop_quit(data.loop);
130
return G_SOURCE_REMOVE;
134
g_timeout_add (std::min(max_ms, test_interval_ms), timerfunc, &data);
135
g_main_loop_run(data.loop);
138
void loop_until_notifications(unsigned int max_seconds=1) {
139
auto test = [this]{ return !notifications->getNotifications().empty(); };
140
loop_until(test, max_seconds);
143
static int unref_idle (gpointer user_data) {
144
g_variant_unref(static_cast<GVariant *>(user_data));
145
return G_SOURCE_REMOVE;
148
std::shared_ptr<MediaPlayerList> playerListMock () {
149
auto playerList = std::shared_ptr<MediaPlayerList>(
150
MEDIA_PLAYER_LIST(media_player_list_mock_new()),
151
[](MediaPlayerList * list) {
152
g_clear_object(&list);
157
std::shared_ptr<IndicatorSoundOptions> optionsMock () {
158
auto options = std::shared_ptr<IndicatorSoundOptions>(
159
INDICATOR_SOUND_OPTIONS(options_mock_new()),
160
[](IndicatorSoundOptions * options){
161
g_clear_object(&options);
166
std::shared_ptr<VolumeControl> volumeControlMock (const std::shared_ptr<IndicatorSoundOptions>& optionsMock) {
167
auto volumeControl = std::shared_ptr<VolumeControl>(
168
VOLUME_CONTROL(volume_control_mock_new(optionsMock.get())),
169
[](VolumeControl * control){
170
g_clear_object(&control);
172
return volumeControl;
175
std::shared_ptr<VolumeWarning> volumeWarningMock (const std::shared_ptr<IndicatorSoundOptions>& optionsMock) {
176
auto volumeWarning = std::shared_ptr<VolumeWarning>(
177
VOLUME_WARNING(volume_warning_mock_new(optionsMock.get())),
178
[](VolumeWarning * warning){
179
g_clear_object(&warning);
181
return volumeWarning;
184
std::shared_ptr<IndicatorSoundService> standardService (
185
const std::shared_ptr<VolumeControl>& volumeControl,
186
const std::shared_ptr<MediaPlayerList>& playerList,
187
const std::shared_ptr<IndicatorSoundOptions>& options,
188
const std::shared_ptr<VolumeWarning>& warning) {
189
auto soundService = std::shared_ptr<IndicatorSoundService>(
190
indicator_sound_service_new(playerList.get(), volumeControl.get(), nullptr, options.get(), warning.get()),
191
[](IndicatorSoundService * service){
192
g_clear_object(&service);
198
void setMockVolume (std::shared_ptr<VolumeControl> volumeControl, double volume, VolumeControlVolumeReasons reason = VOLUME_CONTROL_VOLUME_REASONS_USER_KEYPRESS) {
199
VolumeControlVolume * vol = volume_control_volume_new();
200
vol->volume = volume;
201
vol->reason = reason;
203
volume_control_set_volume(volumeControl.get(), vol);
207
void setIndicatorShown (bool shown) {
208
auto bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
210
g_dbus_connection_call(bus,
211
g_dbus_connection_get_unique_name(bus),
212
"/com/canonical/indicator/sound",
215
g_variant_new("(sva{sv})", "indicator-shown", g_variant_new_boolean(shown), nullptr),
217
G_DBUS_CALL_FLAGS_NONE,
223
g_clear_object(&bus);
40
DbusTestService * service = NULL;
42
GDBusConnection * session = NULL;
43
std::shared_ptr<NotificationsMock> notifications;
45
virtual void SetUp() {
46
g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
47
g_setenv("GSETTINGS_BACKEND", "memory", TRUE);
49
service = dbus_test_service_new(NULL);
50
dbus_test_service_set_bus(service, DBUS_TEST_SERVICE_BUS_SESSION);
52
/* Useful for debugging test failures, not needed all the time (until it fails) */
54
auto bustle = std::shared_ptr<DbusTestTask>([]() {
55
DbusTestTask * bustle = DBUS_TEST_TASK(dbus_test_bustle_new("notifications-test.bustle"));
56
dbus_test_task_set_name(bustle, "Bustle");
57
dbus_test_task_set_bus(bustle, DBUS_TEST_SERVICE_BUS_SESSION);
59
}(), [](DbusTestTask * bustle) {
60
g_clear_object(&bustle);
62
dbus_test_service_add_task(service, bustle.get());
65
notifications = std::make_shared<NotificationsMock>();
67
dbus_test_service_add_task(service, (DbusTestTask*)*notifications);
68
dbus_test_service_start_tasks(service);
70
session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
71
ASSERT_NE(nullptr, session);
72
g_dbus_connection_set_exit_on_close(session, FALSE);
73
g_object_add_weak_pointer(G_OBJECT(session), (gpointer *)&session);
75
/* This is done in main.c */
76
notify_init("indicator-sound");
79
virtual void TearDown() {
80
if (notify_is_initted())
83
notifications.reset();
84
g_clear_object(&service);
86
g_object_unref(session);
88
unsigned int cleartry = 0;
89
while (session != NULL && cleartry < 100) {
94
ASSERT_EQ(nullptr, session);
97
static gboolean timeout_cb (gpointer user_data) {
98
GMainLoop * loop = static_cast<GMainLoop *>(user_data);
99
g_main_loop_quit(loop);
100
return G_SOURCE_REMOVE;
103
void loop (unsigned int ms) {
104
GMainLoop * loop = g_main_loop_new(NULL, FALSE);
105
g_timeout_add(ms, timeout_cb, loop);
106
g_main_loop_run(loop);
107
g_main_loop_unref(loop);
110
void loop_until(const std::function<bool()>& test, unsigned int max_ms=50, unsigned int test_interval_ms=10) {
112
// g_timeout's callback only allows a single pointer,
113
// so use a temporary stack struct to wedge everything into one pointer
114
struct CallbackData {
115
const std::function<bool()>& test;
116
const gint64 deadline;
117
GMainLoop* loop = g_main_loop_new(nullptr, false);
118
CallbackData (const std::function<bool()>& f, unsigned int max_ms):
120
deadline{g_get_monotonic_time() + (max_ms*1000)} {}
121
~CallbackData() {g_main_loop_unref(loop);}
122
} data(test, max_ms);
124
// tell the timer to stop looping on success or deadline
125
auto timerfunc = [](gpointer gdata) -> gboolean {
126
auto& data = *static_cast<CallbackData*>(gdata);
127
if (!data.test() && (g_get_monotonic_time() < data.deadline))
128
return G_SOURCE_CONTINUE;
129
g_main_loop_quit(data.loop);
130
return G_SOURCE_REMOVE;
134
g_timeout_add (std::min(max_ms, test_interval_ms), timerfunc, &data);
135
g_main_loop_run(data.loop);
138
void loop_until_notifications(unsigned int max_seconds=1) {
139
auto test = [this]{ return !notifications->getNotifications().empty(); };
140
loop_until(test, max_seconds);
143
static int unref_idle (gpointer user_data) {
144
g_variant_unref(static_cast<GVariant *>(user_data));
145
return G_SOURCE_REMOVE;
148
std::shared_ptr<MediaPlayerList> playerListMock () {
149
auto playerList = std::shared_ptr<MediaPlayerList>(
150
MEDIA_PLAYER_LIST(media_player_list_mock_new()),
151
[](MediaPlayerList * list) {
152
g_clear_object(&list);
157
std::shared_ptr<IndicatorSoundOptions> optionsMock () {
158
auto options = std::shared_ptr<IndicatorSoundOptions>(
159
INDICATOR_SOUND_OPTIONS(options_mock_new()),
160
[](IndicatorSoundOptions * options){
161
g_clear_object(&options);
166
std::shared_ptr<VolumeControl> volumeControlMock (const std::shared_ptr<IndicatorSoundOptions>& optionsMock) {
167
auto volumeControl = std::shared_ptr<VolumeControl>(
168
VOLUME_CONTROL(volume_control_mock_new(optionsMock.get())),
169
[](VolumeControl * control){
170
g_clear_object(&control);
172
return volumeControl;
175
std::shared_ptr<VolumeWarning> volumeWarningMock (const std::shared_ptr<IndicatorSoundOptions>& optionsMock) {
176
auto volumeWarning = std::shared_ptr<VolumeWarning>(
177
VOLUME_WARNING(volume_warning_mock_new(optionsMock.get())),
178
[](VolumeWarning * warning){
179
g_clear_object(&warning);
181
return volumeWarning;
184
std::shared_ptr<IndicatorSoundService> standardService (
185
const std::shared_ptr<VolumeControl>& volumeControl,
186
const std::shared_ptr<MediaPlayerList>& playerList,
187
const std::shared_ptr<IndicatorSoundOptions>& options,
188
const std::shared_ptr<VolumeWarning>& warning,
189
const std::shared_ptr<AccountsServiceAccess>& accounts_service_access) {
190
auto soundService = std::shared_ptr<IndicatorSoundService>(
191
indicator_sound_service_new(playerList.get(), volumeControl.get(), nullptr, options.get(), warning.get(), accounts_service_access.get()),
192
[](IndicatorSoundService * service){
193
g_clear_object(&service);
199
void setMockVolume (std::shared_ptr<VolumeControl> volumeControl, double volume, VolumeControlVolumeReasons reason = VOLUME_CONTROL_VOLUME_REASONS_USER_KEYPRESS) {
200
VolumeControlVolume * vol = volume_control_volume_new();
201
vol->volume = volume;
202
vol->reason = reason;
204
volume_control_set_volume(volumeControl.get(), vol);
208
void setIndicatorShown (bool shown) {
209
auto bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
211
g_dbus_connection_call(bus,
212
g_dbus_connection_get_unique_name(bus),
213
"/com/canonical/indicator/sound",
216
g_variant_new("(sva{sv})", "indicator-shown", g_variant_new_boolean(shown), nullptr),
218
G_DBUS_CALL_FLAGS_NONE,
224
g_clear_object(&bus);
228
229
TEST_F(NotificationsTest, BasicObject) {
229
auto options = optionsMock();
230
auto volumeControl = volumeControlMock(options);
231
auto volumeWarning = volumeWarningMock(options);
232
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
234
/* Give some time settle */
230
auto options = optionsMock();
231
auto volumeControl = volumeControlMock(options);
232
auto volumeWarning = volumeWarningMock(options);
233
auto accountsService = std::make_shared<AccountsServiceAccess>();
234
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
236
/* Give some time settle */
240
242
TEST_F(NotificationsTest, VolumeChanges) {
241
auto options = optionsMock();
242
auto volumeControl = volumeControlMock(options);
243
auto volumeWarning = volumeWarningMock(options);
244
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
247
notifications->clearNotifications();
248
setMockVolume(volumeControl, 0.50);
250
auto notev = notifications->getNotifications();
251
ASSERT_EQ(1, notev.size());
252
EXPECT_EQ("indicator-sound", notev[0].app_name);
253
EXPECT_EQ("Volume", notev[0].summary);
254
EXPECT_EQ(0, notev[0].actions.size());
255
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-private-synchronous"]);
256
EXPECT_GVARIANT_EQ("@i 50", notev[0].hints["value"]);
258
/* Set a different volume */
259
notifications->clearNotifications();
260
setMockVolume(volumeControl, 0.60);
262
notev = notifications->getNotifications();
263
ASSERT_EQ(1, notev.size());
264
EXPECT_GVARIANT_EQ("@i 60", notev[0].hints["value"]);
266
/* Have pulse set a volume */
267
notifications->clearNotifications();
268
setMockVolume(volumeControl, 0.70, VOLUME_CONTROL_VOLUME_REASONS_PULSE_CHANGE);
270
notev = notifications->getNotifications();
271
ASSERT_EQ(0, notev.size());
273
/* Have AS set the volume */
274
notifications->clearNotifications();
275
setMockVolume(volumeControl, 0.80, VOLUME_CONTROL_VOLUME_REASONS_ACCOUNTS_SERVICE_SET);
277
notev = notifications->getNotifications();
278
ASSERT_EQ(0, notev.size());
243
auto options = optionsMock();
244
auto volumeControl = volumeControlMock(options);
245
auto volumeWarning = volumeWarningMock(options);
246
auto accountsService = std::make_shared<AccountsServiceAccess>();
247
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
250
notifications->clearNotifications();
251
setMockVolume(volumeControl, 0.50);
253
auto notev = notifications->getNotifications();
254
ASSERT_EQ(1, notev.size());
255
EXPECT_EQ("indicator-sound", notev[0].app_name);
256
EXPECT_EQ("Volume", notev[0].summary);
257
EXPECT_EQ(0, notev[0].actions.size());
258
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-private-synchronous"]);
259
EXPECT_GVARIANT_EQ("@i 50", notev[0].hints["value"]);
261
/* Set a different volume */
262
notifications->clearNotifications();
263
setMockVolume(volumeControl, 0.60);
265
notev = notifications->getNotifications();
266
ASSERT_EQ(1, notev.size());
267
EXPECT_GVARIANT_EQ("@i 60", notev[0].hints["value"]);
269
/* Have pulse set a volume */
270
notifications->clearNotifications();
271
setMockVolume(volumeControl, 0.70, VOLUME_CONTROL_VOLUME_REASONS_PULSE_CHANGE);
273
notev = notifications->getNotifications();
274
ASSERT_EQ(0, notev.size());
276
/* Have AS set the volume */
277
notifications->clearNotifications();
278
setMockVolume(volumeControl, 0.80, VOLUME_CONTROL_VOLUME_REASONS_ACCOUNTS_SERVICE_SET);
280
notev = notifications->getNotifications();
281
ASSERT_EQ(0, notev.size());
281
284
TEST_F(NotificationsTest, StreamChanges) {
282
auto options = optionsMock();
283
auto volumeControl = volumeControlMock(options);
284
auto volumeWarning = volumeWarningMock(options);
285
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
288
notifications->clearNotifications();
289
setMockVolume(volumeControl, 0.5);
291
auto notev = notifications->getNotifications();
292
ASSERT_EQ(1, notev.size());
294
/* Change Streams, no volume change */
295
notifications->clearNotifications();
296
volume_control_mock_mock_set_active_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), VOLUME_CONTROL_STREAM_ALARM);
297
setMockVolume(volumeControl, 0.5, VOLUME_CONTROL_VOLUME_REASONS_VOLUME_STREAM_CHANGE);
299
notev = notifications->getNotifications();
300
EXPECT_EQ(0, notev.size());
302
/* Change Streams, volume change */
303
notifications->clearNotifications();
304
volume_control_mock_mock_set_active_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), VOLUME_CONTROL_STREAM_ALERT);
305
setMockVolume(volumeControl, 0.6, VOLUME_CONTROL_VOLUME_REASONS_VOLUME_STREAM_CHANGE);
307
notev = notifications->getNotifications();
308
EXPECT_EQ(0, notev.size());
310
/* Change Streams, no volume change, volume up */
311
notifications->clearNotifications();
312
volume_control_mock_mock_set_active_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), VOLUME_CONTROL_STREAM_MULTIMEDIA);
313
setMockVolume(volumeControl, 0.6, VOLUME_CONTROL_VOLUME_REASONS_VOLUME_STREAM_CHANGE);
315
setMockVolume(volumeControl, 0.65);
316
notev = notifications->getNotifications();
317
EXPECT_EQ(1, notev.size());
318
EXPECT_GVARIANT_EQ("@i 65", notev[0].hints["value"]);
285
auto options = optionsMock();
286
auto volumeControl = volumeControlMock(options);
287
auto volumeWarning = volumeWarningMock(options);
288
auto accountsService = std::make_shared<AccountsServiceAccess>();
289
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
292
notifications->clearNotifications();
293
setMockVolume(volumeControl, 0.5);
295
auto notev = notifications->getNotifications();
296
ASSERT_EQ(1, notev.size());
298
/* Change Streams, no volume change */
299
notifications->clearNotifications();
300
volume_control_mock_mock_set_active_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), VOLUME_CONTROL_STREAM_ALARM);
301
setMockVolume(volumeControl, 0.5, VOLUME_CONTROL_VOLUME_REASONS_VOLUME_STREAM_CHANGE);
303
notev = notifications->getNotifications();
304
EXPECT_EQ(0, notev.size());
306
/* Change Streams, volume change */
307
notifications->clearNotifications();
308
volume_control_mock_mock_set_active_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), VOLUME_CONTROL_STREAM_ALERT);
309
setMockVolume(volumeControl, 0.6, VOLUME_CONTROL_VOLUME_REASONS_VOLUME_STREAM_CHANGE);
311
notev = notifications->getNotifications();
312
EXPECT_EQ(0, notev.size());
314
/* Change Streams, no volume change, volume up */
315
notifications->clearNotifications();
316
volume_control_mock_mock_set_active_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), VOLUME_CONTROL_STREAM_MULTIMEDIA);
317
setMockVolume(volumeControl, 0.6, VOLUME_CONTROL_VOLUME_REASONS_VOLUME_STREAM_CHANGE);
319
setMockVolume(volumeControl, 0.65);
320
notev = notifications->getNotifications();
321
EXPECT_EQ(1, notev.size());
322
EXPECT_GVARIANT_EQ("@i 65", notev[0].hints["value"]);
321
325
TEST_F(NotificationsTest, IconTesting) {
322
auto options = optionsMock();
323
auto volumeControl = volumeControlMock(options);
324
auto volumeWarning = volumeWarningMock(options);
325
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
327
/* Set an initial volume */
328
notifications->clearNotifications();
329
setMockVolume(volumeControl, 0.5);
331
auto notev = notifications->getNotifications();
332
ASSERT_EQ(1, notev.size());
334
/* Generate a set of notifications */
335
notifications->clearNotifications();
336
for (float i = 0.0; i < 1.01; i += 0.1) {
337
setMockVolume(volumeControl, i);
341
notev = notifications->getNotifications();
342
ASSERT_EQ(11, notev.size());
344
EXPECT_EQ("audio-volume-muted", notev[0].app_icon);
345
EXPECT_EQ("audio-volume-low", notev[1].app_icon);
346
EXPECT_EQ("audio-volume-low", notev[2].app_icon);
347
EXPECT_EQ("audio-volume-medium", notev[3].app_icon);
348
EXPECT_EQ("audio-volume-medium", notev[4].app_icon);
349
EXPECT_EQ("audio-volume-medium", notev[5].app_icon);
350
EXPECT_EQ("audio-volume-medium", notev[6].app_icon);
351
EXPECT_EQ("audio-volume-high", notev[7].app_icon);
352
EXPECT_EQ("audio-volume-high", notev[8].app_icon);
353
EXPECT_EQ("audio-volume-high", notev[9].app_icon);
354
EXPECT_EQ("audio-volume-high", notev[10].app_icon);
326
auto options = optionsMock();
327
auto volumeControl = volumeControlMock(options);
328
auto volumeWarning = volumeWarningMock(options);
329
auto accountsService = std::make_shared<AccountsServiceAccess>();
330
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
332
/* Set an initial volume */
333
notifications->clearNotifications();
334
setMockVolume(volumeControl, 0.5);
336
auto notev = notifications->getNotifications();
337
ASSERT_EQ(1, notev.size());
339
/* Generate a set of notifications */
340
notifications->clearNotifications();
341
for (float i = 0.0; i < 1.01; i += 0.1) {
342
setMockVolume(volumeControl, i);
346
notev = notifications->getNotifications();
347
ASSERT_EQ(11, notev.size());
349
EXPECT_EQ("audio-volume-muted", notev[0].app_icon);
350
EXPECT_EQ("audio-volume-low", notev[1].app_icon);
351
EXPECT_EQ("audio-volume-low", notev[2].app_icon);
352
EXPECT_EQ("audio-volume-medium", notev[3].app_icon);
353
EXPECT_EQ("audio-volume-medium", notev[4].app_icon);
354
EXPECT_EQ("audio-volume-medium", notev[5].app_icon);
355
EXPECT_EQ("audio-volume-medium", notev[6].app_icon);
356
EXPECT_EQ("audio-volume-high", notev[7].app_icon);
357
EXPECT_EQ("audio-volume-high", notev[8].app_icon);
358
EXPECT_EQ("audio-volume-high", notev[9].app_icon);
359
EXPECT_EQ("audio-volume-high", notev[10].app_icon);
357
362
TEST_F(NotificationsTest, ServerRestart) {
358
auto options = optionsMock();
359
auto volumeControl = volumeControlMock(options);
360
auto volumeWarning = volumeWarningMock(options);
361
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
364
notifications->clearNotifications();
365
setMockVolume(volumeControl, 0.50);
367
auto notev = notifications->getNotifications();
368
ASSERT_EQ(1, notev.size());
370
/* Restart server without sync notifications */
371
notifications->clearNotifications();
372
dbus_test_service_remove_task(service, (DbusTestTask*)*notifications);
373
notifications.reset();
377
notifications = std::make_shared<NotificationsMock>(std::vector<std::string>({"body", "body-markup", "icon-static"}));
378
dbus_test_service_add_task(service, (DbusTestTask*)*notifications);
379
dbus_test_task_run((DbusTestTask*)*notifications);
381
/* Change the volume */
382
notifications->clearNotifications();
383
setMockVolume(volumeControl, 0.60);
385
notev = notifications->getNotifications();
386
ASSERT_EQ(0, notev.size());
388
/* Put a good server back */
389
dbus_test_service_remove_task(service, (DbusTestTask*)*notifications);
390
notifications.reset();
394
notifications = std::make_shared<NotificationsMock>();
395
dbus_test_service_add_task(service, (DbusTestTask*)*notifications);
396
dbus_test_task_run((DbusTestTask*)*notifications);
398
/* Change the volume again */
399
notifications->clearNotifications();
400
setMockVolume(volumeControl, 0.70);
402
notev = notifications->getNotifications();
403
ASSERT_EQ(1, notev.size());
363
auto options = optionsMock();
364
auto volumeControl = volumeControlMock(options);
365
auto volumeWarning = volumeWarningMock(options);
366
auto accountsService = std::make_shared<AccountsServiceAccess>();
367
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
370
notifications->clearNotifications();
371
setMockVolume(volumeControl, 0.50);
373
auto notev = notifications->getNotifications();
374
ASSERT_EQ(1, notev.size());
376
/* Restart server without sync notifications */
377
notifications->clearNotifications();
378
dbus_test_service_remove_task(service, (DbusTestTask*)*notifications);
379
notifications.reset();
383
notifications = std::make_shared<NotificationsMock>(std::vector<std::string>({"body", "body-markup", "icon-static"}));
384
dbus_test_service_add_task(service, (DbusTestTask*)*notifications);
385
dbus_test_task_run((DbusTestTask*)*notifications);
387
/* Change the volume */
388
notifications->clearNotifications();
389
setMockVolume(volumeControl, 0.60);
391
notev = notifications->getNotifications();
392
ASSERT_EQ(0, notev.size());
394
/* Put a good server back */
395
dbus_test_service_remove_task(service, (DbusTestTask*)*notifications);
396
notifications.reset();
400
notifications = std::make_shared<NotificationsMock>();
401
dbus_test_service_add_task(service, (DbusTestTask*)*notifications);
402
dbus_test_task_run((DbusTestTask*)*notifications);
404
/* Change the volume again */
405
notifications->clearNotifications();
406
setMockVolume(volumeControl, 0.70);
408
notev = notifications->getNotifications();
409
ASSERT_EQ(1, notev.size());
406
412
TEST_F(NotificationsTest, HighVolume) {
407
auto options = optionsMock();
408
auto volumeControl = volumeControlMock(options);
409
auto volumeWarning = volumeWarningMock(options);
410
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
413
notifications->clearNotifications();
414
setMockVolume(volumeControl, 0.50);
416
auto notev = notifications->getNotifications();
417
ASSERT_EQ(1, notev.size());
418
EXPECT_EQ("Volume", notev[0].summary);
419
EXPECT_EQ("Speakers", notev[0].body);
420
EXPECT_GVARIANT_EQ("@s 'false'", notev[0].hints["x-canonical-value-bar-tint"]);
422
/* Set high volume with volume change */
423
notifications->clearNotifications();
424
volume_warning_mock_set_high_volume(VOLUME_WARNING_MOCK(volumeWarning.get()), true);
425
setMockVolume(volumeControl, 0.90);
427
notev = notifications->getNotifications();
428
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 */
429
EXPECT_EQ("Volume", notev[0].summary);
430
EXPECT_EQ("Speakers", notev[0].body);
431
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]);
434
volume_warning_mock_set_high_volume(VOLUME_WARNING_MOCK(volumeWarning.get()), false);
435
setMockVolume(volumeControl, 0.50);
438
/* Set high volume without level change */
439
/* NOTE: This can happen if headphones are plugged in */
440
notifications->clearNotifications();
441
volume_warning_mock_set_high_volume(VOLUME_WARNING_MOCK(volumeWarning.get()), true);
443
notev = notifications->getNotifications();
444
ASSERT_EQ(1, notev.size());
445
EXPECT_EQ("Volume", notev[0].summary);
446
EXPECT_EQ("Speakers", notev[0].body);
447
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]);
413
auto options = optionsMock();
414
auto volumeControl = volumeControlMock(options);
415
auto volumeWarning = volumeWarningMock(options);
416
auto accountsService = std::make_shared<AccountsServiceAccess>();
417
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
420
notifications->clearNotifications();
421
setMockVolume(volumeControl, 0.50);
423
auto notev = notifications->getNotifications();
424
ASSERT_EQ(1, notev.size());
425
EXPECT_EQ("Volume", notev[0].summary);
426
EXPECT_EQ("Speakers", notev[0].body);
427
EXPECT_GVARIANT_EQ("@s 'false'", notev[0].hints["x-canonical-value-bar-tint"]);
429
/* Set high volume with volume change */
430
notifications->clearNotifications();
431
volume_warning_mock_set_high_volume(VOLUME_WARNING_MOCK(volumeWarning.get()), true);
432
setMockVolume(volumeControl, 0.90);
434
notev = notifications->getNotifications();
435
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 */
436
EXPECT_EQ("Volume", notev[0].summary);
437
EXPECT_EQ("Speakers", notev[0].body);
438
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]);
441
volume_warning_mock_set_high_volume(VOLUME_WARNING_MOCK(volumeWarning.get()), false);
442
setMockVolume(volumeControl, 0.50);
445
/* Set high volume without level change */
446
/* NOTE: This can happen if headphones are plugged in */
447
notifications->clearNotifications();
448
volume_warning_mock_set_high_volume(VOLUME_WARNING_MOCK(volumeWarning.get()), true);
450
notev = notifications->getNotifications();
451
ASSERT_EQ(1, notev.size());
452
EXPECT_EQ("Volume", notev[0].summary);
453
EXPECT_EQ("Speakers", notev[0].body);
454
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]);
450
457
TEST_F(NotificationsTest, MenuHide) {
451
auto options = optionsMock();
452
auto volumeControl = volumeControlMock(options);
453
auto volumeWarning = volumeWarningMock(options);
454
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
457
notifications->clearNotifications();
458
setMockVolume(volumeControl, 0.50);
460
auto notev = notifications->getNotifications();
461
EXPECT_EQ(1, notev.size());
463
/* Set the indicator to shown, and set a new volume */
464
notifications->clearNotifications();
465
setIndicatorShown(true);
467
setMockVolume(volumeControl, 0.60);
469
notev = notifications->getNotifications();
470
EXPECT_EQ(0, notev.size());
472
/* Set the indicator to hidden, and set a new volume */
473
notifications->clearNotifications();
474
setIndicatorShown(false);
476
setMockVolume(volumeControl, 0.70);
478
notev = notifications->getNotifications();
479
EXPECT_EQ(1, notev.size());
458
auto options = optionsMock();
459
auto volumeControl = volumeControlMock(options);
460
auto volumeWarning = volumeWarningMock(options);
461
auto accountsService = std::make_shared<AccountsServiceAccess>();
462
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
465
notifications->clearNotifications();
466
setMockVolume(volumeControl, 0.50);
468
auto notev = notifications->getNotifications();
469
EXPECT_EQ(1, notev.size());
471
/* Set the indicator to shown, and set a new volume */
472
notifications->clearNotifications();
473
setIndicatorShown(true);
475
setMockVolume(volumeControl, 0.60);
477
notev = notifications->getNotifications();
478
EXPECT_EQ(0, notev.size());
480
/* Set the indicator to hidden, and set a new volume */
481
notifications->clearNotifications();
482
setIndicatorShown(false);
484
setMockVolume(volumeControl, 0.70);
486
notev = notifications->getNotifications();
487
EXPECT_EQ(1, notev.size());
482
490
TEST_F(NotificationsTest, ExtendendVolumeNotification) {
483
auto options = optionsMock();
484
auto volumeControl = volumeControlMock(options);
485
auto volumeWarning = volumeWarningMock(options);
486
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
489
notifications->clearNotifications();
490
setMockVolume(volumeControl, 0.50);
492
auto notev = notifications->getNotifications();
493
ASSERT_EQ(1, notev.size());
494
EXPECT_EQ("indicator-sound", notev[0].app_name);
495
EXPECT_EQ("Volume", notev[0].summary);
496
EXPECT_EQ(0, notev[0].actions.size());
497
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-private-synchronous"]);
498
EXPECT_GVARIANT_EQ("@i 50", notev[0].hints["value"]);
500
/* Allow an amplified volume */
501
notifications->clearNotifications();
502
volume_control_mock_mock_set_active_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), VOLUME_CONTROL_STREAM_ALARM);
503
options_mock_mock_set_max_volume(OPTIONS_MOCK(options.get()), 1.5);
505
notev = notifications->getNotifications();
506
ASSERT_EQ(1, notev.size());
507
EXPECT_GVARIANT_EQ("@i 33", notev[0].hints["value"]);
509
/* Set to 'over max' */
510
notifications->clearNotifications();
511
setMockVolume(volumeControl, 1.525);
513
notev = notifications->getNotifications();
514
ASSERT_EQ(1, notev.size());
515
EXPECT_GVARIANT_EQ("@i 100", notev[0].hints["value"]);
518
notifications->clearNotifications();
519
options_mock_mock_set_max_volume(OPTIONS_MOCK(options.get()), 1.0);
521
notev = notifications->getNotifications();
522
ASSERT_EQ(1, notev.size());
523
EXPECT_GVARIANT_EQ("@i 100", notev[0].hints["value"]);
491
auto options = optionsMock();
492
auto volumeControl = volumeControlMock(options);
493
auto volumeWarning = volumeWarningMock(options);
494
auto accountsService = std::make_shared<AccountsServiceAccess>();
495
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
498
notifications->clearNotifications();
499
setMockVolume(volumeControl, 0.50);
501
auto notev = notifications->getNotifications();
502
ASSERT_EQ(1, notev.size());
503
EXPECT_EQ("indicator-sound", notev[0].app_name);
504
EXPECT_EQ("Volume", notev[0].summary);
505
EXPECT_EQ(0, notev[0].actions.size());
506
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-private-synchronous"]);
507
EXPECT_GVARIANT_EQ("@i 50", notev[0].hints["value"]);
509
/* Allow an amplified volume */
510
notifications->clearNotifications();
511
volume_control_mock_mock_set_active_stream(VOLUME_CONTROL_MOCK(volumeControl.get()), VOLUME_CONTROL_STREAM_ALARM);
512
options_mock_mock_set_max_volume(OPTIONS_MOCK(options.get()), 1.5);
514
notev = notifications->getNotifications();
515
ASSERT_EQ(1, notev.size());
516
EXPECT_GVARIANT_EQ("@i 33", notev[0].hints["value"]);
518
/* Set to 'over max' */
519
notifications->clearNotifications();
520
setMockVolume(volumeControl, 1.525);
522
notev = notifications->getNotifications();
523
ASSERT_EQ(1, notev.size());
524
EXPECT_GVARIANT_EQ("@i 100", notev[0].hints["value"]);
527
notifications->clearNotifications();
528
options_mock_mock_set_max_volume(OPTIONS_MOCK(options.get()), 1.0);
530
notev = notifications->getNotifications();
531
ASSERT_EQ(1, notev.size());
532
EXPECT_GVARIANT_EQ("@i 100", notev[0].hints["value"]);
526
535
TEST_F(NotificationsTest, TriggerWarning) {
528
// Tests all the conditions needed to trigger a volume warning.
529
// There are many possible combinations, so this test is slow. :P
533
VolumeControlActiveOutput output;
535
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_SPEAKERS },
536
{ true, VOLUME_CONTROL_ACTIVE_OUTPUT_HEADPHONES },
537
{ true, VOLUME_CONTROL_ACTIVE_OUTPUT_BLUETOOTH_HEADPHONES },
538
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_BLUETOOTH_SPEAKER },
539
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_USB_SPEAKER },
540
{ true, VOLUME_CONTROL_ACTIVE_OUTPUT_USB_HEADPHONES },
541
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_HDMI_SPEAKER },
542
{ true, VOLUME_CONTROL_ACTIVE_OUTPUT_HDMI_HEADPHONES },
543
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_CALL_MODE }
549
pa_volume_t loud_volume;
560
} test_approved[] = {
567
bool warnings_enabled;
568
} test_warnings_enabled[] = {
575
bool multimedia_active;
576
} test_multimedia_active[] = {
581
for (const auto& outputs : test_outputs) {
582
for (const auto& volumes : test_volumes) {
583
for (const auto& approved : test_approved) {
584
for (const auto& warnings_enabled : test_warnings_enabled) {
585
for (const auto& multimedia_active : test_multimedia_active) {
587
notifications->clearNotifications();
589
// instantiate the test subjects
590
auto options = optionsMock();
591
auto volumeControl = volumeControlMock(options);
592
auto volumeWarning = volumeWarningMock(options);
593
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning);
596
options_mock_mock_set_loud_volume(OPTIONS_MOCK(options.get()), volumes.loud_volume);
597
options_mock_mock_set_loud_warning_enabled(OPTIONS_MOCK(options.get()), warnings_enabled.warnings_enabled);
598
volume_warning_mock_set_approved(VOLUME_WARNING_MOCK(volumeWarning.get()), approved.approved);
599
volume_warning_mock_set_multimedia_volume(VOLUME_WARNING_MOCK(volumeWarning.get()), volumes.volume);
600
volume_warning_mock_set_multimedia_active(VOLUME_WARNING_MOCK(volumeWarning.get()), multimedia_active.multimedia_active);
601
volume_control_mock_mock_set_active_output(VOLUME_CONTROL_MOCK(volumeControl.get()), outputs.output);
603
loop_until_notifications();
606
auto notev = notifications->getNotifications();
607
const bool warning_expected = outputs.expected && volumes.expected && approved.expected && warnings_enabled.expected && multimedia_active.expected;
608
if (warning_expected) {
609
EXPECT_TRUE(volume_warning_get_active(volumeWarning.get()));
610
ASSERT_EQ(1, notev.size());
611
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-snap-decisions"]);
612
EXPECT_GVARIANT_EQ(nullptr, notev[0].hints["x-canonical-private-synchronous"]);
615
EXPECT_FALSE(volume_warning_get_active(volumeWarning.get()));
616
ASSERT_EQ(1, notev.size());
617
EXPECT_GVARIANT_EQ(nullptr, notev[0].hints["x-canonical-snap-decisions"]);
618
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-private-synchronous"]);
621
} // multimedia_active
622
} // warnings_enabled
537
// Tests all the conditions needed to trigger a volume warning.
538
// There are many possible combinations, so this test is slow. :P
542
VolumeControlActiveOutput output;
544
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_SPEAKERS },
545
{ true, VOLUME_CONTROL_ACTIVE_OUTPUT_HEADPHONES },
546
{ true, VOLUME_CONTROL_ACTIVE_OUTPUT_BLUETOOTH_HEADPHONES },
547
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_BLUETOOTH_SPEAKER },
548
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_USB_SPEAKER },
549
{ true, VOLUME_CONTROL_ACTIVE_OUTPUT_USB_HEADPHONES },
550
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_HDMI_SPEAKER },
551
{ true, VOLUME_CONTROL_ACTIVE_OUTPUT_HDMI_HEADPHONES },
552
{ false, VOLUME_CONTROL_ACTIVE_OUTPUT_CALL_MODE }
558
pa_volume_t loud_volume;
569
} test_approved[] = {
576
bool warnings_enabled;
577
} test_warnings_enabled[] = {
584
bool multimedia_active;
585
} test_multimedia_active[] = {
590
for (const auto& outputs : test_outputs) {
591
for (const auto& volumes : test_volumes) {
592
for (const auto& approved : test_approved) {
593
for (const auto& warnings_enabled : test_warnings_enabled) {
594
for (const auto& multimedia_active : test_multimedia_active) {
596
notifications->clearNotifications();
598
// instantiate the test subjects
599
auto options = optionsMock();
600
auto volumeControl = volumeControlMock(options);
601
auto volumeWarning = volumeWarningMock(options);
602
auto accountsService = std::make_shared<AccountsServiceAccess>();
603
auto soundService = standardService(volumeControl, playerListMock(), options, volumeWarning, accountsService);
606
options_mock_mock_set_loud_volume(OPTIONS_MOCK(options.get()), volumes.loud_volume);
607
options_mock_mock_set_loud_warning_enabled(OPTIONS_MOCK(options.get()), warnings_enabled.warnings_enabled);
608
volume_warning_mock_set_approved(VOLUME_WARNING_MOCK(volumeWarning.get()), approved.approved);
609
volume_warning_mock_set_multimedia_volume(VOLUME_WARNING_MOCK(volumeWarning.get()), volumes.volume);
610
volume_warning_mock_set_multimedia_active(VOLUME_WARNING_MOCK(volumeWarning.get()), multimedia_active.multimedia_active);
611
volume_control_mock_mock_set_active_output(VOLUME_CONTROL_MOCK(volumeControl.get()), outputs.output);
613
loop_until_notifications();
616
auto notev = notifications->getNotifications();
617
const bool warning_expected = outputs.expected && volumes.expected && approved.expected && warnings_enabled.expected && multimedia_active.expected;
618
if (warning_expected) {
619
EXPECT_TRUE(volume_warning_get_active(volumeWarning.get()));
620
ASSERT_EQ(1, notev.size());
621
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-snap-decisions"]);
622
EXPECT_GVARIANT_EQ(nullptr, notev[0].hints["x-canonical-private-synchronous"]);
625
EXPECT_FALSE(volume_warning_get_active(volumeWarning.get()));
626
ASSERT_EQ(1, notev.size());
627
EXPECT_GVARIANT_EQ(nullptr, notev[0].hints["x-canonical-snap-decisions"]);
628
EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-private-synchronous"]);
631
} // multimedia_active
632
} // warnings_enabled