7 #include <UIAutomation.h>
15 #include "flutter/fml/synchronization/waitable_event.h"
17 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
21 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
22 #include "flutter/shell/platform/windows/testing/mock_angle_surface_manager.h"
23 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
24 #include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
25 #include "flutter/shell/platform/windows/testing/test_keyboard.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
34 using ::testing::InSequence;
35 using ::testing::NiceMock;
36 using ::testing::Return;
47 struct TestResponseHandle {
52 static bool test_response =
false;
54 constexpr uint64_t kKeyEventFromChannel = 0x11;
55 constexpr uint64_t kKeyEventFromEmbedder = 0x22;
56 static std::vector<int> key_event_logs;
58 std::unique_ptr<std::vector<uint8_t>> keyHandlingResponse(
bool handled) {
59 rapidjson::Document document;
60 auto& allocator = document.GetAllocator();
62 document.AddMember(
"handled", test_response, allocator);
68 FlutterProjectBundle GetTestProject() {
70 properties.
assets_path = L
"C:\\foo\\flutter_assets";
74 return FlutterProjectBundle{properties};
80 std::unique_ptr<FlutterWindowsEngine> GetTestEngine() {
81 auto engine = std::make_unique<FlutterWindowsEngine>(GetTestProject());
83 EngineModifier modifier(engine.get());
85 auto key_response_controller = std::make_shared<MockKeyResponseController>();
86 key_response_controller->SetChannelResponse(
87 [](MockKeyResponseController::ResponseCallback
callback) {
88 key_event_logs.push_back(kKeyEventFromChannel);
91 key_response_controller->SetEmbedderResponse(
92 [](
const FlutterKeyEvent* event,
93 MockKeyResponseController::ResponseCallback
callback) {
94 key_event_logs.push_back(kKeyEventFromEmbedder);
97 modifier.embedder_api().NotifyDisplayUpdate =
98 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
99 ([engine_instance = engine.get()](
100 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
101 const FlutterEngineDisplaysUpdateType update_type,
102 const FlutterEngineDisplay* embedder_displays,
103 size_t display_count) {
return kSuccess; }));
105 MockEmbedderApiForKeyboard(modifier, key_response_controller);
111 class MockFlutterWindowsEngine :
public FlutterWindowsEngine {
113 MockFlutterWindowsEngine() : FlutterWindowsEngine(GetTestProject()) {}
115 MOCK_METHOD(
bool, running, (), (
const));
116 MOCK_METHOD(
bool, Stop, (), ());
117 MOCK_METHOD(
bool, PostRasterThreadTask, (fml::closure), (
const));
120 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsEngine);
127 TEST(FlutterWindowsViewTest, SubMenuExpandedState) {
128 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
129 EngineModifier modifier(engine.get());
130 modifier.embedder_api().UpdateSemanticsEnabled =
135 auto window_binding_handler =
136 std::make_unique<NiceMock<MockWindowBindingHandler>>();
138 view.SetEngine(engine.get());
141 view.OnUpdateSemanticsEnabled(
true);
143 auto bridge = view.accessibility_bridge().lock();
146 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
151 root.increased_value =
"";
152 root.decreased_value =
"";
153 root.child_count = 0;
154 root.custom_accessibility_actions_count = 0;
155 root.flags =
static_cast<FlutterSemanticsFlag
>(
156 FlutterSemanticsFlag::kFlutterSemanticsFlagHasExpandedState |
157 FlutterSemanticsFlag::kFlutterSemanticsFlagIsExpanded);
158 bridge->AddFlutterSemanticsNodeUpdate(root);
160 bridge->CommitUpdates();
163 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
164 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kExpanded));
167 IAccessible* native_view = root_node->GetNativeViewAccessible();
168 ASSERT_TRUE(native_view !=
nullptr);
171 VARIANT varchild = {};
175 varchild.lVal = CHILDID_SELF;
176 VARIANT native_state = {};
177 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
178 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_EXPANDED);
181 IRawElementProviderSimple* uia_node;
182 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
183 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
184 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
185 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Expanded);
187 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
188 UIA_AriaPropertiesPropertyId, &native_state)));
189 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=true"),
nullptr);
193 root.flags =
static_cast<FlutterSemanticsFlag
>(
194 FlutterSemanticsFlag::kFlutterSemanticsFlagHasExpandedState);
195 bridge->AddFlutterSemanticsNodeUpdate(root);
196 bridge->CommitUpdates();
199 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
200 EXPECT_TRUE(root_node->GetData().HasState(ax::mojom::State::kCollapsed));
203 IAccessible* native_view = root_node->GetNativeViewAccessible();
204 ASSERT_TRUE(native_view !=
nullptr);
207 VARIANT varchild = {};
211 varchild.lVal = CHILDID_SELF;
212 VARIANT native_state = {};
213 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
214 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_COLLAPSED);
217 IRawElementProviderSimple* uia_node;
218 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
219 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
220 UIA_ExpandCollapseExpandCollapseStatePropertyId, &native_state)));
221 EXPECT_EQ(native_state.lVal, ExpandCollapseState_Collapsed);
223 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
224 UIA_AriaPropertiesPropertyId, &native_state)));
225 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"expanded=false"),
nullptr);
231 TEST(FlutterWindowsViewTest, Shutdown) {
232 std::unique_ptr<MockFlutterWindowsEngine> engine =
233 std::make_unique<MockFlutterWindowsEngine>();
234 auto window_binding_handler =
235 std::make_unique<NiceMock<MockWindowBindingHandler>>();
236 std::unique_ptr<MockAngleSurfaceManager> surface_manager =
237 std::make_unique<MockAngleSurfaceManager>();
239 EngineModifier modifier(engine.get());
244 EXPECT_CALL(*engine.get(), Stop).Times(1);
245 EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);
247 modifier.SetSurfaceManager(std::move(surface_manager));
251 TEST(FlutterWindowsViewTest, KeySequence) {
252 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
254 test_response =
false;
256 auto window_binding_handler =
257 std::make_unique<NiceMock<MockWindowBindingHandler>>();
259 view.SetEngine(engine.get());
262 [](
bool handled) {});
264 EXPECT_EQ(key_event_logs.size(), 2);
265 EXPECT_EQ(key_event_logs[0], kKeyEventFromEmbedder);
266 EXPECT_EQ(key_event_logs[1], kKeyEventFromChannel);
268 key_event_logs.clear();
271 TEST(FlutterWindowsViewTest, EnableSemantics) {
272 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
273 EngineModifier modifier(engine.get());
275 bool semantics_enabled =
false;
276 modifier.embedder_api().UpdateSemanticsEnabled = MOCK_ENGINE_PROC(
277 UpdateSemanticsEnabled,
278 [&semantics_enabled](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
280 semantics_enabled = enabled;
284 auto window_binding_handler =
285 std::make_unique<NiceMock<MockWindowBindingHandler>>();
287 view.SetEngine(engine.get());
289 view.OnUpdateSemanticsEnabled(
true);
290 EXPECT_TRUE(semantics_enabled);
293 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdate) {
294 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
295 EngineModifier modifier(engine.get());
296 modifier.embedder_api().UpdateSemanticsEnabled =
301 auto window_binding_handler =
302 std::make_unique<NiceMock<MockWindowBindingHandler>>();
304 view.SetEngine(engine.get());
307 view.OnUpdateSemanticsEnabled(
true);
309 auto bridge = view.accessibility_bridge().lock();
313 FlutterSemanticsNode2 node{
sizeof(FlutterSemanticsNode2), 0};
315 node.value =
"value";
316 node.platform_view_id = -1;
317 bridge->AddFlutterSemanticsNodeUpdate(node);
318 bridge->CommitUpdates();
321 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
326 IAccessible* native_view =
node_delegate->GetNativeViewAccessible();
327 ASSERT_TRUE(native_view !=
nullptr);
332 varchild.lVal = CHILDID_SELF;
335 BSTR bname =
nullptr;
336 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
337 std::string name(_com_util::ConvertBSTRToString(bname));
338 EXPECT_EQ(name,
"name");
341 BSTR bvalue =
nullptr;
342 ASSERT_EQ(native_view->get_accValue(varchild, &bvalue), S_OK);
343 std::string value(_com_util::ConvertBSTRToString(bvalue));
344 EXPECT_EQ(value,
"value");
349 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
350 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
353 IRawElementProviderSimple* uia_view;
354 native_view->QueryInterface(IID_PPV_ARGS(&uia_view));
355 ASSERT_TRUE(uia_view !=
nullptr);
359 ASSERT_EQ(uia_view->GetPropertyValue(UIA_NamePropertyId, &varname), S_OK);
360 EXPECT_EQ(varname.vt, VT_BSTR);
361 name = _com_util::ConvertBSTRToString(varname.bstrVal);
362 EXPECT_EQ(name,
"name");
366 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ValueValuePropertyId, &varvalue),
368 EXPECT_EQ(varvalue.vt, VT_BSTR);
369 value = _com_util::ConvertBSTRToString(varvalue.bstrVal);
370 EXPECT_EQ(value,
"value");
374 ASSERT_EQ(uia_view->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
376 EXPECT_EQ(varrole.vt, VT_I4);
377 EXPECT_EQ(varrole.lVal, UIA_TextControlTypeId);
392 TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdateWithChildren) {
393 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
394 EngineModifier modifier(engine.get());
395 modifier.embedder_api().UpdateSemanticsEnabled =
400 auto window_binding_handler =
401 std::make_unique<NiceMock<MockWindowBindingHandler>>();
403 view.SetEngine(engine.get());
406 view.OnUpdateSemanticsEnabled(
true);
408 auto bridge = view.accessibility_bridge().lock();
412 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
413 std::vector<int32_t> node0_children{1, 2};
414 node0.child_count = node0_children.size();
415 node0.children_in_traversal_order = node0_children.data();
416 node0.children_in_hit_test_order = node0_children.data();
418 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
419 node1.label =
"prefecture";
420 node1.value =
"Kyoto";
421 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
422 std::vector<int32_t> node2_children{3};
423 node2.child_count = node2_children.size();
424 node2.children_in_traversal_order = node2_children.data();
425 node2.children_in_hit_test_order = node2_children.data();
426 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
427 node3.label =
"city";
430 bridge->AddFlutterSemanticsNodeUpdate(node0);
431 bridge->AddFlutterSemanticsNodeUpdate(node1);
432 bridge->AddFlutterSemanticsNodeUpdate(node2);
433 bridge->AddFlutterSemanticsNodeUpdate(node3);
434 bridge->CommitUpdates();
437 auto node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
442 IAccessible* node0_accessible =
node_delegate->GetNativeViewAccessible();
443 ASSERT_TRUE(node0_accessible !=
nullptr);
448 varchild.lVal = CHILDID_SELF;
453 ASSERT_EQ(node0_accessible->get_accRole(varchild, &varrole), S_OK);
454 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
457 long node0_child_count = 0;
458 ASSERT_EQ(node0_accessible->get_accChildCount(&node0_child_count), S_OK);
459 EXPECT_EQ(node0_child_count, 2);
464 IDispatch* node1_dispatch =
nullptr;
465 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node1_dispatch), S_OK);
466 ASSERT_TRUE(node1_dispatch !=
nullptr);
467 IAccessible* node1_accessible =
nullptr;
468 ASSERT_EQ(node1_dispatch->QueryInterface(
469 IID_IAccessible,
reinterpret_cast<void**
>(&node1_accessible)),
471 ASSERT_TRUE(node1_accessible !=
nullptr);
474 varchild.lVal = CHILDID_SELF;
475 BSTR bname =
nullptr;
476 ASSERT_EQ(node1_accessible->get_accName(varchild, &bname), S_OK);
477 std::string name(_com_util::ConvertBSTRToString(bname));
478 EXPECT_EQ(name,
"prefecture");
481 BSTR bvalue =
nullptr;
482 ASSERT_EQ(node1_accessible->get_accValue(varchild, &bvalue), S_OK);
483 std::string value(_com_util::ConvertBSTRToString(bvalue));
484 EXPECT_EQ(value,
"Kyoto");
489 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
490 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
493 IDispatch* parent_dispatch;
494 node1_accessible->get_accParent(&parent_dispatch);
495 IAccessible* parent_accessible;
497 parent_dispatch->QueryInterface(
498 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
500 EXPECT_EQ(parent_accessible, node0_accessible);
505 IDispatch* node2_dispatch =
nullptr;
506 ASSERT_EQ(node0_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
507 ASSERT_TRUE(node2_dispatch !=
nullptr);
508 IAccessible* node2_accessible =
nullptr;
509 ASSERT_EQ(node2_dispatch->QueryInterface(
510 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
512 ASSERT_TRUE(node2_accessible !=
nullptr);
516 long node2_child_count = 0;
517 ASSERT_EQ(node2_accessible->get_accChildCount(&node2_child_count), S_OK);
518 EXPECT_EQ(node2_child_count, 1);
521 varchild.lVal = CHILDID_SELF;
524 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
525 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
528 IDispatch* parent_dispatch;
529 node2_accessible->get_accParent(&parent_dispatch);
530 IAccessible* parent_accessible;
532 parent_dispatch->QueryInterface(
533 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
535 EXPECT_EQ(parent_accessible, node0_accessible);
541 IDispatch* node3_dispatch =
nullptr;
542 ASSERT_EQ(node2_accessible->get_accChild(varchild, &node3_dispatch), S_OK);
543 ASSERT_TRUE(node3_dispatch !=
nullptr);
544 IAccessible* node3_accessible =
nullptr;
545 ASSERT_EQ(node3_dispatch->QueryInterface(
546 IID_IAccessible,
reinterpret_cast<void**
>(&node3_accessible)),
548 ASSERT_TRUE(node3_accessible !=
nullptr);
551 varchild.lVal = CHILDID_SELF;
552 BSTR bname =
nullptr;
553 ASSERT_EQ(node3_accessible->get_accName(varchild, &bname), S_OK);
554 std::string name(_com_util::ConvertBSTRToString(bname));
555 EXPECT_EQ(name,
"city");
558 BSTR bvalue =
nullptr;
559 ASSERT_EQ(node3_accessible->get_accValue(varchild, &bvalue), S_OK);
560 std::string value(_com_util::ConvertBSTRToString(bvalue));
561 EXPECT_EQ(value,
"Uji");
566 ASSERT_EQ(node3_accessible->get_accRole(varchild, &varrole), S_OK);
567 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
570 IDispatch* parent_dispatch;
571 node3_accessible->get_accParent(&parent_dispatch);
572 IAccessible* parent_accessible;
574 parent_dispatch->QueryInterface(
575 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
577 EXPECT_EQ(parent_accessible, node2_accessible);
590 TEST(FlutterWindowsViewTest, NonZeroSemanticsRoot) {
591 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
592 EngineModifier modifier(engine.get());
593 modifier.embedder_api().UpdateSemanticsEnabled =
598 auto window_binding_handler =
599 std::make_unique<NiceMock<MockWindowBindingHandler>>();
601 view.SetEngine(engine.get());
604 view.OnUpdateSemanticsEnabled(
true);
606 auto bridge = view.accessibility_bridge().lock();
610 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
611 std::vector<int32_t> node1_children{2};
612 node1.child_count = node1_children.size();
613 node1.children_in_traversal_order = node1_children.data();
614 node1.children_in_hit_test_order = node1_children.data();
616 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
617 node2.label =
"prefecture";
618 node2.value =
"Kyoto";
620 bridge->AddFlutterSemanticsNodeUpdate(node1);
621 bridge->AddFlutterSemanticsNodeUpdate(node2);
622 bridge->CommitUpdates();
625 auto root_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
626 ASSERT_TRUE(root_delegate);
627 EXPECT_EQ(root_delegate->GetChildCount(), 1);
630 auto child_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
631 ASSERT_TRUE(child_delegate);
632 EXPECT_EQ(child_delegate->GetChildCount(), 0);
635 auto fake_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
636 ASSERT_FALSE(fake_delegate);
639 IAccessible* node1_accessible = root_delegate->GetNativeViewAccessible();
640 ASSERT_TRUE(node1_accessible !=
nullptr);
645 varchild.lVal = CHILDID_SELF;
650 ASSERT_EQ(node1_accessible->get_accRole(varchild, &varrole), S_OK);
651 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_GROUPING);
654 long node1_child_count = 0;
655 ASSERT_EQ(node1_accessible->get_accChildCount(&node1_child_count), S_OK);
656 EXPECT_EQ(node1_child_count, 1);
661 IDispatch* node2_dispatch =
nullptr;
662 ASSERT_EQ(node1_accessible->get_accChild(varchild, &node2_dispatch), S_OK);
663 ASSERT_TRUE(node2_dispatch !=
nullptr);
664 IAccessible* node2_accessible =
nullptr;
665 ASSERT_EQ(node2_dispatch->QueryInterface(
666 IID_IAccessible,
reinterpret_cast<void**
>(&node2_accessible)),
668 ASSERT_TRUE(node2_accessible !=
nullptr);
671 varchild.lVal = CHILDID_SELF;
672 BSTR bname =
nullptr;
673 ASSERT_EQ(node2_accessible->get_accName(varchild, &bname), S_OK);
674 std::string name(_com_util::ConvertBSTRToString(bname));
675 EXPECT_EQ(name,
"prefecture");
678 BSTR bvalue =
nullptr;
679 ASSERT_EQ(node2_accessible->get_accValue(varchild, &bvalue), S_OK);
680 std::string value(_com_util::ConvertBSTRToString(bvalue));
681 EXPECT_EQ(value,
"Kyoto");
686 ASSERT_EQ(node2_accessible->get_accRole(varchild, &varrole), S_OK);
687 EXPECT_EQ(varrole.lVal, ROLE_SYSTEM_STATICTEXT);
690 IDispatch* parent_dispatch;
691 node2_accessible->get_accParent(&parent_dispatch);
692 IAccessible* parent_accessible;
694 parent_dispatch->QueryInterface(
695 IID_IAccessible,
reinterpret_cast<void**
>(&parent_accessible)),
697 EXPECT_EQ(parent_accessible, node1_accessible);
718 TEST(FlutterWindowsViewTest, AccessibilityHitTesting) {
719 constexpr FlutterTransformation kIdentityTransform = {1, 0, 0,
723 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
724 EngineModifier modifier(engine.get());
725 modifier.embedder_api().UpdateSemanticsEnabled =
730 auto window_binding_handler =
731 std::make_unique<NiceMock<MockWindowBindingHandler>>();
733 view.SetEngine(engine.get());
736 view.OnUpdateSemanticsEnabled(
true);
738 auto bridge = view.accessibility_bridge().lock();
742 FlutterSemanticsNode2 node0{
sizeof(FlutterSemanticsNode2), 0};
743 std::vector<int32_t> node0_children{1, 2};
744 node0.rect = {0, 0, 500, 500};
745 node0.transform = kIdentityTransform;
746 node0.child_count = node0_children.size();
747 node0.children_in_traversal_order = node0_children.data();
748 node0.children_in_hit_test_order = node0_children.data();
751 FlutterSemanticsNode2 node1{
sizeof(FlutterSemanticsNode2), 1};
752 node1.rect = {0, 0, 250, 500};
753 node1.transform = kIdentityTransform;
754 node1.label =
"prefecture";
755 node1.value =
"Kyoto";
758 FlutterSemanticsNode2 node2{
sizeof(FlutterSemanticsNode2), 2};
759 std::vector<int32_t> node2_children{3};
760 node2.rect = {0, 0, 250, 500};
761 node2.transform = {1, 0, 250, 0, 1, 0, 0, 0, 1};
762 node2.child_count = node2_children.size();
763 node2.children_in_traversal_order = node2_children.data();
764 node2.children_in_hit_test_order = node2_children.data();
767 FlutterSemanticsNode2 node3{
sizeof(FlutterSemanticsNode2), 3};
768 node3.rect = {0, 0, 250, 250};
769 node3.transform = {1, 0, 0, 0, 1, 250, 0, 0, 1};
770 node3.label =
"city";
773 bridge->AddFlutterSemanticsNodeUpdate(node0);
774 bridge->AddFlutterSemanticsNodeUpdate(node1);
775 bridge->AddFlutterSemanticsNodeUpdate(node2);
776 bridge->AddFlutterSemanticsNodeUpdate(node3);
777 bridge->CommitUpdates();
780 auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
781 ASSERT_TRUE(node0_delegate);
782 auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
783 ASSERT_TRUE(node1_delegate);
784 auto node2_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
785 ASSERT_TRUE(node2_delegate);
786 auto node3_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(3).lock();
787 ASSERT_TRUE(node3_delegate);
790 IAccessible* node0_accessible = node0_delegate->GetNativeViewAccessible();
791 ASSERT_TRUE(node0_accessible !=
nullptr);
795 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(150, 150, &varchild)));
796 EXPECT_EQ(varchild.vt, VT_DISPATCH);
797 EXPECT_EQ(varchild.pdispVal, node1_delegate->GetNativeViewAccessible());
801 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 150, &varchild)));
802 EXPECT_EQ(varchild.vt, VT_DISPATCH);
803 EXPECT_EQ(varchild.pdispVal, node2_delegate->GetNativeViewAccessible());
807 ASSERT_TRUE(SUCCEEDED(node0_accessible->accHitTest(450, 450, &varchild)));
808 EXPECT_EQ(varchild.vt, VT_DISPATCH);
809 EXPECT_EQ(varchild.pdispVal, node3_delegate->GetNativeViewAccessible());
812 TEST(FlutterWindowsViewTest, WindowResizeTests) {
813 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
814 EngineModifier modifier(engine.get());
816 auto window_binding_handler =
817 std::make_unique<NiceMock<MockWindowBindingHandler>>();
818 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
819 std::unique_ptr<MockAngleSurfaceManager> surface_manager =
820 std::make_unique<MockAngleSurfaceManager>();
822 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
823 .WillOnce(Return(
true));
825 *surface_manager.get(),
826 ResizeSurface(_, 500, 500,
false))
828 EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);
831 std::move(windows_proc_table));
832 modifier.SetSurfaceManager(std::move(surface_manager));
835 fml::AutoResetWaitableEvent metrics_sent_latch;
836 modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
837 SendWindowMetricsEvent,
838 ([&metrics_sent_latch](
auto engine,
839 const FlutterWindowMetricsEvent* event) {
840 metrics_sent_latch.Signal();
844 fml::AutoResetWaitableEvent resized_latch;
845 std::thread([&resized_latch, &view]() {
849 resized_latch.Signal();
853 metrics_sent_latch.Wait();
857 resized_latch.Wait();
860 TEST(FlutterWindowsViewTest, WindowRepaintTests) {
861 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
862 EngineModifier modifier(engine.get());
867 bool schedule_frame_called =
false;
868 modifier.embedder_api().ScheduleFrame =
869 MOCK_ENGINE_PROC(ScheduleFrame, ([&schedule_frame_called](
auto engine) {
870 schedule_frame_called =
true;
875 EXPECT_TRUE(schedule_frame_called);
884 TEST(FlutterWindowsViewTest, CheckboxNativeState) {
885 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
886 EngineModifier modifier(engine.get());
887 modifier.embedder_api().UpdateSemanticsEnabled =
892 auto window_binding_handler =
893 std::make_unique<NiceMock<MockWindowBindingHandler>>();
895 view.SetEngine(engine.get());
898 view.OnUpdateSemanticsEnabled(
true);
900 auto bridge = view.accessibility_bridge().lock();
903 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
908 root.increased_value =
"";
909 root.decreased_value =
"";
910 root.child_count = 0;
911 root.custom_accessibility_actions_count = 0;
912 root.flags =
static_cast<FlutterSemanticsFlag
>(
913 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
914 FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked);
915 bridge->AddFlutterSemanticsNodeUpdate(root);
917 bridge->CommitUpdates();
920 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
921 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
922 EXPECT_EQ(root_node->GetData().GetCheckedState(),
923 ax::mojom::CheckedState::kTrue);
926 IAccessible* native_view = root_node->GetNativeViewAccessible();
927 ASSERT_TRUE(native_view !=
nullptr);
930 VARIANT varchild = {};
934 varchild.lVal = CHILDID_SELF;
935 VARIANT native_state = {};
936 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
937 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
940 IRawElementProviderSimple* uia_node;
941 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
942 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
943 UIA_ToggleToggleStatePropertyId, &native_state)));
944 EXPECT_EQ(native_state.lVal, ToggleState_On);
946 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
947 UIA_AriaPropertiesPropertyId, &native_state)));
948 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=true"),
nullptr);
952 root.flags =
static_cast<FlutterSemanticsFlag
>(
953 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState);
954 bridge->AddFlutterSemanticsNodeUpdate(root);
955 bridge->CommitUpdates();
958 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
959 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
960 EXPECT_EQ(root_node->GetData().GetCheckedState(),
961 ax::mojom::CheckedState::kFalse);
964 IAccessible* native_view = root_node->GetNativeViewAccessible();
965 ASSERT_TRUE(native_view !=
nullptr);
968 VARIANT varchild = {};
972 varchild.lVal = CHILDID_SELF;
973 VARIANT native_state = {};
974 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
975 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
978 IRawElementProviderSimple* uia_node;
979 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
980 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
981 UIA_ToggleToggleStatePropertyId, &native_state)));
982 EXPECT_EQ(native_state.lVal, ToggleState_Off);
984 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
985 UIA_AriaPropertiesPropertyId, &native_state)));
986 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=false"),
nullptr);
990 root.flags =
static_cast<FlutterSemanticsFlag
>(
991 FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState |
992 FlutterSemanticsFlag::kFlutterSemanticsFlagIsCheckStateMixed);
993 bridge->AddFlutterSemanticsNodeUpdate(root);
994 bridge->CommitUpdates();
997 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
998 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox);
999 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1000 ax::mojom::CheckedState::kMixed);
1003 IAccessible* native_view = root_node->GetNativeViewAccessible();
1004 ASSERT_TRUE(native_view !=
nullptr);
1007 VARIANT varchild = {};
1008 varchild.vt = VT_I4;
1011 varchild.lVal = CHILDID_SELF;
1012 VARIANT native_state = {};
1013 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1014 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_MIXED);
1017 IRawElementProviderSimple* uia_node;
1018 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1019 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1020 UIA_ToggleToggleStatePropertyId, &native_state)));
1021 EXPECT_EQ(native_state.lVal, ToggleState_Indeterminate);
1023 ASSERT_TRUE(SUCCEEDED(uia_node->GetPropertyValue(
1024 UIA_AriaPropertiesPropertyId, &native_state)));
1025 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"checked=mixed"),
nullptr);
1030 TEST(FlutterWindowsViewTest, SwitchNativeState) {
1031 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1032 EngineModifier modifier(engine.get());
1033 modifier.embedder_api().UpdateSemanticsEnabled =
1034 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1038 auto window_binding_handler =
1039 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1041 view.SetEngine(engine.get());
1044 view.OnUpdateSemanticsEnabled(
true);
1046 auto bridge = view.accessibility_bridge().lock();
1047 ASSERT_TRUE(bridge);
1049 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1051 root.label =
"root";
1054 root.increased_value =
"";
1055 root.decreased_value =
"";
1056 root.child_count = 0;
1057 root.custom_accessibility_actions_count = 0;
1058 root.flags =
static_cast<FlutterSemanticsFlag
>(
1059 FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState |
1060 FlutterSemanticsFlag::kFlutterSemanticsFlagIsToggled);
1061 bridge->AddFlutterSemanticsNodeUpdate(root);
1063 bridge->CommitUpdates();
1066 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1067 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1068 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1069 ax::mojom::CheckedState::kTrue);
1072 IAccessible* native_view = root_node->GetNativeViewAccessible();
1073 ASSERT_TRUE(native_view !=
nullptr);
1076 VARIANT varchild = {};
1077 varchild.vt = VT_I4;
1079 varchild.lVal = CHILDID_SELF;
1080 VARIANT varrole = {};
1083 ASSERT_EQ(native_view->get_accRole(varchild, &varrole), S_OK);
1084 ASSERT_EQ(varrole.lVal, ROLE_SYSTEM_CHECKBUTTON);
1087 VARIANT native_state = {};
1088 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1089 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_PRESSED);
1090 EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED);
1093 IRawElementProviderSimple* uia_node;
1094 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1095 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ControlTypePropertyId, &varrole),
1097 EXPECT_EQ(varrole.lVal, UIA_ButtonControlTypeId);
1098 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1101 EXPECT_EQ(native_state.lVal, ToggleState_On);
1103 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1105 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=true"),
nullptr);
1109 root.flags =
static_cast<FlutterSemanticsFlag
>(
1110 FlutterSemanticsFlag::kFlutterSemanticsFlagHasToggledState);
1111 bridge->AddFlutterSemanticsNodeUpdate(root);
1112 bridge->CommitUpdates();
1115 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1116 EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSwitch);
1117 EXPECT_EQ(root_node->GetData().GetCheckedState(),
1118 ax::mojom::CheckedState::kFalse);
1121 IAccessible* native_view = root_node->GetNativeViewAccessible();
1122 ASSERT_TRUE(native_view !=
nullptr);
1125 VARIANT varchild = {};
1126 varchild.vt = VT_I4;
1129 varchild.lVal = CHILDID_SELF;
1130 VARIANT native_state = {};
1131 ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state)));
1132 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_PRESSED);
1133 EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED);
1136 IRawElementProviderSimple* uia_node;
1137 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1138 ASSERT_EQ(uia_node->GetPropertyValue(UIA_ToggleToggleStatePropertyId,
1141 EXPECT_EQ(native_state.lVal, ToggleState_Off);
1143 uia_node->GetPropertyValue(UIA_AriaPropertiesPropertyId, &native_state),
1145 EXPECT_NE(std::wcsstr(native_state.bstrVal, L
"pressed=false"),
nullptr);
1149 TEST(FlutterWindowsViewTest, TooltipNodeData) {
1150 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
1151 EngineModifier modifier(engine.get());
1152 modifier.embedder_api().UpdateSemanticsEnabled =
1153 [](FLUTTER_API_SYMBOL(
FlutterEngine) engine,
bool enabled) {
1157 auto window_binding_handler =
1158 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1160 view.SetEngine(engine.get());
1163 view.OnUpdateSemanticsEnabled(
true);
1165 auto bridge = view.accessibility_bridge().lock();
1166 ASSERT_TRUE(bridge);
1168 FlutterSemanticsNode2 root{
sizeof(FlutterSemanticsNode2), 0};
1170 root.label =
"root";
1173 root.increased_value =
"";
1174 root.decreased_value =
"";
1175 root.tooltip =
"tooltip";
1176 root.child_count = 0;
1177 root.custom_accessibility_actions_count = 0;
1178 root.flags =
static_cast<FlutterSemanticsFlag
>(
1179 FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField);
1180 bridge->AddFlutterSemanticsNodeUpdate(root);
1182 bridge->CommitUpdates();
1183 auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
1184 std::string tooltip = root_node->GetData().GetStringAttribute(
1185 ax::mojom::StringAttribute::kTooltip);
1186 EXPECT_EQ(tooltip,
"tooltip");
1189 IAccessible* native_view = bridge->GetFlutterPlatformNodeDelegateFromID(0)
1191 ->GetNativeViewAccessible();
1192 VARIANT varchild = {.vt = VT_I4, .lVal = CHILDID_SELF};
1194 ASSERT_EQ(native_view->get_accName(varchild, &bname), S_OK);
1195 EXPECT_NE(std::wcsstr(bname, L
"tooltip"),
nullptr);
1198 IRawElementProviderSimple* uia_node;
1199 native_view->QueryInterface(IID_PPV_ARGS(&uia_node));
1201 ASSERT_EQ(uia_node->GetPropertyValue(UIA_HelpTextPropertyId, &varname), S_OK);
1202 std::string uia_tooltip = _com_util::ConvertBSTRToString(varname.bstrVal);
1203 EXPECT_EQ(uia_tooltip,
"tooltip");
1208 TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) {
1209 std::unique_ptr<MockFlutterWindowsEngine> engine =
1210 std::make_unique<MockFlutterWindowsEngine>();
1211 auto window_binding_handler =
1212 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1213 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1214 std::unique_ptr<MockAngleSurfaceManager> surface_manager =
1215 std::make_unique<MockAngleSurfaceManager>();
1217 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1218 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1220 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1221 .WillOnce(Return(
true));
1223 EngineModifier modifier(engine.get());
1225 std::move(windows_proc_table));
1228 EXPECT_CALL(*surface_manager.get(), CreateSurface(_, _, _))
1230 .WillOnce(Return(
true));
1231 EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(
false)).Times(1);
1232 EXPECT_CALL(*surface_manager.get(), ClearCurrent).WillOnce(Return(
true));
1234 EXPECT_CALL(*engine.get(), Stop).Times(1);
1235 EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);
1237 modifier.SetSurfaceManager(std::move(surface_manager));
1245 TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) {
1246 std::unique_ptr<MockFlutterWindowsEngine> engine =
1247 std::make_unique<MockFlutterWindowsEngine>();
1248 auto window_binding_handler =
1249 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1250 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1251 std::unique_ptr<MockAngleSurfaceManager> surface_manager =
1252 std::make_unique<MockAngleSurfaceManager>();
1254 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
false));
1255 EXPECT_CALL(*engine.get(), PostRasterThreadTask).Times(0);
1256 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1257 .WillOnce(Return(
false));
1259 EngineModifier modifier(engine.get());
1261 std::move(windows_proc_table));
1264 EXPECT_CALL(*surface_manager.get(), CreateSurface(_, _, _))
1266 .WillOnce(Return(
true));
1267 EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(
true)).Times(1);
1268 EXPECT_CALL(*surface_manager.get(), ClearCurrent).WillOnce(Return(
true));
1270 EXPECT_CALL(*engine.get(), Stop).Times(1);
1271 EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);
1273 modifier.SetSurfaceManager(std::move(surface_manager));
1281 TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) {
1282 std::unique_ptr<MockFlutterWindowsEngine> engine =
1283 std::make_unique<MockFlutterWindowsEngine>();
1284 auto window_binding_handler =
1285 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1286 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1287 std::unique_ptr<MockAngleSurfaceManager> surface_manager =
1288 std::make_unique<MockAngleSurfaceManager>();
1290 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1291 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1292 .WillOnce(Return(
true));
1294 EngineModifier modifier(engine.get());
1296 std::move(windows_proc_table));
1299 EXPECT_CALL(*surface_manager.get(), CreateSurface(_, _, _))
1301 .WillOnce(Return(
true));
1302 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1303 .WillOnce([](fml::closure
callback) {
1307 EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(
false)).Times(1);
1308 EXPECT_CALL(*surface_manager.get(), ClearCurrent).Times(0);
1310 EXPECT_CALL(*engine.get(), Stop).Times(1);
1311 EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);
1313 modifier.SetSurfaceManager(std::move(surface_manager));
1321 TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) {
1322 std::unique_ptr<MockFlutterWindowsEngine> engine =
1323 std::make_unique<MockFlutterWindowsEngine>();
1324 auto window_binding_handler =
1325 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1326 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1327 std::unique_ptr<MockAngleSurfaceManager> surface_manager =
1328 std::make_unique<MockAngleSurfaceManager>();
1330 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1332 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1333 .WillOnce(Return(
false));
1335 EngineModifier modifier(engine.get());
1337 std::move(windows_proc_table));
1340 EXPECT_CALL(*surface_manager.get(), CreateSurface(_, _, _))
1342 .WillOnce(Return(
true));
1343 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1344 .WillOnce([](fml::closure
callback) {
1348 EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(
true)).Times(1);
1349 EXPECT_CALL(*surface_manager.get(), ClearCurrent).Times(0);
1351 EXPECT_CALL(*engine.get(), Stop).Times(1);
1352 EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);
1354 modifier.SetSurfaceManager(std::move(surface_manager));
1363 TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) {
1364 std::unique_ptr<MockFlutterWindowsEngine> engine =
1365 std::make_unique<MockFlutterWindowsEngine>();
1366 auto window_binding_handler =
1367 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1368 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
1369 std::unique_ptr<MockAngleSurfaceManager> surface_manager =
1370 std::make_unique<MockAngleSurfaceManager>();
1372 EXPECT_CALL(*engine.get(), running).WillRepeatedly(Return(
true));
1374 EXPECT_CALL(*engine.get(), PostRasterThreadTask)
1375 .WillRepeatedly([](fml::closure
callback) {
1380 EXPECT_CALL(*windows_proc_table.get(), DwmIsCompositionEnabled)
1381 .WillOnce(Return(
false))
1382 .WillOnce(Return(
true));
1384 EXPECT_CALL(*surface_manager.get(), ClearCurrent).Times(0);
1386 EngineModifier modifier(engine.get());
1388 std::move(windows_proc_table));
1391 EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(
true)).Times(1);
1392 EXPECT_CALL(*surface_manager.get(), SetVSyncEnabled(
false)).Times(1);
1394 EXPECT_CALL(*engine.get(), Stop).Times(1);
1395 EXPECT_CALL(*surface_manager.get(), DestroySurface).Times(1);
1397 modifier.SetSurfaceManager(std::move(surface_manager));