Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(292)

Side by Side Diff: mojo/services/files/public/cpp/tests/output_stream_file_unittest.cc

Issue 1388413005: Move //mojo/services/X/public/... to //mojo/services/X/... (part 1). (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium 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 "files/public/cpp/output_stream_file.h"
6
7 #include <string.h>
8
9 #include <memory>
10 #include <string>
11
12 #include "files/public/interfaces/files.mojom.h"
13 #include "files/public/interfaces/types.mojom.h"
14 #include "mojo/public/cpp/application/application_test_base.h"
15 #include "mojo/public/cpp/bindings/interface_request.h"
16 #include "mojo/public/cpp/system/macros.h"
17 #include "mojo/public/cpp/utility/run_loop.h"
18
19 namespace files_impl {
20 namespace {
21
22 using OutputStreamFileTest = mojo::test::ApplicationTestBase;
23
24 void QuitMessageLoop() {
25 mojo::RunLoop::current()->Quit();
26 }
27
28 void RunMessageLoop() {
29 mojo::RunLoop::current()->Run();
30 }
31
32 void RunMessageLoopUntilIdle() {
33 mojo::RunLoop::current()->RunUntilIdle();
34 }
35
36 // Converts a string to a |mojo::Array<uint8_t>|.
37 mojo::Array<uint8_t> StringToArray(const std::string& s) {
38 auto rv = mojo::Array<uint8_t>::New(s.size());
39 if (s.size())
40 memcpy(&rv[0], &s[0], s.size());
41 return rv;
42 }
43
44 class TestClient : public OutputStreamFile::Client {
45 public:
46 TestClient() { Reset(); }
47 ~TestClient() override {}
48
49 void Reset() {
50 got_on_data_received_ = false;
51 data_ = std::string();
52 got_on_closed_ = false;
53 }
54
55 bool got_on_data_received() const { return got_on_data_received_; }
56 const std::string& data() const { return data_; }
57 bool got_on_closed() const { return got_on_closed_; }
58
59 private:
60 // |OutputStreamFile::Client|:
61 void OnDataReceived(const void* bytes, size_t num_bytes) override {
62 got_on_data_received_ = true;
63 data_ = std::string(static_cast<const char*>(bytes), num_bytes);
64 QuitMessageLoop();
65 }
66 void OnClosed() override {
67 got_on_closed_ = true;
68 QuitMessageLoop();
69 }
70
71 bool got_on_data_received_;
72 std::string data_;
73 bool got_on_closed_;
74
75 MOJO_DISALLOW_COPY_AND_ASSIGN(TestClient);
76 };
77
78 void TestWrite(mojo::files::File* file,
79 TestClient* client,
80 const std::string& s) {
81 bool write_cb_called = false;
82 mojo::files::Error error = mojo::files::Error::INTERNAL;
83 uint32_t num_bytes_written = 0;
84 file->Write(StringToArray(s), 0, mojo::files::Whence::FROM_CURRENT,
85 [&write_cb_called, &error, &num_bytes_written](
86 mojo::files::Error e, uint32_t n) {
87 write_cb_called = true;
88 error = e;
89 num_bytes_written = n;
90 QuitMessageLoop();
91 });
92 if (client) {
93 // If there's a client, since we're running everything on one thread, the
94 // impl (which will call the client, which will quit the message loop) will
95 // get called before the callback.
96 client->Reset();
97 RunMessageLoop();
98 EXPECT_TRUE(client->got_on_data_received());
99 EXPECT_EQ(s, client->data());
100 EXPECT_FALSE(client->got_on_closed());
101 EXPECT_FALSE(write_cb_called);
102 // Spin the message loop again to get the callback.
103 client->Reset();
104 RunMessageLoop();
105 EXPECT_FALSE(client->got_on_data_received());
106 EXPECT_FALSE(client->got_on_closed());
107 } else {
108 // Otherwise, only the write callback will be called and quit the message
109 // loop.
110 RunMessageLoop();
111 }
112 EXPECT_TRUE(write_cb_called);
113 EXPECT_EQ(mojo::files::Error::OK, error);
114 EXPECT_EQ(s.size(), num_bytes_written);
115 }
116
117 void TestClose(mojo::files::File* file, TestClient* client) {
118 bool close_cb_called = false;
119 mojo::files::Error error = mojo::files::Error::INTERNAL;
120 file->Close([&close_cb_called, &error](mojo::files::Error e) {
121 close_cb_called = true;
122 error = e;
123 QuitMessageLoop();
124 });
125 // (This is analogous to |TestWrite()|.)
126 if (client) {
127 client->Reset();
128 RunMessageLoop();
129 EXPECT_FALSE(client->got_on_data_received());
130 EXPECT_TRUE(client->got_on_closed());
131 EXPECT_FALSE(close_cb_called);
132 client->Reset();
133 RunMessageLoop();
134 EXPECT_FALSE(client->got_on_data_received());
135 EXPECT_FALSE(client->got_on_closed());
136 } else {
137 RunMessageLoop();
138 }
139 EXPECT_TRUE(close_cb_called);
140 EXPECT_EQ(mojo::files::Error::OK, error);
141 }
142
143 TEST_F(OutputStreamFileTest, Basic) {
144 mojo::files::FilePtr file;
145 TestClient client;
146 std::unique_ptr<OutputStreamFile> file_impl =
147 OutputStreamFile::Create(&client, GetProxy(&file));
148
149 TestWrite(file.get(), &client, "hello");
150 TestWrite(file.get(), &client, "world");
151 TestClose(file.get(), &client);
152 }
153
154 TEST_F(OutputStreamFileTest, SetClient) {
155 mojo::files::FilePtr file;
156 TestClient client1;
157 std::unique_ptr<OutputStreamFile> file_impl =
158 OutputStreamFile::Create(&client1, GetProxy(&file));
159
160 TestWrite(file.get(), &client1, "hello");
161
162 TestClient client2;
163 file_impl->set_client(&client2);
164 TestWrite(file.get(), &client2, "world");
165
166 file_impl->set_client(&client1);
167 TestWrite(file.get(), &client1, "!");
168 TestClose(file.get(), &client1);
169 }
170
171 TEST_F(OutputStreamFileTest, NullClient) {
172 mojo::files::FilePtr file;
173 std::unique_ptr<OutputStreamFile> file_impl =
174 OutputStreamFile::Create(nullptr, GetProxy(&file));
175
176 TestWrite(file.get(), nullptr, "hello");
177
178 TestClient client;
179 file_impl->set_client(&client);
180 TestWrite(file.get(), &client, "world");
181
182 file_impl->set_client(nullptr);
183 client.Reset();
184 TestWrite(file.get(), nullptr, "!");
185 TestClose(file.get(), nullptr);
186 EXPECT_FALSE(client.got_on_data_received());
187 EXPECT_FALSE(client.got_on_closed());
188 }
189
190 TEST_F(OutputStreamFileTest, ImplOnlyClosesMessagePipeOnDestruction) {
191 mojo::files::FilePtr file;
192 std::unique_ptr<OutputStreamFile> file_impl =
193 OutputStreamFile::Create(nullptr, GetProxy(&file));
194 bool got_connection_error = false;
195 file.set_connection_error_handler([&got_connection_error]() {
196 got_connection_error = true;
197 QuitMessageLoop();
198 });
199
200 TestClose(file.get(), nullptr);
201 // The impl should only close its end when it's destroyed (even if |Close()|
202 // has been called).
203 RunMessageLoopUntilIdle();
204 EXPECT_FALSE(got_connection_error);
205 file_impl.reset();
206 RunMessageLoop();
207 EXPECT_TRUE(got_connection_error);
208 }
209
210 TEST_F(OutputStreamFileTest, ClosingMessagePipeCausesOnClosed) {
211 mojo::files::FilePtr file;
212 TestClient client;
213 std::unique_ptr<OutputStreamFile> file_impl =
214 OutputStreamFile::Create(&client, GetProxy(&file));
215
216 file.reset();
217 RunMessageLoop();
218 EXPECT_FALSE(client.got_on_data_received());
219 EXPECT_TRUE(client.got_on_closed());
220 }
221
222 // Clients may own the impl (and this is a typical pattern). This client will
223 // own/destroy its impl on any |Client| call (and we'll test that this doesn't
224 // result in any additional calls to the client).
225 class TestClientDestroysImplClient : public OutputStreamFile::Client {
226 public:
227 explicit TestClientDestroysImplClient(
228 mojo::InterfaceRequest<mojo::files::File> request)
229 : file_impl_(OutputStreamFile::Create(this, request.Pass())) {}
230 ~TestClientDestroysImplClient() override {}
231
232 private:
233 // OutputStreamFile::Client|:
234 void OnDataReceived(const void* /*bytes*/, size_t /*num_bytes*/) override {
235 // We reset the impl on any call, and afterwards it shouldn't call us.
236 EXPECT_TRUE(file_impl_);
237 file_impl_.reset();
238 }
239 void OnClosed() override {
240 // We reset the impl on any call, and afterwards it shouldn't call us.
241 EXPECT_TRUE(file_impl_);
242 file_impl_.reset();
243 }
244
245 std::unique_ptr<OutputStreamFile> file_impl_;
246
247 MOJO_DISALLOW_COPY_AND_ASSIGN(TestClientDestroysImplClient);
248 };
249
250 TEST_F(OutputStreamFileTest, ClientDestroysImpl) {
251 // Test destruction due to writing.
252 {
253 mojo::files::FilePtr file;
254 TestClientDestroysImplClient client(GetProxy(&file));
255 bool got_connection_error = false;
256 file.set_connection_error_handler([&got_connection_error]() {
257 got_connection_error = true;
258 QuitMessageLoop();
259 });
260 // |TestClientDestroysImplClient| doesn't quit the message loop, so it
261 // behaves like a null client.
262 TestWrite(file.get(), nullptr, "hello");
263 // The connection error may be called immediately after the write callback,
264 // in which case we have to spin the message loop again.
265 if (!got_connection_error)
266 RunMessageLoop();
267 EXPECT_TRUE(got_connection_error);
268 }
269
270 // Test destruction due to closing.
271 {
272 mojo::files::FilePtr file;
273 TestClientDestroysImplClient client(GetProxy(&file));
274 bool got_connection_error = false;
275 file.set_connection_error_handler([&got_connection_error]() {
276 got_connection_error = true;
277 QuitMessageLoop();
278 });
279 TestClose(file.get(), nullptr);
280 if (!got_connection_error)
281 RunMessageLoop();
282 EXPECT_TRUE(got_connection_error);
283 }
284 }
285
286 } // namespace
287 } // namespace files_impl
OLDNEW
« no previous file with comments | « mojo/services/files/public/cpp/tests/input_stream_file_unittest.cc ('k') | mojo/services/files/public/interfaces/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698