3db9094a528e0f77bdd2f0586aef5132856cffe5
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / gtk / tests / TestWebKitAccessibility.cpp
1 /*
2  * Copyright (C) 2012 Igalia S.L.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2,1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21
22 #include "TestMain.h"
23 #include "WebViewTest.h"
24
25 // The libatspi headers don't use G_BEGIN_DECLS
26 extern "C" {
27 #include <atspi/atspi.h>
28 }
29
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <glib.h>
33 #include <signal.h>
34 #include <unistd.h>
35 #include <wtf/PassRefPtr.h>
36 #include <wtf/gobject/GOwnPtr.h>
37 #include <wtf/gobject/GRefPtr.h>
38
39 // Name of the test server application creating the webView object.
40 static const char* kTestServerAppName = "AccessibilityTestServer";
41
42 // Max seconds to wait for the test server before inspecting it.
43 static const int kMaxWaitForChild = 5;
44
45 // The PID for the test server running, so we can kill it if needed.
46 static GPid kChildProcessPid = 0;
47
48 // Whether the child has replied and it's ready.
49 static bool kChildIsReady = false;
50
51 static void stopTestServer()
52 {
53     // Do nothing if there's no server running.
54     if (!kChildProcessPid)
55         return;
56
57     g_spawn_close_pid(kChildProcessPid);
58     kill(kChildProcessPid, SIGTERM);
59     kChildProcessPid = 0;
60 }
61
62 static void sigAbortHandler(int sigNum)
63 {
64     // Just stop the test server if SIGABRT was received.
65     stopTestServer();
66 }
67
68 static gpointer testServerMonitorThreadFunc(gpointer)
69 {
70     // Wait for the specified timeout to happen.
71     g_usleep(kMaxWaitForChild * G_USEC_PER_SEC);
72
73     // Kill the child process if not ready yet.
74     if (!kChildIsReady)
75         stopTestServer();
76
77     g_thread_exit(0);
78     return 0;
79 }
80
81 static void startTestServerMonitor()
82 {
83     kChildIsReady = false;
84
85 #if (!GLIB_CHECK_VERSION(2, 31, 0))
86     g_thread_create(testServerMonitorThreadFunc, 0, FALSE, 0);
87 #else
88     g_thread_new("TestServerMonitor", testServerMonitorThreadFunc, 0);
89 #endif
90 }
91
92 static void startTestServer()
93 {
94     // Prepare argv[] for spawning the server process.
95     GOwnPtr<char> testServerPath(g_build_filename(WEBKIT_EXEC_PATH, "WebKit2APITests", kTestServerAppName, NULL));
96
97     char* testServerArgv[2];
98     testServerArgv[0] = testServerPath.get();
99     testServerArgv[1] = 0;
100
101     // Spawn the server, getting its stdout file descriptor to set a
102     // communication channel, so we know when it's ready.
103     int childStdout = 0;
104     if (!g_spawn_async_with_pipes(0, testServerArgv, 0, static_cast<GSpawnFlags>(0), 0, 0,
105                                   &kChildProcessPid, 0, &childStdout, 0, 0)) {
106         close(childStdout);
107         return;
108     }
109
110     // Start monitoring the test server (in a separate thread) to
111     // ensure we don't block on the child process more than a timeout.
112     startTestServerMonitor();
113
114     char msg[2];
115     GIOChannel* ioChannel = g_io_channel_unix_new(childStdout);
116     if (g_io_channel_read_chars(ioChannel, msg, 2, 0, 0) == G_IO_STATUS_NORMAL) {
117         // Check whether the server sent a message saying it's ready
118         // and store the result globally, so the monitor can see it.
119         kChildIsReady = msg[0] == 'O' && msg[1] == 'K';
120     }
121     g_io_channel_unref(ioChannel);
122     close(childStdout);
123
124     // The timeout was reached and the server is not ready yet, so
125     // stop it inmediately, and let the unit tests fail.
126     if (!kChildIsReady)
127         stopTestServer();
128 }
129
130 static void checkAtspiAccessible(AtspiAccessible* accessible, const char* targetName, AtspiRole targetRole)
131 {
132     g_assert(ATSPI_IS_ACCESSIBLE(accessible));
133
134     GOwnPtr<char> name(atspi_accessible_get_name(accessible, 0));
135     g_assert_cmpstr(targetName, ==, name.get());
136     g_assert_cmpint(targetRole, ==, atspi_accessible_get_role(accessible, 0));
137 }
138
139 static GRefPtr<AtspiAccessible> findTestServerApplication()
140 {
141     // Only one desktop is supported by ATSPI at the moment.
142     GRefPtr<AtspiAccessible> desktop = adoptGRef(atspi_get_desktop(0));
143
144     // Look for the server application in the list of apps.
145     GRefPtr<AtspiAccessible> current;
146     int childCount = atspi_accessible_get_child_count(desktop.get(), 0);
147     for (int i = 0; i < childCount; i++) {
148         current = adoptGRef(atspi_accessible_get_child_at_index(desktop.get(), i, 0));
149         if (!g_strcmp0(atspi_accessible_get_name(current.get(), 0), kTestServerAppName))
150             return current;
151     }
152
153     return 0;
154 }
155
156 static void testAtspiBasicHierarchy(WebViewTest* test, gconstpointer)
157 {
158     // The test server's accessibility object (UI Process).
159     GRefPtr<AtspiAccessible> testServerApp = findTestServerApplication();
160     g_assert(ATSPI_IS_ACCESSIBLE(testServerApp.get()));
161     checkAtspiAccessible(testServerApp.get(), "AccessibilityTestServer", ATSPI_ROLE_APPLICATION);
162
163     // The main window's accessibility object (UI Process).
164     GRefPtr<AtspiAccessible> currentParent = testServerApp;
165     GRefPtr<AtspiAccessible> currentChild = adoptGRef(atspi_accessible_get_child_at_index(currentParent.get(), 0, 0));
166     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
167     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_FRAME);
168
169     // The WebView's accessibility object (UI Process).
170     currentParent = currentChild;
171     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
172     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
173     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_FILLER);
174
175     // The WebPage's accessibility object (Web Process).
176     currentParent = currentChild;
177     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
178     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
179     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_FILLER);
180
181     // HTML root element's accessible element (Web Process).
182     currentParent = currentChild;
183     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
184     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
185
186     // HTML body's accessible element (Web Process).
187     currentParent = currentChild;
188     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
189     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
190     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_DOCUMENT_FRAME);
191
192     // HTML H1's accessible element (Web Process).
193     currentParent = currentChild;
194     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
195     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
196     checkAtspiAccessible(currentChild.get(), "This is a test", ATSPI_ROLE_HEADING);
197
198     // HTML first paragraph's accessible element (Web Process).
199     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 1, 0);
200     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
201     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_PARAGRAPH);
202
203     // HTML second paragraph's accessible element (Web Process).
204     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 2, 0);
205     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
206     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_PARAGRAPH);
207
208     // HTML link's accessible element (Web Process).
209     currentParent = currentChild;
210     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
211     g_assert(ATSPI_IS_ACCESSIBLE(currentChild.get()));
212     checkAtspiAccessible(currentChild.get(), "a link", ATSPI_ROLE_LINK);
213 }
214
215 void beforeAll()
216 {
217     // We install a handler to ensure that we kill the child process
218     // if the parent dies because of whatever the reason is.
219     signal(SIGABRT, sigAbortHandler);
220
221     // Start the accessibility test server and load the tests.
222     startTestServer();
223     WebViewTest::add("WebKitAccessibility", "atspi-basic-hierarchy", testAtspiBasicHierarchy);
224 }
225
226 void afterAll()
227 {
228     // Ensure we stop the server.
229     stopTestServer();
230 }