blob: 0c9bdb961890757591de37057cc36ae92c1f42f6 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include "flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h"
#include "flutter/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h"
#include "gtest/gtest.h"
namespace flutter {
namespace {
// Stub implementation to validate calls to the API.
class TestWindowsApi : public testing::StubFlutterWindowsApi {
public:
void PluginRegistrarRegisterTopLevelWindowProcDelegate(
FlutterDesktopWindowProcCallback delegate,
void* user_data) override {
++registered_delegate_count_;
last_registered_delegate_ = delegate;
last_registered_user_data_ = user_data;
}
void PluginRegistrarUnregisterTopLevelWindowProcDelegate(
FlutterDesktopWindowProcCallback delegate) override {
--registered_delegate_count_;
}
int registered_delegate_count() { return registered_delegate_count_; }
FlutterDesktopWindowProcCallback last_registered_delegate() {
return last_registered_delegate_;
}
void* last_registered_user_data() { return last_registered_user_data_; }
private:
int registered_delegate_count_ = 0;
FlutterDesktopWindowProcCallback last_registered_delegate_ = nullptr;
void* last_registered_user_data_ = nullptr;
};
// A test plugin that tries to access registrar state during destruction and
// reports it out via a flag provided at construction.
class TestPlugin : public Plugin {
public:
// registrar_valid_at_destruction will be set at destruction to indicate
// whether or not |registrar->GetView()| was non-null.
TestPlugin(PluginRegistrarWindows* registrar,
bool* registrar_valid_at_destruction)
: registrar_(registrar),
registrar_valid_at_destruction_(registrar_valid_at_destruction) {}
virtual ~TestPlugin() {
*registrar_valid_at_destruction_ = registrar_->GetView() != nullptr;
}
private:
PluginRegistrarWindows* registrar_;
bool* registrar_valid_at_destruction_;
};
} // namespace
TEST(PluginRegistrarWindowsTest, GetView) {
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
std::make_unique<TestWindowsApi>());
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
PluginRegistrarWindows registrar(
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
EXPECT_NE(registrar.GetView(), nullptr);
}
// Tests that the registrar runs plugin destructors before its own teardown.
TEST(PluginRegistrarWindowsTest, PluginDestroyedBeforeRegistrar) {
auto dummy_registrar_handle =
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1);
bool registrar_valid_at_destruction = false;
{
PluginRegistrarWindows registrar(dummy_registrar_handle);
auto plugin = std::make_unique<TestPlugin>(&registrar,
&registrar_valid_at_destruction);
registrar.AddPlugin(std::move(plugin));
}
EXPECT_TRUE(registrar_valid_at_destruction);
}
TEST(PluginRegistrarWindowsTest, RegisterUnregister) {
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
std::make_unique<TestWindowsApi>());
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
PluginRegistrarWindows registrar(
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
WindowProcDelegate delegate = [](HWND hwnd, UINT message, WPARAM wparam,
LPARAM lparam) {
return std::optional<LRESULT>();
};
int id_a = registrar.RegisterTopLevelWindowProcDelegate(delegate);
EXPECT_EQ(test_api->registered_delegate_count(), 1);
int id_b = registrar.RegisterTopLevelWindowProcDelegate(delegate);
// All the C++-level delegates are driven by a since C callback, so the
// registration count should stay the same.
EXPECT_EQ(test_api->registered_delegate_count(), 1);
// Unregistering one of the two delegates shouldn't cause the underlying C
// callback to be unregistered.
registrar.UnregisterTopLevelWindowProcDelegate(id_a);
EXPECT_EQ(test_api->registered_delegate_count(), 1);
// Unregistering both should unregister it.
registrar.UnregisterTopLevelWindowProcDelegate(id_b);
EXPECT_EQ(test_api->registered_delegate_count(), 0);
EXPECT_NE(id_a, id_b);
}
TEST(PluginRegistrarWindowsTest, CallsRegisteredDelegates) {
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
std::make_unique<TestWindowsApi>());
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
PluginRegistrarWindows registrar(
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
HWND dummy_hwnd;
bool called_a = false;
WindowProcDelegate delegate_a = [&called_a, &dummy_hwnd](
HWND hwnd, UINT message, WPARAM wparam,
LPARAM lparam) {
called_a = true;
EXPECT_EQ(hwnd, dummy_hwnd);
EXPECT_EQ(message, 2);
EXPECT_EQ(wparam, 3);
EXPECT_EQ(lparam, 4);
return std::optional<LRESULT>();
};
bool called_b = false;
WindowProcDelegate delegate_b = [&called_b](HWND hwnd, UINT message,
WPARAM wparam, LPARAM lparam) {
called_b = true;
return std::optional<LRESULT>();
};
int id_a = registrar.RegisterTopLevelWindowProcDelegate(delegate_a);
int id_b = registrar.RegisterTopLevelWindowProcDelegate(delegate_b);
LRESULT result = 0;
bool handled = test_api->last_registered_delegate()(
dummy_hwnd, 2, 3, 4, test_api->last_registered_user_data(), &result);
EXPECT_TRUE(called_a);
EXPECT_TRUE(called_b);
EXPECT_FALSE(handled);
}
TEST(PluginRegistrarWindowsTest, StopsOnceHandled) {
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
std::make_unique<TestWindowsApi>());
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
PluginRegistrarWindows registrar(
reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1));
bool called_a = false;
WindowProcDelegate delegate_a = [&called_a](HWND hwnd, UINT message,
WPARAM wparam, LPARAM lparam) {
called_a = true;
return std::optional<LRESULT>(7);
};
bool called_b = false;
WindowProcDelegate delegate_b = [&called_b](HWND hwnd, UINT message,
WPARAM wparam, LPARAM lparam) {
called_b = true;
return std::optional<LRESULT>(7);
};
int id_a = registrar.RegisterTopLevelWindowProcDelegate(delegate_a);
int id_b = registrar.RegisterTopLevelWindowProcDelegate(delegate_b);
HWND dummy_hwnd;
LRESULT result = 0;
bool handled = test_api->last_registered_delegate()(
dummy_hwnd, 2, 3, 4, test_api->last_registered_user_data(), &result);
// Only one of the delegates should have been called, since each claims to
// have fully handled the message.
EXPECT_TRUE(called_a || called_b);
EXPECT_NE(called_a, called_b);
// The return value should propagate through.
EXPECT_TRUE(handled);
EXPECT_EQ(result, 7);
}
} // namespace flutter