diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2020-07-17 14:39:56 +0100 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2020-07-26 20:31:15 +0100 |
commit | 0d87f8cd62358be481050722f7d7847a428670de (patch) | |
tree | 31959c4f9a227845a86e495d9dd4ccd236e97f39 | |
parent | 52c1fb8dfed7a60db9aab756d1c067234b508316 (diff) | |
download | gtk+-0d87f8cd62358be481050722f7d7847a428670de.tar.gz |
a11y: Add testing API
We want to test the accessibility API, as well as the implementation
inside each widget. For that, we should expose an API that lets us
verify that a GtkAccessible has a given role, as well as a given
property.
The API follows the pattern of other GTest API:
- a macro to assert that a condition is respected
- a function that prints out the error message in case of failure
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtkaccessible.h | 4 | ||||
-rw-r--r-- | gtk/gtkatcontext.c | 110 | ||||
-rw-r--r-- | gtk/gtkatcontext.h | 4 | ||||
-rw-r--r-- | gtk/gtkatcontextprivate.h | 10 | ||||
-rw-r--r-- | gtk/gtktestatcontext.c | 84 | ||||
-rw-r--r-- | gtk/gtktestatcontext.h | 73 | ||||
-rw-r--r-- | gtk/gtktestatcontextprivate.h | 13 | ||||
-rw-r--r-- | gtk/meson.build | 3 |
9 files changed, 288 insertions, 14 deletions
@@ -260,6 +260,7 @@ #include <gtk/gtktextview.h> #include <gtk/gtktogglebutton.h> #include <gtk/gtktooltip.h> +#include <gtk/gtktestatcontext.h> #include <gtk/gtktestutils.h> #include <gtk/gtktreednd.h> #include <gtk/gtktreeexpander.h> diff --git a/gtk/gtkaccessible.h b/gtk/gtkaccessible.h index d0a115d205..0f7776a1e4 100644 --- a/gtk/gtkaccessible.h +++ b/gtk/gtkaccessible.h @@ -20,6 +20,10 @@ #pragma once +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + #include <glib-object.h> #include <gtk/gtktypes.h> #include <gtk/gtkenums.h> diff --git a/gtk/gtkatcontext.c b/gtk/gtkatcontext.c index 7ea1f1a6bb..2fa6be8506 100644 --- a/gtk/gtkatcontext.c +++ b/gtk/gtkatcontext.c @@ -192,6 +192,24 @@ static const char *property_attrs[] = { [GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT] = "valuetext", }; +/*< private > + * gtk_accessible_property_get_attribute_name: + * @property: a #GtkAccessibleProperty + * + * Retrieves the name of a #GtkAccessibleProperty. + * + * Returns: (transfer none): the name of the accessible property + */ +const char * +gtk_accessible_property_get_attribute_name (GtkAccessibleProperty property) +{ + g_return_val_if_fail (property >= GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE && + property <= GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT, + "<none>"); + + return property_attrs[property]; +} + static const char *relation_attrs[] = { [GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT] = "activedescendant", [GTK_ACCESSIBLE_RELATION_COL_COUNT] = "colcount", @@ -213,6 +231,24 @@ static const char *relation_attrs[] = { [GTK_ACCESSIBLE_RELATION_SET_SIZE] = "setsize", }; +/*< private > + * gtk_accessible_relation_get_attribute_name: + * @relation: a #GtkAccessibleRelation + * + * Retrieves the name of a #GtkAccessibleRelation. + * + * Returns: (transfer none): the name of the accessible relation + */ +const char * +gtk_accessible_relation_get_attribute_name (GtkAccessibleRelation relation) +{ + g_return_val_if_fail (relation >= GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT && + relation <= GTK_ACCESSIBLE_RELATION_SET_SIZE, + "<none>"); + + return relation_attrs[relation]; +} + static const char *state_attrs[] = { [GTK_ACCESSIBLE_STATE_BUSY] = "busy", [GTK_ACCESSIBLE_STATE_CHECKED] = "checked", @@ -224,6 +260,24 @@ static const char *state_attrs[] = { [GTK_ACCESSIBLE_STATE_SELECTED] = "selected", }; +/*< private > + * gtk_accessible_state_get_attribute_name: + * @state: a #GtkAccessibleState + * + * Retrieves the name of a #GtkAccessibleState. + * + * Returns: (transfer none): the name of the accessible state + */ +const char * +gtk_accessible_state_get_attribute_name (GtkAccessibleState state) +{ + g_return_val_if_fail (state >= GTK_ACCESSIBLE_STATE_BUSY && + state <= GTK_ACCESSIBLE_STATE_SELECTED, + "<none>"); + + return state_attrs[state]; +} + static void gtk_at_context_init (GtkATContext *self) { @@ -355,7 +409,7 @@ gtk_at_context_update (GtkATContext *self) } /*< private > - * gtk_at_context_set_state: + * gtk_at_context_set_accessible_state: * @self: a #GtkATContext * @state: a #GtkAccessibleState * @value: (nullable): #GtkAccessibleValue @@ -381,6 +435,24 @@ gtk_at_context_set_accessible_state (GtkATContext *self, } /*< private > + * gtk_at_context_has_accessible_state: + * @self: a #GtkATContext + * @state: a #GtkAccessibleState + * + * Checks whether a #GtkATContext has the given @state set. + * + * Returns: %TRUE, if the accessible state is set + */ +gboolean +gtk_at_context_has_accessible_state (GtkATContext *self, + GtkAccessibleState state) +{ + g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), FALSE); + + return gtk_accessible_attribute_set_contains (self->states, state); +} + +/*< private > * gtk_at_context_set_accessible_property: * @self: a #GtkATContext * @property: a #GtkAccessibleProperty @@ -407,6 +479,24 @@ gtk_at_context_set_accessible_property (GtkATContext *self, } /*< private > + * gtk_at_context_has_accessible_property: + * @self: a #GtkATContext + * @property: a #GtkAccessibleProperty + * + * Checks whether a #GtkATContext has the given @property set. + * + * Returns: %TRUE, if the accessible property is set + */ +gboolean +gtk_at_context_has_accessible_property (GtkATContext *self, + GtkAccessibleProperty property) +{ + g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), FALSE); + + return gtk_accessible_attribute_set_contains (self->properties, property); +} + +/*< private > * gtk_at_context_set_accessible_relation: * @self: a #GtkATContext * @relation: a #GtkAccessibleRelation @@ -431,3 +521,21 @@ gtk_at_context_set_accessible_relation (GtkATContext *self, else gtk_accessible_attribute_set_remove (self->relations, relation); } + +/*< private > + * gtk_at_context_has_accessible_relation: + * @self: a #GtkATContext + * @relation: a #GtkAccessibleRelation + * + * Checks whether a #GtkATContext has the given @relation set. + * + * Returns: %TRUE, if the accessible relation is set + */ +gboolean +gtk_at_context_has_accessible_relation (GtkATContext *self, + GtkAccessibleRelation relation) +{ + g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), FALSE); + + return gtk_accessible_attribute_set_contains (self->relations, relation); +} diff --git a/gtk/gtkatcontext.h b/gtk/gtkatcontext.h index e2fca0f564..6522e029d6 100644 --- a/gtk/gtkatcontext.h +++ b/gtk/gtkatcontext.h @@ -20,6 +20,10 @@ #pragma once +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + #include <gtk/gtktypes.h> #include <gtk/gtkenums.h> #include <gtk/gtkaccessible.h> diff --git a/gtk/gtkatcontextprivate.h b/gtk/gtkatcontextprivate.h index c7f59f8fae..8c10db276c 100644 --- a/gtk/gtkatcontextprivate.h +++ b/gtk/gtkatcontextprivate.h @@ -113,11 +113,21 @@ void gtk_at_context_update (GtkATContext * void gtk_at_context_set_accessible_state (GtkATContext *self, GtkAccessibleState state, GtkAccessibleValue *value); +gboolean gtk_at_context_has_accessible_state (GtkATContext *self, + GtkAccessibleState state); void gtk_at_context_set_accessible_property (GtkATContext *self, GtkAccessibleProperty property, GtkAccessibleValue *value); +gboolean gtk_at_context_has_accessible_property (GtkATContext *self, + GtkAccessibleProperty property); void gtk_at_context_set_accessible_relation (GtkATContext *self, GtkAccessibleRelation property, GtkAccessibleValue *value); +gboolean gtk_at_context_has_accessible_relation (GtkATContext *self, + GtkAccessibleRelation relation); + +const char * gtk_accessible_property_get_attribute_name (GtkAccessibleProperty property); +const char * gtk_accessible_relation_get_attribute_name (GtkAccessibleRelation relation); +const char * gtk_accessible_state_get_attribute_name (GtkAccessibleState state); G_END_DECLS diff --git a/gtk/gtktestatcontext.c b/gtk/gtktestatcontext.c index 8eade3566c..b7eb29b642 100644 --- a/gtk/gtktestatcontext.c +++ b/gtk/gtktestatcontext.c @@ -24,12 +24,18 @@ #include "gtkatcontextprivate.h" #include "gtkenums.h" +#include "gtktypebuiltins.h" struct _GtkTestATContext { GtkATContext parent_instance; }; +struct _GtkTestATContextClass +{ + GtkATContextClass parent_class; +}; + G_DEFINE_TYPE (GtkTestATContext, gtk_test_at_context, GTK_TYPE_AT_CONTEXT) static void @@ -75,6 +81,16 @@ gtk_test_at_context_init (GtkTestATContext *self) { } +/*< private > + * gtk_test_at_context_new: + * @accessible_role: the #GtkAccessibleRole for the AT context + * @accessible: the #GtkAccessible instance which owns the AT context + * + * Creates a new #GtkTestATContext instance for @accessible, using the + * given @accessible_role. + * + * Returns: (transfer full): the newly created #GtkTestATContext instance + */ GtkATContext * gtk_test_at_context_new (GtkAccessibleRole accessible_role, GtkAccessible *accessible) @@ -84,3 +100,71 @@ gtk_test_at_context_new (GtkAccessibleRole accessible_role, "accessible", accessible, NULL); } + +gboolean +gtk_test_accessible_has_role (GtkAccessible *accessible, + GtkAccessibleRole role) +{ + GtkATContext *context; + + g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE); + + context = gtk_accessible_get_at_context (accessible); + if (context == NULL) + return FALSE; + + return gtk_at_context_get_accessible_role (context) == role; +} + +gboolean +gtk_test_accessible_has_property (GtkAccessible *accessible, + GtkAccessibleProperty property) +{ + GtkATContext *context; + + g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE); + + context = gtk_accessible_get_at_context (accessible); + if (context == NULL) + return FALSE; + + return gtk_at_context_has_accessible_property (context, property); +} + +void +gtk_test_accessible_assertion_message_cmprole (const char *domain, + const char *file, + int line, + const char *func, + const char *expr, + GtkAccessible *accessible, + GtkAccessibleRole role) +{ + char *role_name = g_enum_to_string (GTK_TYPE_ACCESSIBLE_ROLE, role); + char *s = g_strdup_printf ("%s:accessible-role == %s", + G_OBJECT_TYPE_NAME (accessible), + role_name); + + g_assertion_message_expr (domain, file, line, func, s); + + g_free (role_name); + g_free (s); +} + +void +gtk_test_accessible_assertion_message_cmpproperty (const char *domain, + const char *file, + int line, + const char *func, + const char *expr, + GtkAccessible *accessible, + GtkAccessibleProperty property) +{ + char *s = g_strdup_printf ("%s:accessible-property == %s", + G_OBJECT_TYPE_NAME (accessible), + gtk_accessible_property_get_attribute_name (property)); + + g_assertion_message_expr (domain, file, line, func, s); + + g_free (s); +} diff --git a/gtk/gtktestatcontext.h b/gtk/gtktestatcontext.h new file mode 100644 index 0000000000..50ab7302d5 --- /dev/null +++ b/gtk/gtktestatcontext.h @@ -0,0 +1,73 @@ +/* gtktestatcontext.h: Test AT context + * + * Copyright 2020 GNOME Foundation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gtk/gtkatcontext.h> + +G_BEGIN_DECLS + +#define gtk_test_accessible_assert_cmprole(accessible,role) G_STMT_START { \ + GtkAccessible *__a = GTK_ACCESSIBLE (accessible); \ + GtkAccessibleRole __r = (role); \ + if (gtk_test_accessible_has_role (__a, __r)) ; else \ + gtk_test_accessible_assertion_message_cmprole (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + #accessible " == " #role, \ + __a, __r); \ + } G_STMT_END +#define gtk_test_accessible_assert_cmpproperty(accessible,property) G_STMT_START { \ + GtkAccessible *__a = GTK_ACCESSIBLE (accessible); \ + GtkAccessibleProperty __p = (property); \ + if (gtk_test_accessible_has_property (__a, __p)) ; else \ + gtk_test_accessible_assertion_message_cmpproperty (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + #accessible " == " #property, \ + __a, __p); \ + } G_STMT_END + +GDK_AVAILABLE_IN_ALL +gboolean gtk_test_accessible_has_role (GtkAccessible *accessible, + GtkAccessibleRole role); +GDK_AVAILABLE_IN_ALL +gboolean gtk_test_accessible_has_property (GtkAccessible *accessible, + GtkAccessibleProperty property); + +GDK_AVAILABLE_IN_ALL +void gtk_test_accessible_assertion_message_cmprole (const char *domain, + const char *file, + int line, + const char *func, + const char *expr, + GtkAccessible *accessible, + GtkAccessibleRole role) G_GNUC_NORETURN; +GDK_AVAILABLE_IN_ALL +void gtk_test_accessible_assertion_message_cmpproperty (const char *domain, + const char *file, + int line, + const char *func, + const char *expr, + GtkAccessible *accessible, + GtkAccessibleProperty property) G_GNUC_NORETURN; + + +G_END_DECLS diff --git a/gtk/gtktestatcontextprivate.h b/gtk/gtktestatcontextprivate.h index 2b5cc108e3..edafb76c4c 100644 --- a/gtk/gtktestatcontextprivate.h +++ b/gtk/gtktestatcontextprivate.h @@ -20,6 +20,7 @@ #pragma once +#include "gtktestatcontext.h" #include "gtkatcontextprivate.h" G_BEGIN_DECLS @@ -32,16 +33,4 @@ GtkATContext * gtk_test_at_context_new (GtkAccessibleRole accessible_role, GtkAccessible *accessible); -void -gtk_test_at_context_assert_role (GtkTestATContext *self, - GtkAccessibleRole role); - -void -gtk_test_at_context_assert_state_added (GtkTestATContext *self, - GtkAccessibleState state); - -void -gtk_test_at_context_assert_state_removed (GtkTestATContext *self, - GtkAccessibleState state); - G_END_DECLS diff --git a/gtk/meson.build b/gtk/meson.build index 2ae4267e96..bdededeaa8 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -139,7 +139,6 @@ gtk_private_sources = files([ 'gtkstyleanimation.c', 'gtkstylecascade.c', 'gtkstyleproperty.c', - 'gtktestatcontext.c', 'gtktextbtree.c', 'gtktexthistory.c', 'gtktextviewchild.c', @@ -389,6 +388,7 @@ gtk_public_sources = files([ 'gtkstylecontext.c', 'gtkstyleprovider.c', 'gtkswitch.c', + 'gtktestatcontext.c', 'gtktestutils.c', 'gtktext.c', 'gtktextattributes.c', @@ -660,6 +660,7 @@ gtk_public_headers = files([ 'gtkstylecontext.h', 'gtkstyleprovider.h', 'gtkswitch.h', + 'gtktestatcontext.h', 'gtktestutils.h', 'gtktext.h', 'gtktextbuffer.h', |