1 #define wake_up wake_up_void
2 #include "../src/dbus.c"
3 #include "greatest.h"
4
5 #include <assert.h>
6 #include <gdk-pixbuf/gdk-pixbuf.h>
7 #include <gio/gio.h>
8
9 #include "helpers.h"
10 #include "queues.h"
11
12 extern const char *base;
13
wake_up_void(void)14 void wake_up_void(void) { }
15
16 struct signal_actioninvoked {
17 guint id;
18 gchar *key;
19 guint subscription_id;
20 GDBusConnection *conn;
21 };
22
23 struct signal_closed {
24 guint32 id;
25 guint32 reason;
26 guint subscription_id;
27 GDBusConnection *conn;
28 };
29
dbus_signal_cb_actioninvoked(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)30 void dbus_signal_cb_actioninvoked(GDBusConnection *connection,
31 const gchar *sender_name,
32 const gchar *object_path,
33 const gchar *interface_name,
34 const gchar *signal_name,
35 GVariant *parameters,
36 gpointer user_data)
37 {
38 g_return_if_fail(user_data);
39
40 guint32 id;
41 gchar *key;
42
43 struct signal_actioninvoked *sig = (struct signal_actioninvoked*) user_data;
44
45 g_variant_get(parameters, "(us)", &id, &key);
46
47 if (id == sig->id) {
48 sig->id = id;
49 sig->key = key;
50 }
51 }
52
dbus_signal_subscribe_actioninvoked(struct signal_actioninvoked * actioninvoked)53 void dbus_signal_subscribe_actioninvoked(struct signal_actioninvoked *actioninvoked)
54 {
55 assert(actioninvoked);
56
57 actioninvoked->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
58 actioninvoked->subscription_id =
59 g_dbus_connection_signal_subscribe(
60 actioninvoked->conn,
61 FDN_NAME,
62 FDN_IFAC,
63 "ActionInvoked",
64 FDN_PATH,
65 NULL,
66 G_DBUS_SIGNAL_FLAGS_NONE,
67 dbus_signal_cb_actioninvoked,
68 actioninvoked,
69 NULL);
70 }
71
dbus_signal_unsubscribe_actioninvoked(struct signal_actioninvoked * actioninvoked)72 void dbus_signal_unsubscribe_actioninvoked(struct signal_actioninvoked *actioninvoked)
73 {
74 assert(actioninvoked);
75
76 g_dbus_connection_signal_unsubscribe(actioninvoked->conn, actioninvoked->subscription_id);
77 g_object_unref(actioninvoked->conn);
78
79 actioninvoked->conn = NULL;
80 actioninvoked->subscription_id = -1;
81 }
82
dbus_signal_cb_closed(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)83 void dbus_signal_cb_closed(GDBusConnection *connection,
84 const gchar *sender_name,
85 const gchar *object_path,
86 const gchar *interface_name,
87 const gchar *signal_name,
88 GVariant *parameters,
89 gpointer user_data)
90 {
91 g_return_if_fail(user_data);
92
93 guint32 id;
94 guint32 reason;
95
96 struct signal_closed *sig = (struct signal_closed*) user_data;
97 g_variant_get(parameters, "(uu)", &id, &reason);
98
99 if (id == sig->id) {
100 sig->id = id;
101 sig->reason = reason;
102 }
103 }
104
dbus_signal_subscribe_closed(struct signal_closed * closed)105 void dbus_signal_subscribe_closed(struct signal_closed *closed)
106 {
107 assert(closed);
108
109 closed->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
110 closed->subscription_id =
111 g_dbus_connection_signal_subscribe(
112 closed->conn,
113 FDN_NAME,
114 FDN_IFAC,
115 "NotificationClosed",
116 FDN_PATH,
117 NULL,
118 G_DBUS_SIGNAL_FLAGS_NONE,
119 dbus_signal_cb_closed,
120 closed,
121 NULL);
122 }
123
dbus_signal_unsubscribe_closed(struct signal_closed * closed)124 void dbus_signal_unsubscribe_closed(struct signal_closed *closed)
125 {
126 assert(closed);
127
128 g_dbus_connection_signal_unsubscribe(closed->conn, closed->subscription_id);
129 g_object_unref(closed->conn);
130
131 closed->conn = NULL;
132 closed->subscription_id = -1;
133 }
134
dbus_invoke(const char * method,GVariant * params)135 GVariant *dbus_invoke(const char *method, GVariant *params)
136 {
137 GDBusConnection *connection_client;
138 GVariant *retdata;
139 GError *error = NULL;
140
141 connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
142 retdata = g_dbus_connection_call_sync(
143 connection_client,
144 FDN_NAME,
145 FDN_PATH,
146 FDN_IFAC,
147 method,
148 params,
149 NULL,
150 G_DBUS_CALL_FLAGS_NONE,
151 -1,
152 NULL,
153 &error);
154 if (error) {
155 printf("Error while calling GTestDBus instance: %s\n", error->message);
156 g_error_free(error);
157 }
158
159 g_object_unref(connection_client);
160
161 return retdata;
162 }
163
164 struct dbus_notification {
165 const char* app_name;
166 guint replaces_id;
167 const char* app_icon;
168 const char* summary;
169 const char* body;
170 GHashTable *actions;
171 GHashTable *hints;
172 int expire_timeout;
173 };
174
g_free_variant_value(gpointer tofree)175 void g_free_variant_value(gpointer tofree)
176 {
177 g_variant_unref((GVariant*) tofree);
178 }
179
dbus_notification_new(void)180 struct dbus_notification *dbus_notification_new(void)
181 {
182 struct dbus_notification *n = g_malloc0(sizeof(struct dbus_notification));
183 n->expire_timeout = -1;
184 n->replaces_id = 0;
185 n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
186 n->hints = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free_variant_value);
187 return n;
188 }
189
dbus_notification_free(struct dbus_notification * n)190 void dbus_notification_free(struct dbus_notification *n)
191 {
192 g_hash_table_unref(n->hints);
193 g_hash_table_unref(n->actions);
194 g_free(n);
195 }
196
dbus_notification_fire(struct dbus_notification * n,uint * id)197 bool dbus_notification_fire(struct dbus_notification *n, uint *id)
198 {
199 assert(n);
200 assert(id);
201 GVariantBuilder b;
202 GVariantType *t;
203
204 gpointer p_key;
205 gpointer p_value;
206 GHashTableIter iter;
207
208 t = g_variant_type_new("(susssasa{sv}i)");
209 g_variant_builder_init(&b, t);
210 g_variant_type_free(t);
211
212 g_variant_builder_add(&b, "s", n->app_name);
213 g_variant_builder_add(&b, "u", n->replaces_id);
214 g_variant_builder_add(&b, "s", n->app_icon);
215 g_variant_builder_add(&b, "s", n->summary);
216 g_variant_builder_add(&b, "s", n->body);
217
218 // Add the actions
219 t = g_variant_type_new("as");
220 g_variant_builder_open(&b, t);
221 g_hash_table_iter_init(&iter, n->actions);
222 while (g_hash_table_iter_next(&iter, &p_key, &p_value)) {
223 g_variant_builder_add(&b, "s", (char*)p_key);
224 g_variant_builder_add(&b, "s", (char*)p_value);
225 }
226 // Add an invalid appendix to cover odd numbered action arrays
227 // Shouldn't interfere with normal testing
228 g_variant_builder_add(&b, "s", "invalid appendix");
229 g_variant_builder_close(&b);
230 g_variant_type_free(t);
231
232 // Add the hints
233 t = g_variant_type_new("a{sv}");
234 g_variant_builder_open(&b, t);
235 g_hash_table_iter_init(&iter, n->hints);
236 while (g_hash_table_iter_next(&iter, &p_key, &p_value)) {
237 g_variant_builder_add(&b, "{sv}", (char*)p_key, (GVariant*)p_value);
238 }
239 g_variant_builder_close(&b);
240 g_variant_type_free(t);
241
242 g_variant_builder_add(&b, "i", n->expire_timeout);
243
244 GVariant *reply = dbus_invoke("Notify", g_variant_builder_end(&b));
245 if (reply) {
246 g_variant_get(reply, "(u)", id);
247 g_variant_unref(reply);
248 return true;
249 } else {
250 return false;
251 }
252 }
253
dbus_notification_set_raw_image(struct dbus_notification * n_dbus,const char * path)254 void dbus_notification_set_raw_image(struct dbus_notification *n_dbus, const char *path)
255 {
256 GVariant *hint = notification_setup_raw_image(path);
257 if (!hint)
258 return;
259
260 g_hash_table_insert(n_dbus->hints,
261 g_strdup("image-data"),
262 g_variant_ref_sink(hint));
263 }
264
265 /////// TESTS
266 gint owner_id;
267
test_dbus_init(void)268 TEST test_dbus_init(void)
269 {
270 owner_id = dbus_init();
271 uint waiting = 0;
272 while (!dbus_conn && waiting < 2000) {
273 usleep(500);
274 waiting++;
275 }
276 ASSERTm("After 1s, there is still no dbus connection available.",
277 dbus_conn);
278 PASS();
279 }
280
test_dbus_teardown(void)281 TEST test_dbus_teardown(void)
282 {
283 dbus_teardown(owner_id);
284 PASS();
285 }
286
test_invalid_notification(void)287 TEST test_invalid_notification(void)
288 {
289 GVariant *faulty = g_variant_new_boolean(true);
290
291 ASSERT(NULL == dbus_message_to_notification(":123", faulty));
292 ASSERT(NULL == dbus_invoke("Notify", faulty));
293
294 g_variant_unref(faulty);
295 PASS();
296 }
297
test_empty_notification(void)298 TEST test_empty_notification(void)
299 {
300 struct dbus_notification *n = dbus_notification_new();
301 gsize len = queues_length_waiting();
302
303 guint id;
304 ASSERT(dbus_notification_fire(n, &id));
305 ASSERT(id != 0);
306
307 ASSERT_EQ(queues_length_waiting(), len+1);
308 dbus_notification_free(n);
309 PASS();
310 }
311
test_basic_notification(void)312 TEST test_basic_notification(void)
313 {
314 struct dbus_notification *n = dbus_notification_new();
315 gsize len = queues_length_waiting();
316 n->app_name = "dunstteststack";
317 n->app_icon = "NONE";
318 n->summary = "Headline";
319 n->body = "Text";
320 g_hash_table_insert(n->actions, g_strdup("actionid"), g_strdup("Print this text"));
321 g_hash_table_insert(n->hints,
322 g_strdup("x-dunst-stack-tag"),
323 g_variant_ref_sink(g_variant_new_string("volume")));
324
325 n->replaces_id = 10;
326
327 guint id;
328 ASSERT(dbus_notification_fire(n, &id));
329 ASSERT(id != 0);
330
331 ASSERT_EQ(queues_length_waiting(), len+1);
332 dbus_notification_free(n);
333 PASS();
334 }
335
test_dbus_notify_colors(void)336 TEST test_dbus_notify_colors(void)
337 {
338 const char *color_frame = "I allow all string values for frame!";
339 const char *color_bg = "I allow all string values for background!";
340 const char *color_fg = "I allow all string values for foreground!";
341 struct notification *n;
342 struct dbus_notification *n_dbus;
343
344 gsize len = queues_length_waiting();
345
346 n_dbus = dbus_notification_new();
347 n_dbus->app_name = "dunstteststack";
348 n_dbus->app_icon = "NONE";
349 n_dbus->summary = "test_dbus_notify_colors";
350 n_dbus->body = "Summary of it";
351 g_hash_table_insert(n_dbus->hints,
352 g_strdup("frcolor"),
353 g_variant_ref_sink(g_variant_new_string(color_frame)));
354 g_hash_table_insert(n_dbus->hints,
355 g_strdup("bgcolor"),
356 g_variant_ref_sink(g_variant_new_string(color_bg)));
357 g_hash_table_insert(n_dbus->hints,
358 g_strdup("fgcolor"),
359 g_variant_ref_sink(g_variant_new_string(color_fg)));
360
361 guint id;
362 ASSERT(dbus_notification_fire(n_dbus, &id));
363 ASSERT(id != 0);
364
365 ASSERT_EQ(queues_length_waiting(), len+1);
366
367 n = queues_debug_find_notification_by_id(id);
368
369 ASSERT_STR_EQ(n->colors.frame, color_frame);
370 ASSERT_STR_EQ(n->colors.fg, color_fg);
371 ASSERT_STR_EQ(n->colors.bg, color_bg);
372
373 dbus_notification_free(n_dbus);
374
375 PASS();
376 }
377
test_hint_transient(void)378 TEST test_hint_transient(void)
379 {
380 static char msg[50];
381 struct notification *n;
382 struct dbus_notification *n_dbus;
383
384 gsize len = queues_length_waiting();
385
386 n_dbus = dbus_notification_new();
387 n_dbus->app_name = "dunstteststack";
388 n_dbus->app_icon = "NONE";
389 n_dbus->summary = "test_hint_transient";
390 n_dbus->body = "Summary of it";
391
392 bool values[] = { true, true, true, false, false, false, false };
393 GVariant *variants[] = {
394 g_variant_new_boolean(true),
395 g_variant_new_int32(1),
396 g_variant_new_uint32(1),
397 g_variant_new_boolean(false),
398 g_variant_new_int32(0),
399 g_variant_new_uint32(0),
400 g_variant_new_int32(-1),
401 };
402 for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) {
403 g_hash_table_insert(n_dbus->hints,
404 g_strdup("transient"),
405 g_variant_ref_sink(variants[i]));
406
407 guint id;
408 ASSERT(dbus_notification_fire(n_dbus, &id));
409 ASSERT(id != 0);
410
411 ASSERT_EQ(queues_length_waiting(), len+1);
412
413 n = queues_debug_find_notification_by_id(id);
414
415 snprintf(msg, sizeof(msg), "In round %ld", i);
416 ASSERT_EQm(msg, values[i], n->transient);
417 }
418
419 dbus_notification_free(n_dbus);
420
421 PASS();
422 }
423
test_hint_progress(void)424 TEST test_hint_progress(void)
425 {
426 static char msg[50];
427 struct notification *n;
428 struct dbus_notification *n_dbus;
429
430 gsize len = queues_length_waiting();
431
432 n_dbus = dbus_notification_new();
433 n_dbus->app_name = "dunstteststack";
434 n_dbus->app_icon = "NONE";
435 n_dbus->summary = "test_hint_progress";
436 n_dbus->body = "Summary of it";
437
438 int values[] = { 99, 12, 123, 123, -1, -1 };
439 GVariant *variants[] = {
440 g_variant_new_int32(99),
441 g_variant_new_uint32(12),
442 g_variant_new_int32(123), // allow higher than 100
443 g_variant_new_uint32(123),
444 g_variant_new_int32(-192),
445 g_variant_new_uint32(-192),
446 };
447 for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) {
448 g_hash_table_insert(n_dbus->hints,
449 g_strdup("value"),
450 g_variant_ref_sink(variants[i]));
451
452 guint id;
453 ASSERT(dbus_notification_fire(n_dbus, &id));
454 ASSERT(id != 0);
455
456 ASSERT_EQ(queues_length_waiting(), len+1);
457
458 n = queues_debug_find_notification_by_id(id);
459
460 snprintf(msg, sizeof(msg), "In round %ld", i);
461 ASSERT_EQm(msg, values[i], n->progress);
462 }
463
464 dbus_notification_free(n_dbus);
465
466 PASS();
467 }
468
test_hint_icons(void)469 TEST test_hint_icons(void)
470 {
471 struct notification *n;
472 struct dbus_notification *n_dbus;
473 const char *iconname = "NEWICON";
474
475 gsize len = queues_length_waiting();
476
477 n_dbus = dbus_notification_new();
478 n_dbus->app_name = "dunstteststack";
479 n_dbus->app_icon = "NONE";
480 n_dbus->summary = "test_hint_icons";
481 n_dbus->body = "Summary of it";
482
483 g_hash_table_insert(n_dbus->hints,
484 g_strdup("image-path"),
485 g_variant_ref_sink(g_variant_new_string(iconname)));
486
487 guint id;
488 ASSERT(dbus_notification_fire(n_dbus, &id));
489 ASSERT(id != 0);
490
491 ASSERT_EQ(queues_length_waiting(), len+1);
492
493 n = queues_debug_find_notification_by_id(id);
494
495 ASSERT_STR_EQ(iconname, n->iconname);
496
497 dbus_notification_free(n_dbus);
498
499 PASS();
500 }
501
test_hint_category(void)502 TEST test_hint_category(void)
503 {
504 struct notification *n;
505 struct dbus_notification *n_dbus;
506 const char *category = "VOLUME";
507
508 gsize len = queues_length_waiting();
509
510 n_dbus = dbus_notification_new();
511 n_dbus->app_name = "dunstteststack";
512 n_dbus->app_icon = "NONE";
513 n_dbus->summary = "test_hint_category";
514 n_dbus->body = "Summary of it";
515
516 g_hash_table_insert(n_dbus->hints,
517 g_strdup("category"),
518 g_variant_ref_sink(g_variant_new_string(category)));
519
520 guint id;
521 ASSERT(dbus_notification_fire(n_dbus, &id));
522 ASSERT(id != 0);
523
524 ASSERT_EQ(queues_length_waiting(), len+1);
525
526 n = queues_debug_find_notification_by_id(id);
527
528 ASSERT_STR_EQ(category, n->category);
529
530 dbus_notification_free(n_dbus);
531
532 PASS();
533 }
534
test_hint_desktop_entry(void)535 TEST test_hint_desktop_entry(void)
536 {
537 struct notification *n;
538 struct dbus_notification *n_dbus;
539 const char *desktop_entry = "org.dunst-project.dunst";
540
541 gsize len = queues_length_waiting();
542
543 n_dbus = dbus_notification_new();
544 n_dbus->app_name = "dunstteststack";
545 n_dbus->app_icon = "NONE";
546 n_dbus->summary = "test_hint_desktopentry";
547 n_dbus->body = "Summary of my desktop_entry";
548
549 g_hash_table_insert(n_dbus->hints,
550 g_strdup("desktop-entry"),
551 g_variant_ref_sink(g_variant_new_string(desktop_entry)));
552
553 guint id;
554 ASSERT(dbus_notification_fire(n_dbus, &id));
555 ASSERT(id != 0);
556
557 ASSERT_EQ(queues_length_waiting(), len+1);
558
559 n = queues_debug_find_notification_by_id(id);
560
561 ASSERT_STR_EQ(desktop_entry, n->desktop_entry);
562
563 dbus_notification_free(n_dbus);
564
565 PASS();
566 }
567
test_hint_urgency(void)568 TEST test_hint_urgency(void)
569 {
570 static char msg[50];
571 struct notification *n;
572 struct dbus_notification *n_dbus;
573
574 gsize len = queues_length_waiting();
575
576 n_dbus = dbus_notification_new();
577 n_dbus->app_name = "dunstteststack";
578 n_dbus->app_icon = "NONE";
579 n_dbus->summary = "test_hint_urgency";
580 n_dbus->body = "Summary of it";
581
582 enum urgency values[] = { URG_MAX, URG_LOW, URG_NORM, URG_CRIT };
583 GVariant *variants[] = {
584 g_variant_new_byte(10),
585 g_variant_new_byte(0),
586 g_variant_new_byte(1),
587 g_variant_new_byte(2),
588 };
589 for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) {
590 g_hash_table_insert(n_dbus->hints,
591 g_strdup("urgency"),
592 g_variant_ref_sink(variants[i]));
593
594 guint id;
595 ASSERT(dbus_notification_fire(n_dbus, &id));
596 ASSERT(id != 0);
597
598 ASSERT_EQ(queues_length_waiting(), len+1);
599
600 n = queues_debug_find_notification_by_id(id);
601
602 snprintf(msg, sizeof(msg), "In round %ld", i);
603 ASSERT_EQm(msg, values[i], n->urgency);
604
605 queues_notification_close_id(id, REASON_UNDEF);
606 }
607
608 dbus_notification_free(n_dbus);
609
610 PASS();
611 }
612
test_hint_raw_image(void)613 TEST test_hint_raw_image(void)
614 {
615 guint id;
616 struct notification *n;
617 struct dbus_notification *n_dbus;
618
619 char *path = g_strconcat(base, "/data/icons/valid.png", NULL);
620 gsize len = queues_length_waiting();
621
622 n_dbus = dbus_notification_new();
623 dbus_notification_set_raw_image(n_dbus, path);
624 n_dbus->app_name = "dunstteststack";
625 n_dbus->app_icon = "NONE";
626 n_dbus->summary = "test_hint_raw_image";
627 n_dbus->body = "Summary of it";
628
629 ASSERT(dbus_notification_fire(n_dbus, &id));
630 ASSERT(id != 0);
631
632 ASSERT_EQ(queues_length_waiting(), len+1);
633 n = queues_debug_find_notification_by_id(id);
634
635 ASSERT(n->icon);
636 ASSERT(!STR_EQ(n->icon_id, n_dbus->app_icon));
637
638 dbus_notification_free(n_dbus);
639 g_free(path);
640
641 PASS();
642 }
643
644 /* We didn't process the timeout parameter via DBus correctly
645 * and it got limited to an int instead of a long int
646 * See: Issue #646 (The timeout value in dunst wraps around) */
test_timeout_overflow(void)647 TEST test_timeout_overflow(void)
648 {
649 struct notification *n;
650 struct dbus_notification *n_dbus;
651
652 n_dbus = dbus_notification_new();
653 n_dbus->app_name = "dunstteststack";
654 n_dbus->app_icon = "NONE";
655 n_dbus->summary = "test_hint_urgency";
656 n_dbus->body = "Summary of it";
657 n_dbus->expire_timeout = 2147484;
658 gint64 expected_timeout = G_GINT64_CONSTANT(2147484000);
659
660 guint id;
661 ASSERT(dbus_notification_fire(n_dbus, &id));
662 ASSERT(id != 0);
663
664 n = queues_debug_find_notification_by_id(id);
665 ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT);
666
667 dbus_notification_free(n_dbus);
668
669 PASS();
670 }
671
test_server_caps(enum markup_mode markup)672 TEST test_server_caps(enum markup_mode markup)
673 {
674 GVariant *reply;
675 GVariant *caps = NULL;
676 const char **capsarray;
677
678 settings.markup = markup;
679
680 reply = dbus_invoke("GetCapabilities", NULL);
681
682 caps = g_variant_get_child_value(reply, 0);
683 capsarray = g_variant_get_strv(caps, NULL);
684
685 ASSERT(capsarray);
686 ASSERT(g_strv_contains(capsarray, "actions"));
687 ASSERT(g_strv_contains(capsarray, "body"));
688 ASSERT(g_strv_contains(capsarray, "body-hyperlinks"));
689 ASSERT(g_strv_contains(capsarray, "x-dunst-stack-tag"));
690
691 if (settings.markup != MARKUP_NO)
692 ASSERT(g_strv_contains(capsarray, "body-markup"));
693 else
694 ASSERT_FALSE(g_strv_contains(capsarray, "body-markup"));
695
696 g_free(capsarray);
697 g_variant_unref(caps);
698 g_variant_unref(reply);
699 PASS();
700 }
701
test_signal_actioninvoked(void)702 TEST test_signal_actioninvoked(void)
703 {
704 const struct notification *n;
705 struct dbus_notification *n_dbus;
706 struct signal_actioninvoked sig = {0, NULL, -1};
707
708 dbus_signal_subscribe_actioninvoked(&sig);
709
710 n_dbus = dbus_notification_new();
711 n_dbus->app_name = "dunstteststack";
712 n_dbus->app_icon = "NONE2";
713 n_dbus->summary = "Headline for New";
714 n_dbus->body = "Text";
715 g_hash_table_insert(n_dbus->actions, g_strdup("actionkey"), g_strdup("Print this text"));
716
717 dbus_notification_fire(n_dbus, &sig.id);
718 n = queues_debug_find_notification_by_id(sig.id);
719
720 signal_action_invoked(n, "actionkey");
721
722 uint waiting = 0;
723 while (!sig.key && waiting < 2000) {
724 usleep(500);
725 waiting++;
726 }
727
728 ASSERT_STR_EQ("actionkey", sig.key);
729
730 g_free(sig.key);
731 dbus_notification_free(n_dbus);
732 dbus_signal_unsubscribe_actioninvoked(&sig);
733 PASS();
734 }
735
test_close_and_signal(void)736 TEST test_close_and_signal(void)
737 {
738 GVariant *data, *ret;
739 struct dbus_notification *n;
740 struct signal_closed sig = {0, REASON_MIN-1, -1};
741
742 dbus_signal_subscribe_closed(&sig);
743
744 n = dbus_notification_new();
745 n->app_name = "dunstteststack";
746 n->app_icon = "NONE2";
747 n->summary = "Headline for New";
748 n->body = "Text";
749
750 dbus_notification_fire(n, &sig.id);
751
752 data = g_variant_new("(u)", sig.id);
753 ret = dbus_invoke("CloseNotification", data);
754
755 ASSERT(ret);
756
757 uint waiting = 0;
758 while (sig.reason == REASON_MIN-1 && waiting < 2000) {
759 usleep(500);
760 waiting++;
761 }
762
763 ASSERT(sig.reason != REASON_MIN-1);
764
765 dbus_notification_free(n);
766 dbus_signal_unsubscribe_closed(&sig);
767 g_variant_unref(ret);
768 PASS();
769 }
770
test_get_fdn_daemon_info(void)771 TEST test_get_fdn_daemon_info(void)
772 {
773 unsigned int pid_is;
774 pid_t pid_should;
775 char *name, *vendor;
776 GDBusConnection *conn;
777
778 pid_should = getpid();
779 conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
780
781 ASSERT(dbus_get_fdn_daemon_info(conn, &pid_is, &name, &vendor));
782
783 ASSERT_EQ_FMT(pid_should, pid_is, "%d");
784 ASSERT_STR_EQ("dunst", name);
785 ASSERT_STR_EQ("knopwob", vendor);
786
787 g_free(name);
788 g_free(vendor);
789
790 g_object_unref(conn);
791 PASS();
792 }
793
assert_methodlists_sorted(void)794 TEST assert_methodlists_sorted(void)
795 {
796 for (size_t i = 0; i+1 < G_N_ELEMENTS(methods_fdn); i++) {
797 ASSERT(0 > strcmp(
798 methods_fdn[i].method_name,
799 methods_fdn[i+1].method_name));
800 }
801
802 for (size_t i = 0; i+1 < G_N_ELEMENTS(methods_dunst); i++) {
803 ASSERT(0 > strcmp(
804 methods_dunst[i].method_name,
805 methods_dunst[i+1].method_name));
806 }
807
808 PASS();
809 }
810
811
812 // TESTS END
813
814 GMainLoop *loop;
815 GThread *thread_tests;
816
run_threaded_tests(gpointer data)817 gpointer run_threaded_tests(gpointer data)
818 {
819 RUN_TEST(test_dbus_init);
820
821 RUN_TEST(test_get_fdn_daemon_info);
822
823 RUN_TEST(test_empty_notification);
824 RUN_TEST(test_basic_notification);
825 RUN_TEST(test_invalid_notification);
826 RUN_TEST(test_hint_transient);
827 RUN_TEST(test_hint_progress);
828 RUN_TEST(test_hint_icons);
829 RUN_TEST(test_hint_category);
830 RUN_TEST(test_hint_desktop_entry);
831 RUN_TEST(test_hint_urgency);
832 RUN_TEST(test_hint_raw_image);
833 RUN_TEST(test_dbus_notify_colors);
834 RUN_TESTp(test_server_caps, MARKUP_FULL);
835 RUN_TESTp(test_server_caps, MARKUP_STRIP);
836 RUN_TESTp(test_server_caps, MARKUP_NO);
837 RUN_TEST(test_close_and_signal);
838 RUN_TEST(test_signal_actioninvoked);
839 RUN_TEST(test_timeout_overflow);
840
841 RUN_TEST(assert_methodlists_sorted);
842
843 RUN_TEST(test_dbus_teardown);
844 g_main_loop_quit(loop);
845 return NULL;
846 }
847
SUITE(suite_dbus)848 SUITE(suite_dbus)
849 {
850 settings.icon_path = "";
851
852 GTestDBus *dbus_bus;
853 g_test_dbus_unset();
854 queues_init();
855
856 loop = g_main_loop_new(NULL, false);
857
858 dbus_bus = g_test_dbus_new(G_TEST_DBUS_NONE);
859 g_test_dbus_up(dbus_bus);
860
861 thread_tests = g_thread_new("testexecutor", run_threaded_tests, loop);
862 g_main_loop_run(loop);
863
864 queues_teardown();
865 g_test_dbus_down(dbus_bus);
866 g_object_unref(dbus_bus);
867 g_thread_unref(thread_tests);
868 g_main_loop_unref(loop);
869
870 settings.icon_path = NULL;
871 }
872
873 /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
874