[gtk/focus-chain-test: 2/2] Add a focus chain test
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/focus-chain-test: 2/2] Add a focus chain test
- Date: Tue, 11 Jun 2019 14:15:25 +0000 (UTC)
commit 436d7cc0d1fbe8a31819efb2f3873d5bbb259d99
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Jun 11 14:11:28 2019 +0000
Add a focus chain test
Add a test that enumerates the focus chain by
emitting move-focus repeatedly, and compares
the result to expected output.
The test expects a ui file and a reference
file as input. The reference file can be created
using the --generate option.
testsuite/gtk/focus-chain/basic.tab | 2 +
testsuite/gtk/focus-chain/basic.tab-backward | 2 +
testsuite/gtk/focus-chain/basic.ui | 18 ++
testsuite/gtk/meson.build | 29 +++
testsuite/gtk/test-focus-chain.c | 284 +++++++++++++++++++++++++++
5 files changed, 335 insertions(+)
---
diff --git a/testsuite/gtk/focus-chain/basic.tab b/testsuite/gtk/focus-chain/basic.tab
new file mode 100644
index 0000000000..120555fb03
--- /dev/null
+++ b/testsuite/gtk/focus-chain/basic.tab
@@ -0,0 +1,2 @@
+entry1 GtkText
+entry2 GtkText
diff --git a/testsuite/gtk/focus-chain/basic.tab-backward b/testsuite/gtk/focus-chain/basic.tab-backward
new file mode 100644
index 0000000000..7a00af5387
--- /dev/null
+++ b/testsuite/gtk/focus-chain/basic.tab-backward
@@ -0,0 +1,2 @@
+entry2 GtkText
+entry1 GtkText
diff --git a/testsuite/gtk/focus-chain/basic.ui b/testsuite/gtk/focus-chain/basic.ui
new file mode 100644
index 0000000000..571707519c
--- /dev/null
+++ b/testsuite/gtk/focus-chain/basic.ui
@@ -0,0 +1,18 @@
+<interface>
+ <object class="GtkWindow" id="window">
+ <child>
+ <object class="GtkBox">
+ <child>
+ <object class="GtkEntry" id="entry1">
+ <property name="name">entry1</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entry2">
+ <property name="name">entry2</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/testsuite/gtk/meson.build b/testsuite/gtk/meson.build
index 9be60a278e..60163207fe 100644
--- a/testsuite/gtk/meson.build
+++ b/testsuite/gtk/meson.build
@@ -130,6 +130,35 @@ if add_languages('cpp', required: false)
endif
endif
+focus_chain_tests = [
+ # test direction
+ [ 'basic', 'tab' ],
+ [ 'basic', 'tab-backward' ],
+]
+
+focus_chain = executable(
+ 'test-focus-chain',
+ ['test-focus-chain.c'],
+ dependencies: libgtk_dep,
+ install: get_option('install-tests'),
+ install_dir: testexecdir
+)
+
+foreach test : focus_chain_tests
+ test(test[0] + ' ' + test[1], focus_chain,
+ args: [ join_paths(meson.current_source_dir(), 'focus-chain', test[0] + '.ui'),
+ join_paths(meson.current_source_dir(), 'focus-chain', test[0] + '.' + test[1]) ],
+ env: [ 'GIO_USE_VOLUME_MONITOR=unix',
+ 'GSETTINGS_BACKEND=memory',
+ 'GTK_CSD=1',
+ 'G_ENABLE_DIAGNOSTIC=0',
+ 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
+ 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
+ ],
+ suite: [ 'gtk', 'focus' ])
+endforeach
+
+
if get_option('install-tests')
foreach t : tests
test_name = t.get(0)
diff --git a/testsuite/gtk/test-focus-chain.c b/testsuite/gtk/test-focus-chain.c
new file mode 100644
index 0000000000..f8ac319947
--- /dev/null
+++ b/testsuite/gtk/test-focus-chain.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * Author:
+ * Matthias Clasen <mclasen 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+#ifdef G_OS_WIN32
+# include <io.h>
+#endif
+
+struct {
+ GtkDirectionType dir;
+ const char *ext;
+} extensions[] = {
+ { GTK_DIR_TAB_FORWARD, "tab" },
+ { GTK_DIR_TAB_BACKWARD, "tab-backward" },
+ { GTK_DIR_UP, "up" },
+ { GTK_DIR_DOWN, "down" },
+ { GTK_DIR_LEFT, "left" },
+ { GTK_DIR_RIGHT, "right" }
+};
+
+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 char *
+generate_focus_chain (GtkWidget *window,
+ GtkDirectionType dir)
+{
+ char *first = NULL;
+ char *last = NULL;
+ char *name;
+ GString *output = g_string_new ("");
+ GtkWidget *focus;
+
+ gtk_widget_show (window);
+
+ /* start without focus */
+ gtk_window_set_focus (GTK_WINDOW (window), NULL);
+
+ while (TRUE)
+ {
+ g_signal_emit_by_name (window, "move-focus", dir);
+
+ focus = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (focus)
+ {
+ /* ui files can't put a name on the embedded text,
+ * so include the parent entry here
+ */
+ if (GTK_IS_TEXT (focus))
+ name = g_strdup_printf ("%s %s",
+ gtk_widget_get_name (gtk_widget_get_parent (focus)),
+ gtk_widget_get_name (focus));
+ else
+ name = g_strdup (gtk_widget_get_name (focus));
+ }
+ else
+ name = g_strdup ("NONE");
+
+ if (first && g_str_equal (name, first))
+ break; /* cycle completed */
+
+ if (last && g_str_equal (name, last))
+ break; /* dead end */
+
+ g_string_append_printf (output, "%s\n", name);
+
+ if (!first)
+ first = g_strdup (name);
+
+ g_free (last);
+ last = g_strdup (name);
+
+ g_free (name);
+ }
+
+ g_free (first);
+ g_free (last);
+
+ return g_string_free (output, FALSE);
+}
+
+static GtkDirectionType
+get_dir_for_file (const char *path)
+{
+ char *p;
+ int i;
+
+ p = strrchr (path, '.');
+ p++;
+
+ for (i = 0; i < G_N_ELEMENTS (extensions); i++)
+ {
+ if (strcmp (p, extensions[i].ext) == 0)
+ return extensions[i].dir;
+ }
+
+ g_error ("Could not find direction for %s", path);
+
+ return 0;
+}
+
+static gboolean
+load_ui_file (GFile *ui_file,
+ GFile *ref_file,
+ const char *ext)
+{
+ GtkBuilder *builder;
+ GtkWidget *window;
+ char *output;
+ char *diff;
+ char *ui_path, *ref_path;
+ GError *error = NULL;
+ GtkDirectionType dir;
+ gboolean success = FALSE;
+
+ ui_path = g_file_get_path (ui_file);
+
+ builder = gtk_builder_new_from_file (ui_path);
+ window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
+
+ g_assert (window != NULL);
+
+ if (ext)
+ {
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (extensions); i++)
+ {
+ if (g_str_equal (ext, extensions[i].ext))
+ {
+ output = generate_focus_chain (window, extensions[i].dir);
+ g_print ("%s", output);
+ success = TRUE;
+ goto out;
+ }
+ }
+
+ g_error ("Not a supported direction: %s", ext);
+ goto out;
+ }
+
+ g_assert (ref_file != NULL);
+
+ ref_path = g_file_get_path (ref_file);
+
+ dir = get_dir_for_file (ref_path);
+ output = generate_focus_chain (window, dir);
+ diff = diff_with_file (ref_path, output, -1, &error);
+ g_assert_no_error (error);
+
+ if (diff && diff[0])
+ g_print ("Resulting output doesn't match reference:\n%s", diff);
+ else
+ success = TRUE;
+ g_free (ref_path);
+ g_free (diff);
+
+out:
+ g_free (output);
+ g_free (ui_path);
+
+ return success;
+}
+
+static const char *arg_generate;
+
+static const GOptionEntry options[] = {
+ { "generate", 0, 0, G_OPTION_ARG_STRING, &arg_generate, "DIRECTION" },
+ { NULL }
+};
+
+int
+main (int argc, char **argv)
+{
+ GOptionContext *context;
+ GFile *ui_file;
+ GFile *ref_file;
+ GError *error = NULL;
+ gboolean success;
+
+ context = g_option_context_new ("- run focus chain tests");
+ g_option_context_add_main_entries (context, options, NULL);
+ g_option_context_set_ignore_unknown_options (context, TRUE);
+
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_error ("Option parsing failed: %s\n", error->message);
+ return 1;
+ }
+
+ gtk_init ();
+
+ if (arg_generate)
+ {
+ g_assert (argc == 2);
+
+ ui_file = g_file_new_for_commandline_arg (argv[1]);
+
+ success = load_ui_file (ui_file, NULL, arg_generate);
+
+ g_object_unref (ui_file);
+ }
+ else
+ {
+ g_assert (argc == 3);
+
+ ui_file = g_file_new_for_commandline_arg (argv[1]);
+ ref_file = g_file_new_for_commandline_arg (argv[2]);
+
+ success = load_ui_file (ui_file, ref_file, NULL);
+
+ g_object_unref (ui_file);
+ g_object_unref (ref_file);
+ }
+
+ return success ? 0 : 1;
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]