|
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/platform_handler_win32.h" |
6 | | - |
7 | | -#include <memory> |
8 | | - |
9 | | -#include "flutter/shell/platform/common/json_method_codec.h" |
10 | | -#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" |
11 | | -#include "flutter/shell/platform/windows/testing/test_binary_messenger.h" |
12 | | -#include "gmock/gmock.h" |
13 | | -#include "gtest/gtest.h" |
14 | | -#include "rapidjson/document.h" |
15 | | - |
16 | | -namespace flutter { |
17 | | -namespace testing { |
18 | | - |
19 | | -namespace { |
20 | | -using ::testing::_; |
21 | | - |
22 | | -static constexpr char kChannelName[] = "flutter/platform"; |
23 | | - |
24 | | -static constexpr char kHasStringsClipboardMethod[] = "Clipboard.hasStrings"; |
25 | | - |
26 | | -static constexpr char kTextPlainFormat[] = "text/plain"; |
27 | | - |
28 | | -static constexpr char kValueKey[] = "value"; |
29 | | -static constexpr int kAccessDeniedErrorCode = 5; |
30 | | - |
31 | | -} // namespace |
32 | | - |
33 | | -// A test version of the private ScopedClipboard. |
34 | | -class TestScopedClipboard : public ScopedClipboardInterface { |
35 | | - public: |
36 | | - TestScopedClipboard(); |
37 | | - ~TestScopedClipboard(); |
38 | | - |
39 | | - // Prevent copying. |
40 | | - TestScopedClipboard(TestScopedClipboard const&) = delete; |
41 | | - TestScopedClipboard& operator=(TestScopedClipboard const&) = delete; |
42 | | - |
43 | | - int Open(HWND window); |
44 | | - |
45 | | - bool HasString(); |
46 | | - |
47 | | - std::variant<std::wstring, int> GetString(); |
48 | | - |
49 | | - int SetString(const std::wstring string); |
50 | | - |
51 | | - private: |
52 | | - bool opened_ = false; |
53 | | -}; |
54 | | - |
55 | | -TestScopedClipboard::TestScopedClipboard() {} |
56 | | - |
57 | | -TestScopedClipboard::~TestScopedClipboard() { |
58 | | - if (opened_) { |
59 | | - ::CloseClipboard(); |
60 | | - } |
61 | | -} |
62 | | - |
63 | | -// Always fail to open with kAccessDeniedErrorCode. |
64 | | -int TestScopedClipboard::Open(HWND window) { |
65 | | - return kAccessDeniedErrorCode; |
66 | | -} |
67 | | - |
68 | | -bool TestScopedClipboard::HasString() { |
69 | | - return true; |
70 | | -} |
71 | | - |
72 | | -std::variant<std::wstring, int> TestScopedClipboard::GetString() { |
73 | | - return -1; |
74 | | -} |
75 | | - |
76 | | -int TestScopedClipboard::SetString(const std::wstring string) { |
77 | | - return -1; |
78 | | -} |
79 | | - |
80 | | -class MockMethodResult : public MethodResult<rapidjson::Document> { |
81 | | - public: |
82 | | - MOCK_METHOD1(SuccessInternal, void(const rapidjson::Document*)); |
83 | | - MOCK_METHOD3(ErrorInternal, |
84 | | - void(const std::string&, |
85 | | - const std::string&, |
86 | | - const rapidjson::Document*)); |
87 | | - MOCK_METHOD0(NotImplementedInternal, void()); |
88 | | -}; |
89 | | - |
90 | | -TEST(PlatformHandlerWin32, HasStringsAccessDeniedReturnsFalseWithoutError) { |
91 | | - TestBinaryMessenger messenger; |
92 | | - FlutterWindowsView view( |
93 | | - std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>()); |
94 | | - PlatformHandlerWin32 platform_handler(&messenger, &view, |
95 | | - std::make_unique<TestScopedClipboard>()); |
96 | | - |
97 | | - auto args = std::make_unique<rapidjson::Document>(rapidjson::kStringType); |
98 | | - auto& allocator = args->GetAllocator(); |
99 | | - args->SetString(kTextPlainFormat); |
100 | | - auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( |
101 | | - MethodCall<rapidjson::Document>(kHasStringsClipboardMethod, |
102 | | - std::move(args))); |
103 | | - |
104 | | - MockMethodResult result; |
105 | | - rapidjson::Document document; |
106 | | - document.SetObject(); |
107 | | - rapidjson::Document::AllocatorType& document_allocator = |
108 | | - document.GetAllocator(); |
109 | | - document.AddMember(rapidjson::Value(kValueKey, document_allocator), |
110 | | - rapidjson::Value(false), document_allocator); |
111 | | - |
112 | | - EXPECT_CALL(result, SuccessInternal(_)) |
113 | | - .WillOnce([](const rapidjson::Document* document) { |
114 | | - ASSERT_FALSE((*document)[kValueKey].GetBool()); |
115 | | - }); |
116 | | - EXPECT_TRUE(messenger.SimulateEngineMessage( |
117 | | - kChannelName, encoded->data(), encoded->size(), |
118 | | - [&](const uint8_t* reply, size_t reply_size) { |
119 | | - JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( |
120 | | - reply, reply_size, &result); |
121 | | - })); |
122 | | -} |
123 | | - |
124 | | -} // namespace testing |
125 | | -} // namespace flutter |
| 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/platform_handler_win32.h" |
| 6 | + |
| 7 | +#include <memory> |
| 8 | + |
| 9 | +#include "flutter/shell/platform/common/json_method_codec.h" |
| 10 | +#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" |
| 11 | +#include "flutter/shell/platform/windows/testing/test_binary_messenger.h" |
| 12 | +#include "gmock/gmock.h" |
| 13 | +#include "gtest/gtest.h" |
| 14 | +#include "rapidjson/document.h" |
| 15 | + |
| 16 | +namespace flutter { |
| 17 | +namespace testing { |
| 18 | + |
| 19 | +namespace { |
| 20 | +using ::testing::_; |
| 21 | + |
| 22 | +static constexpr char kChannelName[] = "flutter/platform"; |
| 23 | + |
| 24 | +static constexpr char kHasStringsClipboardMethod[] = "Clipboard.hasStrings"; |
| 25 | + |
| 26 | +static constexpr char kTextPlainFormat[] = "text/plain"; |
| 27 | + |
| 28 | +static constexpr char kValueKey[] = "value"; |
| 29 | +static constexpr int kAccessDeniedErrorCode = 5; |
| 30 | +static constexpr int kErrorSuccess = 0; |
| 31 | + |
| 32 | +} // namespace |
| 33 | + |
| 34 | +// A test version of the private ScopedClipboard. |
| 35 | +class TestScopedClipboard : public ScopedClipboardInterface { |
| 36 | + public: |
| 37 | + TestScopedClipboard(int open_error, bool has_strings); |
| 38 | + ~TestScopedClipboard(); |
| 39 | + |
| 40 | + // Prevent copying. |
| 41 | + TestScopedClipboard(TestScopedClipboard const&) = delete; |
| 42 | + TestScopedClipboard& operator=(TestScopedClipboard const&) = delete; |
| 43 | + |
| 44 | + int Open(HWND window); |
| 45 | + |
| 46 | + bool HasString(); |
| 47 | + |
| 48 | + std::variant<std::wstring, int> GetString(); |
| 49 | + |
| 50 | + int SetString(const std::wstring string); |
| 51 | + |
| 52 | + private: |
| 53 | + bool opened_ = false; |
| 54 | + bool has_strings_; |
| 55 | + int open_error_; |
| 56 | +}; |
| 57 | + |
| 58 | +TestScopedClipboard::TestScopedClipboard(int open_error, bool has_strings) { |
| 59 | + open_error_ = open_error; |
| 60 | + has_strings_ = has_strings; |
| 61 | +}; |
| 62 | + |
| 63 | +TestScopedClipboard::~TestScopedClipboard() { |
| 64 | + if (opened_) { |
| 65 | + ::CloseClipboard(); |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +int TestScopedClipboard::Open(HWND window) { |
| 70 | + return open_error_; |
| 71 | +} |
| 72 | + |
| 73 | +bool TestScopedClipboard::HasString() { |
| 74 | + return has_strings_; |
| 75 | +} |
| 76 | + |
| 77 | +std::variant<std::wstring, int> TestScopedClipboard::GetString() { |
| 78 | + return -1; |
| 79 | +} |
| 80 | + |
| 81 | +int TestScopedClipboard::SetString(const std::wstring string) { |
| 82 | + return -1; |
| 83 | +} |
| 84 | + |
| 85 | +class MockMethodResult : public MethodResult<rapidjson::Document> { |
| 86 | + public: |
| 87 | + MOCK_METHOD1(SuccessInternal, void(const rapidjson::Document*)); |
| 88 | + MOCK_METHOD3(ErrorInternal, |
| 89 | + void(const std::string&, |
| 90 | + const std::string&, |
| 91 | + const rapidjson::Document*)); |
| 92 | + MOCK_METHOD0(NotImplementedInternal, void()); |
| 93 | +}; |
| 94 | + |
| 95 | +// Regression test for https://github.com/flutter/flutter/issues/95817. |
| 96 | +TEST(PlatformHandlerWin32, HasStringsAccessDeniedReturnsFalseWithoutError) { |
| 97 | + TestBinaryMessenger messenger; |
| 98 | + FlutterWindowsView view( |
| 99 | + std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>()); |
| 100 | + // HasStrings will receive access denied on the clipboard, but will return |
| 101 | + // false without error. |
| 102 | + PlatformHandlerWin32 platform_handler( |
| 103 | + &messenger, &view, |
| 104 | + std::make_unique<TestScopedClipboard>(kAccessDeniedErrorCode, true)); |
| 105 | + |
| 106 | + auto args = std::make_unique<rapidjson::Document>(rapidjson::kStringType); |
| 107 | + auto& allocator = args->GetAllocator(); |
| 108 | + args->SetString(kTextPlainFormat); |
| 109 | + auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( |
| 110 | + MethodCall<rapidjson::Document>(kHasStringsClipboardMethod, |
| 111 | + std::move(args))); |
| 112 | + |
| 113 | + MockMethodResult result; |
| 114 | + rapidjson::Document document; |
| 115 | + document.SetObject(); |
| 116 | + rapidjson::Document::AllocatorType& document_allocator = |
| 117 | + document.GetAllocator(); |
| 118 | + document.AddMember(rapidjson::Value(kValueKey, document_allocator), |
| 119 | + rapidjson::Value(false), document_allocator); |
| 120 | + |
| 121 | + EXPECT_CALL(result, SuccessInternal(_)) |
| 122 | + .WillOnce([](const rapidjson::Document* document) { |
| 123 | + ASSERT_FALSE((*document)[kValueKey].GetBool()); |
| 124 | + }); |
| 125 | + EXPECT_TRUE(messenger.SimulateEngineMessage( |
| 126 | + kChannelName, encoded->data(), encoded->size(), |
| 127 | + [&](const uint8_t* reply, size_t reply_size) { |
| 128 | + JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( |
| 129 | + reply, reply_size, &result); |
| 130 | + })); |
| 131 | +} |
| 132 | + |
| 133 | +TEST(PlatformHandlerWin32, HasStringsSuccessWithStrings) { |
| 134 | + TestBinaryMessenger messenger; |
| 135 | + FlutterWindowsView view( |
| 136 | + std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>()); |
| 137 | + // HasStrings will succeed and return true. |
| 138 | + PlatformHandlerWin32 platform_handler( |
| 139 | + &messenger, &view, |
| 140 | + std::make_unique<TestScopedClipboard>(kErrorSuccess, true)); |
| 141 | + |
| 142 | + auto args = std::make_unique<rapidjson::Document>(rapidjson::kStringType); |
| 143 | + auto& allocator = args->GetAllocator(); |
| 144 | + args->SetString(kTextPlainFormat); |
| 145 | + auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( |
| 146 | + MethodCall<rapidjson::Document>(kHasStringsClipboardMethod, |
| 147 | + std::move(args))); |
| 148 | + |
| 149 | + MockMethodResult result; |
| 150 | + rapidjson::Document document; |
| 151 | + document.SetObject(); |
| 152 | + rapidjson::Document::AllocatorType& document_allocator = |
| 153 | + document.GetAllocator(); |
| 154 | + document.AddMember(rapidjson::Value(kValueKey, document_allocator), |
| 155 | + rapidjson::Value(false), document_allocator); |
| 156 | + |
| 157 | + EXPECT_CALL(result, SuccessInternal(_)) |
| 158 | + .WillOnce([](const rapidjson::Document* document) { |
| 159 | + ASSERT_TRUE((*document)[kValueKey].GetBool()); |
| 160 | + }); |
| 161 | + EXPECT_TRUE(messenger.SimulateEngineMessage( |
| 162 | + kChannelName, encoded->data(), encoded->size(), |
| 163 | + [&](const uint8_t* reply, size_t reply_size) { |
| 164 | + JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( |
| 165 | + reply, reply_size, &result); |
| 166 | + })); |
| 167 | +} |
| 168 | + |
| 169 | +TEST(PlatformHandlerWin32, HasStringsSuccessWithoutStrings) { |
| 170 | + TestBinaryMessenger messenger; |
| 171 | + FlutterWindowsView view( |
| 172 | + std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>()); |
| 173 | + // HasStrings will succeed and return false. |
| 174 | + PlatformHandlerWin32 platform_handler( |
| 175 | + &messenger, &view, |
| 176 | + std::make_unique<TestScopedClipboard>(kErrorSuccess, false)); |
| 177 | + |
| 178 | + auto args = std::make_unique<rapidjson::Document>(rapidjson::kStringType); |
| 179 | + auto& allocator = args->GetAllocator(); |
| 180 | + args->SetString(kTextPlainFormat); |
| 181 | + auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( |
| 182 | + MethodCall<rapidjson::Document>(kHasStringsClipboardMethod, |
| 183 | + std::move(args))); |
| 184 | + |
| 185 | + MockMethodResult result; |
| 186 | + rapidjson::Document document; |
| 187 | + document.SetObject(); |
| 188 | + rapidjson::Document::AllocatorType& document_allocator = |
| 189 | + document.GetAllocator(); |
| 190 | + document.AddMember(rapidjson::Value(kValueKey, document_allocator), |
| 191 | + rapidjson::Value(false), document_allocator); |
| 192 | + |
| 193 | + EXPECT_CALL(result, SuccessInternal(_)) |
| 194 | + .WillOnce([](const rapidjson::Document* document) { |
| 195 | + ASSERT_FALSE((*document)[kValueKey].GetBool()); |
| 196 | + }); |
| 197 | + EXPECT_TRUE(messenger.SimulateEngineMessage( |
| 198 | + kChannelName, encoded->data(), encoded->size(), |
| 199 | + [&](const uint8_t* reply, size_t reply_size) { |
| 200 | + JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( |
| 201 | + reply, reply_size, &result); |
| 202 | + })); |
| 203 | +} |
| 204 | + |
| 205 | +TEST(PlatformHandlerWin32, HasStringsError) { |
| 206 | + TestBinaryMessenger messenger; |
| 207 | + FlutterWindowsView view( |
| 208 | + std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>()); |
| 209 | + // HasStrings will fail. |
| 210 | + PlatformHandlerWin32 platform_handler( |
| 211 | + &messenger, &view, std::make_unique<TestScopedClipboard>(1, true)); |
| 212 | + |
| 213 | + auto args = std::make_unique<rapidjson::Document>(rapidjson::kStringType); |
| 214 | + auto& allocator = args->GetAllocator(); |
| 215 | + args->SetString(kTextPlainFormat); |
| 216 | + auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( |
| 217 | + MethodCall<rapidjson::Document>(kHasStringsClipboardMethod, |
| 218 | + std::move(args))); |
| 219 | + |
| 220 | + MockMethodResult result; |
| 221 | + rapidjson::Document document; |
| 222 | + document.SetObject(); |
| 223 | + rapidjson::Document::AllocatorType& document_allocator = |
| 224 | + document.GetAllocator(); |
| 225 | + document.AddMember(rapidjson::Value(kValueKey, document_allocator), |
| 226 | + rapidjson::Value(false), document_allocator); |
| 227 | + |
| 228 | + EXPECT_CALL(result, SuccessInternal(_)).Times(0); |
| 229 | + EXPECT_CALL(result, ErrorInternal(_, _, _)).Times(1); |
| 230 | + EXPECT_TRUE(messenger.SimulateEngineMessage( |
| 231 | + kChannelName, encoded->data(), encoded->size(), |
| 232 | + [&](const uint8_t* reply, size_t reply_size) { |
| 233 | + JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( |
| 234 | + reply, reply_size, &result); |
| 235 | + })); |
| 236 | +} |
| 237 | + |
| 238 | +} // namespace testing |
| 239 | +} // namespace flutter |
0 commit comments