22#include "gmock/gmock.h"
23#include "gtest/gtest.h"
29using ::testing::NiceMock;
38class AccessibilityBridgeWindowsSpy :
public AccessibilityBridgeWindows {
42 explicit AccessibilityBridgeWindowsSpy(FlutterWindowsEngine*
engine,
43 FlutterWindowsView*
view)
44 : AccessibilityBridgeWindows(
view) {}
46 void DispatchWinAccessibilityEvent(
47 std::shared_ptr<FlutterPlatformNodeDelegateWindows>
node_delegate,
52 void SetFocus(std::shared_ptr<FlutterPlatformNodeDelegateWindows>
58 dispatched_events_.clear();
59 focused_nodes_.clear();
62 const std::vector<MsaaEvent>& dispatched_events()
const {
63 return dispatched_events_;
66 const std::vector<int32_t> focused_nodes()
const {
67 std::vector<int32_t> ids;
68 std::transform(focused_nodes_.begin(), focused_nodes_.end(),
69 std::back_inserter(ids),
70 [](std::shared_ptr<FlutterPlatformNodeDelegate> node) {
71 return node->GetAXNode()->id();
77 std::weak_ptr<FlutterPlatformNodeDelegate> GetFocusedNode()
override {
78 return focused_nodes_.back();
82 std::vector<MsaaEvent> dispatched_events_;
83 std::vector<std::shared_ptr<FlutterPlatformNodeDelegate>> focused_nodes_;
90class FlutterWindowsViewSpy :
public FlutterWindowsView {
92 FlutterWindowsViewSpy(FlutterWindowsEngine*
engine,
93 std::unique_ptr<WindowBindingHandler>
handler)
101 virtual std::shared_ptr<AccessibilityBridgeWindows>
102 CreateAccessibilityBridge()
override {
103 return std::make_shared<AccessibilityBridgeWindowsSpy>(GetEngine(),
this);
113std::unique_ptr<FlutterWindowsEngine> GetTestEngine() {
115 properties.
assets_path = L
"C:\\foo\\flutter_assets";
118 FlutterProjectBundle project(properties);
119 auto engine = std::make_unique<FlutterWindowsEngine>(project);
121 EngineModifier modifier(
engine.get());
122 modifier.embedder_api().UpdateSemanticsEnabled =
128 std::make_shared<MockKeyResponseController>());
144void PopulateAXTree(std::shared_ptr<AccessibilityBridge> bridge) {
148 std::vector<int32_t> node0_children{1, 2};
149 node0.child_count = node0_children.size();
150 node0.children_in_traversal_order = node0_children.data();
151 node0.children_in_hit_test_order = node0_children.data();
152 node0.flags2 = &empty_flags;
156 node1.
label =
"prefecture";
157 node1.value =
"Kyoto";
158 node1.flags2 = &empty_flags;
162 std::vector<int32_t> node2_children{3, 4};
164 node2.children_in_traversal_order = node2_children.data();
165 node2.children_in_hit_test_order = node2_children.data();
166 node2.flags2 = &empty_flags;
170 node3.
label =
"city";
172 node3.flags2 = &empty_flags;
176 node4.
flags2 = &empty_flags;
178 bridge->AddFlutterSemanticsNodeUpdate(node0);
179 bridge->AddFlutterSemanticsNodeUpdate(node1);
180 bridge->AddFlutterSemanticsNodeUpdate(node2);
181 bridge->AddFlutterSemanticsNodeUpdate(node3);
182 bridge->AddFlutterSemanticsNodeUpdate(node4);
183 bridge->CommitUpdates();
186ui::AXNode* AXNodeFromID(std::shared_ptr<AccessibilityBridge> bridge,
188 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(
id).lock();
192std::shared_ptr<AccessibilityBridgeWindowsSpy> GetAccessibilityBridgeSpy(
193 FlutterWindowsView&
view) {
194 return std::static_pointer_cast<AccessibilityBridgeWindowsSpy>(
195 view.accessibility_bridge().lock());
198void ExpectWinEventFromAXEvent(int32_t node_id,
201 auto engine = GetTestEngine();
202 FlutterWindowsViewSpy
view{
203 engine.get(), std::make_unique<NiceMock<MockWindowBindingHandler>>()};
204 EngineModifier modifier{
engine.get()};
205 modifier.SetImplicitView(&
view);
206 view.OnUpdateSemanticsEnabled(
true);
208 auto bridge = GetAccessibilityBridgeSpy(
view);
209 PopulateAXTree(bridge);
211 bridge->ResetRecords();
212 bridge->OnAccessibilityEvent({AXNodeFromID(bridge, node_id),
214 ASSERT_EQ(bridge->dispatched_events().size(), 1);
215 EXPECT_EQ(bridge->dispatched_events()[0].event_type, expected_event);
218void ExpectWinEventFromAXEventOnFocusNode(int32_t node_id,
222 auto engine = GetTestEngine();
223 FlutterWindowsViewSpy
view{
224 engine.get(), std::make_unique<NiceMock<MockWindowBindingHandler>>()};
225 EngineModifier modifier{
engine.get()};
226 modifier.SetImplicitView(&
view);
227 view.OnUpdateSemanticsEnabled(
true);
229 auto bridge = GetAccessibilityBridgeSpy(
view);
230 PopulateAXTree(bridge);
232 bridge->ResetRecords();
233 auto focus_delegate =
234 bridge->GetFlutterPlatformNodeDelegateFromID(focus_id).lock();
235 bridge->SetFocus(std::static_pointer_cast<FlutterPlatformNodeDelegateWindows>(
237 bridge->OnAccessibilityEvent({AXNodeFromID(bridge, node_id),
239 ASSERT_EQ(bridge->dispatched_events().size(), 1);
240 EXPECT_EQ(bridge->dispatched_events()[0].event_type, expected_event);
241 EXPECT_EQ(bridge->dispatched_events()[0].node_delegate->GetAXNode()->id(),
248 auto engine = GetTestEngine();
249 FlutterWindowsViewSpy
view{
250 engine.get(), std::make_unique<NiceMock<MockWindowBindingHandler>>()};
252 modifier.SetImplicitView(&
view);
253 view.OnUpdateSemanticsEnabled(
true);
255 auto bridge =
view.accessibility_bridge().lock();
256 PopulateAXTree(bridge);
258 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
259 auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
260 EXPECT_EQ(node0_delegate->GetNativeViewAccessible(),
261 node1_delegate->GetParent());
265 auto engine = GetTestEngine();
266 FlutterWindowsViewSpy
view{
267 engine.get(), std::make_unique<NiceMock<MockWindowBindingHandler>>()};
269 modifier.SetImplicitView(&
view);
270 view.OnUpdateSemanticsEnabled(
true);
272 auto bridge =
view.accessibility_bridge().lock();
273 PopulateAXTree(bridge);
275 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
276 ASSERT_TRUE(node0_delegate->GetParent() ==
nullptr);
280 auto engine = GetTestEngine();
281 FlutterWindowsViewSpy
view{
282 engine.get(), std::make_unique<NiceMock<MockWindowBindingHandler>>()};
284 modifier.SetImplicitView(&
view);
285 view.OnUpdateSemanticsEnabled(
true);
287 auto bridge =
view.accessibility_bridge().lock();
288 PopulateAXTree(bridge);
295 actual_action = info->
action;
315 auto engine = GetTestEngine();
316 FlutterWindowsViewSpy
view{
317 engine.get(), std::make_unique<NiceMock<MockWindowBindingHandler>>()};
319 modifier.SetImplicitView(&
view);
320 view.OnUpdateSemanticsEnabled(
true);
322 auto bridge = GetAccessibilityBridgeSpy(
view);
323 PopulateAXTree(bridge);
325 bridge->ResetRecords();
326 bridge->OnAccessibilityEvent({AXNodeFromID(bridge, 1),
330 ASSERT_EQ(bridge->dispatched_events().size(), 1);
331 EXPECT_EQ(bridge->dispatched_events()[0].event_type,
334 ASSERT_EQ(bridge->focused_nodes().size(), 1);
335 EXPECT_EQ(bridge->focused_nodes()[0], 1);
345 ExpectWinEventFromAXEvent(
361 ExpectWinEventFromAXEvent(
367 ExpectWinEventFromAXEvent(
378 ExpectWinEventFromAXEvent(
394 ExpectWinEventFromAXEvent(
400 ExpectWinEventFromAXEventOnFocusNode(
std::shared_ptr< FlutterPlatformNodeDelegateWindows > node_delegate
ax::mojom::Event event_type
void DispatchAccessibilityAction(AccessibilityNodeId target, FlutterSemanticsAction action, fml::MallocMapping data) override
Dispatch accessibility action back to the Flutter framework. These actions are generated in the nativ...
void OnAccessibilityEvent(ui::AXEventGenerator::TargetedEvent targeted_event) override
Handle accessibility events generated due to accessibility tree changes. These events are needed to b...
@ DOCUMENT_SELECTION_CHANGED
@ SCROLL_HORIZONTAL_POSITION_CHANGED
@ IMAGE_ANNOTATION_CHANGED
@ WIN_IACCESSIBLE_STATE_CHANGED
@ SCROLL_VERTICAL_POSITION_CHANGED
@ SELECTED_CHILDREN_CHANGED
#define FLUTTER_API_SYMBOL(symbol)
@ kFlutterSemanticsActionCopy
Copy the current selection to the clipboard.
@ kFlutterSemanticsActionTap
const gchar FlBinaryMessengerMessageHandler handler
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
@ kSelectedChildrenChanged
@ kDocumentSelectionChanged
void MockEmbedderApiForKeyboard(EngineModifier &modifier, std::shared_ptr< MockKeyResponseController > response_controller)
TEST(NativeAssetsManagerTest, NoAvailableAssets)
constexpr int64_t kImplicitViewId
#define MOCK_ENGINE_PROC(proc, mock_impl)
const char * aot_library_path
const char * icu_data_path
size_t child_count
The number of children this node has.
const char * label
A textual description of the node.
FlutterSemanticsFlags * flags2
FlutterSemanticsAction action
The semantics action.