8 #include <wrl/client.h>
11 #include "flutter/fml/synchronization/count_down_latch.h"
12 #include "flutter/fml/synchronization/waitable_event.h"
14 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
16 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
17 #include "flutter/shell/platform/windows/testing/windows_test.h"
18 #include "flutter/shell/platform/windows/testing/windows_test_config_builder.h"
19 #include "flutter/shell/platform/windows/testing/windows_test_context.h"
21 #include "flutter/testing/stream_capture.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "third_party/tonic/converter/dart_converter.h"
32 class HalfBrokenEGLManager :
public egl::Manager {
36 std::unique_ptr<egl::WindowSurface>
37 CreateWindowSurface(HWND hwnd,
size_t width,
size_t height)
override {
42 class MockWindowsLifecycleManager :
public WindowsLifecycleManager {
54 if (::GetMessage(&msg,
nullptr, 0, 0)) {
55 ::TranslateMessage(&msg);
56 ::DispatchMessage(&msg);
64 TEST(WindowsNoFixtureTest, GetTextureRegistrar) {
69 ASSERT_NE(engine,
nullptr);
71 EXPECT_NE(texture_registrar,
nullptr);
77 auto& context = GetContext();
78 WindowsConfigBuilder builder(context);
79 ViewControllerPtr controller{builder.Run()};
80 ASSERT_NE(controller,
nullptr);
84 TEST_F(WindowsTest, LaunchMainHasNoOutput) {
87 StreamCapture stderr_capture(&std::cerr);
89 auto& context = GetContext();
90 WindowsConfigBuilder builder(context);
91 ViewControllerPtr controller{builder.Run()};
92 ASSERT_NE(controller,
nullptr);
94 stderr_capture.Stop();
97 EXPECT_TRUE(stderr_capture.GetOutput().empty());
101 TEST_F(WindowsTest, LaunchCustomEntrypoint) {
102 auto& context = GetContext();
103 WindowsConfigBuilder builder(context);
104 builder.SetDartEntrypoint(
"customEntrypoint");
105 ViewControllerPtr controller{builder.Run()};
106 ASSERT_NE(controller,
nullptr);
114 TEST_F(WindowsTest, LaunchCustomEntrypointInEngineRunInvocation) {
115 auto& context = GetContext();
116 WindowsConfigBuilder builder(context);
117 EnginePtr engine{builder.InitializeEngine()};
118 ASSERT_NE(engine,
nullptr);
124 TEST_F(WindowsTest, LaunchHeadlessEngine) {
125 auto& context = GetContext();
126 WindowsConfigBuilder builder(context);
127 builder.SetDartEntrypoint(
"signalViewIds");
128 EnginePtr engine{builder.RunHeadless()};
129 ASSERT_NE(engine,
nullptr);
131 std::string view_ids;
132 bool signaled =
false;
133 context.AddNativeFunction(
134 "SignalStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
135 auto handle = Dart_GetNativeArgument(args, 0);
136 ASSERT_FALSE(Dart_IsError(handle));
137 view_ids = tonic::DartConverter<std::string>::FromDart(handle);
141 ViewControllerPtr controller{builder.Run()};
142 ASSERT_NE(controller,
nullptr);
149 EXPECT_EQ(view_ids,
"View IDs: [0]");
153 TEST_F(WindowsTest, EngineCanTransitionToHeadless) {
154 auto& context = GetContext();
155 WindowsConfigBuilder builder(context);
156 EnginePtr engine{builder.RunHeadless()};
157 ASSERT_NE(engine,
nullptr);
163 ViewControllerPtr controller{
166 ASSERT_NE(controller,
nullptr);
170 ASSERT_NE(engine,
nullptr);
173 ASSERT_TRUE(engine_ptr->running());
177 TEST_F(WindowsTest, LaunchRefreshesAccessibility) {
178 auto& context = GetContext();
179 WindowsConfigBuilder builder(context);
180 EnginePtr engine{builder.InitializeEngine()};
181 EngineModifier modifier{
186 UpdateAccessibilityFeatures, ([&called](
auto engine,
auto flags) {
191 ViewControllerPtr controller{
202 TEST_F(WindowsTest, LaunchConflictingCustomEntrypoints) {
203 auto& context = GetContext();
204 WindowsConfigBuilder builder(context);
205 builder.SetDartEntrypoint(
"customEntrypoint");
206 EnginePtr engine{builder.InitializeEngine()};
207 ASSERT_NE(engine,
nullptr);
213 TEST_F(WindowsTest, VerifyNativeFunction) {
214 auto& context = GetContext();
215 WindowsConfigBuilder builder(context);
216 builder.SetDartEntrypoint(
"verifyNativeFunction");
218 bool signaled =
false;
220 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { signaled =
true; });
221 context.AddNativeFunction(
"Signal", native_entry);
223 ViewControllerPtr controller{builder.Run()};
224 ASSERT_NE(controller,
nullptr);
234 TEST_F(WindowsTest, VerifyNativeFunctionWithParameters) {
235 auto& context = GetContext();
236 WindowsConfigBuilder builder(context);
237 builder.SetDartEntrypoint(
"verifyNativeFunctionWithParameters");
239 bool bool_value =
false;
240 bool signaled =
false;
241 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
242 auto handle = Dart_GetNativeBooleanArgument(args, 0, &bool_value);
243 ASSERT_FALSE(Dart_IsError(handle));
246 context.AddNativeFunction(
"SignalBoolValue", native_entry);
248 ViewControllerPtr controller{builder.Run()};
249 ASSERT_NE(controller,
nullptr);
255 EXPECT_TRUE(bool_value);
259 TEST_F(WindowsTest, PlatformExecutable) {
260 auto& context = GetContext();
261 WindowsConfigBuilder builder(context);
262 builder.SetDartEntrypoint(
"readPlatformExecutable");
264 std::string executable_name;
265 bool signaled =
false;
266 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
267 auto handle = Dart_GetNativeArgument(args, 0);
268 ASSERT_FALSE(Dart_IsError(handle));
269 executable_name = tonic::DartConverter<std::string>::FromDart(handle);
272 context.AddNativeFunction(
"SignalStringValue", native_entry);
274 ViewControllerPtr controller{builder.Run()};
275 ASSERT_NE(controller,
nullptr);
281 EXPECT_EQ(executable_name,
"flutter_windows_unittests.exe");
286 TEST_F(WindowsTest, VerifyNativeFunctionWithReturn) {
287 auto& context = GetContext();
288 WindowsConfigBuilder builder(context);
289 builder.SetDartEntrypoint(
"verifyNativeFunctionWithReturn");
291 bool bool_value_to_return =
true;
293 auto bool_return_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
294 Dart_SetBooleanReturnValue(args, bool_value_to_return);
297 context.AddNativeFunction(
"SignalBoolReturn", bool_return_entry);
299 bool bool_value_passed =
false;
300 auto bool_pass_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
301 auto handle = Dart_GetNativeBooleanArgument(args, 0, &bool_value_passed);
302 ASSERT_FALSE(Dart_IsError(handle));
305 context.AddNativeFunction(
"SignalBoolValue", bool_pass_entry);
307 ViewControllerPtr controller{builder.Run()};
308 ASSERT_NE(controller,
nullptr);
314 EXPECT_TRUE(bool_value_passed);
320 fml::AutoResetWaitableEvent frame_scheduled_latch;
321 fml::AutoResetWaitableEvent frame_drawn_latch;
322 std::thread::id thread_id;
327 CreateNewThread(
"test_platform_thread")->PostTask([&]() {
328 captures.thread_id = std::this_thread::get_id();
330 auto& context = GetContext();
331 WindowsConfigBuilder builder(context);
332 builder.SetDartEntrypoint(
"drawHelloWorld");
334 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
335 ASSERT_FALSE(captures.frame_drawn_latch.IsSignaledForTest());
336 captures.frame_scheduled_latch.Signal();
338 context.AddNativeFunction(
"NotifyFirstFrameScheduled", native_entry);
340 ViewControllerPtr controller{builder.Run()};
341 ASSERT_NE(controller,
nullptr);
348 auto captures =
static_cast<Captures*
>(
user_data);
350 ASSERT_TRUE(captures->frame_scheduled_latch.IsSignaledForTest());
353 ASSERT_EQ(std::this_thread::get_id(), captures->thread_id);
356 captures->done =
true;
357 captures->frame_drawn_latch.Signal();
362 while (!captures.done) {
367 captures.frame_drawn_latch.Wait();
373 auto& context = GetContext();
374 WindowsConfigBuilder builder(context);
375 builder.SetDartEntrypoint(
"renderImplicitView");
377 EnginePtr engine{builder.RunHeadless()};
378 ASSERT_NE(engine,
nullptr);
385 auto done = reinterpret_cast<std::atomic<bool>*>(user_data);
394 FlutterWindowMetricsEvent metrics = {};
395 metrics.struct_size =
sizeof(FlutterWindowMetricsEvent);
397 metrics.height = 100;
398 metrics.pixel_ratio = 1.0;
400 engine_ptr->SendWindowMetricsEvent(metrics);
410 auto& context = GetContext();
411 WindowsConfigBuilder builder(context);
412 ViewControllerPtr controller{builder.Run()};
413 ASSERT_NE(controller,
nullptr);
420 TEST_F(WindowsTest, GetGraphicsAdapter) {
421 auto& context = GetContext();
422 WindowsConfigBuilder builder(context);
423 ViewControllerPtr controller{builder.Run()};
424 ASSERT_NE(controller,
nullptr);
427 Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
429 ASSERT_NE(dxgi_adapter,
nullptr);
430 DXGI_ADAPTER_DESC desc{};
431 ASSERT_TRUE(SUCCEEDED(dxgi_adapter->GetDesc(&desc)));
434 TEST_F(WindowsTest, GetGraphicsAdapterWithLowPowerPreference) {
437 GTEST_SKIP() <<
"Not able to find low power GPU, nothing to check.";
440 auto& context = GetContext();
441 WindowsConfigBuilder builder(context);
443 ViewControllerPtr controller{builder.Run()};
444 ASSERT_NE(controller,
nullptr);
447 Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
449 ASSERT_NE(dxgi_adapter,
nullptr);
450 DXGI_ADAPTER_DESC desc{};
451 ASSERT_TRUE(SUCCEEDED(dxgi_adapter->GetDesc(&desc)));
452 ASSERT_EQ(desc.AdapterLuid.HighPart, luid->HighPart);
453 ASSERT_EQ(desc.AdapterLuid.LowPart, luid->LowPart);
457 TEST_F(WindowsTest, PluginRegistrarGetImplicitView) {
458 auto& context = GetContext();
459 WindowsConfigBuilder builder(context);
460 ViewControllerPtr controller{builder.Run()};
461 ASSERT_NE(controller,
nullptr);
470 ASSERT_NE(implicit_view,
nullptr);
473 TEST_F(WindowsTest, PluginRegistrarGetView) {
474 auto& context = GetContext();
475 WindowsConfigBuilder builder(context);
476 ViewControllerPtr controller{builder.Run()};
477 ASSERT_NE(controller,
nullptr);
492 ASSERT_NE(view,
nullptr);
493 ASSERT_EQ(view_123,
nullptr);
496 TEST_F(WindowsTest, PluginRegistrarGetViewHeadless) {
497 auto& context = GetContext();
498 WindowsConfigBuilder builder(context);
499 EnginePtr engine{builder.RunHeadless()};
500 ASSERT_NE(engine,
nullptr);
510 ASSERT_EQ(implicit_view,
nullptr);
511 ASSERT_EQ(view_123,
nullptr);
517 auto& context = GetContext();
518 WindowsConfigBuilder builder(context);
519 EnginePtr engine{builder.InitializeEngine()};
520 EngineModifier modifier{
523 auto egl_manager = std::make_unique<HalfBrokenEGLManager>();
524 ASSERT_TRUE(egl_manager->IsValid());
525 modifier.SetEGLManager(std::move(egl_manager));
527 ViewControllerPtr controller{
530 ASSERT_NE(controller,
nullptr);
535 auto& context = GetContext();
536 WindowsConfigBuilder builder(context);
537 EnginePtr engine{builder.InitializeEngine()};
539 EngineModifier modifier{windows_engine};
541 auto lifecycle_manager =
542 std::make_unique<MockWindowsLifecycleManager>(windows_engine);
543 auto lifecycle_manager_ptr = lifecycle_manager.get();
544 modifier.SetLifecycleManager(std::move(lifecycle_manager));
546 EXPECT_CALL(*lifecycle_manager_ptr,
549 lifecycle_manager_ptr->WindowsLifecycleManager::SetLifecycleState(
553 EXPECT_CALL(*lifecycle_manager_ptr,
556 lifecycle_manager_ptr->WindowsLifecycleManager::SetLifecycleState(
564 ViewControllerPtr controller{
569 ASSERT_NE(view,
nullptr);
572 ASSERT_NE(hwnd,
nullptr);
577 ::MoveWindow(hwnd, 0, 0, 100, 100,
580 while (lifecycle_manager_ptr->IsUpdateStateScheduled()) {
587 while (lifecycle_manager_ptr->IsUpdateStateScheduled()) {
592 TEST_F(WindowsTest, GetKeyboardStateHeadless) {
593 auto& context = GetContext();
594 WindowsConfigBuilder builder(context);
595 builder.SetDartEntrypoint(
"sendGetKeyboardState");
597 std::atomic<bool> done =
false;
598 context.AddNativeFunction(
599 "SignalStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
600 auto handle = Dart_GetNativeArgument(args, 0);
601 ASSERT_FALSE(Dart_IsError(handle));
602 auto value = tonic::DartConverter<std::string>::FromDart(handle);
603 EXPECT_EQ(value,
"Success");
607 ViewControllerPtr controller{builder.Run()};
608 ASSERT_NE(controller,
nullptr);
620 std::string view_ids;
622 auto& context = GetContext();
623 WindowsConfigBuilder builder(context);
624 builder.SetDartEntrypoint(
"onMetricsChangedSignalViewIds");
627 context.AddNativeFunction(
629 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { ready =
true; }));
631 context.AddNativeFunction(
632 "SignalStringValue", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
633 auto handle = Dart_GetNativeArgument(args, 0);
634 ASSERT_FALSE(Dart_IsError(handle));
636 std::scoped_lock lock{mutex};
637 view_ids = tonic::DartConverter<std::string>::FromDart(handle);
641 ViewControllerPtr first_controller{builder.Run()};
642 ASSERT_NE(first_controller,
nullptr);
652 properties.
width = 100;
654 ViewControllerPtr second_controller{
656 ASSERT_NE(second_controller,
nullptr);
661 std::scoped_lock lock{mutex};
662 if (view_ids ==
"View IDs: [0, 1]") {
669 second_controller.reset();
672 std::scoped_lock lock{mutex};
673 if (view_ids ==
"View IDs: [0]") {
680 auto& context = GetContext();
681 WindowsConfigBuilder builder(context);
682 builder.SetDartEntrypoint(
"testEngineId");
684 std::optional<int64_t> engineId;
685 context.AddNativeFunction(
686 "NotifyEngineId", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
687 const auto argument = Dart_GetNativeArgument(args, 0);
688 if (!Dart_IsNull(argument)) {
689 const auto handle = tonic::DartConverter<int64_t>::FromDart(argument);
694 ViewControllerPtr first_controller{builder.Run()};
695 ASSERT_NE(first_controller,
nullptr);
697 while (!engineId.has_value()) {
void UpdateAccessibilityFeatures()
WindowsLifecycleManager(FlutterWindowsEngine *engine)
virtual void SetLifecycleState(AppLifecycleState state)
static std::optional< LUID > GetLowPowerGpuLuid()
MOCK_METHOD(void, Quit,(std::optional< HWND >, std::optional< WPARAM >, std::optional< LPARAM >, UINT),(override))
MockWindowsLifecycleManager(FlutterWindowsEngine *engine)
FlutterDesktopEngineRef FlutterDesktopEngineCreate(const FlutterDesktopEngineProperties *engine_properties)
FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopEngineForId(int64_t engine_id)
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetViewById(FlutterDesktopPluginRegistrarRef registrar, FlutterDesktopViewId view_id)
FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(FlutterDesktopEngineRef engine, const char *plugin_name)
FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate(int width, int height, FlutterDesktopEngineRef engine)
bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine_ref)
FlutterDesktopTextureRegistrarRef FlutterDesktopEngineGetTextureRegistrar(FlutterDesktopEngineRef engine)
IDXGIAdapter * FlutterDesktopViewGetGraphicsAdapter(FlutterDesktopViewRef view)
FlutterDesktopViewId FlutterDesktopViewControllerGetViewId(FlutterDesktopViewControllerRef ref)
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(FlutterDesktopViewControllerRef ref)
void FlutterDesktopEngineSetNextFrameCallback(FlutterDesktopEngineRef engine, VoidCallback callback, void *user_data)
HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view)
FlutterDesktopViewRef FlutterDesktopViewControllerGetView(FlutterDesktopViewControllerRef ref)
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(FlutterDesktopPluginRegistrarRef registrar)
FlutterDesktopViewControllerRef FlutterDesktopEngineCreateViewController(FlutterDesktopEngineRef engine, const FlutterDesktopViewControllerProperties *properties)
bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, const char *entry_point)
struct FlutterDesktopEngine * FlutterDesktopEngineRef
int64_t FlutterDesktopViewId
struct FlutterDesktopView * FlutterDesktopViewRef
TEST(AccessibilityBridgeWindows, GetParent)
TEST_F(CompositorOpenGLTest, CreateBackingStore)
constexpr FlutterViewId kImplicitViewId
const wchar_t * icu_data_path
const wchar_t * assets_path