Flutter Engine
The Flutter Engine
plugin_registrar_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 <memory>
6#include <string>
7
8#include "flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h"
9#include "flutter/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h"
10#include "gmock/gmock.h"
11#include "gtest/gtest.h"
12
13namespace flutter {
14
15namespace {
16
17using ::testing::Return;
18
19// Stub implementation to validate calls to the API.
20class TestWindowsApi : public testing::StubFlutterWindowsApi {
21 public:
22 void PluginRegistrarRegisterTopLevelWindowProcDelegate(
24 void* user_data) override {
25 ++registered_delegate_count_;
26 last_registered_delegate_ = delegate;
27 last_registered_user_data_ = user_data;
28 }
29
30 MOCK_METHOD(FlutterDesktopViewRef, PluginRegistrarGetView, (), (override));
31 MOCK_METHOD(FlutterDesktopViewRef,
32 PluginRegistrarGetViewById,
34 (override));
35
36 void PluginRegistrarUnregisterTopLevelWindowProcDelegate(
37 FlutterDesktopWindowProcCallback delegate) override {
38 --registered_delegate_count_;
39 }
40
41 int registered_delegate_count() { return registered_delegate_count_; }
42
43 FlutterDesktopWindowProcCallback last_registered_delegate() {
44 return last_registered_delegate_;
45 }
46
47 void* last_registered_user_data() { return last_registered_user_data_; }
48
49 private:
50 int registered_delegate_count_ = 0;
51 FlutterDesktopWindowProcCallback last_registered_delegate_ = nullptr;
52 void* last_registered_user_data_ = nullptr;
53};
54
55// A test plugin that tries to access registrar state during destruction and
56// reports it out via a flag provided at construction.
57class TestPlugin : public Plugin {
58 public:
59 // registrar_valid_at_destruction will be set at destruction to indicate
60 // whether or not |registrar->GetView()| was non-null.
61 TestPlugin(PluginRegistrarWindows* registrar,
62 bool* registrar_valid_at_destruction)
63 : registrar_(registrar),
64 registrar_valid_at_destruction_(registrar_valid_at_destruction) {}
65 virtual ~TestPlugin() {
66 *registrar_valid_at_destruction_ = registrar_->GetView() != nullptr;
67 }
68
69 private:
70 PluginRegistrarWindows* registrar_;
71 bool* registrar_valid_at_destruction_;
72};
73
74} // namespace
75
76TEST(PluginRegistrarWindowsTest, GetView) {
77 auto windows_api = std::make_unique<TestWindowsApi>();
78 EXPECT_CALL(*windows_api, PluginRegistrarGetView)
79 .WillOnce(Return(reinterpret_cast<FlutterDesktopViewRef>(1)));
80
81 testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
82 auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
83 PluginRegistrarWindows registrar(
84 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
85
86 EXPECT_NE(registrar.GetView(), nullptr);
87}
88
89TEST(PluginRegistrarWindowsTest, GetViewById) {
90 auto windows_api = std::make_unique<TestWindowsApi>();
91 EXPECT_CALL(*windows_api, PluginRegistrarGetView)
92 .WillRepeatedly(Return(nullptr));
93 EXPECT_CALL(*windows_api, PluginRegistrarGetViewById(123))
94 .WillOnce(Return(reinterpret_cast<FlutterDesktopViewRef>(1)));
95 EXPECT_CALL(*windows_api, PluginRegistrarGetViewById(456))
96 .WillOnce(Return(nullptr));
97
98 testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
99 auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
100 PluginRegistrarWindows registrar(
101 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
102
103 EXPECT_EQ(registrar.GetView(), nullptr);
104 EXPECT_NE(registrar.GetViewById(123).get(), nullptr);
105 EXPECT_EQ(registrar.GetViewById(456).get(), nullptr);
106}
107
108// Tests that the registrar runs plugin destructors before its own teardown.
109TEST(PluginRegistrarWindowsTest, PluginDestroyedBeforeRegistrar) {
110 auto windows_api = std::make_unique<TestWindowsApi>();
111 EXPECT_CALL(*windows_api, PluginRegistrarGetView)
112 .WillRepeatedly(Return(reinterpret_cast<FlutterDesktopViewRef>(1)));
113 testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
114 auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
115 PluginRegistrarWindows registrar(
116 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
117
118 auto dummy_registrar_handle =
119 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1);
120 bool registrar_valid_at_destruction = false;
121 {
122 PluginRegistrarWindows registrar(dummy_registrar_handle);
123
124 auto plugin = std::make_unique<TestPlugin>(&registrar,
125 &registrar_valid_at_destruction);
126 registrar.AddPlugin(std::move(plugin));
127 }
128 EXPECT_TRUE(registrar_valid_at_destruction);
129}
130
131TEST(PluginRegistrarWindowsTest, RegisterUnregister) {
132 auto windows_api = std::make_unique<TestWindowsApi>();
133 EXPECT_CALL(*windows_api, PluginRegistrarGetView).WillOnce(Return(nullptr));
134 testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
135 auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
136 PluginRegistrarWindows registrar(
137 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
138
139 WindowProcDelegate delegate = [](HWND hwnd, UINT message, WPARAM wparam,
140 LPARAM lparam) {
141 return std::optional<LRESULT>();
142 };
143 int id_a = registrar.RegisterTopLevelWindowProcDelegate(delegate);
144 EXPECT_EQ(test_api->registered_delegate_count(), 1);
145 int id_b = registrar.RegisterTopLevelWindowProcDelegate(delegate);
146 // All the C++-level delegates are driven by a since C callback, so the
147 // registration count should stay the same.
148 EXPECT_EQ(test_api->registered_delegate_count(), 1);
149
150 // Unregistering one of the two delegates shouldn't cause the underlying C
151 // callback to be unregistered.
153 EXPECT_EQ(test_api->registered_delegate_count(), 1);
154 // Unregistering both should unregister it.
156 EXPECT_EQ(test_api->registered_delegate_count(), 0);
157
158 EXPECT_NE(id_a, id_b);
159}
160
161TEST(PluginRegistrarWindowsTest, CallsRegisteredDelegates) {
162 auto windows_api = std::make_unique<TestWindowsApi>();
163 EXPECT_CALL(*windows_api, PluginRegistrarGetView).WillOnce(Return(nullptr));
164 testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
165 auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
166 PluginRegistrarWindows registrar(
167 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
168
169 HWND dummy_hwnd;
170 bool called_a = false;
171 WindowProcDelegate delegate_a = [&called_a, &dummy_hwnd](
172 HWND hwnd, UINT message, WPARAM wparam,
173 LPARAM lparam) {
174 called_a = true;
175 EXPECT_EQ(hwnd, dummy_hwnd);
176 EXPECT_EQ(message, 2);
177 EXPECT_EQ(wparam, 3);
178 EXPECT_EQ(lparam, 4);
179 return std::optional<LRESULT>();
180 };
181 bool called_b = false;
182 WindowProcDelegate delegate_b = [&called_b](HWND hwnd, UINT message,
183 WPARAM wparam, LPARAM lparam) {
184 called_b = true;
185 return std::optional<LRESULT>();
186 };
187 int id_a = registrar.RegisterTopLevelWindowProcDelegate(delegate_a);
188 int id_b = registrar.RegisterTopLevelWindowProcDelegate(delegate_b);
189
190 LRESULT result = 0;
191 bool handled = test_api->last_registered_delegate()(
192 dummy_hwnd, 2, 3, 4, test_api->last_registered_user_data(), &result);
193 EXPECT_TRUE(called_a);
194 EXPECT_TRUE(called_b);
195 EXPECT_FALSE(handled);
196}
197
198TEST(PluginRegistrarWindowsTest, StopsOnceHandled) {
199 auto windows_api = std::make_unique<TestWindowsApi>();
200 EXPECT_CALL(*windows_api, PluginRegistrarGetView).WillOnce(Return(nullptr));
201 testing::ScopedStubFlutterWindowsApi scoped_api_stub(std::move(windows_api));
202 auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
203 PluginRegistrarWindows registrar(
204 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
205
206 bool called_a = false;
207 WindowProcDelegate delegate_a = [&called_a](HWND hwnd, UINT message,
208 WPARAM wparam, LPARAM lparam) {
209 called_a = true;
210 return std::optional<LRESULT>(7);
211 };
212 bool called_b = false;
213 WindowProcDelegate delegate_b = [&called_b](HWND hwnd, UINT message,
214 WPARAM wparam, LPARAM lparam) {
215 called_b = true;
216 return std::optional<LRESULT>(7);
217 };
218 int id_a = registrar.RegisterTopLevelWindowProcDelegate(delegate_a);
219 int id_b = registrar.RegisterTopLevelWindowProcDelegate(delegate_b);
220
221 HWND dummy_hwnd;
222 LRESULT result = 0;
223 bool handled = test_api->last_registered_delegate()(
224 dummy_hwnd, 2, 3, 4, test_api->last_registered_user_data(), &result);
225 // Only one of the delegates should have been called, since each claims to
226 // have fully handled the message.
227 EXPECT_TRUE(called_a || called_b);
228 EXPECT_NE(called_a, called_b);
229 // The return value should propagate through.
230 EXPECT_TRUE(handled);
231 EXPECT_EQ(result, 7);
232}
233
234} // namespace flutter
int RegisterTopLevelWindowProcDelegate(WindowProcDelegate delegate)
std::shared_ptr< FlutterView > GetViewById(FlutterViewId view_id) const
void UnregisterTopLevelWindowProcDelegate(int proc_id)
void AddPlugin(std::unique_ptr< Plugin > plugin)
GAsyncResult * result
bool(* FlutterDesktopWindowProcCallback)(HWND, UINT, WPARAM, LPARAM, void *, LRESULT *result)
int64_t FlutterDesktopViewId
struct FlutterDesktopView * FlutterDesktopViewRef
Win32Message message
TEST(FrameTimingsRecorderTest, RecordVsync)
std::function< std::optional< LRESULT >(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)> WindowProcDelegate
void * user_data
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678
LONG_PTR LRESULT
Definition: windows_types.h:61
unsigned int UINT
Definition: windows_types.h:32
LONG_PTR LPARAM
Definition: windows_types.h:60
UINT_PTR WPARAM
Definition: windows_types.h:59