blob: 604ffcb0679eba1197a515c01ade4af070ad6dff [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 "flutter/shell/platform/windows/platform_handler.h"
#include <memory>
#include "flutter/shell/platform/common/json_method_codec.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"
#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
#include "flutter/shell/platform/windows/testing/test_binary_messenger.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "rapidjson/document.h"
namespace flutter {
namespace testing {
namespace {
using ::testing::_;
using ::testing::NiceMock;
using ::testing::Return;
static constexpr char kChannelName[] = "flutter/platform";
static constexpr char kClipboardGetDataMessage[] =
"{\"method\":\"Clipboard.getData\",\"args\":\"text/plain\"}";
static constexpr char kClipboardGetDataFakeContentTypeMessage[] =
"{\"method\":\"Clipboard.getData\",\"args\":\"text/madeupcontenttype\"}";
static constexpr char kClipboardHasStringsMessage[] =
"{\"method\":\"Clipboard.hasStrings\",\"args\":\"text/plain\"}";
static constexpr char kClipboardHasStringsFakeContentTypeMessage[] =
"{\"method\":\"Clipboard.hasStrings\",\"args\":\"text/madeupcontenttype\"}";
static constexpr char kClipboardSetDataMessage[] =
"{\"method\":\"Clipboard.setData\",\"args\":{\"text\":\"hello\"}}";
static constexpr char kClipboardSetDataUnknownTypeMessage[] =
"{\"method\":\"Clipboard.setData\",\"args\":{\"madeuptype\":\"hello\"}}";
static constexpr char kSystemSoundTypeAlertMessage[] =
"{\"method\":\"SystemSound.play\",\"args\":\"SystemSoundType.alert\"}";
static constexpr int kAccessDeniedErrorCode = 5;
static constexpr int kErrorSuccess = 0;
static constexpr int kArbitraryErrorCode = 1;
// Test implementation of PlatformHandler to allow testing the PlatformHandler
// logic.
class MockPlatformHandler : public PlatformHandler {
public:
explicit MockPlatformHandler(
BinaryMessenger* messenger,
FlutterWindowsView* view,
std::optional<std::function<std::unique_ptr<ScopedClipboardInterface>()>>
scoped_clipboard_provider = std::nullopt)
: PlatformHandler(messenger, view, scoped_clipboard_provider) {}
virtual ~MockPlatformHandler() = default;
MOCK_METHOD2(GetPlainText,
void(std::unique_ptr<MethodResult<rapidjson::Document>>,
std::string_view key));
MOCK_METHOD1(GetHasStrings,
void(std::unique_ptr<MethodResult<rapidjson::Document>>));
MOCK_METHOD2(SetPlainText,
void(const std::string&,
std::unique_ptr<MethodResult<rapidjson::Document>>));
MOCK_METHOD2(SystemSoundPlay,
void(const std::string&,
std::unique_ptr<MethodResult<rapidjson::Document>>));
};
// A test version of the private ScopedClipboard.
class MockScopedClipboard : public ScopedClipboardInterface {
public:
MOCK_METHOD(int, Open, (HWND window), (override));
MOCK_METHOD(bool, HasString, (), (override));
MOCK_METHOD((std::variant<std::wstring, int>), GetString, (), (override));
MOCK_METHOD(int, SetString, (const std::wstring string), (override));
};
std::string SimulatePlatformMessage(TestBinaryMessenger* messenger,
std::string message) {
std::string result;
EXPECT_TRUE(messenger->SimulateEngineMessage(
kChannelName, reinterpret_cast<const uint8_t*>(message.c_str()),
message.size(),
[result = &result](const uint8_t* reply, size_t reply_size) {
std::string response(reinterpret_cast<const char*>(reply), reply_size);
*result = response;
}));
return result;
}
} // namespace
TEST(PlatformHandler, GetClipboardData) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kErrorSuccess));
EXPECT_CALL(*clipboard.get(), HasString).Times(1).WillOnce(Return(true));
EXPECT_CALL(*clipboard.get(), GetString)
.Times(1)
.WillOnce(Return(std::wstring(L"Hello world")));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardGetDataMessage);
EXPECT_EQ(result, "[{\"text\":\"Hello world\"}]");
}
TEST(PlatformHandler, GetClipboardDataRejectsUnknownContentType) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view);
// Requesting an unknown content type is an error.
std::string result = SimulatePlatformMessage(
&messenger, kClipboardGetDataFakeContentTypeMessage);
EXPECT_EQ(result, "[\"Clipboard error\",\"Unknown clipboard format\",null]");
}
TEST(PlatformHandler, GetClipboardDataReportsOpenFailure) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kArbitraryErrorCode));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardGetDataMessage);
EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to open clipboard\",1]");
}
TEST(PlatformHandler, GetClipboardDataReportsGetDataFailure) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kErrorSuccess));
EXPECT_CALL(*clipboard.get(), HasString).Times(1).WillOnce(Return(true));
EXPECT_CALL(*clipboard.get(), GetString)
.Times(1)
.WillOnce(Return(kArbitraryErrorCode));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardGetDataMessage);
EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to get clipboard data\",1]");
}
TEST(PlatformHandler, ClipboardHasStrings) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kErrorSuccess));
EXPECT_CALL(*clipboard.get(), HasString).Times(1).WillOnce(Return(true));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardHasStringsMessage);
EXPECT_EQ(result, "[{\"value\":true}]");
}
TEST(PlatformHandler, ClipboardHasStringsReturnsFalse) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kErrorSuccess));
EXPECT_CALL(*clipboard.get(), HasString).Times(1).WillOnce(Return(false));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardHasStringsMessage);
EXPECT_EQ(result, "[{\"value\":false}]");
}
TEST(PlatformHandler, ClipboardHasStringsRejectsUnknownContentType) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view);
std::string result = SimulatePlatformMessage(
&messenger, kClipboardHasStringsFakeContentTypeMessage);
EXPECT_EQ(result, "[\"Clipboard error\",\"Unknown clipboard format\",null]");
}
// Regression test for https://github.com/flutter/flutter/issues/95817.
TEST(PlatformHandler, ClipboardHasStringsIgnoresPermissionErrors) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kAccessDeniedErrorCode));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardHasStringsMessage);
EXPECT_EQ(result, "[{\"value\":false}]");
}
TEST(PlatformHandler, ClipboardHasStringsReportsErrors) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kArbitraryErrorCode));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardHasStringsMessage);
EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to open clipboard\",1]");
}
TEST(PlatformHandler, ClipboardSetData) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kErrorSuccess));
EXPECT_CALL(*clipboard.get(), SetString)
.Times(1)
.WillOnce([](std::wstring string) {
EXPECT_EQ(string, L"hello");
return kErrorSuccess;
});
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardSetDataMessage);
EXPECT_EQ(result, "[null]");
}
TEST(PlatformHandler, ClipboardSetDataUnknownType) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view);
std::string result =
SimulatePlatformMessage(&messenger, kClipboardSetDataUnknownTypeMessage);
EXPECT_EQ(result, "[\"Clipboard error\",\"Unknown clipboard format\",null]");
}
TEST(PlatformHandler, ClipboardSetDataReportsOpenFailure) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kArbitraryErrorCode));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardSetDataMessage);
EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to open clipboard\",1]");
}
TEST(PlatformHandler, ClipboardSetDataReportsSetDataFailure) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
PlatformHandler platform_handler(&messenger, &view, []() {
auto clipboard = std::make_unique<MockScopedClipboard>();
EXPECT_CALL(*clipboard.get(), Open)
.Times(1)
.WillOnce(Return(kErrorSuccess));
EXPECT_CALL(*clipboard.get(), SetString)
.Times(1)
.WillOnce(Return(kArbitraryErrorCode));
return clipboard;
});
std::string result =
SimulatePlatformMessage(&messenger, kClipboardSetDataMessage);
EXPECT_EQ(result, "[\"Clipboard error\",\"Unable to set clipboard data\",1]");
}
TEST(PlatformHandler, PlaySystemSound) {
TestBinaryMessenger messenger;
FlutterWindowsView view(
std::make_unique<NiceMock<MockWindowBindingHandler>>());
MockPlatformHandler platform_handler(&messenger, &view);
EXPECT_CALL(platform_handler, SystemSoundPlay("SystemSoundType.alert", _))
.WillOnce([](const std::string& sound,
std::unique_ptr<MethodResult<rapidjson::Document>> result) {
result->Success();
});
std::string result =
SimulatePlatformMessage(&messenger, kSystemSoundTypeAlertMessage);
EXPECT_EQ(result, "[null]");
}
} // namespace testing
} // namespace flutter