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 
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.
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.
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.
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.
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.
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.
350  g_autoptr(FlAccessibleNode) node = fl_accessible_node_new(engine, 123, 0);
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 }
::testing::NiceMock< flutter::testing::MockGtk > mock_gtk
void fl_accessible_node_set_name(FlAccessibleNode *self, const gchar *name)
void fl_accessible_node_set_actions(FlAccessibleNode *self, FlutterSemanticsAction actions)
void fl_accessible_node_set_children(FlAccessibleNode *self, GPtrArray *children)
void fl_accessible_node_set_extents(FlAccessibleNode *self, gint x, gint y, gint width, gint height)
void fl_accessible_node_set_parent(FlAccessibleNode *self, AtkObject *parent, gint index)
void fl_accessible_node_set_flags(FlAccessibleNode *self, FlutterSemanticsFlags *flags)
FlAccessibleNode * fl_accessible_node_new(FlEngine *engine, FlutterViewId view_id, int32_t node_id)
TEST_F(FlAccessibleNodeTest, BuildTree)
self height
g_autoptr(GMutexLocker) locker
self width
return TRUE
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:697
G_BEGIN_DECLS FlutterViewId view_id