[mutter] tests: Move out test client helper from test-runner.c



commit be11c3281539939fc3d5cbb9747fae575e0c6494
Author: Jonas Ådahl <jadahl gmail com>
Date:   Mon Jun 26 16:31:48 2017 +0800

    tests: Move out test client helper from test-runner.c
    
    It could be useful for running other types of test clients in other
    tests.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=730551

 src/Makefile-tests.am   |    5 +-
 src/tests/test-runner.c |  396 +------------------------------------------
 src/tests/test-utils.c  |  428 +++++++++++++++++++++++++++++++++++++++++++++++
 src/tests/test-utils.h  |   79 +++++++++
 4 files changed, 518 insertions(+), 390 deletions(-)
---
diff --git a/src/Makefile-tests.am b/src/Makefile-tests.am
index c0d282e..40370de 100644
--- a/src/Makefile-tests.am
+++ b/src/Makefile-tests.am
@@ -29,7 +29,10 @@ EXTRA_DIST += tests/mutter-all.test.in
 mutter_test_client_SOURCES = tests/test-client.c
 mutter_test_client_LDADD = $(MUTTER_LIBS) libmutter-$(LIBMUTTER_API_VERSION).la
 
-mutter_test_runner_SOURCES = tests/test-runner.c
+mutter_test_runner_SOURCES = \
+       tests/test-utils.c \
+       tests/test-utils.h \
+       tests/test-runner.c
 mutter_test_runner_LDADD = $(MUTTER_LIBS) libmutter-$(LIBMUTTER_API_VERSION).la
 
 mutter_test_unit_tests_SOURCES = \
diff --git a/src/tests/test-runner.c b/src/tests/test-runner.c
index 56ad43f..dd239ac 100644
--- a/src/tests/test-runner.c
+++ b/src/tests/test-runner.c
@@ -29,383 +29,7 @@
 #include "meta-plugin-manager.h"
 #include "wayland/meta-wayland.h"
 #include "window-private.h"
