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

Side by Side Diff: services/files/files_apptest.cc

Issue 875643004: Prototype of Files service. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Remove much of DirectoryImpl implementation until I write tests. Created 5 years, 9 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 <vector>
6
7 #include "base/macros.h"
8 #include "mojo/public/cpp/application/application_impl.h"
9 #include "mojo/public/cpp/application/application_test_base.h"
10 #include "mojo/public/cpp/bindings/interface_request.h"
11 #include "mojo/public/cpp/bindings/type_converter.h"
12 #include "services/files/directory.mojom.h"
13 #include "services/files/file.mojom.h"
14 #include "services/files/files.mojom.h"
15
16 namespace mojo {
17 namespace files {
18 namespace {
19
20 // TODO(vtl): Stuff copied from mojo/public/cpp/bindings/lib/template_util.h.
21 template <class T, T v>
22 struct IntegralConstant {
23 static const T value = v;
24 };
25
26 template <class T, T v>
27 const T IntegralConstant<T, v>::value;
28
29 typedef IntegralConstant<bool, true> TrueType;
30 typedef IntegralConstant<bool, false> FalseType;
31
32 template <class T>
33 struct IsConst : FalseType {};
34 template <class T>
35 struct IsConst<const T> : TrueType {};
36
37 template <bool B, typename T = void>
38 struct EnableIf {};
39
40 template <typename T>
41 struct EnableIf<true, T> {
42 typedef T type;
43 };
44
45 typedef char YesType;
46
47 struct NoType {
48 YesType dummy[2];
49 };
50
51 template <typename T>
52 struct IsMoveOnlyType {
53 template <typename U>
54 static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
55
56 template <typename U>
57 static NoType Test(...);
58
59 static const bool value =
60 sizeof(Test<T>(0)) == sizeof(YesType) && !IsConst<T>::value;
61 };
62
63 template <typename T>
64 typename EnableIf<!IsMoveOnlyType<T>::value, T>::type& Forward(T& t) {
65 return t;
66 }
67
68 template <typename T>
69 typename EnableIf<IsMoveOnlyType<T>::value, T>::type Forward(T& t) {
70 return t.Pass();
71 }
72 // TODO(vtl): (End of stuff copied from template_util.h.)
73
74 template <typename T1>
75 Callback<void(T1)> Capture(T1* t1) {
76 return [t1](T1 got_t1) { *t1 = Forward(got_t1); };
77 }
78
79 template <typename T1, typename T2>
80 Callback<void(T1, T2)> Capture(T1* t1, T2* t2) {
81 return [t1, t2](T1 got_t1, T2 got_t2) {
82 *t1 = Forward(got_t1);
83 *t2 = Forward(got_t2);
84 };
85 }
86
87 class FilesAppTest : public test::ApplicationTestBase {
88 public:
89 FilesAppTest() {}
90 ~FilesAppTest() override {}
91
92 void SetUp() override {
93 test::ApplicationTestBase::SetUp();
94 application_impl()->ConnectToService("mojo:files", &files_);
95 }
96
97 FilesPtr& files() { return files_; }
98
99 private:
100 FilesPtr files_;
101
102 DISALLOW_COPY_AND_ASSIGN(FilesAppTest);
103 };
104
105 TEST_F(FilesAppTest, CreateWriteCloseRenameOpenRead) {
106 // Get a temporary root directory.
107 DirectoryPtr directory;
108 Error error = ERROR_INTERNAL;
109 files()->OpenFileSystem(FILE_SYSTEM_TEMPORARY, GetProxy(&directory),
110 Capture(&error));
111 ASSERT_TRUE(files().WaitForIncomingMethodCall());
112 EXPECT_EQ(ERROR_OK, error);
113
114 {
115 // Create my_file.
116 FilePtr file;
117 error = ERROR_INTERNAL;
118 directory->OpenFile("my_file", GetProxy(&file),
119 kOpenFlagWrite | kOpenFlagCreate, Capture(&error));
120 ASSERT_TRUE(directory.WaitForIncomingMethodCall());
121 EXPECT_EQ(ERROR_OK, error);
122
123 // Write to it.
124 std::vector<uint8_t> bytes_to_write;
125 bytes_to_write.push_back(static_cast<uint8_t>('h'));
126 bytes_to_write.push_back(static_cast<uint8_t>('e'));
127 bytes_to_write.push_back(static_cast<uint8_t>('l'));
128 bytes_to_write.push_back(static_cast<uint8_t>('l'));
129 bytes_to_write.push_back(static_cast<uint8_t>('o'));
130 error = ERROR_INTERNAL;
131 uint32_t num_bytes_written = 0;
132 file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT,
133 Capture(&error, &num_bytes_written));
134 ASSERT_TRUE(file.WaitForIncomingMethodCall());
135 EXPECT_EQ(ERROR_OK, error);
136 EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
137
138 // Close it.
139 error = ERROR_INTERNAL;
140 file->Close(Capture(&error));
141 ASSERT_TRUE(file.WaitForIncomingMethodCall());
142 EXPECT_EQ(ERROR_OK, error);
143 }
144
145 // Rename it.
146 error = ERROR_INTERNAL;
147 directory->Rename("my_file", "your_file", Capture(&error));
148 ASSERT_TRUE(directory.WaitForIncomingMethodCall());
149 EXPECT_EQ(ERROR_OK, error);
150
151 {
152 // Open my_file again.
153 FilePtr file;
154 error = ERROR_INTERNAL;
155 directory->OpenFile("your_file", GetProxy(&file), kOpenFlagRead,
156 Capture(&error));
157 ASSERT_TRUE(directory.WaitForIncomingMethodCall());
158 EXPECT_EQ(ERROR_OK, error);
159
160 // Read from it.
161 Array<uint8_t> bytes_read;
162 error = ERROR_INTERNAL;
163 file->Read(3, 1, WHENCE_FROM_START, Capture(&error, &bytes_read));
164 ASSERT_TRUE(file.WaitForIncomingMethodCall());
165 EXPECT_EQ(ERROR_OK, error);
166 ASSERT_EQ(3u, bytes_read.size());
167 EXPECT_EQ(static_cast<uint8_t>('e'), bytes_read[0]);
168 EXPECT_EQ(static_cast<uint8_t>('l'), bytes_read[1]);
169 EXPECT_EQ(static_cast<uint8_t>('l'), bytes_read[2]);
170 }
171
172 // TODO(vtl): Test various open options.
173 // TODO(vtl): Test read/write offset options.
174 }
175
176 // Note: Ignore nanoseconds, since it may not always be supported. We expect at
177 // least second-resolution support though.
178 TEST_F(FilesAppTest, StatTouch) {
179 // Get a temporary root directory.
180 DirectoryPtr directory;
181 Error error = ERROR_INTERNAL;
182 files()->OpenFileSystem(FILE_SYSTEM_TEMPORARY, GetProxy(&directory),
183 Capture(&error));
184 ASSERT_TRUE(files().WaitForIncomingMethodCall());
185 EXPECT_EQ(ERROR_OK, error);
186
187 // Create my_file.
188 FilePtr file;
189 error = ERROR_INTERNAL;
190 directory->OpenFile("my_file", GetProxy(&file),
191 kOpenFlagWrite | kOpenFlagCreate, Capture(&error));
192 ASSERT_TRUE(directory.WaitForIncomingMethodCall());
193 EXPECT_EQ(ERROR_OK, error);
194
195 // Stat it.
196 error = ERROR_INTERNAL;
197 FileInformationPtr file_info;
198 file->Stat(Capture(&error, &file_info));
199 ASSERT_TRUE(file.WaitForIncomingMethodCall());
200 EXPECT_EQ(ERROR_OK, error);
201 ASSERT_FALSE(file_info.is_null());
202 EXPECT_EQ(0, file_info->size);
203 ASSERT_FALSE(file_info->atime.is_null());
204 EXPECT_GT(file_info->atime->seconds, 0); // Expect that it's not 1970-01-01.
205 ASSERT_FALSE(file_info->mtime.is_null());
206 EXPECT_GT(file_info->mtime->seconds, 0);
207 int64_t first_mtime = file_info->mtime->seconds;
208
209 // Touch only the atime.
210 error = ERROR_INTERNAL;
211 TimespecOrNowPtr t(TimespecOrNow::New());
212 t->now = false;
213 t->timespec = Timespec::New();
214 const int64_t kPartyTime1 = 1234567890; // Party like it's 2009-02-13.
215 t->timespec->seconds = kPartyTime1;
216 file->Touch(t.Pass(), nullptr, Capture(&error));
217 ASSERT_TRUE(file.WaitForIncomingMethodCall());
218 EXPECT_EQ(ERROR_OK, error);
219
220 // Stat again.
221 error = ERROR_INTERNAL;
222 file_info.reset();
223 file->Stat(Capture(&error, &file_info));
224 ASSERT_TRUE(file.WaitForIncomingMethodCall());
225 EXPECT_EQ(ERROR_OK, error);
226 ASSERT_FALSE(file_info.is_null());
227 ASSERT_FALSE(file_info->atime.is_null());
228 EXPECT_EQ(kPartyTime1, file_info->atime->seconds);
229 ASSERT_FALSE(file_info->mtime.is_null());
230 EXPECT_EQ(first_mtime, file_info->mtime->seconds);
231
232 // Touch only the mtime.
233 t = TimespecOrNow::New();
234 t->now = false;
235 t->timespec = Timespec::New();
236 const int64_t kPartyTime2 = 1425059525; // No time like the present.
237 t->timespec->seconds = kPartyTime2;
238 file->Touch(nullptr, t.Pass(), Capture(&error));
239 ASSERT_TRUE(file.WaitForIncomingMethodCall());
240 EXPECT_EQ(ERROR_OK, error);
241
242 // Stat again.
243 error = ERROR_INTERNAL;
244 file_info.reset();
245 file->Stat(Capture(&error, &file_info));
246 ASSERT_TRUE(file.WaitForIncomingMethodCall());
247 EXPECT_EQ(ERROR_OK, error);
248 ASSERT_FALSE(file_info.is_null());
249 ASSERT_FALSE(file_info->atime.is_null());
250 EXPECT_EQ(kPartyTime1, file_info->atime->seconds);
251 ASSERT_FALSE(file_info->mtime.is_null());
252 EXPECT_EQ(kPartyTime2, file_info->mtime->seconds);
253
254 // TODO(vtl): Also test non-zero file size.
255 // TODO(vtl): Also test Touch() "now" options.
256 // TODO(vtl): Also test touching both atime and mtime.
257
258 // Close it.
259 error = ERROR_INTERNAL;
260 file->Close(Capture(&error));
261 ASSERT_TRUE(file.WaitForIncomingMethodCall());
262 EXPECT_EQ(ERROR_OK, error);
263 }
264
265 TEST_F(FilesAppTest, TellSeek) {
266 // Get a temporary root directory.
267 DirectoryPtr directory;
268 Error error = ERROR_INTERNAL;
269 files()->OpenFileSystem(FILE_SYSTEM_TEMPORARY, GetProxy(&directory),
270 Capture(&error));
271 ASSERT_TRUE(files().WaitForIncomingMethodCall());
272 EXPECT_EQ(ERROR_OK, error);
273
274 // Create my_file.
275 FilePtr file;
276 error = ERROR_INTERNAL;
277 directory->OpenFile("my_file", GetProxy(&file),
278 kOpenFlagWrite | kOpenFlagCreate, Capture(&error));
279 ASSERT_TRUE(directory.WaitForIncomingMethodCall());
280 EXPECT_EQ(ERROR_OK, error);
281
282 // Write to it.
283 std::vector<uint8_t> bytes_to_write(1000, '!');
284 error = ERROR_INTERNAL;
285 uint32_t num_bytes_written = 0;
286 file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT,
287 Capture(&error, &num_bytes_written));
288 ASSERT_TRUE(file.WaitForIncomingMethodCall());
289 EXPECT_EQ(ERROR_OK, error);
290 EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
291 const int size = static_cast<int>(num_bytes_written);
292
293 // Tell.
294 error = ERROR_INTERNAL;
295 int64_t position = -1;
296 file->Tell(Capture(&error, &position));
297 ASSERT_TRUE(file.WaitForIncomingMethodCall());
298 // Should be at the end.
299 EXPECT_EQ(ERROR_OK, error);
300 EXPECT_EQ(size, position);
301
302 // Seek back 100.
303 error = ERROR_INTERNAL;
304 position = -1;
305 file->Seek(-100, WHENCE_FROM_CURRENT, Capture(&error, &position));
306 ASSERT_TRUE(file.WaitForIncomingMethodCall());
307 EXPECT_EQ(ERROR_OK, error);
308 EXPECT_EQ(size - 100, position);
309
310 // Tell.
311 error = ERROR_INTERNAL;
312 position = -1;
313 file->Tell(Capture(&error, &position));
314 ASSERT_TRUE(file.WaitForIncomingMethodCall());
315 EXPECT_EQ(ERROR_OK, error);
316 EXPECT_EQ(size - 100, position);
317
318 // Seek to 123 from start.
319 error = ERROR_INTERNAL;
320 position = -1;
321 file->Seek(123, WHENCE_FROM_START, Capture(&error, &position));
322 ASSERT_TRUE(file.WaitForIncomingMethodCall());
323 EXPECT_EQ(ERROR_OK, error);
324 EXPECT_EQ(123, position);
325
326 // Tell.
327 error = ERROR_INTERNAL;
328 position = -1;
329 file->Tell(Capture(&error, &position));
330 ASSERT_TRUE(file.WaitForIncomingMethodCall());
331 EXPECT_EQ(ERROR_OK, error);
332 EXPECT_EQ(123, position);
333
334 // Seek to 123 back from end.
335 error = ERROR_INTERNAL;
336 position = -1;
337 file->Seek(-123, WHENCE_FROM_END, Capture(&error, &position));
338 ASSERT_TRUE(file.WaitForIncomingMethodCall());
339 EXPECT_EQ(ERROR_OK, error);
340 EXPECT_EQ(size - 123, position);
341
342 // Tell.
343 error = ERROR_INTERNAL;
344 position = -1;
345 file->Tell(Capture(&error, &position));
346 ASSERT_TRUE(file.WaitForIncomingMethodCall());
347 EXPECT_EQ(ERROR_OK, error);
348 EXPECT_EQ(size - 123, position);
349
350 // TODO(vtl): Check that seeking actually affects reading/writing.
351 // TODO(vtl): Check that seeking can extend the file?
352
353 // Close it.
354 error = ERROR_INTERNAL;
355 file->Close(Capture(&error));
356 ASSERT_TRUE(file.WaitForIncomingMethodCall());
357 EXPECT_EQ(ERROR_OK, error);
358 }
359
360 TEST_F(FilesAppTest, Dup) {
361 // Get a temporary root directory.
362 DirectoryPtr directory;
363 Error error = ERROR_INTERNAL;
364 files()->OpenFileSystem(FILE_SYSTEM_TEMPORARY, GetProxy(&directory),
365 Capture(&error));
366 ASSERT_TRUE(files().WaitForIncomingMethodCall());
367 EXPECT_EQ(ERROR_OK, error);
368
369 // Create my_file.
370 FilePtr file1;
371 error = ERROR_INTERNAL;
372 directory->OpenFile("my_file", GetProxy(&file1),
373 kOpenFlagRead | kOpenFlagWrite | kOpenFlagCreate,
374 Capture(&error));
375 ASSERT_TRUE(directory.WaitForIncomingMethodCall());
376 EXPECT_EQ(ERROR_OK, error);
377
378 // Write to it.
379 std::vector<uint8_t> bytes_to_write;
380 bytes_to_write.push_back(static_cast<uint8_t>('h'));
381 bytes_to_write.push_back(static_cast<uint8_t>('e'));
382 bytes_to_write.push_back(static_cast<uint8_t>('l'));
383 bytes_to_write.push_back(static_cast<uint8_t>('l'));
384 bytes_to_write.push_back(static_cast<uint8_t>('o'));
385 error = ERROR_INTERNAL;
386 uint32_t num_bytes_written = 0;
387 file1->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT,
388 Capture(&error, &num_bytes_written));
389 ASSERT_TRUE(file1.WaitForIncomingMethodCall());
390 EXPECT_EQ(ERROR_OK, error);
391 EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
392 const int end_hello_pos = static_cast<int>(num_bytes_written);
393
394 // Dup it.
395 FilePtr file2;
396 error = ERROR_INTERNAL;
397 file1->Dup(GetProxy(&file2), Capture(&error));
398 ASSERT_TRUE(file1.WaitForIncomingMethodCall());
399 EXPECT_EQ(ERROR_OK, error);
400
401 // |file2| should have the same position.
402 error = ERROR_INTERNAL;
403 int64_t position = -1;
404 file2->Tell(Capture(&error, &position));
405 ASSERT_TRUE(file2.WaitForIncomingMethodCall());
406 EXPECT_EQ(ERROR_OK, error);
407 EXPECT_EQ(end_hello_pos, position);
408
409 // Write using |file2|.
410 std::vector<uint8_t> more_bytes_to_write;
411 more_bytes_to_write.push_back(static_cast<uint8_t>('w'));
412 more_bytes_to_write.push_back(static_cast<uint8_t>('o'));
413 more_bytes_to_write.push_back(static_cast<uint8_t>('r'));
414 more_bytes_to_write.push_back(static_cast<uint8_t>('l'));
415 more_bytes_to_write.push_back(static_cast<uint8_t>('d'));
416 error = ERROR_INTERNAL;
417 num_bytes_written = 0;
418 file2->Write(Array<uint8_t>::From(more_bytes_to_write), 0,
419 WHENCE_FROM_CURRENT, Capture(&error, &num_bytes_written));
420 ASSERT_TRUE(file2.WaitForIncomingMethodCall());
421 EXPECT_EQ(ERROR_OK, error);
422 EXPECT_EQ(more_bytes_to_write.size(), num_bytes_written);
423 const int end_world_pos = end_hello_pos + static_cast<int>(num_bytes_written);
424
425 // |file1| should have the same position.
426 error = ERROR_INTERNAL;
427 position = -1;
428 file1->Tell(Capture(&error, &position));
429 ASSERT_TRUE(file1.WaitForIncomingMethodCall());
430 EXPECT_EQ(ERROR_OK, error);
431 EXPECT_EQ(end_world_pos, position);
432
433 // Close |file1|.
434 error = ERROR_INTERNAL;
435 file1->Close(Capture(&error));
436 ASSERT_TRUE(file1.WaitForIncomingMethodCall());
437 EXPECT_EQ(ERROR_OK, error);
438
439 // Read everything using |file2|.
440 Array<uint8_t> bytes_read;
441 error = ERROR_INTERNAL;
442 file2->Read(1000, 0, WHENCE_FROM_START, Capture(&error, &bytes_read));
443 ASSERT_TRUE(file2.WaitForIncomingMethodCall());
444 EXPECT_EQ(ERROR_OK, error);
445 ASSERT_EQ(static_cast<size_t>(end_world_pos), bytes_read.size());
446 // Just check the first and last bytes.
447 EXPECT_EQ(static_cast<uint8_t>('h'), bytes_read[0]);
448 EXPECT_EQ(static_cast<uint8_t>('d'), bytes_read[end_world_pos - 1]);
449
450 // Close |file2|.
451 error = ERROR_INTERNAL;
452 file2->Close(Capture(&error));
453 ASSERT_TRUE(file2.WaitForIncomingMethodCall());
454 EXPECT_EQ(ERROR_OK, error);
455
456 // TODO(vtl): Test that |file2| has the same open options as |file1|.
457 }
458
459 } // namespace
460 } // namespace files
461 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698