| Flutter Linux Embedder |

fl_accessible_node_test.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Included first as it collides with the X11 headers.
6 #include "gtest/gtest.h"
7
8 #include "flutter/shell/platform/linux/fl_accessible_node.h"
9 #include "flutter/shell/platform/linux/testing/mock_gtk.h"
10
11 class FlAccessibleNodeTest : public ::testing::Test {
12 protected:
13 void SetUp() override {
14 g_autoptr(FlDartProject) project = fl_dart_project_new();
15 engine = fl_engine_new(project);
16 }
17
18 ~FlAccessibleNodeTest() { g_object_unref(engine); }
19
20 ::testing::NiceMock<flutter::testing::MockGtk> mock_gtk;
21 FlEngine* engine;
22 };
23
24 // Checks can build a tree of nodes.
25 TEST_F(FlAccessibleNodeTest, BuildTree) {
26 int64_t view_id = 123;
27 g_autoptr(FlAccessibleNode) root = fl_accessible_node_new(engine, view_id, 0);
28 g_autoptr(FlAccessibleNode) child1 =
29 fl_accessible_node_new(engine, view_id, 1);
30 fl_accessible_node_set_parent(child1, ATK_OBJECT(root), 0);
31 g_autoptr(FlAccessibleNode) child2 =
32 fl_accessible_node_new(engine, view_id, 1);
33 fl_accessible_node_set_parent(child2, ATK_OBJECT(root), 1);
34 g_autoptr(GPtrArray) children =
35 g_ptr_array_new_with_free_func(g_object_unref);
36 g_ptr_array_add(children, g_object_ref(child1));
37 g_ptr_array_add(children, g_object_ref(child2));
38 fl_accessible_node_set_children(root, children);
39
40 EXPECT_EQ(atk_object_get_n_accessible_children(ATK_OBJECT(root)), 2);
41 EXPECT_EQ(atk_object_get_index_in_parent(ATK_OBJECT(root)), 0);
42 g_autoptr(AtkObject) c1 =
43 atk_object_ref_accessible_child(ATK_OBJECT(root), 0);
44 EXPECT_EQ(ATK_OBJECT(child1), c1);
45 g_autoptr(AtkObject) c2 =
46 atk_object_ref_accessible_child(ATK_OBJECT(root), 1);
47 EXPECT_EQ(ATK_OBJECT(child2), c2);
48 EXPECT_EQ(atk_object_get_parent(ATK_OBJECT(root)), nullptr);
49
50 EXPECT_EQ(atk_object_get_parent(ATK_OBJECT(child1)), ATK_OBJECT(root));
51 EXPECT_EQ(atk_object_get_index_in_parent(ATK_OBJECT(child1)), 0);
52 EXPECT_EQ(atk_object_get_n_accessible_children(ATK_OBJECT(child1)), 0);
53
54 EXPECT_EQ(atk_object_get_parent(ATK_OBJECT(child2)), ATK_OBJECT(root));
55 EXPECT_EQ(atk_object_get_index_in_parent(ATK_OBJECT(child2)), 1);
56 EXPECT_EQ(atk_object_get_n_accessible_children(ATK_OBJECT(child2)), 0);
57 }
58
59 // Checks node name is exposed to ATK.
60 TEST_F(FlAccessibleNodeTest, SetName) {
61 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
62 fl_accessible_node_set_name(node, "test");
63 EXPECT_STREQ(atk_object_get_name(ATK_OBJECT(node)), "test");
64 }
65
66 // Checks node extents are exposed to ATK.
67 TEST_F(FlAccessibleNodeTest, SetExtents) {
68 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
69 fl_accessible_node_set_extents(node, 1, 2, 3, 4);
70 gint x, y, width, height;
71 atk_component_get_extents(ATK_COMPONENT(node), &x, &y, &width, &height,
72 ATK_XY_PARENT);
73 EXPECT_EQ(x, 1);
74 EXPECT_EQ(y, 2);
75 EXPECT_EQ(width, 3);
76 EXPECT_EQ(height, 4);
77 }
78
79 // Checks the Flutter focused flag are mapped to ATK flags.
80 TEST_F(FlAccessibleNodeTest, FocusedFlags) {
81 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
82
83 FlutterSemanticsFlags flags1 = {};
84 flags1.is_focused = kFlutterTristateNone;
85 fl_accessible_node_set_flags(node, &flags1);
86 AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node));
87 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_FOCUSABLE));
88 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_FOCUSED));
89 g_object_unref(state1);
90
91 FlutterSemanticsFlags flags2 = {};
92 flags2.is_focused = kFlutterTristateFalse;
93 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
94 ::testing::_, ATK_STATE_FOCUSABLE, TRUE));
95 fl_accessible_node_set_flags(node, &flags2);
96 AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node));
97 EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_FOCUSABLE));
98 EXPECT_FALSE(atk_state_set_contains_state(state2, ATK_STATE_FOCUSED));
99 g_object_unref(state2);
100
101 FlutterSemanticsFlags flags3 = {};
102 flags3.is_focused = kFlutterTristateTrue;
103 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
104 ::testing::_, ATK_STATE_FOCUSED, TRUE));
105 fl_accessible_node_set_flags(node, &flags3);
106 AtkStateSet* state3 = atk_object_ref_state_set(ATK_OBJECT(node));
107 EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_FOCUSABLE));
108 EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_FOCUSED));
109 g_object_unref(state3);
110 }
111
112 // Checks the Flutter checked and toggled flags are mapped to ATK flags.
113 TEST_F(FlAccessibleNodeTest, CheckedAndToggledFlags) {
114 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
115
116 FlutterSemanticsFlags flags1 = {};
117 flags1.is_checked = kFlutterCheckStateNone;
118 flags1.is_toggled = kFlutterTristateNone;
119 fl_accessible_node_set_flags(node, &flags1);
120 AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node));
121 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_CHECKABLE));
122 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_CHECKED));
123 g_object_unref(state1);
124
125 FlutterSemanticsFlags flags2 = {};
126 flags2.is_checked = kFlutterCheckStateFalse;
127 flags2.is_toggled = kFlutterTristateFalse;
128 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
129 ::testing::_, ATK_STATE_CHECKABLE, TRUE));
130 fl_accessible_node_set_flags(node, &flags2);
131 AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node));
132 EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_CHECKABLE));
133 EXPECT_FALSE(atk_state_set_contains_state(state2, ATK_STATE_CHECKED));
134 g_object_unref(state2);
135
136 FlutterSemanticsFlags flags3 = {};
137 flags3.is_checked = kFlutterCheckStateTrue;
138 flags3.is_toggled = kFlutterTristateTrue;
139 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
140 ::testing::_, ATK_STATE_CHECKED, TRUE));
141 fl_accessible_node_set_flags(node, &flags3);
142 AtkStateSet* state3 = atk_object_ref_state_set(ATK_OBJECT(node));
143 EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_CHECKABLE));
144 EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_CHECKED));
145 g_object_unref(state3);
146
147 FlutterSemanticsFlags flags4 = {};
148 flags4.is_checked = kFlutterCheckStateTrue;
149 flags4.is_toggled = kFlutterTristateNone;
150 fl_accessible_node_set_flags(node, &flags4);
151 AtkStateSet* state4 = atk_object_ref_state_set(ATK_OBJECT(node));
152 EXPECT_TRUE(atk_state_set_contains_state(state4, ATK_STATE_CHECKABLE));
153 EXPECT_TRUE(atk_state_set_contains_state(state4, ATK_STATE_CHECKED));
154 g_object_unref(state4);
155
156 FlutterSemanticsFlags flags5 = {};
157 flags5.is_checked = kFlutterCheckStateNone;
158 flags5.is_toggled = kFlutterTristateTrue;
159 fl_accessible_node_set_flags(node, &flags5);
160 AtkStateSet* state5 = atk_object_ref_state_set(ATK_OBJECT(node));
161 EXPECT_TRUE(atk_state_set_contains_state(state5, ATK_STATE_CHECKABLE));
162 EXPECT_TRUE(atk_state_set_contains_state(state5, ATK_STATE_CHECKED));
163 g_object_unref(state5);
164 }
165
166 // Checks the Flutter selected flag is mapped to ATK flags.
167 TEST_F(FlAccessibleNodeTest, SelectedFlags) {
168 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
169
170 FlutterSemanticsFlags flags1 = {};
171 flags1.is_selected = kFlutterTristateNone;
172 fl_accessible_node_set_flags(node, &flags1);
173 AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node));
174 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_SELECTED));
175 g_object_unref(state1);
176
177 FlutterSemanticsFlags flags2 = {};
178 flags2.is_selected = kFlutterTristateFalse;
179 fl_accessible_node_set_flags(node, &flags2);
180 AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node));
181 EXPECT_FALSE(atk_state_set_contains_state(state2, ATK_STATE_SELECTED));
182 g_object_unref(state2);
183
184 FlutterSemanticsFlags flags3 = {};
185 flags3.is_selected = kFlutterTristateTrue;
186 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
187 ::testing::_, ATK_STATE_SELECTED, TRUE));
188 fl_accessible_node_set_flags(node, &flags3);
189 AtkStateSet* state3 = atk_object_ref_state_set(ATK_OBJECT(node));
190 EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_SELECTED));
191 g_object_unref(state3);
192 }
193
194 // Checks the Flutter enabled flag is mapped to ATK flags.
195 TEST_F(FlAccessibleNodeTest, EnabledFlags) {
196 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
197
198 FlutterSemanticsFlags flags1 = {};
199 flags1.is_enabled = kFlutterTristateNone;
200 fl_accessible_node_set_flags(node, &flags1);
201 AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node));
202 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_SENSITIVE));
203 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_ENABLED));
204 g_object_unref(state1);
205
206 FlutterSemanticsFlags flags2 = {};
207 flags2.is_enabled = kFlutterTristateFalse;
208 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
209 ::testing::_, ATK_STATE_SENSITIVE, TRUE));
210 fl_accessible_node_set_flags(node, &flags2);
211 AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node));
212 EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_SENSITIVE));
213 EXPECT_FALSE(atk_state_set_contains_state(state2, ATK_STATE_ENABLED));
214 g_object_unref(state2);
215
216 FlutterSemanticsFlags flags3 = {};
217 flags3.is_enabled = kFlutterTristateTrue;
218 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
219 ::testing::_, ATK_STATE_ENABLED, TRUE));
220 fl_accessible_node_set_flags(node, &flags3);
221 AtkStateSet* state3 = atk_object_ref_state_set(ATK_OBJECT(node));
222 EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_SENSITIVE));
223 EXPECT_TRUE(atk_state_set_contains_state(state3, ATK_STATE_ENABLED));
224 g_object_unref(state3);
225 }
226
227 // Checks the Flutter obscured flag is mapped to ATK flags.
228 TEST_F(FlAccessibleNodeTest, ObscuredFlags) {
229 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
230
231 FlutterSemanticsFlags flags1 = {};
232 flags1.is_obscured = true;
233 fl_accessible_node_set_flags(node, &flags1);
234 AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node));
235 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_SHOWING));
236 g_object_unref(state1);
237
238 FlutterSemanticsFlags flags2 = {};
239 flags2.is_obscured = false;
240 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
241 ::testing::_, ATK_STATE_SHOWING, TRUE));
242 fl_accessible_node_set_flags(node, &flags2);
243 AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node));
244 EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_SHOWING));
245 g_object_unref(state2);
246 }
247
248 // Checks the Flutter hidden flag is mapped to ATK flags.
249 TEST_F(FlAccessibleNodeTest, HiddenFlags) {
250 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
251
252 FlutterSemanticsFlags flags1 = {};
253 flags1.is_hidden = true;
254 fl_accessible_node_set_flags(node, &flags1);
255 AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node));
256 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_VISIBLE));
257 g_object_unref(state1);
258
259 FlutterSemanticsFlags flags2 = {};
260 flags2.is_hidden = false;
261 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
262 ::testing::_, ATK_STATE_VISIBLE, TRUE));
263 fl_accessible_node_set_flags(node, &flags2);
264 AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node));
265 EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_VISIBLE));
266 g_object_unref(state2);
267 }
268
269 // Checks the Flutter read only flag is mapped to ATK flags.
270 TEST_F(FlAccessibleNodeTest, ReadOnlyFlags) {
271 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
272
273 FlutterSemanticsFlags flags1 = {};
274 flags1.is_read_only = false;
275 fl_accessible_node_set_flags(node, &flags1);
276 AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node));
277 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_READ_ONLY));
278 g_object_unref(state1);
279
280 FlutterSemanticsFlags flags2 = {};
281 flags2.is_read_only = true;
282 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
283 ::testing::_, ATK_STATE_READ_ONLY, TRUE));
284 fl_accessible_node_set_flags(node, &flags2);
285 AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node));
286 EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_READ_ONLY));
287 g_object_unref(state2);
288 }
289
290 // Checks the Flutter text field flag is mapped to ATK flags.
291 TEST_F(FlAccessibleNodeTest, TextFieldFlags) {
292 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
293
294 FlutterSemanticsFlags flags1 = {};
295 flags1.is_text_field = false;
296 fl_accessible_node_set_flags(node, &flags1);
297 AtkStateSet* state1 = atk_object_ref_state_set(ATK_OBJECT(node));
298 EXPECT_FALSE(atk_state_set_contains_state(state1, ATK_STATE_EDITABLE));
299 g_object_unref(state1);
300
301 FlutterSemanticsFlags flags2 = {};
302 flags2.is_text_field = true;
303 EXPECT_CALL(mock_gtk, atk_object_notify_state_change(
304 ::testing::_, ATK_STATE_EDITABLE, TRUE));
305 fl_accessible_node_set_flags(node, &flags2);
306 AtkStateSet* state2 = atk_object_ref_state_set(ATK_OBJECT(node));
307 EXPECT_TRUE(atk_state_set_contains_state(state2, ATK_STATE_EDITABLE));
308 g_object_unref(state2);
309 }
310
311 // Checks Flutter flags are mapped to appropriate ATK roles.
312 TEST_F(FlAccessibleNodeTest, GetRole) {
313 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
314
315 FlutterSemanticsFlags flags1 = {};
316 flags1.is_button = true;
317 fl_accessible_node_set_flags(node, &flags1);
318 EXPECT_EQ(atk_object_get_role(ATK_OBJECT(node)), ATK_ROLE_PUSH_BUTTON);
319
320 FlutterSemanticsFlags flags2 = {};
321 flags2.is_checked = kFlutterCheckStateFalse;
322 fl_accessible_node_set_flags(node, &flags2);
323 EXPECT_EQ(atk_object_get_role(ATK_OBJECT(node)), ATK_ROLE_CHECK_BOX);
324
325 FlutterSemanticsFlags flags3 = {};
326 flags3.is_checked = kFlutterCheckStateFalse;
327 flags3.is_in_mutually_exclusive_group = true;
328 fl_accessible_node_set_flags(node, &flags3);
329 EXPECT_EQ(atk_object_get_role(ATK_OBJECT(node)), ATK_ROLE_RADIO_BUTTON);
330
331 FlutterSemanticsFlags flags4 = {};
332 flags4.is_toggled = kFlutterTristateFalse;
333 fl_accessible_node_set_flags(node, &flags4);
334 EXPECT_EQ(atk_object_get_role(ATK_OBJECT(node)), ATK_ROLE_TOGGLE_BUTTON);
335
336 FlutterSemanticsFlags flags5 = {};
337 flags5.is_text_field = true;
338 fl_accessible_node_set_flags(node, &flags5);
339 EXPECT_EQ(atk_object_get_role(ATK_OBJECT(node)), ATK_ROLE_TEXT);
340
341 FlutterSemanticsFlags flags6 = {};
342 flags6.is_text_field = true;
343 flags6.is_obscured = true;
344 fl_accessible_node_set_flags(node, &flags6);
345 EXPECT_EQ(atk_object_get_role(ATK_OBJECT(node)), ATK_ROLE_PASSWORD_TEXT);
346 }
347
348 // Checks Flutter actions are mapped to the appropriate ATK actions.
349 TEST_F(FlAccessibleNodeTest, SetActions) {
350 g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
351 fl_accessible_node_set_actions(
352 node, static_cast<FlutterSemanticsAction>(
353 kFlutterSemanticsActionTap | kFlutterSemanticsActionLongPress));
354
355 EXPECT_EQ(atk_action_get_n_actions(ATK_ACTION(node)), 2);
356 EXPECT_STREQ(atk_action_get_name(ATK_ACTION(node), 0), "Tap");
357 EXPECT_STREQ(atk_action_get_name(ATK_ACTION(node), 1), "LongPress");
358 }
FlAccessibleNodeTest
Definition: fl_accessible_node_test.cc:11
FlAccessibleNodeTest::SetUp
void SetUp() override
Definition: fl_accessible_node_test.cc:13
FlAccessibleNodeTest::engine
FlEngine * engine
Definition: fl_accessible_node_test.cc:21
FlAccessibleNodeTest::mock_gtk
::testing::NiceMock< flutter::testing::MockGtk > mock_gtk
Definition: fl_accessible_node_test.cc:20
FlAccessibleNodeTest::~FlAccessibleNodeTest
~FlAccessibleNodeTest()
Definition: fl_accessible_node_test.cc:18
fl_accessible_node_set_name
void fl_accessible_node_set_name(FlAccessibleNode *self, const gchar *name)
Definition: fl_accessible_node.cc:607
fl_accessible_node_set_actions
void fl_accessible_node_set_actions(FlAccessibleNode *self, FlutterSemanticsAction actions)
Definition: fl_accessible_node.cc:631
fl_accessible_node_set_children
void fl_accessible_node_set_children(FlAccessibleNode *self, GPtrArray *children)
Definition: fl_accessible_node.cc:580
fl_accessible_node_set_extents
void fl_accessible_node_set_extents(FlAccessibleNode *self, gint x, gint y, gint width, gint height)
Definition: fl_accessible_node.cc:613
fl_accessible_node_set_parent
void fl_accessible_node_set_parent(FlAccessibleNode *self, AtkObject *parent, gint index)
Definition: fl_accessible_node.cc:569
fl_accessible_node_set_flags
void fl_accessible_node_set_flags(FlAccessibleNode *self, FlutterSemanticsFlags *flags)
Definition: fl_accessible_node.cc:624
fl_accessible_node_new
FlAccessibleNode * fl_accessible_node_new(FlEngine *engine, FlutterViewId view_id, int32_t node_id)
Definition: fl_accessible_node.cc:560
fl_accessible_node.h
TEST_F
TEST_F(FlAccessibleNodeTest, BuildTree)
Definition: fl_accessible_node_test.cc:25
height
self height
Definition: fl_compositor_software.cc:43
g_autoptr
g_autoptr(GMutexLocker) locker
width
self width
Definition: fl_compositor_software.cc:42
TRUE
return TRUE
Definition: fl_compositor_software.cc:68
fl_dart_project_new
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
Definition: fl_dart_project.cc:52
fl_engine_new
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:697
view_id
G_BEGIN_DECLS FlutterViewId view_id
Definition: fl_view_accessible.h:49