1 | /* gtktestatcontext.c: Test AT context |
2 | * |
3 | * Copyright 2020 GNOME Foundation |
4 | * |
5 | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | #include "config.h" |
22 | |
23 | #include "gtktestatcontextprivate.h" |
24 | |
25 | #include "gtkatcontextprivate.h" |
26 | #include "gtkaccessibleprivate.h" |
27 | #include "gtkdebug.h" |
28 | #include "gtkenums.h" |
29 | #include "gtkprivate.h" |
30 | #include "gtktypebuiltins.h" |
31 | |
32 | struct _GtkTestATContext |
33 | { |
34 | GtkATContext parent_instance; |
35 | }; |
36 | |
37 | struct _GtkTestATContextClass |
38 | { |
39 | GtkATContextClass parent_class; |
40 | }; |
41 | |
42 | G_DEFINE_TYPE (GtkTestATContext, gtk_test_at_context, GTK_TYPE_AT_CONTEXT) |
43 | |
44 | static void |
45 | gtk_test_at_context_state_change (GtkATContext *self, |
46 | GtkAccessibleStateChange changed_states, |
47 | GtkAccessiblePropertyChange changed_properties, |
48 | GtkAccessibleRelationChange changed_relations, |
49 | GtkAccessibleAttributeSet *states, |
50 | GtkAccessibleAttributeSet *properties, |
51 | GtkAccessibleAttributeSet *relations) |
52 | { |
53 | if (GTK_DEBUG_CHECK (A11Y)) |
54 | { |
55 | char *states_str = gtk_accessible_attribute_set_to_string (self: states); |
56 | char *properties_str = gtk_accessible_attribute_set_to_string (self: properties); |
57 | char *relations_str = gtk_accessible_attribute_set_to_string (self: relations); |
58 | GtkAccessibleRole role = gtk_at_context_get_accessible_role (self); |
59 | GtkAccessible *accessible = gtk_at_context_get_accessible (self); |
60 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_ACCESSIBLE_ROLE); |
61 | GEnumValue *value = g_enum_get_value (enum_class: class, value: role); |
62 | |
63 | g_print (format: "*** Accessible state changed for accessible “%s”, with role “%s” (%d):\n" |
64 | "*** states = %s\n" |
65 | "*** properties = %s\n" |
66 | "*** relations = %s\n" , |
67 | G_OBJECT_TYPE_NAME (accessible), |
68 | value->value_nick, |
69 | role, |
70 | states_str, |
71 | properties_str, |
72 | relations_str); |
73 | g_type_class_unref (g_class: class); |
74 | |
75 | g_free (mem: states_str); |
76 | g_free (mem: properties_str); |
77 | g_free (mem: relations_str); |
78 | } |
79 | } |
80 | |
81 | static void |
82 | gtk_test_at_context_platform_change (GtkATContext *self, |
83 | GtkAccessiblePlatformChange changed_platform) |
84 | { |
85 | if (GTK_DEBUG_CHECK (A11Y)) |
86 | { |
87 | GtkAccessible *accessible; |
88 | |
89 | accessible = gtk_at_context_get_accessible (self); |
90 | |
91 | g_print (format: "*** Accessible platform state changed for accessible “%s”:\n" , |
92 | G_OBJECT_TYPE_NAME (accessible)); |
93 | if (changed_platform & GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSABLE) |
94 | g_print (format: "*** focusable = %d\n" , |
95 | gtk_accessible_get_platform_state (self: accessible, state: GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE)); |
96 | if (changed_platform & GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSED) |
97 | g_print (format: "*** focused = %d\n" , |
98 | gtk_accessible_get_platform_state (self: accessible, state: GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED)); |
99 | if (changed_platform & GTK_ACCESSIBLE_PLATFORM_CHANGE_ACTIVE) |
100 | g_print (format: "*** active = %d\n" , |
101 | gtk_accessible_get_platform_state (self: accessible, state: GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE)); |
102 | } |
103 | } |
104 | |
105 | static void |
106 | gtk_test_at_context_class_init (GtkTestATContextClass *klass) |
107 | { |
108 | GtkATContextClass *context_class = GTK_AT_CONTEXT_CLASS (ptr: klass); |
109 | |
110 | context_class->state_change = gtk_test_at_context_state_change; |
111 | context_class->platform_change = gtk_test_at_context_platform_change; |
112 | } |
113 | |
114 | static void |
115 | gtk_test_at_context_init (GtkTestATContext *self) |
116 | { |
117 | } |
118 | |
119 | /*< private > |
120 | * gtk_test_at_context_new: |
121 | * @accessible_role: the `GtkAccessibleRole` for the AT context |
122 | * @accessible: the `GtkAccessible` instance which owns the AT context |
123 | * @display: a `GdkDisplay` |
124 | * |
125 | * Creates a new `GtkTestATContext` instance for @accessible, using the |
126 | * given @accessible_role. |
127 | * |
128 | * Returns: (transfer full): the newly created `GtkTestATContext` instance |
129 | */ |
130 | GtkATContext * |
131 | gtk_test_at_context_new (GtkAccessibleRole accessible_role, |
132 | GtkAccessible *accessible, |
133 | GdkDisplay *display) |
134 | { |
135 | return g_object_new (GTK_TYPE_TEST_AT_CONTEXT, |
136 | first_property_name: "accessible-role" , accessible_role, |
137 | "accessible" , accessible, |
138 | "display" , display, |
139 | NULL); |
140 | } |
141 | |
142 | /** |
143 | * gtk_test_accessible_has_role: |
144 | * @accessible: a `GtkAccessible` |
145 | * @role: a `GtkAccessibleRole` |
146 | * |
147 | * Checks whether the `GtkAccessible:accessible-role` of the accessible |
148 | * is @role. |
149 | * |
150 | * Returns: %TRUE if the role matches |
151 | */ |
152 | gboolean |
153 | gtk_test_accessible_has_role (GtkAccessible *accessible, |
154 | GtkAccessibleRole role) |
155 | { |
156 | g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE); |
157 | |
158 | return gtk_accessible_get_accessible_role (self: accessible) == role; |
159 | } |
160 | |
161 | /** |
162 | * gtk_test_accessible_has_property: |
163 | * @accessible: a `GtkAccessible` |
164 | * @property: a `GtkAccessibleProperty` |
165 | * |
166 | * Checks whether the `GtkAccessible` has @property set. |
167 | * |
168 | * Returns: %TRUE if the @property is set in the @accessible |
169 | */ |
170 | gboolean |
171 | gtk_test_accessible_has_property (GtkAccessible *accessible, |
172 | GtkAccessibleProperty property) |
173 | { |
174 | GtkATContext *context; |
175 | |
176 | g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE); |
177 | |
178 | context = gtk_accessible_get_at_context (self: accessible); |
179 | if (context == NULL) |
180 | return FALSE; |
181 | |
182 | return gtk_at_context_has_accessible_property (self: context, property); |
183 | } |
184 | |
185 | /** |
186 | * gtk_test_accessible_check_property: |
187 | * @accessible: a `GtkAccessible` |
188 | * @property: a `GtkAccessibleProperty` |
189 | * @...: the expected value of @property |
190 | * |
191 | * Checks whether the accessible @property of @accessible is set to |
192 | * a specific value. |
193 | * |
194 | * Returns: (transfer full): the value of the accessible property |
195 | */ |
196 | char * |
197 | gtk_test_accessible_check_property (GtkAccessible *accessible, |
198 | GtkAccessibleProperty property, |
199 | ...) |
200 | { |
201 | char *res = NULL; |
202 | va_list args; |
203 | |
204 | va_start (args, property); |
205 | |
206 | GError *error = NULL; |
207 | GtkAccessibleValue *check_value = |
208 | gtk_accessible_value_collect_for_property (property, error: &error, args: &args); |
209 | |
210 | va_end (args); |
211 | |
212 | if (error != NULL) |
213 | { |
214 | res = g_strdup (str: error->message); |
215 | g_error_free (error); |
216 | return res; |
217 | } |
218 | |
219 | if (check_value == NULL) |
220 | check_value = gtk_accessible_value_get_default_for_property (property); |
221 | |
222 | GtkATContext *context = gtk_accessible_get_at_context (self: accessible); |
223 | GtkAccessibleValue *real_value = |
224 | gtk_at_context_get_accessible_property (self: context, property); |
225 | |
226 | if (gtk_accessible_value_equal (value_a: check_value, value_b: real_value)) |
227 | goto out; |
228 | |
229 | res = gtk_accessible_value_to_string (self: real_value); |
230 | |
231 | out: |
232 | gtk_accessible_value_unref (self: check_value); |
233 | |
234 | return res; |
235 | } |
236 | |
237 | /** |
238 | * gtk_test_accessible_has_state: |
239 | * @accessible: a `GtkAccessible` |
240 | * @state: a `GtkAccessibleState` |
241 | * |
242 | * Checks whether the `GtkAccessible` has @state set. |
243 | * |
244 | * Returns: %TRUE if the @state is set in the @accessible |
245 | */ |
246 | gboolean |
247 | gtk_test_accessible_has_state (GtkAccessible *accessible, |
248 | GtkAccessibleState state) |
249 | { |
250 | GtkATContext *context; |
251 | |
252 | g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE); |
253 | |
254 | context = gtk_accessible_get_at_context (self: accessible); |
255 | if (context == NULL) |
256 | return FALSE; |
257 | |
258 | return gtk_at_context_has_accessible_state (self: context, state); |
259 | } |
260 | |
261 | /** |
262 | * gtk_test_accessible_check_state: |
263 | * @accessible: a `GtkAccessible` |
264 | * @state: a `GtkAccessibleState` |
265 | * @...: the expected value of @state |
266 | * |
267 | * Checks whether the accessible @state of @accessible is set to |
268 | * a specific value. |
269 | * |
270 | * Returns: (transfer full): the value of the accessible state |
271 | */ |
272 | char * |
273 | gtk_test_accessible_check_state (GtkAccessible *accessible, |
274 | GtkAccessibleState state, |
275 | ...) |
276 | { |
277 | char *res = NULL; |
278 | va_list args; |
279 | |
280 | va_start (args, state); |
281 | |
282 | GError *error = NULL; |
283 | GtkAccessibleValue *check_value = |
284 | gtk_accessible_value_collect_for_state (state, error: &error, args: &args); |
285 | |
286 | va_end (args); |
287 | |
288 | if (error != NULL) |
289 | { |
290 | res = g_strdup (str: error->message); |
291 | g_error_free (error); |
292 | return res; |
293 | } |
294 | |
295 | if (check_value == NULL) |
296 | check_value = gtk_accessible_value_get_default_for_state (state); |
297 | |
298 | GtkATContext *context = gtk_accessible_get_at_context (self: accessible); |
299 | GtkAccessibleValue *real_value = |
300 | gtk_at_context_get_accessible_state (self: context, state); |
301 | |
302 | if (gtk_accessible_value_equal (value_a: check_value, value_b: real_value)) |
303 | goto out; |
304 | |
305 | res = gtk_accessible_value_to_string (self: real_value); |
306 | |
307 | out: |
308 | gtk_accessible_value_unref (self: check_value); |
309 | |
310 | return res; |
311 | } |
312 | |
313 | /** |
314 | * gtk_test_accessible_has_relation: |
315 | * @accessible: a `GtkAccessible` |
316 | * @relation: a `GtkAccessibleRelation` |
317 | * |
318 | * Checks whether the `GtkAccessible` has @relation set. |
319 | * |
320 | * Returns: %TRUE if the @relation is set in the @accessible |
321 | */ |
322 | gboolean |
323 | gtk_test_accessible_has_relation (GtkAccessible *accessible, |
324 | GtkAccessibleRelation relation) |
325 | { |
326 | GtkATContext *context; |
327 | |
328 | g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE); |
329 | |
330 | context = gtk_accessible_get_at_context (self: accessible); |
331 | if (context == NULL) |
332 | return FALSE; |
333 | |
334 | return gtk_at_context_has_accessible_relation (self: context, relation); |
335 | } |
336 | |
337 | /** |
338 | * gtk_test_accessible_check_relation: |
339 | * @accessible: a `GtkAccessible` |
340 | * @relation: a `GtkAccessibleRelation` |
341 | * @...: the expected value of @relation |
342 | * |
343 | * Checks whether the accessible @relation of @accessible is set to |
344 | * a specific value. |
345 | * |
346 | * Returns: (transfer full): the value of the accessible relation |
347 | */ |
348 | char * |
349 | gtk_test_accessible_check_relation (GtkAccessible *accessible, |
350 | GtkAccessibleRelation relation, |
351 | ...) |
352 | { |
353 | char *res = NULL; |
354 | va_list args; |
355 | |
356 | va_start (args, relation); |
357 | |
358 | GError *error = NULL; |
359 | GtkAccessibleValue *check_value = |
360 | gtk_accessible_value_collect_for_relation (relation, error: &error, args: &args); |
361 | |
362 | va_end (args); |
363 | |
364 | if (error != NULL) |
365 | { |
366 | res = g_strdup (str: error->message); |
367 | g_error_free (error); |
368 | return res; |
369 | } |
370 | |
371 | if (check_value == NULL) |
372 | check_value = gtk_accessible_value_get_default_for_relation (relation); |
373 | |
374 | GtkATContext *context = gtk_accessible_get_at_context (self: accessible); |
375 | GtkAccessibleValue *real_value = |
376 | gtk_at_context_get_accessible_relation (self: context, relation); |
377 | |
378 | if (gtk_accessible_value_equal (value_a: check_value, value_b: real_value)) |
379 | goto out; |
380 | |
381 | res = gtk_accessible_value_to_string (self: real_value); |
382 | |
383 | out: |
384 | gtk_accessible_value_unref (self: check_value); |
385 | |
386 | return res; |
387 | } |
388 | |
389 | /*< private > |
390 | * gtk_test_accessible_assertion_message_role: |
391 | * @domain: a domain |
392 | * @file: a file name |
393 | * @line: the line in @file |
394 | * @func: a function name in @file |
395 | * @expr: the expression being tested |
396 | * @accessible: a `GtkAccessible` |
397 | * @expected_role: the expected `GtkAccessibleRole` |
398 | * @actual_role: the actual `GtkAccessibleRole` |
399 | * |
400 | * Prints an assertion message for gtk_test_accessible_assert_role(). |
401 | */ |
402 | void |
403 | gtk_test_accessible_assertion_message_role (const char *domain, |
404 | const char *file, |
405 | int line, |
406 | const char *func, |
407 | const char *expr, |
408 | GtkAccessible *accessible, |
409 | GtkAccessibleRole expected_role, |
410 | GtkAccessibleRole actual_role) |
411 | { |
412 | char *role_name = g_enum_to_string (g_enum_type: GTK_TYPE_ACCESSIBLE_ROLE, value: actual_role); |
413 | char *s = g_strdup_printf (format: "assertion failed: (%s): %s.accessible-role = %s (%d)" , |
414 | expr, |
415 | G_OBJECT_TYPE_NAME (accessible), |
416 | role_name, |
417 | actual_role); |
418 | |
419 | g_assertion_message (domain, file, line, func, message: s); |
420 | |
421 | g_free (mem: role_name); |
422 | g_free (mem: s); |
423 | } |
424 | |