-
-#define TEST_RUNNER_ERROR test_runner_error_quark ()
-
-typedef enum
-{
-  TEST_RUNNER_ERROR_BAD_COMMAND,
-  TEST_RUNNER_ERROR_RUNTIME_ERROR,
-  TEST_RUNNER_ERROR_ASSERTION_FAILED
-} TestRunnerError;
-
-
-GQuark test_runner_error_quark (void);
-
-G_DEFINE_QUARK (test-runner-error-quark, test_runner_error)
-
-/**********************************************************************/
-
-typedef struct {
-  XSyncCounter counter;
-  int counter_value;
-  XSyncAlarm alarm;
-
-  GMainLoop *loop;
-  int counter_wait_value;
-} AsyncWaiter;
-
-static AsyncWaiter *
-async_waiter_new (void)
-{
-  AsyncWaiter *waiter = g_new0 (AsyncWaiter, 1);
-
-  Display *xdisplay = meta_get_display ()->xdisplay;
-  XSyncValue value;
-  XSyncAlarmAttributes attr;
-
-  waiter->counter_value = 0;
-  XSyncIntToValue (&value, waiter->counter_value);
-
-  waiter->counter = XSyncCreateCounter (xdisplay, value);
-
-  attr.trigger.counter = waiter->counter;
-  attr.trigger.test_type = XSyncPositiveComparison;
-
-  /* Initialize to one greater than the current value */
-  attr.trigger.value_type = XSyncRelative;
-  XSyncIntToValue (&attr.trigger.wait_value, 1);
-
-  /* After triggering, increment test_value by this until
-   * until the test condition is false */
-  XSyncIntToValue (&attr.delta, 1);
-
-  /* we want events (on by default anyway) */
-  attr.events = True;
-
-  waiter->alarm = XSyncCreateAlarm (xdisplay,
-                                    XSyncCACounter |
-                                    XSyncCAValueType |
-                                    XSyncCAValue |
-                                    XSyncCATestType |
-                                    XSyncCADelta |
-                                    XSyncCAEvents,
-                                    &attr);
-
-  waiter->loop = g_main_loop_new (NULL, FALSE);
-
-  return waiter;
-}
-
-static void
-async_waiter_destroy (AsyncWaiter *waiter)
-{
-  Display *xdisplay = meta_get_display ()->xdisplay;
-
-  XSyncDestroyAlarm (xdisplay, waiter->alarm);
-  XSyncDestroyCounter (xdisplay, waiter->counter);
-  g_main_loop_unref (waiter->loop);
-}
-
-static int
-async_waiter_next_value (AsyncWaiter *waiter)
-{
-  return waiter->counter_value + 1;
-}
-
-static void
-async_waiter_wait (AsyncWaiter *waiter,
-                   int          wait_value)
-{
-  if (waiter->counter_value < wait_value)
-    {
-      waiter->counter_wait_value = wait_value;
-      g_main_loop_run (waiter->loop);
-      waiter->counter_wait_value = 0;
-    }
-}
-
-static void
-async_waiter_set_and_wait (AsyncWaiter *waiter)
-{
-  Display *xdisplay = meta_get_display ()->xdisplay;
-  int wait_value = async_waiter_next_value (waiter);
-
-  XSyncValue sync_value;
-  XSyncIntToValue (&sync_value, wait_value);
-
-  XSyncSetCounter (xdisplay, waiter->counter, sync_value);
-  async_waiter_wait (waiter, wait_value);
-}
-
-static gboolean
-async_waiter_alarm_filter (AsyncWaiter           *waiter,
-                           MetaDisplay           *display,
-                           XSyncAlarmNotifyEvent *event)
-{
-  if (event->alarm != waiter->alarm)
-    return FALSE;
-
-  waiter->counter_value = XSyncValueLow32 (event->counter_value);
-
-  if (waiter->counter_wait_value != 0 &&
-      waiter->counter_value >= waiter->counter_wait_value)
-    g_main_loop_quit (waiter->loop);
-
-  return TRUE;
-}
-
-/**********************************************************************/
-
-typedef struct {
-  char *id;
-  MetaWindowClientType type;
-  GSubprocess *subprocess;
-  GCancellable *cancellable;
-  GMainLoop *loop;
-  GDataOutputStream *in;
-  GDataInputStream *out;
-
-  char *line;
-  GError **error;
-
-  AsyncWaiter *waiter;
-} TestClient;
-
-static char *test_client_path;
-
-static TestClient *
-test_client_new (const char          *id,
-                 MetaWindowClientType type,
-                 GError             **error)
-{
-  TestClient *client = g_new0 (TestClient, 1);
-  GSubprocessLauncher *launcher;
-  GSubprocess *subprocess;
-
-  launcher =  g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE);
-
-  g_assert (meta_is_wayland_compositor ());
-  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
-
-  g_subprocess_launcher_setenv (launcher,
-                                "WAYLAND_DISPLAY", meta_wayland_get_wayland_display_name (compositor),
-                                TRUE);
-  g_subprocess_launcher_setenv (launcher,
-                                "DISPLAY", meta_wayland_get_xwayland_display_name (compositor),
-                                TRUE);
-
-  subprocess = g_subprocess_launcher_spawn (launcher,
-                                            error,
-                                            test_client_path,
-                                            "--client-id",
-                                            id,
-                                            type == META_WINDOW_CLIENT_TYPE_WAYLAND ? "--wayland" : NULL,
-                                            NULL);
-  g_object_unref (launcher);
-
-  if (!subprocess)
-    return NULL;
-
-  client->type = type;
-  client->id = g_strdup (id);
-  client->cancellable = g_cancellable_new ();
-  client->subprocess = subprocess;
-  client->in = g_data_output_stream_new (g_subprocess_get_stdin_pipe (subprocess));
-  client->out = g_data_input_stream_new (g_subprocess_get_stdout_pipe (subprocess));
-  client->loop = g_main_loop_new (NULL, FALSE);
-
-  if (client->type == META_WINDOW_CLIENT_TYPE_X11)
-    client->waiter = async_waiter_new ();
-
-  return client;
-}
-
-static void
-test_client_destroy (TestClient *client)
-{
-  GError *error = NULL;
-
-  if (client->waiter)
-    async_waiter_destroy (client->waiter);
-
-  g_output_stream_close (G_OUTPUT_STREAM (client->in), NULL, &error);
-  if (error)
-    {
-      g_warning ("Error closing client stdin: %s", error->message);
-      g_clear_error (&error);
-    }
-  g_object_unref (client->in);
-
-  g_input_stream_close (G_INPUT_STREAM (client->out), NULL, &error);
-  if (error)
-    {
-      g_warning ("Error closing client stdout: %s", error->message);
-      g_clear_error (&error);
-    }
-  g_object_unref (client->out);
-
-  g_object_unref (client->cancellable);
-  g_object_unref (client->subprocess);
-  g_main_loop_unref (client->loop);
-  g_free (client->id);
-  g_free (client);
-}
-
-static void
-test_client_line_read (GObject      *source,
-                       GAsyncResult *result,
-                       gpointer      data)
-{
-  TestClient *client = data;
-
-  client->line = g_data_input_stream_read_line_finish_utf8 (client->out, result,
-                                                            NULL, client->error);
-  g_main_loop_quit (client->loop);
-}
-
-static gboolean test_client_do (TestClient *client,
-                                GError   **error,
-                                ...) G_GNUC_NULL_TERMINATED;
-
-static gboolean
-test_client_do (TestClient *client,
-                GError    **error,
-                ...)
-{
-  GString *command = g_string_new (NULL);
-  char *line = NULL;
-
-  va_list vap;
-  va_start (vap, error);
-
-  while (TRUE)
-    {
-      char *word = va_arg (vap, char *);
-      if (word == NULL)
-        break;
-
-      if (command->len > 0)
-        g_string_append_c (command, ' ');
-
-      char *quoted = g_shell_quote (word);
-      g_string_append (command, quoted);
-      g_free (quoted);
-    }
-
-  va_end (vap);
-
-  g_string_append_c (command, '\n');
-
-  if (!g_data_output_stream_put_string (client->in, command->str,
-                                        client->cancellable, error))
-    goto out;
-
-  g_data_input_stream_read_line_async (client->out,
-                                       G_PRIORITY_DEFAULT,
-                                       client->cancellable,
-                                       test_client_line_read,
-                                       client);
-
-  client->error = error;
-  g_main_loop_run (client->loop);
-  line = client->line;
-  client->line = NULL;
-  client->error = NULL;
-
-  if (!line)
-    {
-      if (*error == NULL)
-        g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_RUNTIME_ERROR,
-                     "test client exited");
-      goto out;
-    }
-
-  if (strcmp (line, "OK") != 0)
-    {
-      g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_RUNTIME_ERROR,
-                   "%s", line);
-      goto out;
-    }
-
- out:
-  g_string_free (command, TRUE);
-  g_free (line);
-
-  return *error == NULL;
-}
-
-static gboolean
-test_client_wait (TestClient *client,
-                  GError    **error)
-{
-  if (client->type == META_WINDOW_CLIENT_TYPE_WAYLAND)
-    {
-      return test_client_do (client, error, "sync", NULL);
-    }
-  else
-    {
-      int wait_value = async_waiter_next_value (client->waiter);
-      char *counter_str = g_strdup_printf ("%lu", client->waiter->counter);
-      char *wait_value_str = g_strdup_printf ("%d", wait_value);
-
-      gboolean success = test_client_do (client, error, "set_counter", counter_str, wait_value_str, NULL);
-      g_free (counter_str);
-      g_free (wait_value_str);
-      if (!success)
-        return FALSE;
-
-      async_waiter_wait (client->waiter, wait_value);
-      return TRUE;
-    }
-}
-
-static MetaWindow *
-test_client_find_window (TestClient *client,
-                         const char *window_id,
-                         GError    **error)
-{
-  MetaDisplay *display = meta_get_display ();
-
-  GSList *windows = meta_display_list_windows (display,
-                                               META_LIST_INCLUDE_OVERRIDE_REDIRECT);
-  MetaWindow *result = NULL;
-  char *expected_title = g_strdup_printf ("test/%s/%s",
-                                          client->id, window_id);
-  GSList *l;
-
-  for (l = windows; l; l = l->next)
-    {
-      MetaWindow *window = l->data;
-      if (g_strcmp0 (window->title, expected_title) == 0)
-        {
-          result = window;
-          break;
-        }
-    }
-
-  g_slist_free (windows);
-  g_free (expected_title);
-
-  if (result == NULL)
-    g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_RUNTIME_ERROR,
-                 "window %s/%s isn't known to Mutter", client->id, window_id);
-
-  return result;
-}
-
-static gboolean
-test_client_alarm_filter (TestClient            *client,
-                          MetaDisplay           *display,
-                          XSyncAlarmNotifyEvent *event)
-{
-  if (client->waiter)
-    return async_waiter_alarm_filter (client->waiter, display, event);
-  else
-    return FALSE;
-}
-
-/**********************************************************************/
+#include "tests/test-utils.h"
 
 typedef struct {
   GHashTable *clients;
@@ -711,6 +335,7 @@ test_case_do (TestCase *test,
   if (strcmp (argv[0], "new_client") == 0)
     {
       MetaWindowClientType type;
+      TestClient *client;
 
       if (argc != 3)
         BAD_COMMAND("usage: new_client <client-id> [wayland|x11]");
@@ -725,11 +350,11 @@ test_case_do (TestCase *test,
       if (g_hash_table_lookup (test->clients, argv[1]))
         BAD_COMMAND("client %s already exists", argv[1]);
 
-      TestClient *client = test_client_new (argv[1], type, error);
+      client = test_client_new (argv[1], type, error);
       if (!client)
         return FALSE;
 
-      g_hash_table_insert (test->clients, client->id, client);
+      g_hash_table_insert (test->clients, test_client_get_id (client), client);
     }
   else if (strcmp (argv[0], "quit_client") == 0)
     {
@@ -746,7 +371,7 @@ test_case_do (TestCase *test,
       if (!test_client_wait (client, error))
         return FALSE;
 
-      g_hash_table_remove (test->clients, client->id);
+      g_hash_table_remove (test->clients, test_client_get_id (client));
       test_client_destroy (client);
     }
   else if (strcmp (argv[0], "create") == 0)
@@ -1106,6 +731,8 @@ main (int argc, char **argv)
 
   g_option_context_free (ctx);
 
+  test_init (argc, argv);
+
   GPtrArray *tests = g_ptr_array_new ();
 
   if (all_tests)
@@ -1141,15 +768,6 @@ main (int argc, char **argv)
   char **fake_argv = fake_args;
   int fake_argc = G_N_ELEMENTS (fake_args);
 
-  char *basename = g_path_get_basename (argv[0]);
-  char *dirname = g_path_get_dirname (argv[0]);
-  if (g_str_has_prefix (basename, "lt-"))
-    test_client_path = g_build_filename (dirname, "../mutter-test-client", NULL);
-  else
-    test_client_path = g_build_filename (dirname, "mutter-test-client", NULL);
-  g_free (basename);
-  g_free (dirname);
-
   ctx = meta_get_option_context ();
   if (!g_option_context_parse (ctx, &fake_argc, &fake_argv, &error))
     {
diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c
new file mode 100644
index 0000000..88d1bc3
--- /dev/null
+++ b/src/tests/test-utils.c
@@ -0,0 +1,428 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2014-2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "tests/test-utils.h"
+
+#include <gio/gio.h>
+#include <string.h>
+
+#include "core/display-private.h"
+#include "core/window-private.h"
+#include "wayland/meta-wayland.h"
+
+struct _TestClient {
+  char *id;
+  MetaWindowClientType type;
+  GSubprocess *subprocess;
+  GCancellable *cancellable;
+  GMainLoop *loop;
+  GDataOutputStream *in;
+  GDataInputStream *out;
+
+  char *line;
+  GError **error;
+
+  AsyncWaiter *waiter;
+};
+
+struct _AsyncWaiter {
+  XSyncCounter counter;
+  int counter_value;
+  XSyncAlarm alarm;
+
+  GMainLoop *loop;
+  int counter_wait_value;
+};
+
+G_DEFINE_QUARK (test-runner-error-quark, test_runner_error)
+
+static char *test_client_path;
+
+void
+test_init (int    argc,
+           char **argv)
+{
+  char *basename = g_path_get_basename (argv[0]);
+  char *dirname = g_path_get_dirname (argv[0]);
+
+  if (g_str_has_prefix (basename, "lt-"))
+    test_client_path = g_build_filename (dirname,
+                                         "../mutter-test-client", NULL);
+  else
+    test_client_path = g_build_filename (dirname,
+                                         "mutter-test-client", NULL);
+  g_free (basename);
+  g_free (dirname);
+}
+
+AsyncWaiter *
+async_waiter_new (void)
+{
+  AsyncWaiter *waiter = g_new0 (AsyncWaiter, 1);
+
+  Display *xdisplay = meta_get_display ()->xdisplay;
+  XSyncValue value;
+  XSyncAlarmAttributes attr;
+
+  waiter->counter_value = 0;
+  XSyncIntToValue (&value, waiter->counter_value);
+
+  waiter->counter = XSyncCreateCounter (xdisplay, value);
+
+  attr.trigger.counter = waiter->counter;
+  attr.trigger.test_type = XSyncPositiveComparison;
+
+  /* Initialize to one greater than the current value */
+  attr.trigger.value_type = XSyncRelative;
+  XSyncIntToValue (&attr.trigger.wait_value, 1);
+
+  /* After triggering, increment test_value by this until
+   * until the test condition is false */
+  XSyncIntToValue (&attr.delta, 1);
+
+  /* we want events (on by default anyway) */
+  attr.events = True;
+
+  waiter->alarm = XSyncCreateAlarm (xdisplay,
+                                    XSyncCACounter |
+                                    XSyncCAValueType |
+                                    XSyncCAValue |
+                                    XSyncCATestType |
+                                    XSyncCADelta |
+                                    XSyncCAEvents,
+                                    &attr);
+
+  waiter->loop = g_main_loop_new (NULL, FALSE);
+
+  return waiter;
+}
+
+void
+async_waiter_destroy (AsyncWaiter *waiter)
+{
+  Display *xdisplay = meta_get_display ()->xdisplay;
+
+  XSyncDestroyAlarm (xdisplay, waiter->alarm);
+  XSyncDestroyCounter (xdisplay, waiter->counter);
+  g_main_loop_unref (waiter->loop);
+}
+
+static int
+async_waiter_next_value (AsyncWaiter *waiter)
+{
+  return waiter->counter_value + 1;
+}
+
+static void
+async_waiter_wait (AsyncWaiter *waiter,
+                   int          wait_value)
+{
+  if (waiter->counter_value < wait_value)
+    {
+      waiter->counter_wait_value = wait_value;
+      g_main_loop_run (waiter->loop);
+      waiter->counter_wait_value = 0;
+    }
+}
+
+void
+async_waiter_set_and_wait (AsyncWaiter *waiter)
+{
+  Display *xdisplay = meta_get_display ()->xdisplay;
+  int wait_value = async_waiter_next_value (waiter);
+
+  XSyncValue sync_value;
+  XSyncIntToValue (&sync_value, wait_value);
+
+  XSyncSetCounter (xdisplay, waiter->counter, sync_value);
+  async_waiter_wait (waiter, wait_value);
+}
+
+gboolean
+async_waiter_alarm_filter (AsyncWaiter           *waiter,
+                           MetaDisplay           *display,
+                           XSyncAlarmNotifyEvent *event)
+{
+  if (event->alarm != waiter->alarm)
+    return FALSE;
+
+  waiter->counter_value = XSyncValueLow32 (event->counter_value);
+
+  if (waiter->counter_wait_value != 0 &&
+      waiter->counter_value >= waiter->counter_wait_value)
+    g_main_loop_quit (waiter->loop);
+
+  return TRUE;
+}
+
+char *
+test_client_get_id (TestClient *client)
+{
+  return client->id;
+}
+
+static void
+test_client_line_read (GObject      *source,
+                       GAsyncResult *result,
+                       gpointer      data)
+{
+  TestClient *client = data;
+
+  client->line = g_data_input_stream_read_line_finish_utf8 (client->out,
+                                                            result,
+                                                            NULL,
+                                                            client->error);
+  g_main_loop_quit (client->loop);
+}
+
+gboolean
+test_client_do (TestClient *client,
+                GError    **error,
+                ...)
+{
+  GString *command = g_string_new (NULL);
+  char *line = NULL;
+  va_list vap;
+
+  va_start (vap, error);
+
+  while (TRUE)
+    {
+      char *word = va_arg (vap, char *);
+      char *quoted;
+
+      if (word == NULL)
+        break;
+
+      if (command->len > 0)
+        g_string_append_c (command, ' ');
+
+      quoted = g_shell_quote (word);
+      g_string_append (command, quoted);
+      g_free (quoted);
+    }
+
+  va_end (vap);
+
+  g_string_append_c (command, '\n');
+
+  if (!g_data_output_stream_put_string (client->in, command->str,
+                                        client->cancellable, error))
+    goto out;
+
+  g_data_input_stream_read_line_async (client->out,
+                                       G_PRIORITY_DEFAULT,
+                                       client->cancellable,
+                                       test_client_line_read,
+                                       client);
+
+  client->error = error;
+  g_main_loop_run (client->loop);
+  line = client->line;
+  client->line = NULL;
+  client->error = NULL;
+
+  if (!line)
+    {
+      if (*error == NULL)
+        g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_RUNTIME_ERROR,
+                     "test client exited");
+      goto out;
+    }
+
+  if (strcmp (line, "OK") != 0)
+    {
+      g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_RUNTIME_ERROR,
+                   "%s", line);
+      goto out;
+    }
+
+ out:
+  g_string_free (command, TRUE);
+  g_free (line);
+
+  return *error == NULL;
+}
+
+gboolean
+test_client_wait (TestClient *client,
+                  GError    **error)
+{
+  if (client->type == META_WINDOW_CLIENT_TYPE_WAYLAND)
+    {
+      return test_client_do (client, error, "sync", NULL);
+    }
+  else
+    {
+      int wait_value = async_waiter_next_value (client->waiter);
+      char *counter_str = g_strdup_printf ("%lu", client->waiter->counter);
+      char *wait_value_str = g_strdup_printf ("%d", wait_value);
+      gboolean success;
+
+      success = test_client_do (client, error,
+                                "set_counter", counter_str, wait_value_str,
+                                NULL);
+      g_free (counter_str);
+      g_free (wait_value_str);
+      if (!success)
+        return FALSE;
+
+      async_waiter_wait (client->waiter, wait_value);
+      return TRUE;
+    }
+}
+
+MetaWindow *
+test_client_find_window (TestClient *client,
+                         const char *window_id,
+                         GError    **error)
+{
+  MetaDisplay *display = meta_get_display ();
+  GSList *windows;
+  GSList *l;
+  MetaWindow *result;
+  char *expected_title;
+
+  windows =
+    meta_display_list_windows (display,
+                               META_LIST_INCLUDE_OVERRIDE_REDIRECT);
+
+  expected_title = g_strdup_printf ("test/%s/%s", client->id, window_id);
+
+  result = NULL;
+  for (l = windows; l; l = l->next)
+    {
+      MetaWindow *window = l->data;
+
+      if (g_strcmp0 (window->title, expected_title) == 0)
+        {
+          result = window;
+          break;
+        }
+    }
+
+  g_slist_free (windows);
+  g_free (expected_title);
+
+  if (result == NULL)
+    g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_RUNTIME_ERROR,
+                 "window %s/%s isn't known to Mutter", client->id, window_id);
+
+  return result;
+}
+
+gboolean
+test_client_alarm_filter (TestClient            *client,
+                          MetaDisplay           *display,
+                          XSyncAlarmNotifyEvent *event)
+{
+  if (client->waiter)
+    return async_waiter_alarm_filter (client->waiter, display, event);
+  else
+    return FALSE;
+}
+
+TestClient *
+test_client_new (const char          *id,
+                 MetaWindowClientType type,
+                 GError             **error)
+{
+  TestClient *client = g_new0 (TestClient, 1);
+  GSubprocessLauncher *launcher;
+  GSubprocess *subprocess;
+  MetaWaylandCompositor *compositor;
+  const char *wayland_display_name;
+  const char *x11_display_name;
+
+  launcher =  g_subprocess_launcher_new ((G_SUBPROCESS_FLAGS_STDIN_PIPE |
+                                          G_SUBPROCESS_FLAGS_STDOUT_PIPE));
+
+  g_assert (meta_is_wayland_compositor ());
+  compositor = meta_wayland_compositor_get_default ();
+  wayland_display_name = meta_wayland_get_wayland_display_name (compositor);
+  x11_display_name = meta_wayland_get_xwayland_display_name (compositor);
+
+  g_subprocess_launcher_setenv (launcher,
+                                "WAYLAND_DISPLAY", wayland_display_name,
+                                TRUE);
+  g_subprocess_launcher_setenv (launcher,
+                                "DISPLAY", x11_display_name,
+                                TRUE);
+
+  subprocess = g_subprocess_launcher_spawn (launcher,
+                                            error,
+                                            test_client_path,
+                                            "--client-id",
+                                            id,
+                                            (type == META_WINDOW_CLIENT_TYPE_WAYLAND ?
+                                             "--wayland" : NULL),
+                                            NULL);
+  g_object_unref (launcher);
+
+  if (!subprocess)
+    return NULL;
+
+  client->type = type;
+  client->id = g_strdup (id);
+  client->cancellable = g_cancellable_new ();
+  client->subprocess = subprocess;
+  client->in =
+    g_data_output_stream_new (g_subprocess_get_stdin_pipe (subprocess));
+  client->out =
+    g_data_input_stream_new (g_subprocess_get_stdout_pipe (subprocess));
+  client->loop = g_main_loop_new (NULL, FALSE);
+
+  if (client->type == META_WINDOW_CLIENT_TYPE_X11)
+    client->waiter = async_waiter_new ();
+
+  return client;
+}
+
+void
+test_client_destroy (TestClient *client)
+{
+  GError *error = NULL;
+
+  if (client->waiter)
+    async_waiter_destroy (client->waiter);
+
+  g_output_stream_close (G_OUTPUT_STREAM (client->in), NULL, &error);
+  if (error)
+    {
+      g_warning ("Error closing client stdin: %s", error->message);
+      g_clear_error (&error);
+    }
+  g_object_unref (client->in);
+
+  g_input_stream_close (G_INPUT_STREAM (client->out), NULL, &error);
+  if (error)
+    {
+      g_warning ("Error closing client stdout: %s", error->message);
+      g_clear_error (&error);
+    }
+  g_object_unref (client->out);
+
+  g_object_unref (client->cancellable);
+  g_object_unref (client->subprocess);
+  g_main_loop_unref (client->loop);
+  g_free (client->id);
+  g_free (client);
+}
diff --git a/src/tests/test-utils.h b/src/tests/test-utils.h
new file mode 100644
index 0000000..5b57ef6
--- /dev/null
+++ b/src/tests/test-utils.h
@@ -0,0 +1,79 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TEST_UTILS_H
+#define TEST_UTILS_H
+
+#include <glib.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/sync.h>
+
+#include "meta/window.h"
+
+#define TEST_RUNNER_ERROR test_runner_error_quark ()
+
+typedef enum
+{
+  TEST_RUNNER_ERROR_BAD_COMMAND,
+  TEST_RUNNER_ERROR_RUNTIME_ERROR,
+  TEST_RUNNER_ERROR_ASSERTION_FAILED
+} TestRunnerError;
+
+GQuark test_runner_error_quark (void);
+
+typedef struct _AsyncWaiter AsyncWaiter;
+typedef struct _TestClient TestClient;
+
+void test_init (int    argc,
+                char **argv);
+
+gboolean async_waiter_alarm_filter (AsyncWaiter           *waiter,
+                                    MetaDisplay           *display,
+                                    XSyncAlarmNotifyEvent *event);
+
+void async_waiter_set_and_wait (AsyncWaiter *waiter);
+
+AsyncWaiter * async_waiter_new (void);
+
+void async_waiter_destroy (AsyncWaiter *waiter);
+
+char * test_client_get_id (TestClient *client);
+
+gboolean test_client_alarm_filter (TestClient            *client,
+                                   MetaDisplay           *display,
+                                   XSyncAlarmNotifyEvent *event);
+
+gboolean test_client_wait (TestClient *client,
+                           GError    **error);
+
+gboolean test_client_do (TestClient *client,
+                         GError   **error,
+                         ...) G_GNUC_NULL_TERMINATED;
+
+MetaWindow * test_client_find_window (TestClient *client,
+                                      const char *window_id,
+                                      GError    **error);
+
+TestClient * test_client_new (const char          *id,
+                              MetaWindowClientType type,
+                              GError             **error);
+
+void test_client_destroy (TestClient *client);
+
+#endif /* TEST_UTILS_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]