Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 0ee66bc

Browse files
committed
Code review: Full tests for hasstrings
1 parent 98d160f commit 0ee66bc

File tree

2 files changed

+240
-126
lines changed

2 files changed

+240
-126
lines changed

shell/platform/windows/platform_handler_win32.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class FlutterWindowsView;
1919
// PlatformHandlerWin32.
2020
class ScopedClipboardInterface {
2121
public:
22-
virtual ~ScopedClipboardInterface() {};
22+
virtual ~ScopedClipboardInterface(){};
2323

2424
// Attempts to open the clipboard for the given window, returning the error
2525
// code in the case of failure and 0 otherwise.
Lines changed: 239 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,239 @@
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

Comments
 (0)