1
/*
2
 * AT-SPI - Assistive Technology Service Provider Interface
3
 * (Gnome Accessibility Project; https://wiki.gnome.org/Accessibility)
4
 *
5
 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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, write to the
19
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
 * Boston, MA 02110-1301, USA.
21
 */
22

            
23
#include "atk_test_util.h"
24
#include <signal.h>
25

            
26
static AtspiEventListener *fixture_listener = NULL;
27
static TestAppFixture *current_fixture = NULL;
28

            
29
static pid_t
30
161
run_app (const char *file_name, const char *name_to_claim)
31
{
32
161
  pid_t child_pid = fork ();
33
161
  if (child_pid == 0)
34
    {
35
      execlp (TESTS_BUILD_DIR "/app-test",
36
              TESTS_BUILD_DIR "/app-test",
37
              "--test-data-file",
38
              file_name,
39
              "--atspi-dbus-name",
40
              name_to_claim,
41
              NULL);
42
      _exit (EXIT_SUCCESS);
43
    }
44

            
45
161
  return child_pid;
46
}
47

            
48
static AtspiAccessible *
49
161
try_get_root_obj (AtspiAccessible *obj)
50
{
51
161
  GError *error = NULL;
52
  gchar *name;
53
  int i;
54

            
55
161
  gint child_count = atspi_accessible_get_child_count (obj, &error);
56
161
  if (child_count < 0)
57
    {
58
      if (error)
59
        {
60
          g_print ("  get_child_count: %s\n", error->message);
61
          g_error_free (error);
62
        }
63
      else
64
        {
65
          g_print ("  get_child_count=%d with no error\n", child_count);
66
        }
67
      return NULL;
68
    }
69
161
  else if (child_count < 1)
70
    {
71
      g_print ("  child_count == %d, bailing out\n", child_count);
72
      return NULL;
73
    }
74

            
75
161
  for (i = child_count - 1; i >= 0; i--)
76
    {
77
161
      AtspiAccessible *child = atspi_accessible_get_child_at_index (obj, i, &error);
78
161
      if (!child)
79
        {
80
          if (error)
81
            {
82
              g_print ("  getting child_at_index: %s\n", error->message);
83
              g_error_free (error);
84
              error = NULL;
85
            }
86
          else
87
            {
88
              g_print ("  getting child_at_index returned NULL child with no error\n");
89
            }
90
          continue;
91
        }
92
161
      if ((name = atspi_accessible_get_name (child, &error)) != NULL)
93
        {
94
161
          if (!strcmp (name, "root_object"))
95
            {
96
161
              g_free (name);
97
161
              return child;
98
            }
99
          g_print ("  name=%s\n", name);
100
          g_free (name);
101
          if (error)
102
            {
103
              g_error_free (error);
104
              error = NULL;
105
            }
106
        }
107
      else
108
        {
109
          if (error)
110
            {
111
              g_print ("try_get_root_obj getting child name: %s\n", error->message);
112
              g_error_free (error);
113
              error = NULL;
114
            }
115
          else
116
            {
117
              g_print ("  get_name returned NULL name with no error\n");
118
            }
119
        }
120
      g_object_unref (child);
121
    }
122

            
123
  return NULL;
124
}
125

            
126
/* Callback from AtspiEventListener.  We monitor children-changed on the root, so we can know
127
 * when the helper test-application has launched and registered.
128
 */
129
static void
130
321
listener_event_cb (AtspiEvent *event, void *user_data)
131
{
132
321
  TestAppFixture *fixture = current_fixture;
133

            
134
321
  if (atspi_accessible_get_role (event->source, NULL) == ATSPI_ROLE_DESKTOP_FRAME && strstr (event->type, "add"))
135
    {
136
161
      AtspiAccessible *obj = atspi_get_desktop (0);
137

            
138
161
      fixture->root_obj = try_get_root_obj (obj);
139
161
      g_object_unref (obj);
140

            
141
161
      if (fixture->root_obj)
142
        {
143
161
          fixture->state = FIXTURE_STATE_CHILD_ACQUIRED;
144
161
          atspi_event_quit ();
145
        }
146
    }
147
321
  g_boxed_free (ATSPI_TYPE_EVENT, event);
148
321
}
149

            
150
/* Sets up the atspi event listener for the test-application helpers.
151
 *
152
 * We get notified when the test-application registers its root object by listening
153
 * to the children-changed signal.
154
 */
