Flutter Windows Embedder
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 
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 
13 namespace flutter {
14 
15 namespace {
16 
17 using ::testing::Return;
18 
19 // Stub implementation to validate calls to the API.
20 class 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.
57 class 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 
76 TEST(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 
89 TEST(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.
109 TEST(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 
131 TEST(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.
152  registrar.UnregisterTopLevelWindowProcDelegate(id_a);
153  EXPECT_EQ(test_api->registered_delegate_count(), 1);
154  // Unregistering both should unregister it.
155  registrar.UnregisterTopLevelWindowProcDelegate(id_b);
156  EXPECT_EQ(test_api->registered_delegate_count(), 0);
157 
158  EXPECT_NE(id_a, id_b);
159 }
160 
161 TEST(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 
198 TEST(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
flutter::PluginRegistrarWindows::UnregisterTopLevelWindowProcDelegate
void UnregisterTopLevelWindowProcDelegate(int proc_id)
Definition: plugin_registrar_windows.h:99
flutter::PluginRegistrarWindows::RegisterTopLevelWindowProcDelegate
int RegisterTopLevelWindowProcDelegate(WindowProcDelegate delegate)
Definition: plugin_registrar_windows.h:88
FlutterDesktopViewId
int64_t FlutterDesktopViewId
Definition: flutter_windows.h:36
user_data
void * user_data
Definition: flutter_windows_view_unittests.cc:53
flutter::PluginRegistrarWindows
Definition: plugin_registrar_windows.h:28
flutter::PluginRegistrarWindows::GetViewById
std::shared_ptr< FlutterView > GetViewById(FlutterViewId view_id) const
Definition: plugin_registrar_windows.h:65
flutter::TEST
TEST(FlutterEngineTest, CreateDestroy)
Definition: flutter_engine_unittests.cc:103
FlutterDesktopViewRef
struct FlutterDesktopView * FlutterDesktopViewRef
Definition: flutter_windows.h:29
flutter
Definition: accessibility_bridge_windows.cc:11
plugin_registrar_windows.h
flutter::PluginRegistrar::AddPlugin
void AddPlugin(std::unique_ptr< Plugin > plugin)
Definition: plugin_registrar.cc:38
flutter::WindowProcDelegate
std::function< std::optional< LRESULT >(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)> WindowProcDelegate
Definition: plugin_registrar_windows.h:24
message
Win32Message message
Definition: keyboard_unittests.cc:137
FlutterDesktopPluginRegistrar
Definition: window_state.h:23
flutter::PluginRegistrarWindows::GetView
FlutterView * GetView()
Definition: plugin_registrar_windows.h:59
FlutterDesktopWindowProcCallback
bool(* FlutterDesktopWindowProcCallback)(HWND, UINT, WPARAM, LPARAM, void *, LRESULT *result)
Definition: flutter_windows.h:245