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
32struct _GtkTestATContext
33{
34 GtkATContext parent_instance;
35};
36
37struct _GtkTestATContextClass
38{
39 GtkATContextClass parent_class;
40};
41
42G_DEFINE_TYPE (GtkTestATContext, gtk_test_at_context, GTK_TYPE_AT_CONTEXT)
43
44static void
45gtk_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
81static void
82gtk_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
105static void
106gtk_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
114static void
115gtk_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 */
130GtkATContext *
131gtk_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 */
152gboolean
153gtk_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 */
170gboolean
171gtk_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 */
196char *
197gtk_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
231out:
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 */
246gboolean
247gtk_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 */
272char *
273gtk_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
307out:
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 */
322gboolean
323gtk_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 */
348char *
349gtk_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
383out:
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 */
402void
403gtk_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

source code of gtk/gtk/gtktestatcontext.c