| Flutter Windows Embedder |

flutter_windows_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/windows/public/flutter_windows.h"
6
7 #include <dxgi.h>
8 #include <wrl/client.h>
9 #include <thread>
10
11 #include "flutter/fml/synchronization/count_down_latch.h"
12 #include "flutter/fml/synchronization/waitable_event.h"
13 #include "flutter/shell/platform/windows/testing/windows_test.h"
14 #include "flutter/shell/platform/windows/testing/windows_test_config_builder.h"
15 #include "flutter/shell/platform/windows/testing/windows_test_context.h"
16 #include "gtest/gtest.h"
17 #include "third_party/tonic/converter/dart_converter.h"
18
19 namespace flutter {
20 namespace testing {
21
22 // Verify that we can fetch a texture registrar.
23 // Prevent regression: https://github.com/flutter/flutter/issues/86617
24 TEST(WindowsNoFixtureTest, GetTextureRegistrar) {
25 FlutterDesktopEngineProperties properties = {};
26 properties.assets_path = L"";
27 properties.icu_data_path = L"icudtl.dat";
28 auto engine = FlutterDesktopEngineCreate(&properties);
29 ASSERT_NE(engine, nullptr);
30 auto texture_registrar = FlutterDesktopEngineGetTextureRegistrar(engine);
31 EXPECT_NE(texture_registrar, nullptr);
32 FlutterDesktopEngineDestroy(engine);
33 }
34
35 // Verify we can successfully launch main().
36 TEST_F(WindowsTest, LaunchMain) {
37 auto& context = GetContext();
38 WindowsConfigBuilder builder(context);
39 ViewControllerPtr controller{builder.Run()};
40 ASSERT_NE(controller, nullptr);
41 }
42
43 // Verify there is no unexpected output from launching main.
44 TEST_F(WindowsTest, LaunchMainHasNoOutput) {
45 // Replace stdout & stderr stream buffers with our own.
46 std::stringstream cout_buffer;
47 std::stringstream cerr_buffer;
48 std::streambuf* old_cout_buffer = std::cout.rdbuf();
49 std::streambuf* old_cerr_buffer = std::cerr.rdbuf();
50 std::cout.rdbuf(cout_buffer.rdbuf());
51 std::cerr.rdbuf(cerr_buffer.rdbuf());
52
53 auto& context = GetContext();
54 WindowsConfigBuilder builder(context);
55 ViewControllerPtr controller{builder.Run()};
56 ASSERT_NE(controller, nullptr);
57
58 // Restore original stdout & stderr stream buffer.
59 std::cout.rdbuf(old_cout_buffer);
60 std::cerr.rdbuf(old_cerr_buffer);
61
62 // Verify stdout & stderr have no output.
63 std::string cout = cout_buffer.str();
64 std::string cerr = cerr_buffer.str();
65 EXPECT_TRUE(cout.empty());
66 EXPECT_TRUE(cerr.empty());
67 }
68
69 // Verify we can successfully launch a custom entry point.
70 TEST_F(WindowsTest, LaunchCustomEntrypoint) {
71 auto& context = GetContext();
72 WindowsConfigBuilder builder(context);
73 builder.SetDartEntrypoint("customEntrypoint");
74 ViewControllerPtr controller{builder.Run()};
75 ASSERT_NE(controller, nullptr);
76 }
77
78 // Verify that engine launches with the custom entrypoint specified in the
79 // FlutterDesktopEngineRun parameter when no entrypoint is specified in
80 // FlutterDesktopEngineProperties.dart_entrypoint.
81 //
82 // TODO(cbracken): https://github.com/flutter/flutter/issues/109285
83 TEST_F(WindowsTest, LaunchCustomEntrypointInEngineRunInvocation) {
84 auto& context = GetContext();
85 WindowsConfigBuilder builder(context);
86 EnginePtr engine{builder.InitializeEngine()};
87 ASSERT_NE(engine, nullptr);
88
89 ASSERT_TRUE(FlutterDesktopEngineRun(engine.get(), "customEntrypoint"));
90 }
91
92 // Verify that the engine can launch in headless mode.
93 TEST_F(WindowsTest, LaunchHeadlessEngine) {
94 auto& context = GetContext();
95 WindowsConfigBuilder builder(context);
96 EnginePtr engine{builder.InitializeEngine()};
97 ASSERT_NE(engine, nullptr);
98
99 ASSERT_TRUE(FlutterDesktopEngineRun(engine.get(), nullptr));
100 }
101
102 // Verify that engine fails to launch when a conflicting entrypoint in
103 // FlutterDesktopEngineProperties.dart_entrypoint and the
104 // FlutterDesktopEngineRun parameter.
105 //
106 // TODO(cbracken): https://github.com/flutter/flutter/issues/109285
107 TEST_F(WindowsTest, LaunchConflictingCustomEntrypoints) {
108 auto& context = GetContext();
109 WindowsConfigBuilder builder(context);
110 builder.SetDartEntrypoint("customEntrypoint");
111 EnginePtr engine{builder.InitializeEngine()};
112 ASSERT_NE(engine, nullptr);
113
114 ASSERT_FALSE(FlutterDesktopEngineRun(engine.get(), "conflictingEntrypoint"));
115 }
116
117 // Verify that native functions can be registered and resolved.
118 TEST_F(WindowsTest, VerifyNativeFunction) {
119 auto& context = GetContext();
120 WindowsConfigBuilder builder(context);
121 builder.SetDartEntrypoint("verifyNativeFunction");
122
123 fml::AutoResetWaitableEvent latch;
124 auto native_entry =
125 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); });
126 context.AddNativeFunction("Signal", native_entry);
127
128 ViewControllerPtr controller{builder.Run()};
129 ASSERT_NE(controller, nullptr);
130
131 // Wait until signal has been called.
132 latch.Wait();
133 }
134
135 // Verify that native functions that pass parameters can be registered and
136 // resolved.
137 TEST_F(WindowsTest, VerifyNativeFunctionWithParameters) {
138 auto& context = GetContext();
139 WindowsConfigBuilder builder(context);
140 builder.SetDartEntrypoint("verifyNativeFunctionWithParameters");
141
142 bool bool_value = false;
143 fml::AutoResetWaitableEvent latch;
144 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
145 auto handle = Dart_GetNativeBooleanArgument(args, 0, &bool_value);
146 ASSERT_FALSE(Dart_IsError(handle));
147 latch.Signal();
148 });
149 context.AddNativeFunction("SignalBoolValue", native_entry);
150
151 ViewControllerPtr controller{builder.Run()};
152 ASSERT_NE(controller, nullptr);
153
154 // Wait until signalBoolValue has been called.
155 latch.Wait();
156 EXPECT_TRUE(bool_value);
157 }
158
159 // Verify that Platform.executable returns the executable name.
160 TEST_F(WindowsTest, PlatformExecutable) {
161 auto& context = GetContext();
162 WindowsConfigBuilder builder(context);
163 builder.SetDartEntrypoint("readPlatformExecutable");
164
165 std::string executable_name;
166 fml::AutoResetWaitableEvent latch;
167 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
168 auto handle = Dart_GetNativeArgument(args, 0);
169 ASSERT_FALSE(Dart_IsError(handle));
170 executable_name = tonic::DartConverter<std::string>::FromDart(handle);
171 latch.Signal();
172 });
173 context.AddNativeFunction("SignalStringValue", native_entry);
174
175 ViewControllerPtr controller{builder.Run()};
176 ASSERT_NE(controller, nullptr);
177
178 // Wait until signalStringValue has been called.
179 latch.Wait();
180 EXPECT_EQ(executable_name, "flutter_windows_unittests.exe");
181 }
182
183 // Verify that native functions that return values can be registered and
184 // resolved.
185 TEST_F(WindowsTest, VerifyNativeFunctionWithReturn) {
186 auto& context = GetContext();
187 WindowsConfigBuilder builder(context);
188 builder.SetDartEntrypoint("verifyNativeFunctionWithReturn");
189
190 bool bool_value_to_return = true;
191 fml::CountDownLatch latch(2);
192 auto bool_return_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
193 Dart_SetBooleanReturnValue(args, bool_value_to_return);
194 latch.CountDown();
195 });
196 context.AddNativeFunction("SignalBoolReturn", bool_return_entry);
197
198 bool bool_value_passed = false;
199 auto bool_pass_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
200 auto handle = Dart_GetNativeBooleanArgument(args, 0, &bool_value_passed);
201 ASSERT_FALSE(Dart_IsError(handle));
202 latch.CountDown();
203 });
204 context.AddNativeFunction("SignalBoolValue", bool_pass_entry);
205
206 ViewControllerPtr controller{builder.Run()};
207 ASSERT_NE(controller, nullptr);
208
209 // Wait until signalBoolReturn and signalBoolValue have been called.
210 latch.Wait();
211 EXPECT_TRUE(bool_value_passed);
212 }
213
214 // Verify the next frame callback is executed.
215 TEST_F(WindowsTest, NextFrameCallback) {
216 struct Captures {
217 fml::AutoResetWaitableEvent frame_scheduled_latch;
218 fml::AutoResetWaitableEvent frame_drawn_latch;
219 std::thread::id thread_id;
220 };
221 Captures captures;
222
223 CreateNewThread("test_platform_thread")->PostTask([&]() {
224 captures.thread_id = std::this_thread::get_id();
225
226 auto& context = GetContext();
227 WindowsConfigBuilder builder(context);
228 builder.SetDartEntrypoint("drawHelloWorld");
229
230 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
231 ASSERT_FALSE(captures.frame_drawn_latch.IsSignaledForTest());
232 captures.frame_scheduled_latch.Signal();
233 });
234 context.AddNativeFunction("NotifyFirstFrameScheduled", native_entry);
235
236 ViewControllerPtr controller{builder.Run()};
237 ASSERT_NE(controller, nullptr);
238
239 auto engine = FlutterDesktopViewControllerGetEngine(controller.get());
240
241 FlutterDesktopEngineSetNextFrameCallback(
242 engine,
243 [](void* user_data) {
244 auto captures = static_cast<Captures*>(user_data);
245
246 ASSERT_TRUE(captures->frame_scheduled_latch.IsSignaledForTest());
247
248 // Callback should execute on platform thread.
249 ASSERT_EQ(std::this_thread::get_id(), captures->thread_id);
250
251 // Signal the test passed and end the Windows message loop.
252 captures->frame_drawn_latch.Signal();
253 ::PostQuitMessage(0);
254 },
255 &captures);
256
257 // Pump messages for the Windows platform task runner.
258 ::MSG msg;
259 while (::GetMessage(&msg, nullptr, 0, 0)) {
260 ::TranslateMessage(&msg);
261 ::DispatchMessage(&msg);
262 }
263 });
264
265 captures.frame_drawn_latch.Wait();
266 }
267
268 TEST_F(WindowsTest, GetGraphicsAdapter) {
269 auto& context = GetContext();
270 WindowsConfigBuilder builder(context);
271 ViewControllerPtr controller{builder.Run()};
272 ASSERT_NE(controller, nullptr);
273 auto view = FlutterDesktopViewControllerGetView(controller.get());
274
275 Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
276 dxgi_adapter = FlutterDesktopViewGetGraphicsAdapter(view);
277 ASSERT_NE(dxgi_adapter, nullptr);
278 DXGI_ADAPTER_DESC desc{};
279 ASSERT_TRUE(SUCCEEDED(dxgi_adapter->GetDesc(&desc)));
280 }
281
282 } // namespace testing
283 } // namespace flutter
FlutterDesktopViewControllerGetView
FlutterDesktopViewRef FlutterDesktopViewControllerGetView(FlutterDesktopViewControllerRef controller)
Definition: flutter_windows.cc:100
FlutterDesktopEngineGetTextureRegistrar
FlutterDesktopTextureRegistrarRef FlutterDesktopEngineGetTextureRegistrar(FlutterDesktopEngineRef engine)
Definition: flutter_windows.cc:177
FlutterDesktopEngineProperties
Definition: flutter_windows.h:36
FlutterDesktopViewControllerGetEngine
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(FlutterDesktopViewControllerRef controller)
Definition: flutter_windows.cc:95
user_data
void * user_data
Definition: flutter_windows_view_unittests.cc:47
FlutterDesktopEngineProperties::icu_data_path
const wchar_t * icu_data_path
Definition: flutter_windows.h:45
flutter::testing::TEST_F
TEST_F(CursorHandlerTest, ActivateSystemCursor)
Definition: cursor_handler_unittests.cc:95
flutter
Definition: accessibility_bridge_windows.cc:11
FlutterDesktopEngineDestroy
bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine_ref)
Definition: flutter_windows.cc:134
FlutterDesktopEngineCreate
FlutterDesktopEngineRef FlutterDesktopEngineCreate(const FlutterDesktopEngineProperties *engine_properties)
Definition: flutter_windows.cc:127
flutter_windows.h
flutter::testing::TEST
TEST(AccessibilityBridgeWindows, GetParent)
Definition: accessibility_bridge_windows_unittests.cc:233
FlutterDesktopEngineSetNextFrameCallback
void FlutterDesktopEngineSetNextFrameCallback(FlutterDesktopEngineRef engine, VoidCallback callback, void *user_data)
Definition: flutter_windows.cc:183
FlutterDesktopViewGetGraphicsAdapter
IDXGIAdapter * FlutterDesktopViewGetGraphicsAdapter(FlutterDesktopViewRef view)
Definition: flutter_windows.cc:194
FlutterDesktopEngineProperties::assets_path
const wchar_t * assets_path
Definition: flutter_windows.h:40
FlutterDesktopEngineRun
bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, const char *entry_point)
Definition: flutter_windows.cc:144