gtk/tests/a11y/accessibility-dump.c
Benjamin Otte 2f744db943 tests: Don't print selection count
Selection count is tested via assertions and can be inferred from
looking at the number of selected children.

And I'd like to reduce the output of the tests. We're outputting way too
much anyway.
2011-07-05 16:08:56 -04:00

868 lines
23 KiB
C

/*
* Copyright (C) 2011 Red Hat Inc.
*
* Author:
* Benjamin Otte <otte@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#define DEPTH_INCREMENT 2
static char *
get_test_file (const char *test_file,
const char *extension,
gboolean must_exist)
{
GString *file = g_string_new (NULL);
if (g_str_has_suffix (test_file, ".ui"))
g_string_append_len (file, test_file, strlen (test_file) - strlen (".ui"));
else
g_string_append (file, test_file);
g_string_append (file, extension);
if (must_exist &&
!g_file_test (file->str, G_FILE_TEST_EXISTS))
{
g_string_free (file, TRUE);
return NULL;
}
return g_string_free (file, FALSE);
}
static char *
diff_with_file (const char *file1,
char *text,
gssize len,
GError **error)
{
const char *command[] = { "diff", "-u", file1, NULL, NULL };
char *diff, *tmpfile;
int fd;
diff = NULL;
if (len < 0)
len = strlen (text);
/* write the text buffer to a temporary file */
fd = g_file_open_tmp (NULL, &tmpfile, error);
if (fd < 0)
return NULL;
if (write (fd, text, len) != (int) len)
{
close (fd);
g_set_error (error,
G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Could not write data to temporary file '%s'", tmpfile);
goto done;
}
close (fd);
command[3] = tmpfile;
/* run diff command */
g_spawn_sync (NULL,
(char **) command,
NULL,
G_SPAWN_SEARCH_PATH,
NULL, NULL,
&diff,
NULL, NULL,
error);
done:
g_unlink (tmpfile);
g_free (tmpfile);
return diff;
}
static int unnamed_object_count;
static void
setup_test (void)
{
unnamed_object_count = 0;
}
static const char *
get_name (AtkObject *accessible)
{
char *name;
name = g_object_get_data (G_OBJECT (accessible), "gtk-accessibility-dump-name");
if (name)
return name;
if (GTK_IS_ACCESSIBLE (accessible))
{
GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
name = g_strdup (gtk_buildable_get_name (GTK_BUILDABLE (widget)));
}
if (name == NULL && ATK_IS_TEXT (accessible))
{
name = atk_text_get_text (ATK_TEXT (accessible), 0, -1);
}
if (name == NULL)
{
/* Generate a unique, repeatable name */
name = g_strdup_printf ("unnamed-%s-%d", G_OBJECT_TYPE_NAME (accessible), unnamed_object_count++);
}
g_object_set_data_full (G_OBJECT (accessible), "gtk-accessibility-dump-name", name, g_free);
return name;
}
static void
dump_relation (GString *string,
guint depth,
AtkRelation *relation)
{
GPtrArray *targets;
const char *name;
guint i;
targets = atk_relation_get_target (relation);
if (targets == NULL || targets->len == 0)
return;
name = atk_relation_type_get_name (atk_relation_get_relation_type (relation));
g_string_append_printf (string, "%*s%s: %s\n", depth, "", name, get_name (g_ptr_array_index (targets, 0)));
depth += strlen (name) + 2;
for (i = 1; i < targets->len; i++)
{
g_string_append_printf (string, "%*s%s\n", depth, "", get_name (g_ptr_array_index (targets, i)));
}
}
static void
dump_relation_set (GString *string,
guint depth,
AtkRelationSet *set)
{
guint i;
if (set == NULL)
return;
for (i = 0; i < atk_relation_set_get_n_relations (set); i++)
{
AtkRelation *relation;
relation = atk_relation_set_get_relation (set, i);
dump_relation (string, depth, relation);
}
g_object_unref (set);
}
static void
dump_state_set (GString *string,
guint depth,
AtkStateSet *set)
{
guint i;
if (set == NULL)
return;
if (!atk_state_set_is_empty (set))
{
g_string_append_printf (string, "%*sstate:", depth, "");
for (i = 0; i < ATK_STATE_LAST_DEFINED; i++)
{
if (atk_state_set_contains_state (set, i))
g_string_append_printf (string, " %s", atk_state_type_get_name (i));
}
g_string_append_c (string, '\n');
}
g_object_unref (set);
}
static void
dump_attribute (GString *string,
guint depth,
AtkAttribute *attribute)
{
g_string_append_printf (string, "%*s%s: %s\n", depth, "", attribute->name, attribute->value);
}
static void
dump_attribute_set (GString *string,
guint depth,
AtkAttributeSet *set)
{
GSList *l;
AtkAttribute *attribute;
for (l = set; l; l = l->next)
{
attribute = l->data;
dump_attribute (string, depth, attribute);
}
}
static gint
compare_attr (gconstpointer a, gconstpointer b)
{
const AtkAttribute *aattr = a;
const AtkAttribute *battr = b;
return strcmp (aattr->name, battr->name);
}
static void
dump_text_attributes (GString *string,
gint depth,
const gchar *name,
AtkAttributeSet *attributes)
{
GSList *l;
AtkAttribute *attr;
const gchar *value;
if (attributes == NULL)
return;
attributes = g_slist_sort (attributes, compare_attr);
for (l = attributes; l; l = l->next)
{
attr = l->data;
/* don't dump values that depend on the environment */
if (strcmp (attr->name, "family-name") == 0 ||
strcmp (attr->name, "size") == 0 ||
strcmp (attr->name, "weight") == 0 ||
strcmp (attr->name, "stretch") == 0 ||
strcmp (attr->name, "variant") == 0 ||
strcmp (attr->name, "style") == 0 ||
strcmp (attr->name, "language") == 0 ||
strcmp (attr->name, "fg-color") == 0 ||
strcmp (attr->name, "bg-color") == 0 ||
strcmp (attr->name, "direction") == 0)
value = "<omitted>";
else
value = attr->value;
if (name)
{
/* first time this loop is run */
g_string_append_printf (string, "%*s%s: %s: %s\n", depth, "", name, attr->name, value);
depth += strlen (name) + 2;
name = NULL;
}
else
{
/* every other time */
g_string_append_printf (string, "%*s%s: %s\n", depth, "", attr->name, value);
}
}
atk_attribute_set_free (attributes);
}
extern GType atk_layer_get_type (void);
static const gchar *
layer_name (AtkLayer layer)
{
GEnumClass *class;
GEnumValue *value;
class = g_type_class_ref (atk_layer_get_type ());
value = g_enum_get_value (class, layer);
g_type_class_unref (class);
return value->value_nick;
}
static void
dump_atk_component (AtkComponent *atk_component,
guint depth,
GString *string)
{
AtkLayer layer;
g_string_append_printf (string, "%*s<AtkComponent>\n", depth, "");
layer = atk_component_get_layer (atk_component);
g_string_append_printf (string, "%*slayer: %s\n", depth, "", layer_name (layer));
g_string_append_printf (string, "%*salpha: %g\n", depth, "", atk_component_get_alpha (atk_component));
}
static void
dump_atk_text (AtkText *atk_text,
guint depth,
GString *string)
{
gchar *text;
gint i, start, end;
g_string_append_printf (string, "%*s<AtkText>\n", depth, "");
text = atk_text_get_text (atk_text, 0, -1);
g_string_append_printf (string, "%*stext: %s\n", depth, "", text);
g_free (text);
g_string_append_printf (string, "%*scharacter count: %d\n", depth, "", atk_text_get_character_count (atk_text));
g_string_append_printf (string, "%*scaret offset: %d\n", depth, "", atk_text_get_caret_offset (atk_text));
for (i = 0; i < atk_text_get_n_selections (atk_text); i++)
{
text = atk_text_get_selection (atk_text, i, &start, &end);
if (text)
g_string_append_printf (string, "%*sselection %d: (%d, %d) %s\n", depth, "", i, start, end, text);
g_free (text);
}
dump_text_attributes (string, depth, "default attributes", atk_text_get_default_attributes (atk_text));
}
static void
dump_atk_image (AtkImage *atk_image,
guint depth,
GString *string)
{
gint width, height;
g_string_append_printf (string, "%*s<AtkImage>\n", depth, "");
atk_image_get_image_size (atk_image, &width, &height);
g_string_append_printf (string, "%*simage size: %d x %d\n", depth, "", width, height);
g_string_append_printf (string, "%*simage description: %s\n", depth, "", atk_image_get_image_description (atk_image));
}
static void
dump_atk_action (AtkAction *atk_action,
guint depth,
GString *string)
{
gint i;
g_string_append_printf (string, "%*s<AtkAction>\n", depth, "");
for (i = 0; i < atk_action_get_n_actions (atk_action); i++)
{
if (atk_action_get_name (atk_action, i))
g_string_append_printf (string, "%*saction %d name: %s\n", depth, "", i, atk_action_get_name (atk_action, i));
if (atk_action_get_description (atk_action, i))
g_string_append_printf (string, "%*saction %d description: %s\n", depth, "", i, atk_action_get_description (atk_action, i));
if (atk_action_get_keybinding (atk_action, i))
g_string_append_printf (string, "%*saction %d keybinding: %s\n", depth, "", i, atk_action_get_keybinding (atk_action, i));
}
}
static void
dump_atk_selection (AtkSelection *atk_selection,
guint depth,
GString *string)
{
guint n_selections, n_counted_selections;
gint i;
g_string_append_printf (string, "%*s<AtkSelection>\n", depth, "");
n_selections = atk_selection_get_selection_count (atk_selection);
n_counted_selections = 0;
for (i = 0; i < atk_object_get_n_accessible_children (ATK_OBJECT (atk_selection)); i++)
{
if (atk_selection_is_child_selected (atk_selection, i))
{
AtkObject *object = atk_object_ref_accessible_child (ATK_OBJECT (atk_selection), i);
g_assert (object);
if (n_counted_selections == 0)
{
g_string_append_printf (string, "%*sselected children: %s\n", depth, "", get_name (object));
depth += strlen ("selected children: ");
}
else
g_string_append_printf (string, "%*s%s\n", depth, "", get_name (object));
n_counted_selections++;
}
}
g_assert_cmpint (n_selections, ==, n_counted_selections);
g_assert_cmpint (n_selections, ==, atk_selection_get_selection_count (atk_selection));
}
static void
dump_atk_value (AtkValue *atk_value,
guint depth,
GString *string)
{
GValue value = { 0, };
GValue svalue = { 0, };
g_string_append_printf (string, "%*s<AtkValue>\n", depth, "");
g_value_init (&value, G_TYPE_DOUBLE);
g_value_init (&svalue, G_TYPE_STRING);
atk_value_get_minimum_value (atk_value, &value);
if (g_value_transform (&value, &svalue))
g_string_append_printf (string, "%*sminimum value: %s\n", depth, "", g_value_get_string (&svalue));
else
g_string_append_printf (string, "%*sminimum value: <%s>\n", depth, "", G_VALUE_TYPE_NAME (&value));
g_value_reset (&value);
g_value_reset (&svalue);
atk_value_get_maximum_value (atk_value, &value);
if (g_value_transform (&value, &svalue))
g_string_append_printf (string, "%*smaximum value: %s\n", depth, "", g_value_get_string (&svalue));
else
g_string_append_printf (string, "%*smaximum value: <%s>\n", depth, "", G_VALUE_TYPE_NAME (&value));
g_value_reset (&value);
g_value_reset (&svalue);
atk_value_get_current_value (atk_value, &value);
if (g_value_transform (&value, &svalue))
g_string_append_printf (string, "%*scurrent value: %s\n", depth, "", g_value_get_string (&svalue));
else
g_string_append_printf (string, "%*scurrent value: %s\n", depth, "", G_VALUE_TYPE_NAME (&value));
g_value_reset (&value);
g_value_reset (&svalue);
atk_value_get_minimum_increment (atk_value, &value);
if (g_value_transform (&value, &svalue))
g_string_append_printf (string, "%*sminimum increment: %s\n", depth, "", g_value_get_string (&svalue));
else
g_string_append_printf (string, "%*sminimum increment: %s\n", depth, "", G_VALUE_TYPE_NAME (&value));
g_value_reset (&value);
g_value_reset (&svalue);
}
static void
dump_atk_hyperlink_impl (AtkHyperlinkImpl *impl,
guint depth,
GString *string)
{
AtkHyperlink *atk_link;
gint i;
g_string_append_printf (string, "%*s<AtkHyperlinkImpl>\n", depth, "");
atk_link = atk_hyperlink_impl_get_hyperlink (impl);
g_string_append_printf (string, "%*sanchors:", depth, "");
for (i = 0; i < atk_hyperlink_get_n_anchors (atk_link); i++)
{
gchar *uri;
uri = atk_hyperlink_get_uri (atk_link, i);
g_string_append_printf (string, " %s", uri);
g_free (uri);
}
g_string_append_c (string, '\n');
g_object_unref (atk_link);
}
static void
dump_atk_streamable_content (AtkStreamableContent *content,
guint depth,
GString *string)
{
gint i;
g_string_append_printf (string, "%*s<AtkStreamableContent>\n", depth, "");
g_string_append_printf (string, "%*smime types:", depth, "");
for (i = 0; i < atk_streamable_content_get_n_mime_types (content); i++)
g_string_append_printf (string, " %s", atk_streamable_content_get_mime_type (content, i));
g_string_append_c (string, '\n');
}
static void dump_accessible (AtkObject *accessible,
guint depth,
GString *string);
static void
dump_atk_table (AtkTable *table,
guint depth,
GString *string)
{
gint *selected;
gint n_selected;
gint i;
AtkObject *obj;
const gchar *desc;
g_string_append_printf (string, "%*s<AtkTable>\n", depth, "");
obj = atk_table_get_summary (table);
if (obj)
{
g_string_append_printf (string, "%*s<summary>\n", depth, "");
dump_accessible (obj, depth, string);
}
obj = atk_table_get_caption (table);
if (obj)
{
g_string_append_printf (string, "%*s<caption>\n", depth, "");
dump_accessible (obj, depth, string);
}
g_string_append_printf (string, "%*srows: %d\n", depth, "", atk_table_get_n_rows (table));
g_string_append_printf (string, "%*scolumns: %d\n", depth, "", atk_table_get_n_columns (table));
selected = NULL;
n_selected = atk_table_get_selected_rows (table, &selected);
if (n_selected > 0)
{
g_string_append_printf (string, "%*sselected rows:", depth, "");
for (i = 0; i < n_selected; i++)
g_string_append_printf (string, " %d", selected[i]);
g_string_append_c (string, '\n');
}
g_free (selected);
selected = NULL;
n_selected = atk_table_get_selected_columns (table, &selected);
if (n_selected > 0)
{
g_string_append_printf (string, "%*sselected columns:", depth, "");
for (i = 0; i < n_selected; i++)
g_string_append_printf (string, " %d", selected[i]);
g_string_append_c (string, '\n');
}
g_free (selected);
for (i = 0; i < atk_table_get_n_columns (table); i++)
{
desc = atk_table_get_column_description (table, i);
if (desc)
g_string_append_printf (string, "%*scolumn %d description: %s\n", depth, "", i, desc);
obj = atk_table_get_column_header (table, i);
if (obj)
{
g_string_append_printf (string, "%*s<column %d header>\n", depth, "", i);
dump_accessible (obj, depth, string);
}
}
for (i = 0; i < atk_table_get_n_rows (table); i++)
{
desc = atk_table_get_row_description (table, i);
if (desc)
g_string_append_printf (string, "%*srow %d description: %s\n", depth, "", i, desc);
obj = atk_table_get_row_header (table, i);
if (obj)
{
g_string_append_printf (string, "%*s<row %d header>\n", depth, "", i);
dump_accessible (obj, depth, string);
}
}
}
static void
dump_accessible (AtkObject *accessible,
guint depth,
GString *string)
{
guint i;
g_string_append_printf (string, "%*s%s\n", depth, "", get_name (accessible));
depth += DEPTH_INCREMENT;
g_string_append_printf (string, "%*s\"%s\"\n", depth, "", atk_role_get_name (atk_object_get_role (accessible)));
if (GTK_IS_ACCESSIBLE (atk_object_get_parent (accessible)))
g_string_append_printf (string, "%*sparent: %s\n", depth, "", get_name (atk_object_get_parent (accessible)));
if (atk_object_get_index_in_parent (accessible) != -1)
g_string_append_printf (string, "%*sindex: %d\n", depth, "", atk_object_get_index_in_parent (accessible));
if (atk_object_get_name (accessible))
g_string_append_printf (string, "%*sname: %s\n", depth, "", atk_object_get_name (accessible));
if (atk_object_get_description (accessible))
g_string_append_printf (string, "%*sdescription: %s\n", depth, "", atk_object_get_description (accessible));
dump_relation_set (string, depth, atk_object_ref_relation_set (accessible));
dump_state_set (string, depth, atk_object_ref_state_set (accessible));
dump_attribute_set (string, depth, atk_object_get_attributes (accessible));
if (ATK_IS_COMPONENT (accessible))
dump_atk_component (ATK_COMPONENT (accessible), depth, string);
if (ATK_IS_TEXT (accessible))
dump_atk_text (ATK_TEXT (accessible), depth, string);
if (ATK_IS_IMAGE (accessible))
dump_atk_image (ATK_IMAGE (accessible), depth, string);
if (ATK_IS_ACTION (accessible))
dump_atk_action (ATK_ACTION (accessible), depth, string);
if (ATK_IS_SELECTION (accessible))
dump_atk_selection (ATK_SELECTION (accessible), depth, string);
if (ATK_IS_VALUE (accessible))
dump_atk_value (ATK_VALUE (accessible), depth, string);
if (ATK_IS_HYPERLINK_IMPL (accessible))
dump_atk_hyperlink_impl (ATK_HYPERLINK_IMPL (accessible), depth, string);
if (ATK_IS_STREAMABLE_CONTENT (accessible))
dump_atk_streamable_content (ATK_STREAMABLE_CONTENT (accessible), depth, string);
if (ATK_IS_TABLE (accessible))
dump_atk_table (ATK_TABLE (accessible), depth, string);
for (i = 0; i < atk_object_get_n_accessible_children (accessible); i++)
{
AtkObject *child = atk_object_ref_accessible_child (accessible, i);
dump_accessible (child, depth, string);
g_object_unref (child);
}
}
static GtkWidget *
builder_get_toplevel (GtkBuilder *builder)
{
GSList *list, *walk;
GtkWidget *window = NULL;
list = gtk_builder_get_objects (builder);
for (walk = list; walk; walk = walk->next)
{
if (GTK_IS_WINDOW (walk->data) &&
gtk_widget_get_parent (walk->data) == NULL)
{
window = walk->data;
break;
}
}
g_slist_free (list);
return window;
}
static void
dump_ui_file (const char *ui_file,
GString *string)
{
GtkWidget *window;
GtkBuilder *builder;
GError *error = NULL;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, ui_file, &error);
g_assert_no_error (error);
window = builder_get_toplevel (builder);
g_object_unref (builder);
g_assert (window);
gtk_widget_show (window);
dump_accessible (gtk_widget_get_accessible (window), 0, string);
gtk_widget_destroy (window);
}
static void
dump_to_stdout (GFile *file)
{
char *ui_file;
GString *dump;
ui_file = g_file_get_path (file);
dump = g_string_new ("");
dump_ui_file (ui_file, dump);
g_print ("%s", dump->str);
g_string_free (dump, TRUE);
g_free (ui_file);
}
static void
test_ui_file (GFile *file)
{
char *ui_file, *a11y_file;
GString *dump;
GError *error = NULL;
ui_file = g_file_get_path (file);
a11y_file = get_test_file (ui_file, ".txt", TRUE);
dump = g_string_new ("");
dump_ui_file (ui_file, dump);
if (a11y_file)
{
char *diff = diff_with_file (a11y_file, dump->str, dump->len, &error);
g_assert_no_error (error);
if (diff && diff[0])
{
g_test_message ("Contents don't match expected contents:\n%s", diff);
g_test_fail ();
g_free (diff);
}
}
else if (dump->str[0])
{
g_test_message ("Expected a reference file:\n%s", dump->str);
g_test_fail ();
}
g_string_free (dump, TRUE);
g_free (a11y_file);
g_free (ui_file);
}
static void
add_test_for_file (GFile *file)
{
g_test_add_vtable (g_file_get_path (file),
0,
g_object_ref (file),
(GTestFixtureFunc) setup_test,
(GTestFixtureFunc) test_ui_file,
(GTestFixtureFunc) g_object_unref);
}
static int
compare_files (gconstpointer a, gconstpointer b)
{
GFile *file1 = G_FILE (a);
GFile *file2 = G_FILE (b);
char *path1, *path2;
int result;
path1 = g_file_get_path (file1);
path2 = g_file_get_path (file2);
result = strcmp (path1, path2);
g_free (path1);
g_free (path2);
return result;
}
static void
add_tests_for_files_in_directory (GFile *dir)
{
GFileEnumerator *enumerator;
GFileInfo *info;
GList *files;
GError *error = NULL;
enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
g_assert_no_error (error);
files = NULL;
while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
{
const char *filename;
filename = g_file_info_get_name (info);
if (!g_str_has_suffix (filename, ".ui"))
{
g_object_unref (info);
continue;
}
files = g_list_prepend (files, g_file_get_child (dir, filename));
g_object_unref (info);
}
g_assert_no_error (error);
g_object_unref (enumerator);
files = g_list_sort (files, compare_files);
g_list_foreach (files, (GFunc) add_test_for_file, NULL);
g_list_free_full (files, g_object_unref);
}
int
main (int argc, char **argv)
{
gtk_test_init (&argc, &argv);
if (argc < 2)
{
const char *basedir;
GFile *dir;
if (g_getenv ("srcdir"))
basedir = g_getenv ("srcdir");
else
basedir = ".";
dir = g_file_new_for_path (basedir);
add_tests_for_files_in_directory (dir);
g_object_unref (dir);
}
else if (argc == 3 && strcmp (argv[1], "--generate") == 0)
{
GFile *file = g_file_new_for_commandline_arg (argv[2]);
dump_to_stdout (file);
g_object_unref (file);
return 0;
}
else
{
guint i;
for (i = 1; i < argc; i++)
{
GFile *file = g_file_new_for_commandline_arg (argv[i]);
add_test_for_file (file);
g_object_unref (file);
}
}
return g_test_run ();
}