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