1 | #include <gio/gio.h> |
2 | #include <stdlib.h> |
3 | #include <string.h> |
4 | |
5 | #include "gdbus-sessionbus.h" |
6 | |
7 | typedef struct |
8 | { |
9 | GVariant *params; |
10 | gboolean did_run; |
11 | } Activation; |
12 | |
13 | static void |
14 | activate (GAction *action, |
15 | GVariant *parameter, |
16 | gpointer user_data) |
17 | { |
18 | Activation *activation = user_data; |
19 | |
20 | if (parameter) |
21 | activation->params = g_variant_ref (value: parameter); |
22 | else |
23 | activation->params = NULL; |
24 | activation->did_run = TRUE; |
25 | } |
26 | |
27 | static void |
28 | test_basic (void) |
29 | { |
30 | Activation a = { 0, }; |
31 | GSimpleAction *action; |
32 | gchar *name; |
33 | GVariantType *parameter_type; |
34 | gboolean enabled; |
35 | GVariantType *state_type; |
36 | GVariant *state; |
37 | |
38 | action = g_simple_action_new (name: "foo" , NULL); |
39 | g_assert_true (g_action_get_enabled (G_ACTION (action))); |
40 | g_assert_null (g_action_get_parameter_type (G_ACTION (action))); |
41 | g_assert_null (g_action_get_state_type (G_ACTION (action))); |
42 | g_assert_null (g_action_get_state_hint (G_ACTION (action))); |
43 | g_assert_null (g_action_get_state (G_ACTION (action))); |
44 | g_object_get (object: action, |
45 | first_property_name: "name" , &name, |
46 | "parameter-type" , ¶meter_type, |
47 | "enabled" , &enabled, |
48 | "state-type" , &state_type, |
49 | "state" , &state, |
50 | NULL); |
51 | g_assert_cmpstr (name, ==, "foo" ); |
52 | g_assert_null (parameter_type); |
53 | g_assert_true (enabled); |
54 | g_assert_null (state_type); |
55 | g_assert_null (state); |
56 | g_free (mem: name); |
57 | |
58 | g_signal_connect (action, "activate" , G_CALLBACK (activate), &a); |
59 | g_assert_false (a.did_run); |
60 | g_action_activate (G_ACTION (action), NULL); |
61 | g_assert_true (a.did_run); |
62 | a.did_run = FALSE; |
63 | |
64 | g_simple_action_set_enabled (simple: action, FALSE); |
65 | g_action_activate (G_ACTION (action), NULL); |
66 | g_assert_false (a.did_run); |
67 | |
68 | if (g_test_undefined ()) |
69 | { |
70 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
71 | pattern: "*assertion*g_variant_is_of_type*failed*" ); |
72 | g_action_activate (G_ACTION (action), parameter: g_variant_new_string (string: "xxx" )); |
73 | g_test_assert_expected_messages (); |
74 | } |
75 | |
76 | g_object_unref (object: action); |
77 | g_assert_false (a.did_run); |
78 | |
79 | action = g_simple_action_new (name: "foo" , G_VARIANT_TYPE_STRING); |
80 | g_assert_true (g_action_get_enabled (G_ACTION (action))); |
81 | g_assert_true (g_variant_type_equal (g_action_get_parameter_type (G_ACTION (action)), G_VARIANT_TYPE_STRING)); |
82 | g_assert_null (g_action_get_state_type (G_ACTION (action))); |
83 | g_assert_null (g_action_get_state_hint (G_ACTION (action))); |
84 | g_assert_null (g_action_get_state (G_ACTION (action))); |
85 | |
86 | g_signal_connect (action, "activate" , G_CALLBACK (activate), &a); |
87 | g_assert_false (a.did_run); |
88 | g_action_activate (G_ACTION (action), parameter: g_variant_new_string (string: "Hello world" )); |
89 | g_assert_true (a.did_run); |
90 | g_assert_cmpstr (g_variant_get_string (a.params, NULL), ==, "Hello world" ); |
91 | g_variant_unref (value: a.params); |
92 | a.did_run = FALSE; |
93 | |
94 | if (g_test_undefined ()) |
95 | { |
96 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
97 | pattern: "*assertion*!= NULL*failed*" ); |
98 | g_action_activate (G_ACTION (action), NULL); |
99 | g_test_assert_expected_messages (); |
100 | } |
101 | |
102 | g_object_unref (object: action); |
103 | g_assert_false (a.did_run); |
104 | } |
105 | |
106 | static void |
107 | test_name (void) |
108 | { |
109 | g_assert_false (g_action_name_is_valid ("" )); |
110 | g_assert_false (g_action_name_is_valid ("(" )); |
111 | g_assert_false (g_action_name_is_valid ("%abc" )); |
112 | g_assert_false (g_action_name_is_valid ("$x1" )); |
113 | g_assert_true (g_action_name_is_valid ("abc.def" )); |
114 | g_assert_true (g_action_name_is_valid ("ABC-DEF" )); |
115 | } |
116 | |
117 | static gboolean |
118 | strv_has_string (gchar **haystack, |
119 | const gchar *needle) |
120 | { |
121 | guint n; |
122 | |
123 | for (n = 0; haystack != NULL && haystack[n] != NULL; n++) |
124 | { |
125 | if (g_strcmp0 (str1: haystack[n], str2: needle) == 0) |
126 | return TRUE; |
127 | } |
128 | return FALSE; |
129 | } |
130 | |
131 | static gboolean |
132 | strv_strv_cmp (gchar **a, gchar **b) |
133 | { |
134 | guint n; |
135 | |
136 | for (n = 0; a[n] != NULL; n++) |
137 | { |
138 | if (!strv_has_string (haystack: b, needle: a[n])) |
139 | return FALSE; |
140 | } |
141 | |
142 | for (n = 0; b[n] != NULL; n++) |
143 | { |
144 | if (!strv_has_string (haystack: a, needle: b[n])) |
145 | return FALSE; |
146 | } |
147 | |
148 | return TRUE; |
149 | } |
150 | |
151 | static gboolean |
152 | strv_set_equal (gchar **strv, ...) |
153 | { |
154 | gint count; |
155 | va_list list; |
156 | const gchar *str; |
157 | gboolean res; |
158 | |
159 | res = TRUE; |
160 | count = 0; |
161 | va_start (list, strv); |
162 | while (1) |
163 | { |
164 | str = va_arg (list, const gchar *); |
165 | if (str == NULL) |
166 | break; |
167 | if (!strv_has_string (haystack: strv, needle: str)) |
168 | { |
169 | res = FALSE; |
170 | break; |
171 | } |
172 | count++; |
173 | } |
174 | va_end (list); |
175 | |
176 | if (res) |
177 | res = g_strv_length (str_array: (gchar**)strv) == count; |
178 | |
179 | return res; |
180 | } |
181 | |
182 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
183 | |
184 | static void |
185 | test_simple_group (void) |
186 | { |
187 | GSimpleActionGroup *group; |
188 | Activation a = { 0, }; |
189 | GSimpleAction *simple; |
190 | GAction *action; |
191 | gchar **actions; |
192 | GVariant *state; |
193 | |
194 | simple = g_simple_action_new (name: "foo" , NULL); |
195 | g_signal_connect (simple, "activate" , G_CALLBACK (activate), &a); |
196 | g_assert_false (a.did_run); |
197 | g_action_activate (G_ACTION (simple), NULL); |
198 | g_assert_true (a.did_run); |
199 | a.did_run = FALSE; |
200 | |
201 | group = g_simple_action_group_new (); |
202 | g_simple_action_group_insert (simple: group, G_ACTION (simple)); |
203 | g_object_unref (object: simple); |
204 | |
205 | g_assert_false (a.did_run); |
206 | g_action_group_activate_action (G_ACTION_GROUP (group), action_name: "foo" , NULL); |
207 | g_assert_true (a.did_run); |
208 | |
209 | simple = g_simple_action_new_stateful (name: "bar" , G_VARIANT_TYPE_STRING, state: g_variant_new_string (string: "hihi" )); |
210 | g_simple_action_group_insert (simple: group, G_ACTION (simple)); |
211 | g_object_unref (object: simple); |
212 | |
213 | g_assert_true (g_action_group_has_action (G_ACTION_GROUP (group), "foo" )); |
214 | g_assert_true (g_action_group_has_action (G_ACTION_GROUP (group), "bar" )); |
215 | g_assert_false (g_action_group_has_action (G_ACTION_GROUP (group), "baz" )); |
216 | actions = g_action_group_list_actions (G_ACTION_GROUP (group)); |
217 | g_assert_cmpint (g_strv_length (actions), ==, 2); |
218 | g_assert_true (strv_set_equal (actions, "foo" , "bar" , NULL)); |
219 | g_strfreev (str_array: actions); |
220 | g_assert_true (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "foo" )); |
221 | g_assert_true (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar" )); |
222 | g_assert_null (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "foo" )); |
223 | g_assert_true (g_variant_type_equal (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "bar" ), G_VARIANT_TYPE_STRING)); |
224 | g_assert_null (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "foo" )); |
225 | g_assert_true (g_variant_type_equal (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "bar" ), G_VARIANT_TYPE_STRING)); |
226 | g_assert_null (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "foo" )); |
227 | g_assert_null (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "bar" )); |
228 | g_assert_null (g_action_group_get_action_state (G_ACTION_GROUP (group), "foo" )); |
229 | state = g_action_group_get_action_state (G_ACTION_GROUP (group), action_name: "bar" ); |
230 | g_assert_true (g_variant_type_equal (g_variant_get_type (state), G_VARIANT_TYPE_STRING)); |
231 | g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi" ); |
232 | g_variant_unref (value: state); |
233 | |
234 | g_action_group_change_action_state (G_ACTION_GROUP (group), action_name: "bar" , value: g_variant_new_string (string: "boo" )); |
235 | state = g_action_group_get_action_state (G_ACTION_GROUP (group), action_name: "bar" ); |
236 | g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "boo" ); |
237 | g_variant_unref (value: state); |
238 | |
239 | action = g_simple_action_group_lookup (simple: group, action_name: "bar" ); |
240 | g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE); |
241 | g_assert_false (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar" )); |
242 | |
243 | g_simple_action_group_remove (simple: group, action_name: "bar" ); |
244 | action = g_simple_action_group_lookup (simple: group, action_name: "foo" ); |
245 | g_assert_cmpstr (g_action_get_name (action), ==, "foo" ); |
246 | action = g_simple_action_group_lookup (simple: group, action_name: "bar" ); |
247 | g_assert_null (action); |
248 | |
249 | simple = g_simple_action_new (name: "foo" , NULL); |
250 | g_simple_action_group_insert (simple: group, G_ACTION (simple)); |
251 | g_object_unref (object: simple); |
252 | |
253 | a.did_run = FALSE; |
254 | g_object_unref (object: group); |
255 | g_assert_false (a.did_run); |
256 | } |
257 | |
258 | G_GNUC_END_IGNORE_DEPRECATIONS |
259 | |
260 | static void |
261 | test_stateful (void) |
262 | { |
263 | GSimpleAction *action; |
264 | GVariant *state; |
265 | |
266 | action = g_simple_action_new_stateful (name: "foo" , NULL, state: g_variant_new_string (string: "hihi" )); |
267 | g_assert_true (g_action_get_enabled (G_ACTION (action))); |
268 | g_assert_null (g_action_get_parameter_type (G_ACTION (action))); |
269 | g_assert_null (g_action_get_state_hint (G_ACTION (action))); |
270 | g_assert_true (g_variant_type_equal (g_action_get_state_type (G_ACTION (action)), |
271 | G_VARIANT_TYPE_STRING)); |
272 | state = g_action_get_state (G_ACTION (action)); |
273 | g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi" ); |
274 | g_variant_unref (value: state); |
275 | |
276 | if (g_test_undefined ()) |
277 | { |
278 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
279 | pattern: "*assertion*g_variant_is_of_type*failed*" ); |
280 | g_simple_action_set_state (simple: action, value: g_variant_new_int32 (value: 123)); |
281 | g_test_assert_expected_messages (); |
282 | } |
283 | |
284 | g_simple_action_set_state (simple: action, value: g_variant_new_string (string: "hello" )); |
285 | state = g_action_get_state (G_ACTION (action)); |
286 | g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hello" ); |
287 | g_variant_unref (value: state); |
288 | |
289 | g_object_unref (object: action); |
290 | |
291 | action = g_simple_action_new (name: "foo" , NULL); |
292 | |
293 | if (g_test_undefined ()) |
294 | { |
295 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
296 | pattern: "*assertion*!= NULL*failed*" ); |
297 | g_simple_action_set_state (simple: action, value: g_variant_new_int32 (value: 123)); |
298 | g_test_assert_expected_messages (); |
299 | } |
300 | |
301 | g_object_unref (object: action); |
302 | } |
303 | |
304 | static void |
305 | test_default_activate (void) |
306 | { |
307 | GSimpleAction *action; |
308 | GVariant *state; |
309 | |
310 | /* Test changing state via activation with parameter */ |
311 | action = g_simple_action_new_stateful (name: "foo" , G_VARIANT_TYPE_STRING, state: g_variant_new_string (string: "hihi" )); |
312 | g_action_activate (G_ACTION (action), parameter: g_variant_new_string (string: "bye" )); |
313 | state = g_action_get_state (G_ACTION (action)); |
314 | g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "bye" ); |
315 | g_variant_unref (value: state); |
316 | g_object_unref (object: action); |
317 | |
318 | /* Test toggling a boolean action via activation with no parameter */ |
319 | action = g_simple_action_new_stateful (name: "foo" , NULL, state: g_variant_new_boolean (FALSE)); |
320 | g_action_activate (G_ACTION (action), NULL); |
321 | state = g_action_get_state (G_ACTION (action)); |
322 | g_assert_true (g_variant_get_boolean (state)); |
323 | g_variant_unref (value: state); |
324 | /* and back again */ |
325 | g_action_activate (G_ACTION (action), NULL); |
326 | state = g_action_get_state (G_ACTION (action)); |
327 | g_assert_false (g_variant_get_boolean (state)); |
328 | g_variant_unref (value: state); |
329 | g_object_unref (object: action); |
330 | } |
331 | |
332 | static gboolean foo_activated = FALSE; |
333 | static gboolean bar_activated = FALSE; |
334 | |
335 | static void |
336 | activate_foo (GSimpleAction *simple, |
337 | GVariant *parameter, |
338 | gpointer user_data) |
339 | { |
340 | g_assert_true (user_data == GINT_TO_POINTER (123)); |
341 | g_assert_null (parameter); |
342 | foo_activated = TRUE; |
343 | } |
344 | |
345 | static void |
346 | activate_bar (GSimpleAction *simple, |
347 | GVariant *parameter, |
348 | gpointer user_data) |
349 | { |
350 | g_assert_true (user_data == GINT_TO_POINTER (123)); |
351 | g_assert_cmpstr (g_variant_get_string (parameter, NULL), ==, "param" ); |
352 | bar_activated = TRUE; |
353 | } |
354 | |
355 | static void |
356 | change_volume_state (GSimpleAction *action, |
357 | GVariant *value, |
358 | gpointer user_data) |
359 | { |
360 | gint requested; |
361 | |
362 | requested = g_variant_get_int32 (value); |
363 | |
364 | /* Volume only goes from 0 to 10 */ |
365 | if (0 <= requested && requested <= 10) |
366 | g_simple_action_set_state (simple: action, value); |
367 | } |
368 | |
369 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
370 | |
371 | static void |
372 | test_entries (void) |
373 | { |
374 | const GActionEntry entries[] = { |
375 | { "foo" , activate_foo }, |
376 | { "bar" , activate_bar, "s" }, |
377 | { "toggle" , NULL, NULL, "false" }, |
378 | { "volume" , NULL, NULL, "0" , change_volume_state } |
379 | }; |
380 | GSimpleActionGroup *actions; |
381 | GVariant *state; |
382 | |
383 | actions = g_simple_action_group_new (); |
384 | g_simple_action_group_add_entries (simple: actions, entries, |
385 | G_N_ELEMENTS (entries), |
386 | GINT_TO_POINTER (123)); |
387 | |
388 | g_assert_false (foo_activated); |
389 | g_action_group_activate_action (G_ACTION_GROUP (actions), action_name: "foo" , NULL); |
390 | g_assert_true (foo_activated); |
391 | foo_activated = FALSE; |
392 | |
393 | g_assert_false (bar_activated); |
394 | g_action_group_activate_action (G_ACTION_GROUP (actions), action_name: "bar" , |
395 | parameter: g_variant_new_string (string: "param" )); |
396 | g_assert_true (bar_activated); |
397 | g_assert_false (foo_activated); |
398 | |
399 | if (g_test_undefined ()) |
400 | { |
401 | const GActionEntry bad_type = { |
402 | "bad-type" , NULL, "ss" |
403 | }; |
404 | const GActionEntry bad_state = { |
405 | "bad-state" , NULL, NULL, "flse" |
406 | }; |
407 | |
408 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
409 | pattern: "*not a valid GVariant type string*" ); |
410 | g_simple_action_group_add_entries (simple: actions, entries: &bad_type, n_entries: 1, NULL); |
411 | g_test_assert_expected_messages (); |
412 | |
413 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
414 | pattern: "*could not parse*" ); |
415 | g_simple_action_group_add_entries (simple: actions, entries: &bad_state, n_entries: 1, NULL); |
416 | g_test_assert_expected_messages (); |
417 | } |
418 | |
419 | state = g_action_group_get_action_state (G_ACTION_GROUP (actions), action_name: "volume" ); |
420 | g_assert_cmpint (g_variant_get_int32 (state), ==, 0); |
421 | g_variant_unref (value: state); |
422 | |
423 | /* should change */ |
424 | g_action_group_change_action_state (G_ACTION_GROUP (actions), action_name: "volume" , |
425 | value: g_variant_new_int32 (value: 7)); |
426 | state = g_action_group_get_action_state (G_ACTION_GROUP (actions), action_name: "volume" ); |
427 | g_assert_cmpint (g_variant_get_int32 (state), ==, 7); |
428 | g_variant_unref (value: state); |
429 | |
430 | /* should not change */ |
431 | g_action_group_change_action_state (G_ACTION_GROUP (actions), action_name: "volume" , |
432 | value: g_variant_new_int32 (value: 11)); |
433 | state = g_action_group_get_action_state (G_ACTION_GROUP (actions), action_name: "volume" ); |
434 | g_assert_cmpint (g_variant_get_int32 (state), ==, 7); |
435 | g_variant_unref (value: state); |
436 | |
437 | g_object_unref (object: actions); |
438 | } |
439 | |
440 | G_GNUC_END_IGNORE_DEPRECATIONS |
441 | |
442 | static void |
443 | test_parse_detailed (void) |
444 | { |
445 | struct { |
446 | const gchar *detailed; |
447 | const gchar *expected_name; |
448 | const gchar *expected_target; |
449 | const gchar *expected_error; |
450 | const gchar *detailed_roundtrip; |
451 | } testcases[] = { |
452 | { "abc" , "abc" , NULL, NULL, "abc" }, |
453 | { " abc" , NULL, NULL, "invalid format" , NULL }, |
454 | { " abc" , NULL, NULL, "invalid format" , NULL }, |
455 | { "abc:" , NULL, NULL, "invalid format" , NULL }, |
456 | { ":abc" , NULL, NULL, "invalid format" , NULL }, |
457 | { "abc(" , NULL, NULL, "invalid format" , NULL }, |
458 | { "abc)" , NULL, NULL, "invalid format" , NULL }, |
459 | { "(abc" , NULL, NULL, "invalid format" , NULL }, |
460 | { ")abc" , NULL, NULL, "invalid format" , NULL }, |
461 | { "abc::xyz" , "abc" , "'xyz'" , NULL, "abc::xyz" }, |
462 | { "abc('xyz')" , "abc" , "'xyz'" , NULL, "abc::xyz" }, |
463 | { "abc(42)" , "abc" , "42" , NULL, "abc(42)" }, |
464 | { "abc(int32 42)" , "abc" , "42" , NULL, "abc(42)" }, |
465 | { "abc(@i 42)" , "abc" , "42" , NULL, "abc(42)" }, |
466 | { "abc (42)" , NULL, NULL, "invalid format" , NULL }, |
467 | { "abc(42abc)" , NULL, NULL, "invalid character in number" , NULL }, |
468 | { "abc(42, 4)" , "abc" , "(42, 4)" , "expected end of input" , NULL }, |
469 | { "abc(42,)" , "abc" , "(42,)" , "expected end of input" , NULL } |
470 | }; |
471 | gint i; |
472 | |
473 | for (i = 0; i < G_N_ELEMENTS (testcases); i++) |
474 | { |
475 | GError *error = NULL; |
476 | GVariant *target; |
477 | gboolean success; |
478 | gchar *name; |
479 | |
480 | success = g_action_parse_detailed_name (detailed_name: testcases[i].detailed, action_name: &name, target_value: &target, error: &error); |
481 | g_assert_true (success == (error == NULL)); |
482 | if (success && testcases[i].expected_error) |
483 | g_error ("Unexpected success on '%s'. Expected error containing '%s'" , |
484 | testcases[i].detailed, testcases[i].expected_error); |
485 | |
486 | if (!success && !testcases[i].expected_error) |
487 | g_error ("Unexpected failure on '%s': %s" , testcases[i].detailed, error->message); |
488 | |
489 | if (!success) |
490 | { |
491 | if (!strstr (haystack: error->message, needle: testcases[i].expected_error)) |
492 | g_error ("Failure message '%s' for string '%s' did not contained expected substring '%s'" , |
493 | error->message, testcases[i].detailed, testcases[i].expected_error); |
494 | |
495 | g_error_free (error); |
496 | continue; |
497 | } |
498 | |
499 | g_assert_cmpstr (name, ==, testcases[i].expected_name); |
500 | g_assert_true ((target == NULL) == (testcases[i].expected_target == NULL)); |
501 | |
502 | if (success) |
503 | { |
504 | gchar *detailed; |
505 | |
506 | detailed = g_action_print_detailed_name (action_name: name, target_value: target); |
507 | g_assert_cmpstr (detailed, ==, testcases[i].detailed_roundtrip); |
508 | g_free (mem: detailed); |
509 | } |
510 | |
511 | if (target) |
512 | { |
513 | GVariant *expected; |
514 | |
515 | expected = g_variant_parse (NULL, text: testcases[i].expected_target, NULL, NULL, NULL); |
516 | g_assert_true (expected); |
517 | |
518 | g_assert_cmpvariant (expected, target); |
519 | g_variant_unref (value: expected); |
520 | g_variant_unref (value: target); |
521 | } |
522 | |
523 | g_free (mem: name); |
524 | } |
525 | } |
526 | |
527 | GHashTable *activation_counts; |
528 | |
529 | static void |
530 | count_activation (const gchar *action) |
531 | { |
532 | gint count; |
533 | |
534 | if (activation_counts == NULL) |
535 | activation_counts = g_hash_table_new (hash_func: g_str_hash, key_equal_func: g_str_equal); |
536 | count = GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action)); |
537 | count++; |
538 | g_hash_table_insert (hash_table: activation_counts, key: (gpointer)action, GINT_TO_POINTER (count)); |
539 | } |
540 | |
541 | static gint |
542 | activation_count (const gchar *action) |
543 | { |
544 | if (activation_counts == NULL) |
545 | return 0; |
546 | |
547 | return GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action)); |
548 | } |
549 | |
550 | static void |
551 | activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) |
552 | { |
553 | count_activation (action: g_action_get_name (G_ACTION (action))); |
554 | } |
555 | |
556 | static void |
557 | activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data) |
558 | { |
559 | GVariant *old_state, *new_state; |
560 | |
561 | count_activation (action: g_action_get_name (G_ACTION (action))); |
562 | |
563 | old_state = g_action_get_state (G_ACTION (action)); |
564 | new_state = g_variant_new_boolean (value: !g_variant_get_boolean (value: old_state)); |
565 | g_simple_action_set_state (simple: action, value: new_state); |
566 | g_variant_unref (value: old_state); |
567 | } |
568 | |
569 | static void |
570 | activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data) |
571 | { |
572 | GVariant *new_state; |
573 | |
574 | count_activation (action: g_action_get_name (G_ACTION (action))); |
575 | |
576 | new_state = g_variant_new_string (string: g_variant_get_string (value: parameter, NULL)); |
577 | g_simple_action_set_state (simple: action, value: new_state); |
578 | } |
579 | |
580 | static gboolean |
581 | compare_action_groups (GActionGroup *a, GActionGroup *b) |
582 | { |
583 | gchar **alist; |
584 | gchar **blist; |
585 | gint i; |
586 | gboolean equal; |
587 | gboolean ares, bres; |
588 | gboolean aenabled, benabled; |
589 | const GVariantType *aparameter_type, *bparameter_type; |
590 | const GVariantType *astate_type, *bstate_type; |
591 | GVariant *astate_hint, *bstate_hint; |
592 | GVariant *astate, *bstate; |
593 | |
594 | alist = g_action_group_list_actions (action_group: a); |
595 | blist = g_action_group_list_actions (action_group: b); |
596 | equal = strv_strv_cmp (a: alist, b: blist); |
597 | |
598 | for (i = 0; equal && alist[i]; i++) |
599 | { |
600 | ares = g_action_group_query_action (action_group: a, action_name: alist[i], enabled: &aenabled, parameter_type: &aparameter_type, state_type: &astate_type, state_hint: &astate_hint, state: &astate); |
601 | bres = g_action_group_query_action (action_group: b, action_name: alist[i], enabled: &benabled, parameter_type: &bparameter_type, state_type: &bstate_type, state_hint: &bstate_hint, state: &bstate); |
602 | |
603 | if (ares && bres) |
604 | { |
605 | equal = equal && (aenabled == benabled); |
606 | equal = equal && ((!aparameter_type && !bparameter_type) || g_variant_type_equal (type1: aparameter_type, type2: bparameter_type)); |
607 | equal = equal && ((!astate_type && !bstate_type) || g_variant_type_equal (type1: astate_type, type2: bstate_type)); |
608 | equal = equal && ((!astate_hint && !bstate_hint) || g_variant_equal (one: astate_hint, two: bstate_hint)); |
609 | equal = equal && ((!astate && !bstate) || g_variant_equal (one: astate, two: bstate)); |
610 | |
611 | if (astate_hint) |
612 | g_variant_unref (value: astate_hint); |
613 | if (bstate_hint) |
614 | g_variant_unref (value: bstate_hint); |
615 | if (astate) |
616 | g_variant_unref (value: astate); |
617 | if (bstate) |
618 | g_variant_unref (value: bstate); |
619 | } |
620 | else |
621 | equal = FALSE; |
622 | } |
623 | |
624 | g_strfreev (str_array: alist); |
625 | g_strfreev (str_array: blist); |
626 | |
627 | return equal; |
628 | } |
629 | |
630 | static gboolean |
631 | stop_loop (gpointer data) |
632 | { |
633 | GMainLoop *loop = data; |
634 | |
635 | g_main_loop_quit (loop); |
636 | |
637 | return G_SOURCE_REMOVE; |
638 | } |
639 | |
640 | static GActionEntry exported_entries[] = { |
641 | { "undo" , activate_action, NULL, NULL, NULL }, |
642 | { "redo" , activate_action, NULL, NULL, NULL }, |
643 | { "cut" , activate_action, NULL, NULL, NULL }, |
644 | { "copy" , activate_action, NULL, NULL, NULL }, |
645 | { "paste" , activate_action, NULL, NULL, NULL }, |
646 | { "bold" , activate_toggle, NULL, "true" , NULL }, |
647 | { "lang" , activate_radio, "s" , "'latin'" , NULL }, |
648 | }; |
649 | |
650 | static void |
651 | list_cb (GObject *source, |
652 | GAsyncResult *res, |
653 | gpointer user_data) |
654 | { |
655 | GDBusConnection *bus = G_DBUS_CONNECTION (source); |
656 | GMainLoop *loop = user_data; |
657 | GError *error = NULL; |
658 | GVariant *v; |
659 | gchar **actions; |
660 | |
661 | v = g_dbus_connection_call_finish (connection: bus, res, error: &error); |
662 | g_assert_nonnull (v); |
663 | g_variant_get (value: v, format_string: "(^a&s)" , &actions); |
664 | g_assert_cmpint (g_strv_length (actions), ==, G_N_ELEMENTS (exported_entries)); |
665 | g_free (mem: actions); |
666 | g_variant_unref (value: v); |
667 | g_main_loop_quit (loop); |
668 | } |
669 | |
670 | static gboolean |
671 | call_list (gpointer user_data) |
672 | { |
673 | GDBusConnection *bus; |
674 | |
675 | bus = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
676 | g_dbus_connection_call (connection: bus, |
677 | bus_name: g_dbus_connection_get_unique_name (connection: bus), |
678 | object_path: "/" , |
679 | interface_name: "org.gtk.Actions" , |
680 | method_name: "List" , |
681 | NULL, |
682 | NULL, |
683 | flags: 0, |
684 | G_MAXINT, |
685 | NULL, |
686 | callback: list_cb, |
687 | user_data); |
688 | g_object_unref (object: bus); |
689 | |
690 | return G_SOURCE_REMOVE; |
691 | } |
692 | |
693 | static void |
694 | describe_cb (GObject *source, |
695 | GAsyncResult *res, |
696 | gpointer user_data) |
697 | { |
698 | GDBusConnection *bus = G_DBUS_CONNECTION (source); |
699 | GMainLoop *loop = user_data; |
700 | GError *error = NULL; |
701 | GVariant *v; |
702 | gboolean enabled; |
703 | gchar *param; |
704 | GVariantIter *iter; |
705 | |
706 | v = g_dbus_connection_call_finish (connection: bus, res, error: &error); |
707 | g_assert_nonnull (v); |
708 | /* FIXME: there's an extra level of tuplelization in here */ |
709 | g_variant_get (value: v, format_string: "((bgav))" , &enabled, ¶m, &iter); |
710 | g_assert_true (enabled); |
711 | g_assert_cmpstr (param, ==, "" ); |
712 | g_assert_cmpint (g_variant_iter_n_children (iter), ==, 0); |
713 | g_free (mem: param); |
714 | g_variant_iter_free (iter); |
715 | g_variant_unref (value: v); |
716 | |
717 | g_main_loop_quit (loop); |
718 | } |
719 | |
720 | static gboolean |
721 | call_describe (gpointer user_data) |
722 | { |
723 | GDBusConnection *bus; |
724 | |
725 | bus = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
726 | g_dbus_connection_call (connection: bus, |
727 | bus_name: g_dbus_connection_get_unique_name (connection: bus), |
728 | object_path: "/" , |
729 | interface_name: "org.gtk.Actions" , |
730 | method_name: "Describe" , |
731 | parameters: g_variant_new (format_string: "(s)" , "copy" ), |
732 | NULL, |
733 | flags: 0, |
734 | G_MAXINT, |
735 | NULL, |
736 | callback: describe_cb, |
737 | user_data); |
738 | g_object_unref (object: bus); |
739 | |
740 | return G_SOURCE_REMOVE; |
741 | } |
742 | |
743 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
744 | |
745 | static void |
746 | test_dbus_export (void) |
747 | { |
748 | GDBusConnection *bus; |
749 | GSimpleActionGroup *group; |
750 | GDBusActionGroup *proxy; |
751 | GSimpleAction *action; |
752 | GMainLoop *loop; |
753 | GError *error = NULL; |
754 | GVariant *v; |
755 | guint id; |
756 | gchar **actions; |
757 | |
758 | loop = g_main_loop_new (NULL, FALSE); |
759 | |
760 | session_bus_up (); |
761 | bus = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
762 | |
763 | group = g_simple_action_group_new (); |
764 | g_simple_action_group_add_entries (simple: group, |
765 | entries: exported_entries, |
766 | G_N_ELEMENTS (exported_entries), |
767 | NULL); |
768 | |
769 | id = g_dbus_connection_export_action_group (connection: bus, object_path: "/" , G_ACTION_GROUP (group), error: &error); |
770 | g_assert_no_error (error); |
771 | |
772 | proxy = g_dbus_action_group_get (connection: bus, bus_name: g_dbus_connection_get_unique_name (connection: bus), object_path: "/" ); |
773 | |
774 | actions = g_action_group_list_actions (G_ACTION_GROUP (proxy)); |
775 | g_assert_cmpint (g_strv_length (actions), ==, 0); |
776 | g_strfreev (str_array: actions); |
777 | |
778 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
779 | g_main_loop_run (loop); |
780 | |
781 | actions = g_action_group_list_actions (G_ACTION_GROUP (proxy)); |
782 | g_assert_cmpint (g_strv_length (actions), ==, G_N_ELEMENTS (exported_entries)); |
783 | g_strfreev (str_array: actions); |
784 | |
785 | /* check that calling "List" works too */ |
786 | g_idle_add (function: call_list, data: loop); |
787 | g_main_loop_run (loop); |
788 | |
789 | /* check that calling "Describe" works */ |
790 | g_idle_add (function: call_describe, data: loop); |
791 | g_main_loop_run (loop); |
792 | |
793 | /* test that the initial transfer works */ |
794 | g_assert_true (G_IS_DBUS_ACTION_GROUP (proxy)); |
795 | g_assert_true (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy))); |
796 | |
797 | /* test that various changes get propagated from group to proxy */ |
798 | action = g_simple_action_new_stateful (name: "italic" , NULL, state: g_variant_new_boolean (FALSE)); |
799 | g_simple_action_group_insert (simple: group, G_ACTION (action)); |
800 | g_object_unref (object: action); |
801 | |
802 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
803 | g_main_loop_run (loop); |
804 | |
805 | g_assert_true (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy))); |
806 | |
807 | action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "cut" )); |
808 | g_simple_action_set_enabled (simple: action, FALSE); |
809 | |
810 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
811 | g_main_loop_run (loop); |
812 | |
813 | g_assert_true (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy))); |
814 | |
815 | action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "bold" )); |
816 | g_simple_action_set_state (simple: action, value: g_variant_new_boolean (FALSE)); |
817 | |
818 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
819 | g_main_loop_run (loop); |
820 | |
821 | g_assert_true (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy))); |
822 | |
823 | g_simple_action_group_remove (simple: group, action_name: "italic" ); |
824 | |
825 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
826 | g_main_loop_run (loop); |
827 | |
828 | g_assert_true (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy))); |
829 | |
830 | /* test that activations and state changes propagate the other way */ |
831 | |
832 | g_assert_cmpint (activation_count ("copy" ), ==, 0); |
833 | g_action_group_activate_action (G_ACTION_GROUP (proxy), action_name: "copy" , NULL); |
834 | |
835 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
836 | g_main_loop_run (loop); |
837 | |
838 | g_assert_cmpint (activation_count ("copy" ), ==, 1); |
839 | g_assert_true (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy))); |
840 | |
841 | g_assert_cmpint (activation_count ("bold" ), ==, 0); |
842 | g_action_group_activate_action (G_ACTION_GROUP (proxy), action_name: "bold" , NULL); |
843 | |
844 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
845 | g_main_loop_run (loop); |
846 | |
847 | g_assert_cmpint (activation_count ("bold" ), ==, 1); |
848 | g_assert_true (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy))); |
849 | v = g_action_group_get_action_state (G_ACTION_GROUP (group), action_name: "bold" ); |
850 | g_assert_true (g_variant_get_boolean (v)); |
851 | g_variant_unref (value: v); |
852 | |
853 | g_action_group_change_action_state (G_ACTION_GROUP (proxy), action_name: "bold" , value: g_variant_new_boolean (FALSE)); |
854 | |
855 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
856 | g_main_loop_run (loop); |
857 | |
858 | g_assert_cmpint (activation_count ("bold" ), ==, 1); |
859 | g_assert_true (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy))); |
860 | v = g_action_group_get_action_state (G_ACTION_GROUP (group), action_name: "bold" ); |
861 | g_assert_false (g_variant_get_boolean (v)); |
862 | g_variant_unref (value: v); |
863 | |
864 | g_dbus_connection_unexport_action_group (connection: bus, export_id: id); |
865 | |
866 | g_object_unref (object: proxy); |
867 | g_object_unref (object: group); |
868 | g_main_loop_unref (loop); |
869 | g_object_unref (object: bus); |
870 | |
871 | session_bus_down (); |
872 | } |
873 | |
874 | static gpointer |
875 | do_export (gpointer data) |
876 | { |
877 | GActionGroup *group = data; |
878 | GMainContext *ctx; |
879 | gint i; |
880 | GError *error = NULL; |
881 | guint id; |
882 | GDBusConnection *bus; |
883 | GAction *action; |
884 | gchar *path; |
885 | |
886 | ctx = g_main_context_new (); |
887 | |
888 | g_main_context_push_thread_default (context: ctx); |
889 | |
890 | bus = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
891 | path = g_strdup_printf(format: "/%p" , data); |
892 | |
893 | for (i = 0; i < 10000; i++) |
894 | { |
895 | id = g_dbus_connection_export_action_group (connection: bus, object_path: path, G_ACTION_GROUP (group), error: &error); |
896 | g_assert_no_error (error); |
897 | |
898 | action = g_simple_action_group_lookup (G_SIMPLE_ACTION_GROUP (group), action_name: "a" ); |
899 | g_simple_action_set_enabled (G_SIMPLE_ACTION (action), |
900 | enabled: !g_action_get_enabled (action)); |
901 | |
902 | g_dbus_connection_unexport_action_group (connection: bus, export_id: id); |
903 | |
904 | while (g_main_context_iteration (context: ctx, FALSE)); |
905 | } |
906 | |
907 | g_free (mem: path); |
908 | g_object_unref (object: bus); |
909 | |
910 | g_main_context_pop_thread_default (context: ctx); |
911 | |
912 | g_main_context_unref (context: ctx); |
913 | |
914 | return NULL; |
915 | } |
916 | |
917 | static void |
918 | test_dbus_threaded (void) |
919 | { |
920 | GSimpleActionGroup *group[10]; |
921 | GThread *export[10]; |
922 | static GActionEntry entries[] = { |
923 | { "a" , activate_action, NULL, NULL, NULL }, |
924 | { "b" , activate_action, NULL, NULL, NULL }, |
925 | }; |
926 | gint i; |
927 | |
928 | session_bus_up (); |
929 | |
930 | for (i = 0; i < 10; i++) |
931 | { |
932 | group[i] = g_simple_action_group_new (); |
933 | g_simple_action_group_add_entries (simple: group[i], entries, G_N_ELEMENTS (entries), NULL); |
934 | export[i] = g_thread_new (name: "export" , func: do_export, data: group[i]); |
935 | } |
936 | |
937 | for (i = 0; i < 10; i++) |
938 | g_thread_join (thread: export[i]); |
939 | |
940 | for (i = 0; i < 10; i++) |
941 | g_object_unref (object: group[i]); |
942 | |
943 | session_bus_down (); |
944 | } |
945 | |
946 | G_GNUC_END_IGNORE_DEPRECATIONS |
947 | |
948 | static void |
949 | test_bug679509 (void) |
950 | { |
951 | GDBusConnection *bus; |
952 | GDBusActionGroup *proxy; |
953 | GMainLoop *loop; |
954 | |
955 | loop = g_main_loop_new (NULL, FALSE); |
956 | |
957 | session_bus_up (); |
958 | bus = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
959 | |
960 | proxy = g_dbus_action_group_get (connection: bus, bus_name: g_dbus_connection_get_unique_name (connection: bus), object_path: "/" ); |
961 | g_strfreev (str_array: g_action_group_list_actions (G_ACTION_GROUP (proxy))); |
962 | g_object_unref (object: proxy); |
963 | |
964 | g_timeout_add (interval: 100, function: stop_loop, data: loop); |
965 | g_main_loop_run (loop); |
966 | |
967 | g_main_loop_unref (loop); |
968 | g_object_unref (object: bus); |
969 | |
970 | session_bus_down (); |
971 | } |
972 | |
973 | static gchar *state_change_log; |
974 | |
975 | static void |
976 | state_changed (GActionGroup *group, |
977 | const gchar *action_name, |
978 | GVariant *value, |
979 | gpointer user_data) |
980 | { |
981 | GString *string; |
982 | |
983 | g_assert_false (state_change_log); |
984 | |
985 | string = g_string_new (init: action_name); |
986 | g_string_append_c (string, ':'); |
987 | g_variant_print_string (value, string, TRUE); |
988 | state_change_log = g_string_free (string, FALSE); |
989 | } |
990 | |
991 | static void |
992 | verify_changed (const gchar *log_entry) |
993 | { |
994 | g_assert_cmpstr (state_change_log, ==, log_entry); |
995 | g_clear_pointer (&state_change_log, g_free); |
996 | } |
997 | |
998 | static void |
999 | ensure_state (GSimpleActionGroup *group, |
1000 | const gchar *action_name, |
1001 | const gchar *expected) |
1002 | { |
1003 | GVariant *value; |
1004 | gchar *printed; |
1005 | |
1006 | value = g_action_group_get_action_state (G_ACTION_GROUP (group), action_name); |
1007 | printed = g_variant_print (value, TRUE); |
1008 | g_variant_unref (value); |
1009 | |
1010 | g_assert_cmpstr (printed, ==, expected); |
1011 | g_free (mem: printed); |
1012 | } |
1013 | |
1014 | static void |
1015 | test_property_actions (void) |
1016 | { |
1017 | GSimpleActionGroup *group; |
1018 | GPropertyAction *action; |
1019 | GSocketClient *client; |
1020 | GApplication *app; |
1021 | gchar *name; |
1022 | GVariantType *ptype, *stype; |
1023 | gboolean enabled; |
1024 | GVariant *state; |
1025 | |
1026 | group = g_simple_action_group_new (); |
1027 | g_signal_connect (group, "action-state-changed" , G_CALLBACK (state_changed), NULL); |
1028 | |
1029 | client = g_socket_client_new (); |
1030 | app = g_application_new (application_id: "org.gtk.test" , flags: 0); |
1031 | |
1032 | /* string... */ |
1033 | action = g_property_action_new (name: "app-id" , object: app, property_name: "application-id" ); |
1034 | g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); |
1035 | g_object_unref (object: action); |
1036 | |
1037 | /* uint... */ |
1038 | action = g_property_action_new (name: "keepalive" , object: app, property_name: "inactivity-timeout" ); |
1039 | g_object_get (object: action, first_property_name: "name" , &name, "parameter-type" , &ptype, "enabled" , &enabled, "state-type" , &stype, "state" , &state, NULL); |
1040 | g_assert_cmpstr (name, ==, "keepalive" ); |
1041 | g_assert_true (enabled); |
1042 | g_free (mem: name); |
1043 | g_variant_type_free (type: ptype); |
1044 | g_variant_type_free (type: stype); |
1045 | g_variant_unref (value: state); |
1046 | |
1047 | g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); |
1048 | g_object_unref (object: action); |
1049 | |
1050 | /* bool... */ |
1051 | action = g_property_action_new (name: "tls" , object: client, property_name: "tls" ); |
1052 | g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); |
1053 | g_object_unref (object: action); |
1054 | |
1055 | /* inverted */ |
1056 | action = g_object_new (G_TYPE_PROPERTY_ACTION, |
1057 | first_property_name: "name" , "disable-proxy" , |
1058 | "object" , client, |
1059 | "property-name" , "enable-proxy" , |
1060 | "invert-boolean" , TRUE, |
1061 | NULL); |
1062 | g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); |
1063 | g_object_unref (object: action); |
1064 | |
1065 | /* enum... */ |
1066 | action = g_property_action_new (name: "type" , object: client, property_name: "type" ); |
1067 | g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action)); |
1068 | g_object_unref (object: action); |
1069 | |
1070 | /* the objects should be held alive by the actions... */ |
1071 | g_object_unref (object: client); |
1072 | g_object_unref (object: app); |
1073 | |
1074 | ensure_state (group, action_name: "app-id" , expected: "'org.gtk.test'" ); |
1075 | ensure_state (group, action_name: "keepalive" , expected: "uint32 0" ); |
1076 | ensure_state (group, action_name: "tls" , expected: "false" ); |
1077 | ensure_state (group, action_name: "disable-proxy" , expected: "false" ); |
1078 | ensure_state (group, action_name: "type" , expected: "'stream'" ); |
1079 | |
1080 | verify_changed (NULL); |
1081 | |
1082 | /* some string tests... */ |
1083 | g_action_group_change_action_state (G_ACTION_GROUP (group), action_name: "app-id" , value: g_variant_new (format_string: "s" , "org.gtk.test2" )); |
1084 | verify_changed (log_entry: "app-id:'org.gtk.test2'" ); |
1085 | g_assert_cmpstr (g_application_get_application_id (app), ==, "org.gtk.test2" ); |
1086 | ensure_state (group, action_name: "app-id" , expected: "'org.gtk.test2'" ); |
1087 | |
1088 | g_action_group_activate_action (G_ACTION_GROUP (group), action_name: "app-id" , parameter: g_variant_new (format_string: "s" , "org.gtk.test3" )); |
1089 | verify_changed (log_entry: "app-id:'org.gtk.test3'" ); |
1090 | g_assert_cmpstr (g_application_get_application_id (app), ==, "org.gtk.test3" ); |
1091 | ensure_state (group, action_name: "app-id" , expected: "'org.gtk.test3'" ); |
1092 | |
1093 | g_application_set_application_id (application: app, application_id: "org.gtk.test" ); |
1094 | verify_changed (log_entry: "app-id:'org.gtk.test'" ); |
1095 | ensure_state (group, action_name: "app-id" , expected: "'org.gtk.test'" ); |
1096 | |
1097 | /* uint tests */ |
1098 | g_action_group_change_action_state (G_ACTION_GROUP (group), action_name: "keepalive" , value: g_variant_new (format_string: "u" , 1234)); |
1099 | verify_changed (log_entry: "keepalive:uint32 1234" ); |
1100 | g_assert_cmpuint (g_application_get_inactivity_timeout (app), ==, 1234); |
1101 | ensure_state (group, action_name: "keepalive" , expected: "uint32 1234" ); |
1102 | |
1103 | g_action_group_activate_action (G_ACTION_GROUP (group), action_name: "keepalive" , parameter: g_variant_new (format_string: "u" , 5678)); |
1104 | verify_changed (log_entry: "keepalive:uint32 5678" ); |
1105 | g_assert_cmpuint (g_application_get_inactivity_timeout (app), ==, 5678); |
1106 | ensure_state (group, action_name: "keepalive" , expected: "uint32 5678" ); |
1107 | |
1108 | g_application_set_inactivity_timeout (application: app, inactivity_timeout: 0); |
1109 | verify_changed (log_entry: "keepalive:uint32 0" ); |
1110 | ensure_state (group, action_name: "keepalive" , expected: "uint32 0" ); |
1111 | |
1112 | /* bool tests */ |
1113 | g_action_group_change_action_state (G_ACTION_GROUP (group), action_name: "tls" , value: g_variant_new (format_string: "b" , TRUE)); |
1114 | verify_changed (log_entry: "tls:true" ); |
1115 | g_assert_true (g_socket_client_get_tls (client)); |
1116 | ensure_state (group, action_name: "tls" , expected: "true" ); |
1117 | |
1118 | g_action_group_change_action_state (G_ACTION_GROUP (group), action_name: "disable-proxy" , value: g_variant_new (format_string: "b" , TRUE)); |
1119 | verify_changed (log_entry: "disable-proxy:true" ); |
1120 | ensure_state (group, action_name: "disable-proxy" , expected: "true" ); |
1121 | g_assert_false (g_socket_client_get_enable_proxy (client)); |
1122 | |
1123 | /* test toggle true->false */ |
1124 | g_action_group_activate_action (G_ACTION_GROUP (group), action_name: "tls" , NULL); |
1125 | verify_changed (log_entry: "tls:false" ); |
1126 | g_assert_false (g_socket_client_get_tls (client)); |
1127 | ensure_state (group, action_name: "tls" , expected: "false" ); |
1128 | |
1129 | /* and now back false->true */ |
1130 | g_action_group_activate_action (G_ACTION_GROUP (group), action_name: "tls" , NULL); |
1131 | verify_changed (log_entry: "tls:true" ); |
1132 | g_assert_true (g_socket_client_get_tls (client)); |
1133 | ensure_state (group, action_name: "tls" , expected: "true" ); |
1134 | |
1135 | g_socket_client_set_tls (client, FALSE); |
1136 | verify_changed (log_entry: "tls:false" ); |
1137 | ensure_state (group, action_name: "tls" , expected: "false" ); |
1138 | |
1139 | /* now do the same for the inverted action */ |
1140 | g_action_group_activate_action (G_ACTION_GROUP (group), action_name: "disable-proxy" , NULL); |
1141 | verify_changed (log_entry: "disable-proxy:false" ); |
1142 | g_assert_true (g_socket_client_get_enable_proxy (client)); |
1143 | ensure_state (group, action_name: "disable-proxy" , expected: "false" ); |
1144 | |
1145 | g_action_group_activate_action (G_ACTION_GROUP (group), action_name: "disable-proxy" , NULL); |
1146 | verify_changed (log_entry: "disable-proxy:true" ); |
1147 | g_assert_false (g_socket_client_get_enable_proxy (client)); |
1148 | ensure_state (group, action_name: "disable-proxy" , expected: "true" ); |
1149 | |
1150 | g_socket_client_set_enable_proxy (client, TRUE); |
1151 | verify_changed (log_entry: "disable-proxy:false" ); |
1152 | ensure_state (group, action_name: "disable-proxy" , expected: "false" ); |
1153 | |
1154 | /* enum tests */ |
1155 | g_action_group_change_action_state (G_ACTION_GROUP (group), action_name: "type" , value: g_variant_new (format_string: "s" , "datagram" )); |
1156 | verify_changed (log_entry: "type:'datagram'" ); |
1157 | g_assert_cmpint (g_socket_client_get_socket_type (client), ==, G_SOCKET_TYPE_DATAGRAM); |
1158 | ensure_state (group, action_name: "type" , expected: "'datagram'" ); |
1159 | |
1160 | g_action_group_activate_action (G_ACTION_GROUP (group), action_name: "type" , parameter: g_variant_new (format_string: "s" , "stream" )); |
1161 | verify_changed (log_entry: "type:'stream'" ); |
1162 | g_assert_cmpint (g_socket_client_get_socket_type (client), ==, G_SOCKET_TYPE_STREAM); |
1163 | ensure_state (group, action_name: "type" , expected: "'stream'" ); |
1164 | |
1165 | g_socket_client_set_socket_type (client, type: G_SOCKET_TYPE_SEQPACKET); |
1166 | verify_changed (log_entry: "type:'seqpacket'" ); |
1167 | ensure_state (group, action_name: "type" , expected: "'seqpacket'" ); |
1168 | |
1169 | /* Check some error cases... */ |
1170 | g_test_expect_message (log_domain: "GLib-GIO" , log_level: G_LOG_LEVEL_CRITICAL, pattern: "*non-existent*" ); |
1171 | action = g_property_action_new (name: "foo" , object: app, property_name: "xyz" ); |
1172 | g_test_assert_expected_messages (); |
1173 | g_object_unref (object: action); |
1174 | |
1175 | g_test_expect_message (log_domain: "GLib-GIO" , log_level: G_LOG_LEVEL_CRITICAL, pattern: "*writable*" ); |
1176 | action = g_property_action_new (name: "foo" , object: app, property_name: "is-registered" ); |
1177 | g_test_assert_expected_messages (); |
1178 | g_object_unref (object: action); |
1179 | |
1180 | g_test_expect_message (log_domain: "GLib-GIO" , log_level: G_LOG_LEVEL_CRITICAL, pattern: "*type 'GSocketAddress'*" ); |
1181 | action = g_property_action_new (name: "foo" , object: client, property_name: "local-address" ); |
1182 | g_test_assert_expected_messages (); |
1183 | g_object_unref (object: action); |
1184 | |
1185 | g_object_unref (object: group); |
1186 | } |
1187 | |
1188 | int |
1189 | main (int argc, char **argv) |
1190 | { |
1191 | g_test_init (argc: &argc, argv: &argv, NULL); |
1192 | |
1193 | g_test_add_func (testpath: "/actions/basic" , test_func: test_basic); |
1194 | g_test_add_func (testpath: "/actions/name" , test_func: test_name); |
1195 | g_test_add_func (testpath: "/actions/simplegroup" , test_func: test_simple_group); |
1196 | g_test_add_func (testpath: "/actions/stateful" , test_func: test_stateful); |
1197 | g_test_add_func (testpath: "/actions/default-activate" , test_func: test_default_activate); |
1198 | g_test_add_func (testpath: "/actions/entries" , test_func: test_entries); |
1199 | g_test_add_func (testpath: "/actions/parse-detailed" , test_func: test_parse_detailed); |
1200 | g_test_add_func (testpath: "/actions/dbus/export" , test_func: test_dbus_export); |
1201 | g_test_add_func (testpath: "/actions/dbus/threaded" , test_func: test_dbus_threaded); |
1202 | g_test_add_func (testpath: "/actions/dbus/bug679509" , test_func: test_bug679509); |
1203 | g_test_add_func (testpath: "/actions/property" , test_func: test_property_actions); |
1204 | |
1205 | return g_test_run (); |
1206 | } |
1207 | |