Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
accessibility_bridge_unittest.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
6
7#include <fuchsia/ui/views/cpp/fidl.h>
8#include <lib/async-loop/cpp/loop.h>
9#include <lib/async-loop/default.h>
10#include <lib/async/cpp/executor.h>
11#include <lib/fidl/cpp/binding_set.h>
12#include <lib/fidl/cpp/interface_request.h>
13#include <lib/inspect/cpp/hierarchy.h>
14#include <lib/inspect/cpp/inspector.h>
15#include <lib/inspect/cpp/reader.h>
16#include <lib/sys/cpp/testing/service_directory_provider.h>
17#include <lib/zx/eventpair.h>
18#include <zircon/status.h>
19#include <zircon/types.h>
20
21#include <memory>
22
23#include "flutter/lib/ui/semantics/semantics_node.h"
24#include "gtest/gtest.h"
25
27
29
30namespace {
31
32void ExpectNodeHasRole(
33 const fuchsia::accessibility::semantics::Node& node,
34 const std::unordered_map<uint32_t, fuchsia::accessibility::semantics::Role>
35 roles_by_node_id) {
36 ASSERT_TRUE(node.has_node_id());
37 ASSERT_NE(roles_by_node_id.find(node.node_id()), roles_by_node_id.end());
38 EXPECT_TRUE(node.has_role());
39 EXPECT_EQ(node.role(), roles_by_node_id.at(node.node_id()));
40}
41
42} // namespace
43
45 public:
46 void SetSemanticsEnabled(bool enabled) { enabled_ = enabled; }
47 void DispatchSemanticsAction(int32_t node_id,
49 actions.push_back(std::make_pair(node_id, action));
50 }
51
52 bool enabled() { return enabled_; }
53 std::vector<std::pair<int32_t, flutter::SemanticsAction>> actions;
54
55 private:
56 bool enabled_;
57};
58
59class AccessibilityBridgeTest : public testing::Test {
60 public:
62 : loop_(&kAsyncLoopConfigAttachToCurrentThread),
63 services_provider_(loop_.dispatcher()),
64 executor_(loop_.dispatcher()) {
65 services_provider_.AddService(
66 semantics_manager_.GetHandler(loop_.dispatcher()),
67 SemanticsManager::Name_);
68 }
69
71 loop_.RunUntilIdle();
72 loop_.ResetQuit();
73 }
74
75 void RunPromiseToCompletion(fpromise::promise<> promise) {
76 bool done = false;
77 executor_.schedule_task(
78 std::move(promise).and_then([&done]() { done = true; }));
79 while (loop_.GetState() == ASYNC_LOOP_RUNNABLE) {
80 if (done) {
81 loop_.ResetQuit();
82 return;
83 }
84
85 loop_.Run(zx::deadline_after(zx::duration::infinite()), true);
86 }
87 loop_.ResetQuit();
88 }
89
90 protected:
91 void SetUp() override {
92 // Connect to SemanticsManager service.
93 fuchsia::accessibility::semantics::SemanticsManagerHandle semantics_manager;
94 zx_status_t semantics_status =
95 services_provider_.service_directory()
96 ->Connect<fuchsia::accessibility::semantics::SemanticsManager>(
97 semantics_manager.NewRequest());
98 if (semantics_status != ZX_OK) {
99 FML_LOG(WARNING)
100 << "fuchsia::accessibility::semantics::SemanticsManager connection "
101 "failed: "
102 << zx_status_get_string(semantics_status);
103 }
104
106 inspector_ = std::make_unique<inspect::Inspector>();
108 set_semantics_enabled_callback = [this](bool enabled) {
110 };
112 dispatch_semantics_action_callback =
113 [this](int32_t node_id, flutter::SemanticsAction action) {
115 };
116
117 fuchsia::ui::views::ViewRefControl view_ref_control;
118 fuchsia::ui::views::ViewRef view_ref;
119 auto status = zx::eventpair::create(
120 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
121 ASSERT_EQ(status, ZX_OK);
122 view_ref_control.reference.replace(
123 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
124 &view_ref_control.reference);
125 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
127 std::make_unique<flutter_runner::AccessibilityBridge>(
128 std::move(set_semantics_enabled_callback),
129 std::move(dispatch_semantics_action_callback),
130 std::move(semantics_manager), std::move(view_ref),
131 inspector_->GetRoot().CreateChild("test_node"));
132
134 }
135
136 void TearDown() override { semantics_manager_.ResetTree(); }
137
140 std::unique_ptr<flutter_runner::AccessibilityBridge> accessibility_bridge_;
141 // Required to verify inspect metrics.
142 std::unique_ptr<inspect::Inspector> inspector_;
143
144 private:
145 async::Loop loop_;
146 sys::testing::ServiceDirectoryProvider services_provider_;
147 // Required to retrieve inspect metrics.
148 async::Executor executor_;
149};
150
151TEST_F(AccessibilityBridgeTest, RegistersViewRef) {
152 EXPECT_TRUE(semantics_manager_.RegisterViewCalled());
153}
154
156 EXPECT_FALSE(accessibility_delegate_.enabled());
157 std::unique_ptr<fuchsia::accessibility::semantics::SemanticListener> listener(
158 accessibility_bridge_.release());
159 listener->OnSemanticsModeChanged(true, nullptr);
160 EXPECT_TRUE(accessibility_delegate_.enabled());
161}
162
164 accessibility_bridge_->RequestAnnounce("message");
165 RunLoopUntilIdle();
166
167 auto& last_events = semantics_manager_.GetLastEvents();
168 ASSERT_EQ(last_events.size(), 1u);
169 ASSERT_TRUE(last_events[0].is_announce());
170 EXPECT_EQ(last_events[0].announce().message(), "message");
171}
172
173TEST_F(AccessibilityBridgeTest, PopulatesIsKeyboardKeyAttribute) {
175 node0.id = 0;
176 node0.flags = static_cast<int>(flutter::SemanticsFlags::kIsKeyboardKey);
177
178 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
179 RunLoopUntilIdle();
180
181 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
182 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
183 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
184 EXPECT_TRUE(fuchsia_node.has_attributes());
185 EXPECT_TRUE(fuchsia_node.attributes().is_keyboard_key());
186}
187
188TEST_F(AccessibilityBridgeTest, UpdatesNodeRoles) {
190
192 node0.id = 0;
193 node0.flags |= static_cast<int>(flutter::SemanticsFlags::kIsButton);
194 node0.childrenInTraversalOrder = {1, 2, 3, 4, 5, 6, 7, 8};
195 node0.childrenInHitTestOrder = {1, 2, 3, 4, 5, 6, 7, 8};
196 updates.emplace(0, node0);
197
199 node1.id = 1;
200 node1.flags |= static_cast<int>(flutter::SemanticsFlags::kIsHeader);
201 node1.childrenInTraversalOrder = {};
202 node1.childrenInHitTestOrder = {};
203 updates.emplace(1, node1);
204
206 node2.id = 2;
207 node2.flags |= static_cast<int>(flutter::SemanticsFlags::kIsImage);
208 node2.childrenInTraversalOrder = {};
209 node2.childrenInHitTestOrder = {};
210 updates.emplace(2, node2);
211
213 node3.id = 3;
214 node3.flags |= static_cast<int>(flutter::SemanticsFlags::kIsTextField);
215 node3.childrenInTraversalOrder = {};
216 node3.childrenInHitTestOrder = {};
217 updates.emplace(3, node3);
218
220 node4.childrenInTraversalOrder = {};
221 node4.childrenInHitTestOrder = {};
222 node4.id = 4;
223 node4.flags |= static_cast<int>(flutter::SemanticsFlags::kIsSlider);
224 updates.emplace(4, node4);
225
227 node5.childrenInTraversalOrder = {};
228 node5.childrenInHitTestOrder = {};
229 node5.id = 5;
230 node5.flags |= static_cast<int>(flutter::SemanticsFlags::kIsLink);
231 updates.emplace(5, node5);
232
234 node6.childrenInTraversalOrder = {};
235 node6.childrenInHitTestOrder = {};
236 node6.id = 6;
237 node6.flags |= static_cast<int>(flutter::SemanticsFlags::kHasCheckedState);
238 node6.flags |=
240 updates.emplace(6, node6);
241
243 node7.childrenInTraversalOrder = {};
244 node7.childrenInHitTestOrder = {};
245 node7.id = 7;
246 node7.flags |= static_cast<int>(flutter::SemanticsFlags::kHasCheckedState);
247 updates.emplace(7, node7);
248
250 node8.childrenInTraversalOrder = {};
251 node8.childrenInHitTestOrder = {};
252 node8.id = 8;
253 node8.flags |= static_cast<int>(flutter::SemanticsFlags::kHasToggledState);
254 updates.emplace(7, node8);
255
256 accessibility_bridge_->AddSemanticsNodeUpdate(std::move(updates), 1.f);
257 RunLoopUntilIdle();
258
259 std::unordered_map<uint32_t, fuchsia::accessibility::semantics::Role>
260 roles_by_node_id = {
261 {0u, fuchsia::accessibility::semantics::Role::BUTTON},
262 {1u, fuchsia::accessibility::semantics::Role::HEADER},
263 {2u, fuchsia::accessibility::semantics::Role::IMAGE},
264 {3u, fuchsia::accessibility::semantics::Role::TEXT_FIELD},
265 {4u, fuchsia::accessibility::semantics::Role::SLIDER},
266 {5u, fuchsia::accessibility::semantics::Role::LINK},
267 {6u, fuchsia::accessibility::semantics::Role::RADIO_BUTTON},
268 {7u, fuchsia::accessibility::semantics::Role::CHECK_BOX},
269 {8u, fuchsia::accessibility::semantics::Role::TOGGLE_SWITCH}};
270
271 EXPECT_EQ(0, semantics_manager_.DeleteCount());
272 EXPECT_EQ(1, semantics_manager_.UpdateCount());
273 EXPECT_EQ(1, semantics_manager_.CommitCount());
274 EXPECT_EQ(8u, semantics_manager_.LastUpdatedNodes().size());
275 for (const auto& node : semantics_manager_.LastUpdatedNodes()) {
276 ExpectNodeHasRole(node, roles_by_node_id);
277 }
278
279 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
280 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
281}
282
283TEST_F(AccessibilityBridgeTest, DeletesChildrenTransitively) {
284 // Test that when a node is deleted, so are its transitive children.
286 node2.id = 2;
287
289 node1.id = 1;
290 node1.childrenInTraversalOrder = {2};
291 node1.childrenInHitTestOrder = {2};
292
294 node0.id = 0;
295 node0.childrenInTraversalOrder = {1};
296 node0.childrenInHitTestOrder = {1};
297
298 accessibility_bridge_->AddSemanticsNodeUpdate(
299 {
300 {0, node0},
301 {1, node1},
302 {2, node2},
303 },
304 1.f);
305 RunLoopUntilIdle();
306
307 EXPECT_EQ(0, semantics_manager_.DeleteCount());
308 EXPECT_EQ(1, semantics_manager_.UpdateCount());
309 EXPECT_EQ(1, semantics_manager_.CommitCount());
310 EXPECT_EQ(3U, semantics_manager_.LastUpdatedNodes().size());
311 EXPECT_EQ(0U, semantics_manager_.LastDeletedNodeIds().size());
312 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
313 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
314
315 // Remove the children
316 node0.childrenInTraversalOrder.clear();
317 node0.childrenInHitTestOrder.clear();
318 accessibility_bridge_->AddSemanticsNodeUpdate(
319 {
320 {0, node0},
321 },
322 1.f);
323 RunLoopUntilIdle();
324
325 EXPECT_EQ(1, semantics_manager_.DeleteCount());
326 EXPECT_EQ(2, semantics_manager_.UpdateCount());
327 EXPECT_EQ(2, semantics_manager_.CommitCount());
328 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
329 ASSERT_EQ(std::vector<uint32_t>({1, 2}),
330 semantics_manager_.LastDeletedNodeIds());
331 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
332 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
333}
334
335TEST_F(AccessibilityBridgeTest, PopulatesRoleButton) {
337 node0.id = 0;
338 node0.flags = static_cast<int>(flutter::SemanticsFlags::kIsButton);
339
340 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
341 RunLoopUntilIdle();
342
343 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
344 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
345 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
346 EXPECT_TRUE(fuchsia_node.has_role());
347 EXPECT_EQ(fuchsia_node.role(),
348 fuchsia::accessibility::semantics::Role::BUTTON);
349}
350
351TEST_F(AccessibilityBridgeTest, PopulatesRoleImage) {
353 node0.id = 0;
354 node0.flags = static_cast<int>(flutter::SemanticsFlags::kIsImage);
355
356 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
357 RunLoopUntilIdle();
358
359 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
360 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
361 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
362 EXPECT_TRUE(fuchsia_node.has_role());
363 EXPECT_EQ(fuchsia_node.role(),
364 fuchsia::accessibility::semantics::Role::IMAGE);
365}
366
367TEST_F(AccessibilityBridgeTest, PopulatesRoleSlider) {
369 node0.id = 0;
370 node0.actions |= static_cast<int>(flutter::SemanticsAction::kIncrease);
371
372 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
373 RunLoopUntilIdle();
374
375 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
376 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
377 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
378 EXPECT_TRUE(fuchsia_node.has_role());
379 EXPECT_EQ(fuchsia_node.role(),
380 fuchsia::accessibility::semantics::Role::SLIDER);
381}
382
383TEST_F(AccessibilityBridgeTest, PopulatesRoleHeader) {
385 node0.id = 0;
386 node0.flags = static_cast<int>(flutter::SemanticsFlags::kIsHeader);
387
388 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
389 RunLoopUntilIdle();
390
391 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
392 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
393 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
394 EXPECT_TRUE(fuchsia_node.has_role());
395 EXPECT_EQ(fuchsia_node.role(),
396 fuchsia::accessibility::semantics::Role::HEADER);
397}
398
399TEST_F(AccessibilityBridgeTest, PopulatesCheckedState) {
401 node0.id = 0;
402 // HasCheckedState = true
403 // IsChecked = true
404 // IsSelected = false
405 node0.flags |= static_cast<int>(flutter::SemanticsFlags::kHasCheckedState);
406 node0.flags |= static_cast<int>(flutter::SemanticsFlags::kIsChecked);
407 node0.value = "value";
408
409 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
410 RunLoopUntilIdle();
411
412 EXPECT_EQ(0, semantics_manager_.DeleteCount());
413 EXPECT_EQ(1, semantics_manager_.UpdateCount());
414 EXPECT_EQ(1, semantics_manager_.CommitCount());
415 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
416 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
417 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
418 EXPECT_TRUE(fuchsia_node.has_states());
419 const auto& states = fuchsia_node.states();
420 EXPECT_TRUE(states.has_checked_state());
421 EXPECT_EQ(states.checked_state(),
422 fuchsia::accessibility::semantics::CheckedState::CHECKED);
423 EXPECT_TRUE(states.has_selected());
424 EXPECT_FALSE(states.selected());
425 EXPECT_TRUE(states.has_value());
426 EXPECT_EQ(states.value(), node0.value);
427
428 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
429 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
430}
431
432TEST_F(AccessibilityBridgeTest, PopulatesSelectedState) {
434 node0.id = 0;
435 // HasCheckedState = false
436 // IsChecked = false
437 // IsSelected = true
438 node0.flags = static_cast<int>(flutter::SemanticsFlags::kIsSelected);
439
440 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
441 RunLoopUntilIdle();
442
443 EXPECT_EQ(0, semantics_manager_.DeleteCount());
444 EXPECT_EQ(1, semantics_manager_.UpdateCount());
445 EXPECT_EQ(1, semantics_manager_.CommitCount());
446 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
447 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
448 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
449 EXPECT_TRUE(fuchsia_node.has_states());
450 const auto& states = fuchsia_node.states();
451 EXPECT_TRUE(states.has_checked_state());
452 EXPECT_EQ(states.checked_state(),
453 fuchsia::accessibility::semantics::CheckedState::NONE);
454 EXPECT_TRUE(states.has_selected());
455 EXPECT_TRUE(states.selected());
456
457 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
458 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
459}
460
461TEST_F(AccessibilityBridgeTest, PopulatesToggledState) {
463 node0.id = 0;
464 node0.flags |= static_cast<int>(flutter::SemanticsFlags::kHasToggledState);
465 node0.flags |= static_cast<int>(flutter::SemanticsFlags::kIsToggled);
466
467 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
468 RunLoopUntilIdle();
469
470 EXPECT_EQ(0, semantics_manager_.DeleteCount());
471 EXPECT_EQ(1, semantics_manager_.UpdateCount());
472 EXPECT_EQ(1, semantics_manager_.CommitCount());
473 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
474 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
475 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
476 EXPECT_TRUE(fuchsia_node.has_states());
477 const auto& states = fuchsia_node.states();
478 EXPECT_TRUE(states.has_toggled_state());
479 EXPECT_EQ(states.toggled_state(),
480 fuchsia::accessibility::semantics::ToggledState::ON);
481
482 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
483 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
484}
485
486TEST_F(AccessibilityBridgeTest, PopulatesEnabledState) {
488 node0.id = 0;
489 // HasEnabledState = true
490 // IsEnabled = true
491 node0.flags |= static_cast<int>(flutter::SemanticsFlags::kHasEnabledState);
492 node0.flags |= static_cast<int>(flutter::SemanticsFlags::kIsEnabled);
493 node0.value = "value";
494
495 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
496 RunLoopUntilIdle();
497
498 EXPECT_EQ(0, semantics_manager_.DeleteCount());
499 EXPECT_EQ(1, semantics_manager_.UpdateCount());
500 EXPECT_EQ(1, semantics_manager_.CommitCount());
501 EXPECT_EQ(1U, semantics_manager_.LastUpdatedNodes().size());
502 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
503 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
504 EXPECT_TRUE(fuchsia_node.has_states());
505 const auto& states = fuchsia_node.states();
506 EXPECT_TRUE(states.has_enabled_state());
507 EXPECT_EQ(states.enabled_state(),
508 fuchsia::accessibility::semantics::EnabledState::ENABLED);
509 EXPECT_TRUE(states.has_value());
510 EXPECT_EQ(states.value(), node0.value);
511
512 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
513 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
514}
515
516TEST_F(AccessibilityBridgeTest, ApplyViewPixelRatioToRoot) {
518 node0.id = 0;
519 node0.flags = static_cast<int>(flutter::SemanticsFlags::kIsSelected);
520
521 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.25f);
522 RunLoopUntilIdle();
523 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
524 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
525 EXPECT_EQ(fuchsia_node.transform().matrix[0], 0.8f);
526 EXPECT_EQ(fuchsia_node.transform().matrix[5], 0.8f);
527 EXPECT_EQ(fuchsia_node.transform().matrix[10], 1.f);
528}
529
530TEST_F(AccessibilityBridgeTest, DoesNotPopulatesHiddenState) {
531 // Flutter's notion of a hidden node is different from Fuchsia's hidden node.
532 // This test make sures that this state does not get sent.
534 node0.id = 0;
535 // HasCheckedState = false
536 // IsChecked = false
537 // IsSelected = false
538 // IsHidden = true
539 node0.flags = static_cast<int>(flutter::SemanticsFlags::kIsHidden);
540
541 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
542 RunLoopUntilIdle();
543
544 EXPECT_EQ(0, semantics_manager_.DeleteCount());
545 EXPECT_EQ(1, semantics_manager_.UpdateCount());
546 EXPECT_EQ(1, semantics_manager_.CommitCount());
547 EXPECT_EQ(1u, semantics_manager_.LastUpdatedNodes().size());
548 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
549 EXPECT_EQ(fuchsia_node.node_id(), static_cast<unsigned int>(node0.id));
550 EXPECT_TRUE(fuchsia_node.has_states());
551 const auto& states = fuchsia_node.states();
552 EXPECT_TRUE(states.has_checked_state());
553 EXPECT_EQ(states.checked_state(),
554 fuchsia::accessibility::semantics::CheckedState::NONE);
555 EXPECT_TRUE(states.has_selected());
556 EXPECT_FALSE(states.selected());
557 EXPECT_FALSE(states.has_hidden());
558
559 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
560 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
561}
562
563TEST_F(AccessibilityBridgeTest, PopulatesActions) {
565 node0.id = 0;
566 node0.actions |= static_cast<int>(flutter::SemanticsAction::kTap);
567 node0.actions |= static_cast<int>(flutter::SemanticsAction::kLongPress);
568 node0.actions |= static_cast<int>(flutter::SemanticsAction::kShowOnScreen);
569 node0.actions |= static_cast<int>(flutter::SemanticsAction::kIncrease);
570 node0.actions |= static_cast<int>(flutter::SemanticsAction::kDecrease);
571
572 accessibility_bridge_->AddSemanticsNodeUpdate({{0, node0}}, 1.f);
573 RunLoopUntilIdle();
574
575 EXPECT_EQ(0, semantics_manager_.DeleteCount());
576 EXPECT_EQ(1, semantics_manager_.UpdateCount());
577 EXPECT_EQ(1, semantics_manager_.CommitCount());
578 EXPECT_EQ(1u, semantics_manager_.LastUpdatedNodes().size());
579 const auto& fuchsia_node = semantics_manager_.LastUpdatedNodes().at(0u);
580 EXPECT_EQ(fuchsia_node.actions().size(), 5u);
581 EXPECT_EQ(fuchsia_node.actions().at(0u),
582 fuchsia::accessibility::semantics::Action::DEFAULT);
583 EXPECT_EQ(fuchsia_node.actions().at(1u),
584 fuchsia::accessibility::semantics::Action::SECONDARY);
585 EXPECT_EQ(fuchsia_node.actions().at(2u),
586 fuchsia::accessibility::semantics::Action::SHOW_ON_SCREEN);
587 EXPECT_EQ(fuchsia_node.actions().at(3u),
588 fuchsia::accessibility::semantics::Action::INCREMENT);
589 EXPECT_EQ(fuchsia_node.actions().at(4u),
590 fuchsia::accessibility::semantics::Action::DECREMENT);
591}
592
593TEST_F(AccessibilityBridgeTest, TruncatesLargeLabel) {
594 // Test that labels which are too long are truncated.
596 node0.id = 0;
597
599 node1.id = 1;
600
601 flutter::SemanticsNode bad_node;
602 bad_node.id = 2;
603 bad_node.label =
604 std::string(fuchsia::accessibility::semantics::MAX_LABEL_SIZE + 1, '2');
605
606 node0.childrenInTraversalOrder = {1, 2};
607 node0.childrenInHitTestOrder = {1, 2};
608
609 accessibility_bridge_->AddSemanticsNodeUpdate(
610 {
611 {0, node0},
612 {1, node1},
613 {2, bad_node},
614 },
615 1.f);
616 RunLoopUntilIdle();
617
618 // Nothing to delete, but we should have broken
619 EXPECT_EQ(0, semantics_manager_.DeleteCount());
620 EXPECT_EQ(1, semantics_manager_.UpdateCount());
621 EXPECT_EQ(1, semantics_manager_.CommitCount());
622 EXPECT_EQ(3U, semantics_manager_.LastUpdatedNodes().size());
623 auto trimmed_node =
624 std::find_if(semantics_manager_.LastUpdatedNodes().begin(),
625 semantics_manager_.LastUpdatedNodes().end(),
626 [id = static_cast<uint32_t>(bad_node.id)](
627 fuchsia::accessibility::semantics::Node const& node) {
628 return node.node_id() == id;
629 });
630 ASSERT_NE(trimmed_node, semantics_manager_.LastUpdatedNodes().end());
631 ASSERT_TRUE(trimmed_node->has_attributes());
632 EXPECT_EQ(
633 trimmed_node->attributes().label(),
634 std::string(fuchsia::accessibility::semantics::MAX_LABEL_SIZE, '2'));
635 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
636 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
637}
638
639TEST_F(AccessibilityBridgeTest, TruncatesLargeToolTip) {
640 // Test that tooltips which are too long are truncated.
642 node0.id = 0;
643
645 node1.id = 1;
646
647 flutter::SemanticsNode bad_node;
648 bad_node.id = 2;
649 bad_node.tooltip =
650 std::string(fuchsia::accessibility::semantics::MAX_LABEL_SIZE + 1, '2');
651
652 node0.childrenInTraversalOrder = {1, 2};
653 node0.childrenInHitTestOrder = {1, 2};
654
655 accessibility_bridge_->AddSemanticsNodeUpdate(
656 {
657 {0, node0},
658 {1, node1},
659 {2, bad_node},
660 },
661 1.f);
662 RunLoopUntilIdle();
663
664 // Nothing to delete, but we should have broken
665 EXPECT_EQ(0, semantics_manager_.DeleteCount());
666 EXPECT_EQ(1, semantics_manager_.UpdateCount());
667 EXPECT_EQ(1, semantics_manager_.CommitCount());
668 EXPECT_EQ(3U, semantics_manager_.LastUpdatedNodes().size());
669 auto trimmed_node =
670 std::find_if(semantics_manager_.LastUpdatedNodes().begin(),
671 semantics_manager_.LastUpdatedNodes().end(),
672 [id = static_cast<uint32_t>(bad_node.id)](
673 fuchsia::accessibility::semantics::Node const& node) {
674 return node.node_id() == id;
675 });
676 ASSERT_NE(trimmed_node, semantics_manager_.LastUpdatedNodes().end());
677 ASSERT_TRUE(trimmed_node->has_attributes());
678 EXPECT_EQ(
679 trimmed_node->attributes().secondary_label(),
680 std::string(fuchsia::accessibility::semantics::MAX_LABEL_SIZE, '2'));
681 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
682 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
683}
684
685TEST_F(AccessibilityBridgeTest, TruncatesLargeValue) {
686 // Test that values which are too long are truncated.
688 node0.id = 0;
689
691 node1.id = 1;
692
693 flutter::SemanticsNode bad_node;
694 bad_node.id = 2;
695 bad_node.value =
696 std::string(fuchsia::accessibility::semantics::MAX_VALUE_SIZE + 1, '2');
697
698 node0.childrenInTraversalOrder = {1, 2};
699 node0.childrenInHitTestOrder = {1, 2};
700
701 accessibility_bridge_->AddSemanticsNodeUpdate(
702 {
703 {0, node0},
704 {1, node1},
705 {2, bad_node},
706 },
707 1.f);
708 RunLoopUntilIdle();
709
710 EXPECT_EQ(0, semantics_manager_.DeleteCount());
711 EXPECT_EQ(1, semantics_manager_.UpdateCount());
712 EXPECT_EQ(1, semantics_manager_.CommitCount());
713 EXPECT_EQ(3U, semantics_manager_.LastUpdatedNodes().size());
714 auto trimmed_node =
715 std::find_if(semantics_manager_.LastUpdatedNodes().begin(),
716 semantics_manager_.LastUpdatedNodes().end(),
717 [id = static_cast<uint32_t>(bad_node.id)](
718 fuchsia::accessibility::semantics::Node const& node) {
719 return node.node_id() == id;
720 });
721 ASSERT_NE(trimmed_node, semantics_manager_.LastUpdatedNodes().end());
722 ASSERT_TRUE(trimmed_node->has_states());
723 EXPECT_EQ(
724 trimmed_node->states().value(),
725 std::string(fuchsia::accessibility::semantics::MAX_VALUE_SIZE, '2'));
726 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
727 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
728}
729
730TEST_F(AccessibilityBridgeTest, SplitsLargeUpdates) {
731 // Test that labels which are too long are truncated.
733 node0.id = 0;
734
736 node1.id = 1;
737 node1.label =
738 std::string(fuchsia::accessibility::semantics::MAX_LABEL_SIZE, '1');
739
741 node2.id = 2;
742 node2.label = "2";
743
745 node3.id = 3;
746 node3.label = "3";
747
749 node4.id = 4;
750 node4.value =
751 std::string(fuchsia::accessibility::semantics::MAX_VALUE_SIZE, '4');
752
753 node0.childrenInTraversalOrder = {1, 2};
754 node0.childrenInHitTestOrder = {1, 2};
755 node1.childrenInTraversalOrder = {3, 4};
756 node1.childrenInHitTestOrder = {3, 4};
757
758 accessibility_bridge_->AddSemanticsNodeUpdate(
759 {
760 {0, node0},
761 {1, node1},
762 {2, node2},
763 {3, node3},
764 {4, node4},
765 },
766 1.f);
767 RunLoopUntilIdle();
768
769 // Nothing to delete, but we should have broken into groups (4, 3, 2), (1, 0)
770 EXPECT_EQ(0, semantics_manager_.DeleteCount());
771 EXPECT_EQ(2, semantics_manager_.UpdateCount());
772 EXPECT_EQ(1, semantics_manager_.CommitCount());
773 EXPECT_EQ(2U, semantics_manager_.LastUpdatedNodes().size());
774 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
775 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
776}
777
779 // Test that cycles don't cause fatal error.
781 node0.id = 0;
782 node0.childrenInTraversalOrder.push_back(0);
783 node0.childrenInHitTestOrder.push_back(0);
784 accessibility_bridge_->AddSemanticsNodeUpdate(
785 {
786 {0, node0},
787 },
788 1.f);
789 RunLoopUntilIdle();
790
791 EXPECT_EQ(0, semantics_manager_.DeleteCount());
792 EXPECT_EQ(1, semantics_manager_.UpdateCount());
793 EXPECT_EQ(1, semantics_manager_.CommitCount());
794 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
795 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
796
797 node0.childrenInTraversalOrder = {0, 1};
798 node0.childrenInHitTestOrder = {0, 1};
800 node1.id = 1;
801 node1.childrenInTraversalOrder = {0};
802 node1.childrenInHitTestOrder = {0};
803 accessibility_bridge_->AddSemanticsNodeUpdate(
804 {
805 {0, node0},
806 {1, node1},
807 },
808 1.f);
809 RunLoopUntilIdle();
810
811 EXPECT_EQ(0, semantics_manager_.DeleteCount());
812 EXPECT_EQ(2, semantics_manager_.UpdateCount());
813 EXPECT_EQ(2, semantics_manager_.CommitCount());
814 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
815 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
816}
817
818TEST_F(AccessibilityBridgeTest, BatchesLargeMessages) {
819 // Tests that messages get batched appropriately.
821 node0.id = 0;
822
824
825 const int32_t child_nodes = 100;
826 const int32_t leaf_nodes = 100;
827 for (int32_t i = 1; i < child_nodes + 1; i++) {
829 node.id = i;
830 node0.childrenInTraversalOrder.push_back(i);
831 node0.childrenInHitTestOrder.push_back(i);
832 for (int32_t j = 0; j < leaf_nodes; j++) {
833 flutter::SemanticsNode leaf_node;
834 int id = (i * child_nodes) + ((j + 1) * leaf_nodes);
835 leaf_node.id = id;
836 leaf_node.label = "A relatively simple label";
837 node.childrenInTraversalOrder.push_back(id);
838 node.childrenInHitTestOrder.push_back(id);
839 update.insert(std::make_pair(id, std::move(leaf_node)));
840 }
841 update.insert(std::make_pair(i, std::move(node)));
842 }
843
844 update.insert(std::make_pair(0, std::move(node0)));
845
846 // Make the semantics manager hold answering to this commit to test the flow
847 // control. This means the second update will not be pushed until the first
848 // one has processed.
849 semantics_manager_.SetShouldHoldCommitResponse(true);
850 accessibility_bridge_->AddSemanticsNodeUpdate(update, 1.f);
851 RunLoopUntilIdle();
852
853 EXPECT_EQ(0, semantics_manager_.DeleteCount());
854
855 EXPECT_TRUE(6 <= semantics_manager_.UpdateCount() &&
856 semantics_manager_.UpdateCount() <= 12);
857 EXPECT_EQ(1, semantics_manager_.CommitCount());
858 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
859 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
860
861 int next_update_count = semantics_manager_.UpdateCount() + 1;
862 // Remove the children
863 node0.childrenInTraversalOrder.clear();
864 node0.childrenInHitTestOrder.clear();
865 accessibility_bridge_->AddSemanticsNodeUpdate(
866 {
867 {0, node0},
868 },
869 1.f);
870 RunLoopUntilIdle();
871
872 // Should still be 0, because the commit was not answered yet.
873 EXPECT_EQ(0, semantics_manager_.DeleteCount());
874
875 semantics_manager_.InvokeCommitCallback();
876 RunLoopUntilIdle();
877
878 EXPECT_EQ(1, semantics_manager_.DeleteCount());
879 EXPECT_EQ(next_update_count, semantics_manager_.UpdateCount());
880 EXPECT_EQ(2, semantics_manager_.CommitCount());
881 EXPECT_FALSE(semantics_manager_.DeleteOverflowed());
882 EXPECT_FALSE(semantics_manager_.UpdateOverflowed());
883}
884
887 node0.id = 0;
888 node0.rect.setLTRB(0, 0, 100, 100);
889 node0.flags |= static_cast<int32_t>(flutter::SemanticsFlags::kIsFocusable);
890
892 node1.id = 1;
893 node1.rect.setLTRB(10, 10, 20, 20);
894 // Setting platform view id ensures this node is considered focusable.
895 node1.platformViewId = 1u;
896
898 node2.id = 2;
899 node2.rect.setLTRB(25, 10, 45, 20);
900 // Setting label ensures this node is considered focusable.
901 node2.label = "label";
902
904 node3.id = 3;
905 node3.rect.setLTRB(10, 25, 20, 45);
906 // Setting actions to a nonzero value ensures this node is considered
907 // focusable.
908 node3.actions = 1u;
909
911 node4.id = 4;
912 node4.rect.setLTRB(10, 10, 20, 20);
913 node4.transform.setTranslate(20, 20, 0);
914 node4.flags |= static_cast<int32_t>(flutter::SemanticsFlags::kIsFocusable);
915
916 node0.childrenInTraversalOrder = {1, 2, 3, 4};
917 node0.childrenInHitTestOrder = {1, 2, 3, 4};
918
919 accessibility_bridge_->AddSemanticsNodeUpdate(
920 {
921 {0, node0},
922 {1, node1},
923 {2, node2},
924 {3, node3},
925 {4, node4},
926 },
927 1.f);
928 RunLoopUntilIdle();
929
930 uint32_t hit_node_id;
931 auto callback = [&hit_node_id](fuchsia::accessibility::semantics::Hit hit) {
932 EXPECT_TRUE(hit.has_node_id());
933 hit_node_id = hit.node_id();
934 };
935
936 // Nodes are:
937 // ----------
938 // | 1 2 |
939 // | 3 4 |
940 // ----------
941
942 accessibility_bridge_->HitTest({1, 1}, callback);
943 EXPECT_EQ(hit_node_id, 0u);
944 accessibility_bridge_->HitTest({15, 15}, callback);
945 EXPECT_EQ(hit_node_id, 1u);
946 accessibility_bridge_->HitTest({30, 15}, callback);
947 EXPECT_EQ(hit_node_id, 2u);
948 accessibility_bridge_->HitTest({15, 30}, callback);
949 EXPECT_EQ(hit_node_id, 3u);
950 accessibility_bridge_->HitTest({30, 30}, callback);
951 EXPECT_EQ(hit_node_id, 4u);
952}
953
954TEST_F(AccessibilityBridgeTest, HitTestWithPixelRatio) {
956 node0.id = 0;
957 node0.rect.setLTRB(0, 0, 100, 100);
958 node0.flags |= static_cast<int32_t>(flutter::SemanticsFlags::kIsFocusable);
959
961 node1.id = 1;
962 node1.rect.setLTRB(10, 10, 20, 20);
963 // Setting platform view id ensures this node is considered focusable.
964 node1.platformViewId = 1u;
965
966 node0.childrenInTraversalOrder = {1};
967 node0.childrenInHitTestOrder = {1};
968
969 accessibility_bridge_->AddSemanticsNodeUpdate(
970 {
971 {0, node0},
972 {1, node1},
973 },
974 // Pick a very small pixel ratio so that a point within the bounds of
975 // the node's root-space coordinates will be well outside the "screen"
976 // bounds of the node.
977 .1f);
978 RunLoopUntilIdle();
979
980 uint32_t hit_node_id;
981 auto callback = [&hit_node_id](fuchsia::accessibility::semantics::Hit hit) {
982 EXPECT_TRUE(hit.has_node_id());
983 hit_node_id = hit.node_id();
984 };
985 accessibility_bridge_->HitTest({15, 15}, callback);
986 EXPECT_EQ(hit_node_id, 0u);
987}
988
989TEST_F(AccessibilityBridgeTest, HitTestUnfocusableChild) {
991 node0.id = 0;
992 node0.rect.setLTRB(0, 0, 100, 100);
993
995 node1.id = 1;
996 node1.rect.setLTRB(10, 10, 60, 60);
997
999 node2.id = 2;
1000 node2.rect.setLTRB(50, 50, 100, 100);
1001 node2.flags |= static_cast<int32_t>(flutter::SemanticsFlags::kIsFocusable);
1002
1003 node0.childrenInTraversalOrder = {1, 2};
1004 node0.childrenInHitTestOrder = {1, 2};
1005
1006 accessibility_bridge_->AddSemanticsNodeUpdate(
1007 {
1008 {0, node0},
1009 {1, node1},
1010 {2, node2},
1011 },
1012 1.f);
1013 RunLoopUntilIdle();
1014
1015 uint32_t hit_node_id;
1016 auto callback = [&hit_node_id](fuchsia::accessibility::semantics::Hit hit) {
1017 EXPECT_TRUE(hit.has_node_id());
1018 hit_node_id = hit.node_id();
1019 };
1020
1021 accessibility_bridge_->HitTest({55, 55}, callback);
1022 EXPECT_EQ(hit_node_id, 2u);
1023}
1024
1025TEST_F(AccessibilityBridgeTest, HitTestOverlapping) {
1026 // Tests that the first node in hit test order wins, even if a later node
1027 // would be able to receive the hit.
1029 node0.id = 0;
1030 node0.rect.setLTRB(0, 0, 100, 100);
1031 node0.flags |= static_cast<int32_t>(flutter::SemanticsFlags::kIsFocusable);
1032
1034 node1.id = 1;
1035 node1.rect.setLTRB(0, 0, 100, 100);
1036 node1.flags |= static_cast<int32_t>(flutter::SemanticsFlags::kIsFocusable);
1037
1039 node2.id = 2;
1040 node2.rect.setLTRB(25, 10, 45, 20);
1041 node2.flags |= static_cast<int32_t>(flutter::SemanticsFlags::kIsFocusable);
1042
1043 node0.childrenInTraversalOrder = {1, 2};
1044 node0.childrenInHitTestOrder = {2, 1};
1045
1046 accessibility_bridge_->AddSemanticsNodeUpdate(
1047 {
1048 {0, node0},
1049 {1, node1},
1050 {2, node2},
1051 },
1052 1.f);
1053 RunLoopUntilIdle();
1054
1055 uint32_t hit_node_id;
1056 auto callback = [&hit_node_id](fuchsia::accessibility::semantics::Hit hit) {
1057 EXPECT_TRUE(hit.has_node_id());
1058 hit_node_id = hit.node_id();
1059 };
1060
1061 accessibility_bridge_->HitTest({30, 15}, callback);
1062 EXPECT_EQ(hit_node_id, 2u);
1063}
1064
1067 node0.id = 0;
1068
1070 node1.id = 1;
1071
1072 node0.childrenInTraversalOrder = {1};
1073 node0.childrenInHitTestOrder = {1};
1074
1075 accessibility_bridge_->AddSemanticsNodeUpdate(
1076 {
1077 {0, node0},
1078 {1, node1},
1079 },
1080 1.f);
1081 RunLoopUntilIdle();
1082
1083 auto handled_callback = [](bool handled) { EXPECT_TRUE(handled); };
1084 auto unhandled_callback = [](bool handled) { EXPECT_FALSE(handled); };
1085
1086 accessibility_bridge_->OnAccessibilityActionRequested(
1087 0u, fuchsia::accessibility::semantics::Action::DEFAULT, handled_callback);
1088 EXPECT_EQ(accessibility_delegate_.actions.size(), 1u);
1089 EXPECT_EQ(accessibility_delegate_.actions.back(),
1090 std::make_pair(0, flutter::SemanticsAction::kTap));
1091
1092 accessibility_bridge_->OnAccessibilityActionRequested(
1093 0u, fuchsia::accessibility::semantics::Action::SECONDARY,
1094 handled_callback);
1095 EXPECT_EQ(accessibility_delegate_.actions.size(), 2u);
1096 EXPECT_EQ(accessibility_delegate_.actions.back(),
1097 std::make_pair(0, flutter::SemanticsAction::kLongPress));
1098
1099 accessibility_bridge_->OnAccessibilityActionRequested(
1100 0u, fuchsia::accessibility::semantics::Action::SET_FOCUS,
1101 unhandled_callback);
1102 EXPECT_EQ(accessibility_delegate_.actions.size(), 2u);
1103
1104 accessibility_bridge_->OnAccessibilityActionRequested(
1105 0u, fuchsia::accessibility::semantics::Action::SET_VALUE,
1106 unhandled_callback);
1107 EXPECT_EQ(accessibility_delegate_.actions.size(), 2u);
1108
1109 accessibility_bridge_->OnAccessibilityActionRequested(
1110 0u, fuchsia::accessibility::semantics::Action::SHOW_ON_SCREEN,
1111 handled_callback);
1112 EXPECT_EQ(accessibility_delegate_.actions.size(), 3u);
1113 EXPECT_EQ(accessibility_delegate_.actions.back(),
1114 std::make_pair(0, flutter::SemanticsAction::kShowOnScreen));
1115
1116 accessibility_bridge_->OnAccessibilityActionRequested(
1117 2u, fuchsia::accessibility::semantics::Action::DEFAULT,
1118 unhandled_callback);
1119 EXPECT_EQ(accessibility_delegate_.actions.size(), 3u);
1120
1121 accessibility_bridge_->OnAccessibilityActionRequested(
1122 0u, fuchsia::accessibility::semantics::Action::INCREMENT,
1123 handled_callback);
1124 EXPECT_EQ(accessibility_delegate_.actions.size(), 4u);
1125 EXPECT_EQ(accessibility_delegate_.actions.back(),
1126 std::make_pair(0, flutter::SemanticsAction::kIncrease));
1127
1128 accessibility_bridge_->OnAccessibilityActionRequested(
1129 0u, fuchsia::accessibility::semantics::Action::DECREMENT,
1130 handled_callback);
1131 EXPECT_EQ(accessibility_delegate_.actions.size(), 5u);
1132 EXPECT_EQ(accessibility_delegate_.actions.back(),
1133 std::make_pair(0, flutter::SemanticsAction::kDecrease));
1134}
1135
1136#if !FLUTTER_RELEASE
1140 node0.id = 0;
1141 node0.label = "node0";
1142 node0.hint = "node0_hint";
1143 node0.value = "value";
1144 node0.flags |= static_cast<int>(flutter::SemanticsFlags::kIsButton);
1145 node0.childrenInTraversalOrder = {1};
1146 node0.childrenInHitTestOrder = {1};
1147 node0.rect.setLTRB(0, 0, 100, 100);
1148 updates.emplace(0, node0);
1149
1151 node1.id = 1;
1152 node1.flags |= static_cast<int>(flutter::SemanticsFlags::kIsHeader);
1153 node1.childrenInTraversalOrder = {};
1154 node1.childrenInHitTestOrder = {};
1155 updates.emplace(1, node1);
1156
1157 accessibility_bridge_->AddSemanticsNodeUpdate(std::move(updates), 1.f);
1158 RunLoopUntilIdle();
1159
1160 fpromise::result<inspect::Hierarchy> hierarchy;
1161 ASSERT_FALSE(hierarchy.is_ok());
1162 RunPromiseToCompletion(
1163 inspect::ReadFromInspector(*inspector_)
1164 .then([&hierarchy](fpromise::result<inspect::Hierarchy>& result) {
1165 hierarchy = std::move(result);
1166 }));
1167 ASSERT_TRUE(hierarchy.is_ok());
1168
1169 auto tree_inspect_hierarchy = hierarchy.value().GetByPath({"test_node"});
1170 ASSERT_NE(tree_inspect_hierarchy, nullptr);
1171 // TODO(http://fxbug.dev/75841): Rewrite flutter engine accessibility bridge
1172 // tests using inspect matchers. The checks bellow verify that the tree was
1173 // built, and that it matches the format of the input tree. This will be
1174 // updated in the future when test matchers are available to verify individual
1175 // property values.
1176 const auto& root = tree_inspect_hierarchy->children();
1177 ASSERT_EQ(root.size(), 1u);
1178 EXPECT_EQ(root[0].name(), "semantic_tree_root");
1179 const auto& child = root[0].children();
1180 ASSERT_EQ(child.size(), 1u);
1181 EXPECT_EQ(child[0].name(), "node_1");
1182}
1183#endif // !FLUTTER_RELEASE
1184
1185} // namespace flutter_runner_test
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition DM.cpp:263
SkM44 & setTranslate(SkScalar x, SkScalar y, SkScalar z=0)
Definition SkM44.h:301
std::function< void(bool)> SetSemanticsEnabledCallback
std::function< void(int32_t, flutter::SemanticsAction)> DispatchSemanticsActionCallback
std::vector< std::pair< int32_t, flutter::SemanticsAction > > actions
void DispatchSemanticsAction(int32_t node_id, flutter::SemanticsAction action)
std::unique_ptr< flutter_runner::AccessibilityBridge > accessibility_bridge_
fidl::InterfaceRequestHandler< SemanticsManager > GetHandler(async_dispatcher_t *dispatcher)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
#define FML_LOG(severity)
Definition logging.h:82
const char * name
Definition fuchsia.cc:50
Win32Message message
TEST_F(AccessibilityBridgeTest, RegistersViewRef)
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
void setLTRB(float left, float top, float right, float bottom)
Definition SkRect.h:865
std::vector< int32_t > childrenInHitTestOrder
std::vector< int32_t > childrenInTraversalOrder
const uintptr_t id
#define EXPECT_TRUE(handle)
Definition unit_test.h:685