155
void
156
1
fixture_listener_init (void)
157
{
158
1
  GError *error = NULL;
159

            
160
1
  fixture_listener = atspi_event_listener_new (listener_event_cb, NULL, NULL);
161
1
  if (!atspi_event_listener_register (fixture_listener, "object:children-changed", &error))
162
    {
163
      g_error ("Could not register event listener for children-changed: %s\n", error->message);
164
    }
165
1
}
166

            
167
void
168
fixture_listener_destroy (void)
169
{
170
  GError *error = NULL;
171

            
172
  if (!atspi_event_listener_deregister (fixture_listener, "object:children-changed", &error))
173
    {
174
      g_error ("Could not deregister event listener: %s", error->message);
175
    }
176

            
177
  g_object_unref (fixture_listener);
178
  fixture_listener = NULL;
179
}
180

            
181
static gboolean
182
wait_for_test_app_timeout_cb (gpointer user_data)
183
{
184
  TestAppFixture *fixture = user_data;
185

            
186
  fixture->test_app_timed_out = TRUE;
187
  fixture->wait_for_test_app_timeout = 0;
188
  atspi_event_quit ();
189

            
190
  return FALSE;
191
}
192

            
193
/* Each of the helper programs with the test fixtures claims a different DBus name,
194
 * to make them non-ambiguous when they get restarted all the time.  This is the serial
195
 * number that gets appended to each name.
196
 */
197
static guint fixture_serial = 0;
198

            
199
void
200
161
fixture_setup (TestAppFixture *fixture, gconstpointer user_data)
201
{
202
161
  const char *file_name = user_data;
203

            
204
161
  fixture->state = FIXTURE_STATE_WAITING_FOR_CHILD;
205
161
  fixture->name_to_claim = g_strdup_printf ("org.a11y.Atspi2Atk.TestApplication_%u", fixture_serial);
206
161
  fixture_serial += 1;
207

            
208
161
  fixture->child_pid = run_app (file_name, fixture->name_to_claim);
209

            
210
161
  fixture->test_app_timed_out = FALSE;
211
161
  fixture->wait_for_test_app_timeout = g_timeout_add (500, wait_for_test_app_timeout_cb, fixture); /* 500 msec */
212

            
213
161
  current_fixture = fixture;
214
161
  putenv ("ATSPI_IN_TESTS=1");
215
161
  atspi_event_main ();
216

            
217
161
  if (fixture->wait_for_test_app_timeout)
218
161
    g_source_remove (fixture->wait_for_test_app_timeout);
219
161
  fixture->wait_for_test_app_timeout = 0;
220

            
221
161
  if (fixture->test_app_timed_out)
222
    {
223
      g_print ("test app timed out before registering its root object");
224
      g_test_fail ();
225
    }
226
161
}
227

            
228
void
229
161
fixture_teardown (TestAppFixture *fixture, gconstpointer user_data)
230
{
231
161
  current_fixture = NULL;
232

            
233
161
  kill (fixture->child_pid, SIGTERM);
234
161
  fixture->child_pid = -1;
235

            
236
161
  if (fixture->root_obj)
237
    {
238
161
      g_object_unref (fixture->root_obj);
239
161
      fixture->root_obj = NULL;
240
    }
241

            
242
161
  g_free (fixture->name_to_claim);
243
161
  fixture->name_to_claim = NULL;
244
161
}
245

            
246
void
247
33
check_name (AtspiAccessible *accessible, const char *expected_name)
248
{
249
  gchar *obj_name;
250

            
251
33
  g_assert_nonnull (accessible);
252
33
  obj_name = atspi_accessible_get_name (accessible, NULL);
253
33
  g_assert_cmpstr (expected_name, ==, obj_name);
254
33
  g_free (obj_name);
255
33
}