| Flutter macOS Embedder |

flutter_platform_node_delegate_unittests.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 #include "flutter_platform_node_delegate.h"
6
7 #include "flutter/third_party/accessibility/ax/ax_action_data.h"
8 #include "gtest/gtest.h"
9
10 #include "test_accessibility_bridge.h"
11
12 namespace flutter {
13 namespace testing {
14
15 TEST(FlutterPlatformNodeDelegateTest, NodeDelegateHasUniqueId) {
16 std::shared_ptr<TestAccessibilityBridge> bridge =
17 std::make_shared<TestAccessibilityBridge>();
18
19 // Add node 0: root.
20 FlutterSemanticsNode2 node0{sizeof(FlutterSemanticsNode2), 0};
21 std::vector<int32_t> node0_children{1};
22 FlutterSemanticsFlags emptyFlags = FlutterSemanticsFlags{};
23 node0.child_count = node0_children.size();
24 node0.children_in_traversal_order = node0_children.data();
25 node0.children_in_hit_test_order = node0_children.data();
26 node0.flags2 = &emptyFlags;
27
28 // Add node 1: text child of node 0.
29 FlutterSemanticsNode2 node1{sizeof(FlutterSemanticsNode2), 1};
30 node1.label = "prefecture";
31 node1.value = "Kyoto";
32 node1.flags2 = &emptyFlags;
33
34 bridge->AddFlutterSemanticsNodeUpdate(node0);
35 bridge->AddFlutterSemanticsNodeUpdate(node1);
36 bridge->CommitUpdates();
37
38 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
39 auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
40 EXPECT_TRUE(node0_delegate->GetUniqueId() != node1_delegate->GetUniqueId());
41 }
42
43 TEST(FlutterPlatformNodeDelegateTest, canPerfomActions) {
44 std::shared_ptr<TestAccessibilityBridge> bridge =
45 std::make_shared<TestAccessibilityBridge>();
46 FlutterSemanticsNode2 root;
47 root.id = 0;
48 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
49 flags.is_text_field = true;
50 root.flags2 = &flags;
51 root.actions = static_cast<FlutterSemanticsAction>(0);
52 root.text_selection_base = -1;
53 root.text_selection_extent = -1;
54 root.label = "root";
55 root.hint = "";
56 root.value = "";
57 root.increased_value = "";
58 root.decreased_value = "";
59 root.tooltip = "";
60 root.child_count = 0;
61 root.custom_accessibility_actions_count = 0;
62 bridge->AddFlutterSemanticsNodeUpdate(root);
63
64 bridge->CommitUpdates();
65
66 auto accessibility = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
67 // Performs an AXAction.
68 ui::AXActionData action_data;
69 action_data.action = ax::mojom::Action::kDoDefault;
70 accessibility->AccessibilityPerformAction(action_data);
71 EXPECT_EQ(bridge->performed_actions.size(), size_t{1});
72 EXPECT_EQ(bridge->performed_actions[0],
73 FlutterSemanticsAction::kFlutterSemanticsActionTap);
74
75 action_data.action = ax::mojom::Action::kFocus;
76 accessibility->AccessibilityPerformAction(action_data);
77 EXPECT_EQ(bridge->performed_actions.size(), size_t{2});
78 EXPECT_EQ(
79 bridge->performed_actions[1],
80 FlutterSemanticsAction::kFlutterSemanticsActionDidGainAccessibilityFocus);
81
82 action_data.action = ax::mojom::Action::kScrollToMakeVisible;
83 accessibility->AccessibilityPerformAction(action_data);
84 EXPECT_EQ(bridge->performed_actions.size(), size_t{3});
85 EXPECT_EQ(bridge->performed_actions[2],
86 FlutterSemanticsAction::kFlutterSemanticsActionShowOnScreen);
87 }
88
89 TEST(FlutterPlatformNodeDelegateTest, canGetAXNode) {
90 // Set up a flutter accessibility node.
91 std::shared_ptr<TestAccessibilityBridge> bridge =
92 std::make_shared<TestAccessibilityBridge>();
93 FlutterSemanticsNode2 root;
94 root.id = 0;
95 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
96 flags.is_text_field = true;
97 root.flags2 = &flags;
98 root.actions = static_cast<FlutterSemanticsAction>(0);
99 root.text_selection_base = -1;
100 root.text_selection_extent = -1;
101 root.label = "root";
102 root.hint = "";
103 root.value = "";
104 root.increased_value = "";
105 root.decreased_value = "";
106 root.tooltip = "";
107 root.child_count = 0;
108 root.custom_accessibility_actions_count = 0;
109 bridge->AddFlutterSemanticsNodeUpdate(root);
110
111 bridge->CommitUpdates();
112
113 auto accessibility = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
114 EXPECT_EQ(accessibility->GetData().id, 0);
115 }
116
117 TEST(FlutterPlatformNodeDelegateTest, canCalculateBoundsCorrectly) {
118 std::shared_ptr<TestAccessibilityBridge> bridge =
119 std::make_shared<TestAccessibilityBridge>();
120 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
121 FlutterSemanticsNode2 root;
122 root.id = 0;
123 root.label = "root";
124 root.hint = "";
125 root.value = "";
126 root.increased_value = "";
127 root.decreased_value = "";
128 root.tooltip = "";
129 root.child_count = 1;
130 root.flags2 = &flags;
131 int32_t children[] = {1};
132 root.children_in_traversal_order = children;
133 root.custom_accessibility_actions_count = 0;
134 root.rect = {0, 0, 100, 100}; // LTRB
135 root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
136 bridge->AddFlutterSemanticsNodeUpdate(root);
137
138 FlutterSemanticsNode2 child1;
139 child1.id = 1;
140 child1.label = "child 1";
141 child1.hint = "";
142 child1.value = "";
143 child1.increased_value = "";
144 child1.decreased_value = "";
145 child1.tooltip = "";
146 child1.child_count = 0;
147 child1.flags2 = &flags;
148 child1.custom_accessibility_actions_count = 0;
149 child1.rect = {0, 0, 50, 50}; // LTRB
150 child1.transform = {0.5, 0, 0, 0, 0.5, 0, 0, 0, 1};
151 bridge->AddFlutterSemanticsNodeUpdate(child1);
152
153 bridge->CommitUpdates();
154 auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
155 ui::AXOffscreenResult result;
156 gfx::Rect bounds =
157 child1_node->GetBoundsRect(ui::AXCoordinateSystem::kScreenDIPs,
158 ui::AXClippingBehavior::kClipped, &result);
159 EXPECT_EQ(bounds.x(), 0);
160 EXPECT_EQ(bounds.y(), 0);
161 EXPECT_EQ(bounds.width(), 25);
162 EXPECT_EQ(bounds.height(), 25);
163 EXPECT_EQ(result, ui::AXOffscreenResult::kOnscreen);
164 }
165
166 TEST(FlutterPlatformNodeDelegateTest, canCalculateOffScreenBoundsCorrectly) {
167 std::shared_ptr<TestAccessibilityBridge> bridge =
168 std::make_shared<TestAccessibilityBridge>();
169 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
170 FlutterSemanticsNode2 root;
171 root.id = 0;
172 root.label = "root";
173 root.hint = "";
174 root.value = "";
175 root.increased_value = "";
176 root.decreased_value = "";
177 root.tooltip = "";
178 root.child_count = 1;
179 root.flags2 = &flags;
180 int32_t children[] = {1};
181 root.children_in_traversal_order = children;
182 root.custom_accessibility_actions_count = 0;
183 root.rect = {0, 0, 100, 100}; // LTRB
184 root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
185 bridge->AddFlutterSemanticsNodeUpdate(root);
186
187 FlutterSemanticsNode2 child1;
188 child1.id = 1;
189 child1.label = "child 1";
190 child1.hint = "";
191 child1.value = "";
192 child1.increased_value = "";
193 child1.decreased_value = "";
194 child1.tooltip = "";
195 child1.child_count = 0;
196 child1.flags2 = &flags;
197 child1.custom_accessibility_actions_count = 0;
198 child1.rect = {90, 90, 100, 100}; // LTRB
199 child1.transform = {2, 0, 0, 0, 2, 0, 0, 0, 1};
200 bridge->AddFlutterSemanticsNodeUpdate(child1);
201
202 bridge->CommitUpdates();
203 auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
204 ui::AXOffscreenResult result;
205 gfx::Rect bounds =
206 child1_node->GetBoundsRect(ui::AXCoordinateSystem::kScreenDIPs,
207 ui::AXClippingBehavior::kUnclipped, &result);
208 EXPECT_EQ(bounds.x(), 180);
209 EXPECT_EQ(bounds.y(), 180);
210 EXPECT_EQ(bounds.width(), 20);
211 EXPECT_EQ(bounds.height(), 20);
212 EXPECT_EQ(result, ui::AXOffscreenResult::kOffscreen);
213 }
214
215 TEST(FlutterPlatformNodeDelegateTest, canUseOwnerBridge) {
216 std::shared_ptr<TestAccessibilityBridge> bridge =
217 std::make_shared<TestAccessibilityBridge>();
218 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
219 FlutterSemanticsNode2 root;
220 root.id = 0;
221 root.label = "root";
222 root.hint = "";
223 root.value = "";
224 root.increased_value = "";
225 root.decreased_value = "";
226 root.tooltip = "";
227 root.child_count = 1;
228 root.flags2 = &flags;
229 int32_t children[] = {1};
230 root.children_in_traversal_order = children;
231 root.custom_accessibility_actions_count = 0;
232 root.rect = {0, 0, 100, 100}; // LTRB
233 root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
234 bridge->AddFlutterSemanticsNodeUpdate(root);
235
236 FlutterSemanticsNode2 child1;
237 child1.id = 1;
238 child1.label = "child 1";
239 child1.hint = "";
240 child1.value = "";
241 child1.increased_value = "";
242 child1.decreased_value = "";
243 child1.tooltip = "";
244 child1.child_count = 0;
245 child1.flags2 = &flags;
246 child1.custom_accessibility_actions_count = 0;
247 child1.rect = {0, 0, 50, 50}; // LTRB
248 child1.transform = {0.5, 0, 0, 0, 0.5, 0, 0, 0, 1};
249 bridge->AddFlutterSemanticsNodeUpdate(child1);
250
251 bridge->CommitUpdates();
252 auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
253 auto owner_bridge = child1_node->GetOwnerBridge().lock();
254
255 bool result;
256 gfx::RectF bounds = owner_bridge->RelativeToGlobalBounds(
257 child1_node->GetAXNode(), result, true);
258 EXPECT_EQ(bounds.x(), 0);
259 EXPECT_EQ(bounds.y(), 0);
260 EXPECT_EQ(bounds.width(), 25);
261 EXPECT_EQ(bounds.height(), 25);
262 EXPECT_EQ(result, false);
263 }
264
265 TEST(FlutterPlatformNodeDelegateTest, selfIsLowestPlatformAncestor) {
266 std::shared_ptr<TestAccessibilityBridge> bridge =
267 std::make_shared<TestAccessibilityBridge>();
268 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
269 FlutterSemanticsNode2 root;
270 root.id = 0;
271 root.label = "root";
272 root.hint = "";
273 root.value = "";
274 root.increased_value = "";
275 root.decreased_value = "";
276 root.tooltip = "";
277 root.child_count = 0;
278 root.flags2 = &flags;
279 root.children_in_traversal_order = nullptr;
280 root.custom_accessibility_actions_count = 0;
281 bridge->AddFlutterSemanticsNodeUpdate(root);
282
283 bridge->CommitUpdates();
284 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
285 auto lowest_platform_ancestor = root_node->GetLowestPlatformAncestor();
286 EXPECT_EQ(root_node->GetNativeViewAccessible(), lowest_platform_ancestor);
287 }
288
289 TEST(FlutterPlatformNodeDelegateTest, canGetFromNodeID) {
290 std::shared_ptr<TestAccessibilityBridge> bridge =
291 std::make_shared<TestAccessibilityBridge>();
292 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
293 FlutterSemanticsNode2 root;
294 root.id = 0;
295 root.label = "root";
296 root.hint = "";
297 root.value = "";
298 root.increased_value = "";
299 root.decreased_value = "";
300 root.tooltip = "";
301 root.child_count = 1;
302 root.flags2 = &flags;
303 int32_t children[] = {1};
304 root.children_in_traversal_order = children;
305 root.custom_accessibility_actions_count = 0;
306 bridge->AddFlutterSemanticsNodeUpdate(root);
307
308 FlutterSemanticsNode2 child1;
309 child1.id = 1;
310 child1.label = "child 1";
311 child1.hint = "";
312 child1.value = "";
313 child1.increased_value = "";
314 child1.decreased_value = "";
315 child1.tooltip = "";
316 child1.child_count = 0;
317 child1.flags2 = &flags;
318 child1.custom_accessibility_actions_count = 0;
319 bridge->AddFlutterSemanticsNodeUpdate(child1);
320
321 bridge->CommitUpdates();
322 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
323 auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
324 auto node_by_id = root_node->GetFromNodeID(1);
325 EXPECT_EQ(child1_node->GetPlatformNode(), node_by_id);
326 }
327
328 } // namespace testing
329 } // namespace flutter
flutter_platform_node_delegate.h
flutter::testing::TEST
TEST(FlutterAppDelegateTest, DoesNotCallDelegatesWithoutHandler)
Definition: FlutterAppDelegateTest.mm:32
flutter
Definition: AccessibilityBridgeMac.h:16
test_accessibility_bridge.h