Fix build break
[chromium-blink-merge.git] / ppapi / tests / test_file_io.cc
blobca6412f1f7d434fc5906ce9c39de0887975d4b1b
1 // Copyright (c) 2012 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.
5 #include "ppapi/tests/test_file_io.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
13 #include <vector>
15 #include "ppapi/c/dev/ppb_testing_dev.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/c/ppb_file_io.h"
18 #include "ppapi/c/private/pp_file_handle.h"
19 #include "ppapi/c/trusted/ppb_file_io_trusted.h"
20 #include "ppapi/cpp/file_io.h"
21 #include "ppapi/cpp/file_ref.h"
22 #include "ppapi/cpp/file_system.h"
23 #include "ppapi/cpp/instance.h"
24 #include "ppapi/cpp/module.h"
25 #include "ppapi/cpp/private/file_io_private.h"
26 #include "ppapi/tests/test_utils.h"
27 #include "ppapi/tests/testing_instance.h"
29 #if defined(PPAPI_OS_WIN)
30 # include <io.h>
31 # include <windows.h>
32 // TODO(hamaji): Use standard windows APIs instead of compatibility layer?
33 # define lseek _lseek
34 # define read _read
35 # define write _write
36 # define ssize_t int
37 #else
38 # include <sys/mman.h>
39 # include <unistd.h>
40 #endif
42 REGISTER_TEST_CASE(FileIO);
44 namespace {
46 std::string ReportMismatch(const std::string& method_name,
47 const std::string& returned_result,
48 const std::string& expected_result) {
49 return method_name + " returned '" + returned_result + "'; '" +
50 expected_result + "' expected.";
53 std::string ReportOpenError(int32_t open_flags) {
54 static const char* kFlagNames[] = {
55 "PP_FILEOPENFLAG_READ",
56 "PP_FILEOPENFLAG_WRITE",
57 "PP_FILEOPENFLAG_CREATE",
58 "PP_FILEOPENFLAG_TRUNCATE",
59 "PP_FILEOPENFLAG_EXCLUSIVE"
62 std::string result = "FileIO:Open had unexpected behavior with flags: ";
63 bool first_flag = true;
64 for (int32_t mask = 1, index = 0; mask <= PP_FILEOPENFLAG_EXCLUSIVE;
65 mask <<= 1, ++index) {
66 if (mask & open_flags) {
67 if (first_flag) {
68 first_flag = false;
69 } else {
70 result += " | ";
72 result += kFlagNames[index];
75 if (first_flag)
76 result += "[None]";
78 return result;
81 int32_t ReadEntireFile(PP_Instance instance,
82 pp::FileIO* file_io,
83 int32_t offset,
84 std::string* data,
85 CallbackType callback_type) {
86 TestCompletionCallback callback(instance, callback_type);
87 char buf[256];
88 int32_t read_offset = offset;
90 for (;;) {
91 callback.WaitForResult(
92 file_io->Read(read_offset, buf, sizeof(buf), callback.GetCallback()));
93 if (callback.result() < 0)
94 return callback.result();
95 if (callback.result() == 0)
96 break;
97 read_offset += callback.result();
98 data->append(buf, callback.result());
101 return PP_OK;
104 int32_t ReadToArrayEntireFile(PP_Instance instance,
105 pp::FileIO* file_io,
106 int32_t offset,
107 std::string* data,
108 CallbackType callback_type) {
109 TestCompletionCallbackWithOutput< std::vector<char> > callback(
110 instance, callback_type);
112 for (;;) {
113 callback.WaitForResult(file_io->Read(offset, 256, callback.GetCallback()));
114 int32_t rv = callback.result();
115 if (rv < 0)
116 return rv;
117 if (rv == 0)
118 break;
119 const std::vector<char>& output = callback.output();
120 assert(rv == static_cast<int32_t>(output.size()));
121 offset += rv;
122 data->append(output.begin(), output.end());
125 return PP_OK;
128 int32_t WriteEntireBuffer(PP_Instance instance,
129 pp::FileIO* file_io,
130 int32_t offset,
131 const std::string& data,
132 CallbackType callback_type) {
133 TestCompletionCallback callback(instance, callback_type);
134 int32_t write_offset = offset;
135 const char* buf = data.c_str();
136 int32_t size = data.size();
138 while (write_offset < offset + size) {
139 callback.WaitForResult(file_io->Write(write_offset,
140 &buf[write_offset - offset],
141 size - write_offset + offset,
142 callback.GetCallback()));
143 if (callback.result() < 0)
144 return callback.result();
145 if (callback.result() == 0)
146 return PP_ERROR_FAILED;
147 write_offset += callback.result();
150 return PP_OK;
153 } // namespace
155 bool TestFileIO::Init() {
156 return CheckTestingInterface() && EnsureRunningOverHTTP();
159 void TestFileIO::RunTests(const std::string& filter) {
160 RUN_CALLBACK_TEST(TestFileIO, Open, filter);
161 RUN_CALLBACK_TEST(TestFileIO, OpenDirectory, filter);
162 RUN_CALLBACK_TEST(TestFileIO, ReadWriteSetLength, filter);
163 RUN_CALLBACK_TEST(TestFileIO, ReadToArrayWriteSetLength, filter);
164 RUN_CALLBACK_TEST(TestFileIO, TouchQuery, filter);
165 RUN_CALLBACK_TEST(TestFileIO, AbortCalls, filter);
166 RUN_CALLBACK_TEST(TestFileIO, ParallelReads, filter);
167 RUN_CALLBACK_TEST(TestFileIO, ParallelWrites, filter);
168 RUN_CALLBACK_TEST(TestFileIO, NotAllowMixedReadWrite, filter);
169 RUN_CALLBACK_TEST(TestFileIO, WillWriteWillSetLength, filter);
170 RUN_CALLBACK_TEST(TestFileIO, RequestOSFileHandle, filter);
172 // TODO(viettrungluu): add tests:
173 // - that PP_ERROR_PENDING is correctly returned
174 // - that operations respect the file open modes (flags)
177 std::string TestFileIO::TestOpen() {
178 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
180 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
181 pp::FileRef file_ref(file_system, "/file_open");
183 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
184 CHECK_CALLBACK_BEHAVIOR(callback);
185 ASSERT_EQ(PP_OK, callback.result());
187 std::string result;
188 result = MatchOpenExpectations(
189 &file_system,
190 PP_FILEOPENFLAG_READ,
191 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
192 if (!result.empty())
193 return result;
195 // Test the behavior of the power set of
196 // { PP_FILEOPENFLAG_CREATE,
197 // PP_FILEOPENFLAG_TRUNCATE,
198 // PP_FILEOPENFLAG_EXCLUSIVE }.
200 // First of all, none of them are specified.
201 result = MatchOpenExpectations(
202 &file_system,
203 PP_FILEOPENFLAG_WRITE,
204 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
205 if (!result.empty())
206 return result;
208 result = MatchOpenExpectations(
209 &file_system,
210 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE,
211 CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
212 if (!result.empty())
213 return result;
215 result = MatchOpenExpectations(
216 &file_system,
217 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE,
218 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
219 if (!result.empty())
220 return result;
222 result = MatchOpenExpectations(
223 &file_system,
224 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_TRUNCATE,
225 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS);
226 if (!result.empty())
227 return result;
229 result = MatchOpenExpectations(
230 &file_system,
231 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE |
232 PP_FILEOPENFLAG_EXCLUSIVE,
233 CREATE_IF_DOESNT_EXIST | DONT_OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
234 if (!result.empty())
235 return result;
237 result = MatchOpenExpectations(
238 &file_system,
239 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_TRUNCATE,
240 CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS);
241 if (!result.empty())
242 return result;
244 result = MatchOpenExpectations(
245 &file_system,
246 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE |
247 PP_FILEOPENFLAG_TRUNCATE,
248 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS);
249 if (!result.empty())
250 return result;
252 result = MatchOpenExpectations(
253 &file_system,
254 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE |
255 PP_FILEOPENFLAG_EXCLUSIVE | PP_FILEOPENFLAG_TRUNCATE,
256 CREATE_IF_DOESNT_EXIST | DONT_OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
257 if (!result.empty())
258 return result;
260 // Invalid combination: PP_FILEOPENFLAG_TRUNCATE without
261 // PP_FILEOPENFLAG_WRITE.
262 result = MatchOpenExpectations(
263 &file_system,
264 PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_TRUNCATE,
265 INVALID_FLAG_COMBINATION);
266 if (!result.empty())
267 return result;
269 PASS();
272 std::string TestFileIO::TestOpenDirectory() {
273 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
275 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
276 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
277 CHECK_CALLBACK_BEHAVIOR(callback);
278 ASSERT_EQ(PP_OK, callback.result());
280 // Make a directory.
281 pp::FileRef dir_ref(file_system, "/test_dir_open_directory");
282 callback.WaitForResult(dir_ref.MakeDirectory(callback.GetCallback()));
283 CHECK_CALLBACK_BEHAVIOR(callback);
284 ASSERT_EQ(PP_OK, callback.result());
286 // Open the directory. This is expected to fail since directories cannot be
287 // opened.
288 pp::FileIO file_io(instance_);
289 callback.WaitForResult(file_io.Open(dir_ref, PP_FILEOPENFLAG_READ,
290 callback.GetCallback()));
291 CHECK_CALLBACK_BEHAVIOR(callback);
292 ASSERT_EQ(PP_ERROR_NOTAFILE, callback.result());
294 PASS();
297 std::string TestFileIO::TestReadWriteSetLength() {
298 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
300 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
301 pp::FileRef file_ref(file_system, "/file_read_write_setlength");
302 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
303 CHECK_CALLBACK_BEHAVIOR(callback);
304 ASSERT_EQ(PP_OK, callback.result());
306 pp::FileIO file_io(instance_);
307 callback.WaitForResult(file_io.Open(file_ref,
308 PP_FILEOPENFLAG_CREATE |
309 PP_FILEOPENFLAG_TRUNCATE |
310 PP_FILEOPENFLAG_READ |
311 PP_FILEOPENFLAG_WRITE,
312 callback.GetCallback()));
313 CHECK_CALLBACK_BEHAVIOR(callback);
314 ASSERT_EQ(PP_OK, callback.result());
316 // Write something to the file.
317 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
318 "test_test", callback_type());
319 ASSERT_EQ(PP_OK, rv);
321 // Attempt to read a negative number of bytes; it should fail.
322 char buf[256];
323 callback.WaitForResult(file_io.Read(0,
324 buf,
326 callback.GetCallback()));
327 CHECK_CALLBACK_BEHAVIOR(callback);
328 ASSERT_EQ(PP_ERROR_FAILED, callback.result());
330 // Read the entire file.
331 std::string read_buffer;
332 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
333 callback_type());
334 ASSERT_EQ(PP_OK, rv);
335 ASSERT_EQ(std::string("test_test"), read_buffer);
337 // Truncate the file.
338 callback.WaitForResult(file_io.SetLength(4, callback.GetCallback()));
339 CHECK_CALLBACK_BEHAVIOR(callback);
340 ASSERT_EQ(PP_OK, callback.result());
342 // Check the file contents.
343 read_buffer.clear();
344 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
345 callback_type());
346 ASSERT_EQ(PP_OK, rv);
347 ASSERT_EQ(std::string("test"), read_buffer);
349 // Try to read past the end of the file.
350 read_buffer.clear();
351 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 100, &read_buffer,
352 callback_type());
353 ASSERT_EQ(PP_OK, rv);
354 ASSERT_TRUE(read_buffer.empty());
356 // Write past the end of the file. The file should be zero-padded.
357 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 8, "test",
358 callback_type());
359 ASSERT_EQ(PP_OK, rv);
361 // Check the contents of the file.
362 read_buffer.clear();
363 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
364 callback_type());
365 ASSERT_EQ(PP_OK, rv);
366 ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer);
368 // Extend the file.
369 callback.WaitForResult(file_io.SetLength(16, callback.GetCallback()));
370 CHECK_CALLBACK_BEHAVIOR(callback);
371 ASSERT_EQ(PP_OK, callback.result());
373 // Check the contents of the file.
374 read_buffer.clear();
375 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
376 callback_type());
377 ASSERT_EQ(PP_OK, rv);
378 ASSERT_EQ(std::string("test\0\0\0\0test\0\0\0\0", 16), read_buffer);
380 // Write in the middle of the file.
381 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 4, "test",
382 callback_type());
383 ASSERT_EQ(PP_OK, rv);
385 // Check the contents of the file.
386 read_buffer.clear();
387 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
388 callback_type());
389 ASSERT_EQ(PP_OK, rv);
390 ASSERT_EQ(std::string("testtesttest\0\0\0\0", 16), read_buffer);
392 // Read from the middle of the file.
393 read_buffer.clear();
394 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 4, &read_buffer,
395 callback_type());
396 ASSERT_EQ(PP_OK, rv);
397 ASSERT_EQ(std::string("testtest\0\0\0\0", 12), read_buffer);
399 PASS();
402 // This is basically a copy of TestReadWriteSetLength, but with the new Read
403 // API. With this test case, we can make sure the two Read's have the same
404 // behavior.
405 std::string TestFileIO::TestReadToArrayWriteSetLength() {
406 if (callback_type() == PP_BLOCKING) {
407 // This test does not make sense for blocking callbacks.
408 PASS();
410 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
412 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
413 pp::FileRef file_ref(file_system, "/file_read_write_setlength");
414 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
415 CHECK_CALLBACK_BEHAVIOR(callback);
416 ASSERT_EQ(PP_OK, callback.result());
418 pp::FileIO file_io(instance_);
419 callback.WaitForResult(file_io.Open(file_ref,
420 PP_FILEOPENFLAG_CREATE |
421 PP_FILEOPENFLAG_TRUNCATE |
422 PP_FILEOPENFLAG_READ |
423 PP_FILEOPENFLAG_WRITE,
424 callback.GetCallback()));
425 CHECK_CALLBACK_BEHAVIOR(callback);
426 ASSERT_EQ(PP_OK, callback.result());
428 // Write something to the file.
429 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
430 "test_test", callback_type());
431 ASSERT_EQ(PP_OK, rv);
433 TestCompletionCallbackWithOutput< std::vector<char> > callback2(
434 instance_->pp_instance(), callback_type());
435 // Attempt to read a negative number of bytes; it should fail.
436 callback2.WaitForResult(file_io.Read(0, -1, callback2.GetCallback()));
437 CHECK_CALLBACK_BEHAVIOR(callback2);
438 ASSERT_EQ(PP_ERROR_FAILED, callback2.result());
440 // Read the entire file.
441 std::string read_buffer;
442 read_buffer.reserve(10);
443 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
444 &read_buffer, callback_type());
445 ASSERT_EQ(PP_OK, rv);
446 ASSERT_EQ(std::string("test_test"), read_buffer);
448 // Truncate the file.
449 callback.WaitForResult(file_io.SetLength(4, callback.GetCallback()));
450 CHECK_CALLBACK_BEHAVIOR(callback);
451 ASSERT_EQ(PP_OK, rv);
453 // Check the file contents.
454 read_buffer.clear();
455 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
456 &read_buffer, callback_type());
457 ASSERT_EQ(PP_OK, rv);
458 ASSERT_EQ(std::string("test"), read_buffer);
460 // Try to read past the end of the file.
461 read_buffer.clear();
462 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 100,
463 &read_buffer, callback_type());
464 ASSERT_EQ(PP_OK, rv);
465 ASSERT_TRUE(read_buffer.empty());
467 // Write past the end of the file. The file should be zero-padded.
468 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 8, "test",
469 callback_type());
470 ASSERT_EQ(PP_OK, rv);
472 // Check the contents of the file.
473 read_buffer.clear();
474 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
475 &read_buffer, callback_type());
476 ASSERT_EQ(PP_OK, rv);
477 ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer);
479 // Extend the file.
480 callback.WaitForResult(file_io.SetLength(16, callback.GetCallback()));
481 CHECK_CALLBACK_BEHAVIOR(callback);
482 ASSERT_EQ(PP_OK, callback.result());
484 // Check the contents of the file.
485 read_buffer.clear();
486 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
487 &read_buffer, callback_type());
488 ASSERT_EQ(PP_OK, rv);
489 ASSERT_EQ(std::string("test\0\0\0\0test\0\0\0\0", 16), read_buffer);
491 // Write in the middle of the file.
492 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 4, "test",
493 callback_type());
494 ASSERT_EQ(PP_OK, rv);
496 // Check the contents of the file.
497 read_buffer.clear();
498 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
499 &read_buffer, callback_type());
500 ASSERT_EQ(PP_OK, rv);
501 ASSERT_EQ(std::string("testtesttest\0\0\0\0", 16), read_buffer);
503 // Read from the middle of the file.
504 read_buffer.clear();
505 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 4,
506 &read_buffer, callback_type());
507 ASSERT_EQ(PP_OK, rv);
508 ASSERT_EQ(std::string("testtest\0\0\0\0", 12), read_buffer);
510 PASS();
513 std::string TestFileIO::TestTouchQuery() {
514 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
516 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
517 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
518 CHECK_CALLBACK_BEHAVIOR(callback);
519 ASSERT_EQ(PP_OK, callback.result());
521 pp::FileRef file_ref(file_system, "/file_touch");
522 pp::FileIO file_io(instance_);
523 callback.WaitForResult(file_io.Open(file_ref,
524 PP_FILEOPENFLAG_CREATE |
525 PP_FILEOPENFLAG_TRUNCATE |
526 PP_FILEOPENFLAG_WRITE,
527 callback.GetCallback()));
528 CHECK_CALLBACK_BEHAVIOR(callback);
529 ASSERT_EQ(PP_OK, callback.result());
531 // Write some data to have a non-zero file size.
532 callback.WaitForResult(file_io.Write(0, "test", 4, callback.GetCallback()));
533 CHECK_CALLBACK_BEHAVIOR(callback);
534 ASSERT_EQ(4, callback.result());
536 // last_access_time's granularity is 1 day
537 // last_modified_time's granularity is 2 seconds
538 const PP_Time last_access_time = 123 * 24 * 3600.0;
539 const PP_Time last_modified_time = 246.0;
540 callback.WaitForResult(file_io.Touch(last_access_time, last_modified_time,
541 callback.GetCallback()));
542 CHECK_CALLBACK_BEHAVIOR(callback);
543 ASSERT_EQ(PP_OK, callback.result());
545 PP_FileInfo info;
546 callback.WaitForResult(file_io.Query(&info, callback.GetCallback()));
547 CHECK_CALLBACK_BEHAVIOR(callback);
548 ASSERT_EQ(PP_OK, callback.result());
550 if ((info.size != 4) ||
551 (info.type != PP_FILETYPE_REGULAR) ||
552 (info.system_type != PP_FILESYSTEMTYPE_LOCALTEMPORARY) ||
553 (info.last_access_time != last_access_time) ||
554 (info.last_modified_time != last_modified_time))
555 return "FileIO::Query() has returned bad data.";
557 // Call |Query()| again, to make sure it works a second time.
558 callback.WaitForResult(file_io.Query(&info, callback.GetCallback()));
559 CHECK_CALLBACK_BEHAVIOR(callback);
560 ASSERT_EQ(PP_OK, callback.result());
562 PASS();
565 std::string TestFileIO::TestAbortCalls() {
566 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
568 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
569 pp::FileRef file_ref(file_system, "/file_abort_calls");
570 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
571 CHECK_CALLBACK_BEHAVIOR(callback);
572 ASSERT_EQ(PP_OK, callback.result());
574 int32_t rv = PP_ERROR_FAILED;
575 // First, create a file on which to do ops.
577 pp::FileIO file_io(instance_);
578 callback.WaitForResult(
579 file_io.Open(file_ref,
580 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE,
581 callback.GetCallback()));
582 CHECK_CALLBACK_BEHAVIOR(callback);
583 ASSERT_EQ(PP_OK, callback.result());
585 // N.B.: Should write at least 3 bytes.
586 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
587 "foobarbazquux", callback_type());
588 ASSERT_EQ(PP_OK, rv);
591 // Abort |Open()|.
593 rv = pp::FileIO(instance_)
594 .Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback());
596 callback.WaitForAbortResult(rv);
597 CHECK_CALLBACK_BEHAVIOR(callback);
599 // Abort |Query()|.
601 PP_FileInfo info = { 0 };
602 // Save a copy and make sure |info| doesn't get written to if it is aborted.
603 PP_FileInfo info_copy;
604 memcpy(&info_copy, &info, sizeof(info));
606 pp::FileIO file_io(instance_);
607 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ,
608 callback.GetCallback()));
609 CHECK_CALLBACK_BEHAVIOR(callback);
610 ASSERT_EQ(PP_OK, callback.result());
612 rv = file_io.Query(&info, callback.GetCallback());
613 } // Destroy |file_io|.
614 callback.WaitForResult(rv);
615 CHECK_CALLBACK_BEHAVIOR(callback);
616 if (callback_type() == PP_BLOCKING) {
617 ASSERT_EQ(callback.result(), PP_OK);
618 // The operation completed synchronously, so |info| should have changed.
619 ASSERT_NE(0, memcmp(&info_copy, &info, sizeof(info)));
620 } else {
621 ASSERT_EQ(callback.result(), PP_ERROR_ABORTED);
622 ASSERT_EQ(0, memcmp(&info_copy, &info, sizeof(info)));
626 // Abort |Touch()|.
629 pp::FileIO file_io(instance_);
630 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE,
631 callback.GetCallback()));
632 CHECK_CALLBACK_BEHAVIOR(callback);
633 ASSERT_EQ(PP_OK, callback.result());
635 rv = file_io.Touch(0, 0, callback.GetCallback());
636 } // Destroy |file_io|.
637 callback.WaitForAbortResult(rv);
638 CHECK_CALLBACK_BEHAVIOR(callback);
641 // Abort |Read()|.
643 char buf[3] = { 0 };
645 pp::FileIO file_io(instance_);
646 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ,
647 callback.GetCallback()));
648 CHECK_CALLBACK_BEHAVIOR(callback);
649 ASSERT_EQ(PP_OK, callback.result());
651 rv = file_io.Read(0, buf, sizeof(buf), callback.GetCallback());
652 } // Destroy |file_io|.
653 // Save a copy to make sure buf isn't written to in the async case.
654 char buf_copy[3];
655 memcpy(&buf_copy, &buf, sizeof(buf));
656 callback.WaitForResult(rv);
657 CHECK_CALLBACK_BEHAVIOR(callback);
658 if (callback_type() == PP_BLOCKING) {
659 ASSERT_EQ(callback.result(), sizeof(buf));
660 } else {
661 ASSERT_EQ(callback.result(), PP_ERROR_ABORTED);
662 ASSERT_EQ(0, memcmp(&buf_copy, &buf, sizeof(buf)));
666 // Abort |Write()|.
668 char buf[3] = { 0 };
670 pp::FileIO file_io(instance_);
671 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE,
672 callback.GetCallback()));
673 CHECK_CALLBACK_BEHAVIOR(callback);
674 ASSERT_EQ(PP_OK, callback.result());
676 rv = file_io.Write(0, buf, sizeof(buf), callback.GetCallback());
677 } // Destroy |file_io|.
678 callback.WaitForResult(rv);
679 CHECK_CALLBACK_BEHAVIOR(callback);
680 if (callback_type() == PP_BLOCKING)
681 ASSERT_EQ(callback.result(), sizeof(buf));
682 else
683 ASSERT_EQ(callback.result(), PP_ERROR_ABORTED);
686 // Abort |SetLength()|.
689 pp::FileIO file_io(instance_);
690 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ,
691 callback.GetCallback()));
692 CHECK_CALLBACK_BEHAVIOR(callback);
693 ASSERT_EQ(PP_OK, callback.result());
695 rv = file_io.SetLength(3, callback.GetCallback());
696 } // Destroy |file_io|.
697 callback.WaitForAbortResult(rv);
698 CHECK_CALLBACK_BEHAVIOR(callback);
701 // Abort |Flush|.
704 pp::FileIO file_io(instance_);
705 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE,
706 callback.GetCallback()));
707 CHECK_CALLBACK_BEHAVIOR(callback);
708 ASSERT_EQ(PP_OK, callback.result());
710 rv = file_io.Flush(callback.GetCallback());
711 } // Destroy |file_io|.
712 callback.WaitForAbortResult(rv);
713 CHECK_CALLBACK_BEHAVIOR(callback);
716 PASS();
719 std::string TestFileIO::TestParallelReads() {
720 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
721 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
722 pp::FileRef file_ref(file_system, "/file_parallel_reads");
723 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
724 CHECK_CALLBACK_BEHAVIOR(callback);
725 ASSERT_EQ(PP_OK, callback.result());
727 pp::FileIO file_io(instance_);
728 callback.WaitForResult(file_io.Open(file_ref,
729 PP_FILEOPENFLAG_CREATE |
730 PP_FILEOPENFLAG_TRUNCATE |
731 PP_FILEOPENFLAG_READ |
732 PP_FILEOPENFLAG_WRITE,
733 callback.GetCallback()));
734 CHECK_CALLBACK_BEHAVIOR(callback);
735 ASSERT_EQ(PP_OK, callback.result());
737 // Set up testing contents.
738 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
739 "abcdefghijkl", callback_type());
740 ASSERT_EQ(PP_OK, rv);
742 // Parallel read operations.
743 const char* border = "__border__";
744 const int32_t border_size = strlen(border);
746 TestCompletionCallback callback_1(instance_->pp_instance(), callback_type());
747 int32_t read_offset_1 = 0;
748 int32_t size_1 = 3;
749 std::vector<char> extended_buf_1(border_size * 2 + size_1);
750 char* buf_1 = &extended_buf_1[border_size];
751 memcpy(&extended_buf_1[0], border, border_size);
752 memcpy(buf_1 + size_1, border, border_size);
754 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
755 int32_t read_offset_2 = size_1;
756 int32_t size_2 = 9;
757 std::vector<char> extended_buf_2(border_size * 2 + size_2);
758 char* buf_2 = &extended_buf_2[border_size];
759 memcpy(&extended_buf_2[0], border, border_size);
760 memcpy(buf_2 + size_2, border, border_size);
762 int32_t rv_1 = PP_OK;
763 int32_t rv_2 = PP_OK;
764 while (size_1 >= 0 && size_2 >= 0 && size_1 + size_2 > 0) {
765 if (size_1 > 0) {
766 rv_1 = file_io.Read(read_offset_1, buf_1, size_1,
767 callback_1.GetCallback());
769 if (size_2 > 0) {
770 rv_2 = file_io.Read(read_offset_2, buf_2, size_2,
771 callback_2.GetCallback());
773 if (size_1 > 0) {
774 callback_1.WaitForResult(rv_1);
775 CHECK_CALLBACK_BEHAVIOR(callback_1);
776 ASSERT_TRUE(callback_1.result() > 0);
777 read_offset_1 += callback_1.result();
778 buf_1 += callback_1.result();
779 size_1 -= callback_1.result();
782 if (size_2 > 0) {
783 callback_2.WaitForResult(rv_2);
784 CHECK_CALLBACK_BEHAVIOR(callback_2);
785 ASSERT_TRUE(callback_2.result() > 0);
786 read_offset_2 += callback_2.result();
787 buf_2 += callback_2.result();
788 size_2 -= callback_2.result();
792 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s).
793 ASSERT_EQ(0, size_1);
794 ASSERT_EQ(0, size_2);
796 // Make sure every read operation writes into the correct buffer.
797 const char expected_result_1[] = "__border__abc__border__";
798 const char expected_result_2[] = "__border__defghijkl__border__";
799 ASSERT_TRUE(strncmp(&extended_buf_1[0], expected_result_1,
800 strlen(expected_result_1)) == 0);
801 ASSERT_TRUE(strncmp(&extended_buf_2[0], expected_result_2,
802 strlen(expected_result_2)) == 0);
803 PASS();
806 std::string TestFileIO::TestParallelWrites() {
807 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
808 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
809 pp::FileRef file_ref(file_system, "/file_parallel_writes");
810 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
811 CHECK_CALLBACK_BEHAVIOR(callback);
812 ASSERT_EQ(PP_OK, callback.result());
814 pp::FileIO file_io(instance_);
815 callback.WaitForResult(file_io.Open(file_ref,
816 PP_FILEOPENFLAG_CREATE |
817 PP_FILEOPENFLAG_TRUNCATE |
818 PP_FILEOPENFLAG_READ |
819 PP_FILEOPENFLAG_WRITE,
820 callback.GetCallback()));
821 CHECK_CALLBACK_BEHAVIOR(callback);
822 ASSERT_EQ(PP_OK, callback.result());
824 // Parallel write operations.
825 TestCompletionCallback callback_1(instance_->pp_instance(), callback_type());
826 int32_t write_offset_1 = 0;
827 const char* buf_1 = "abc";
828 int32_t size_1 = strlen(buf_1);
830 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
831 int32_t write_offset_2 = size_1;
832 const char* buf_2 = "defghijkl";
833 int32_t size_2 = strlen(buf_2);
835 int32_t rv_1 = PP_OK;
836 int32_t rv_2 = PP_OK;
837 while (size_1 >= 0 && size_2 >= 0 && size_1 + size_2 > 0) {
838 if (size_1 > 0) {
839 rv_1 = file_io.Write(write_offset_1, buf_1, size_1,
840 callback_1.GetCallback());
842 if (size_2 > 0) {
843 rv_2 = file_io.Write(write_offset_2, buf_2, size_2,
844 callback_2.GetCallback());
847 if (size_1 > 0) {
848 callback_1.WaitForResult(rv_1);
849 CHECK_CALLBACK_BEHAVIOR(callback_1);
850 ASSERT_TRUE(callback_1.result() > 0);
851 write_offset_1 += callback_1.result();
852 buf_1 += callback_1.result();
853 size_1 -= callback_1.result();
856 if (size_2 > 0) {
857 callback_2.WaitForResult(rv_2);
858 CHECK_CALLBACK_BEHAVIOR(callback_2);
859 ASSERT_TRUE(callback_2.result() > 0);
860 write_offset_2 += callback_2.result();
861 buf_2 += callback_2.result();
862 size_2 -= callback_2.result();
866 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s).
867 ASSERT_EQ(0, size_1);
868 ASSERT_EQ(0, size_2);
870 // Check the file contents.
871 std::string read_buffer;
872 int32_t rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0,
873 &read_buffer, callback_type());
874 ASSERT_EQ(PP_OK, rv);
875 ASSERT_EQ(std::string("abcdefghijkl"), read_buffer);
877 PASS();
880 std::string TestFileIO::TestNotAllowMixedReadWrite() {
881 if (callback_type() == PP_BLOCKING) {
882 // This test does not make sense for blocking callbacks.
883 PASS();
885 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
887 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
888 pp::FileRef file_ref(file_system, "/file_not_allow_mixed_read_write");
889 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
890 CHECK_CALLBACK_BEHAVIOR(callback);
891 ASSERT_EQ(PP_OK, callback.result());
893 pp::FileIO file_io(instance_);
894 callback.WaitForResult(file_io.Open(file_ref,
895 PP_FILEOPENFLAG_CREATE |
896 PP_FILEOPENFLAG_TRUNCATE |
897 PP_FILEOPENFLAG_READ |
898 PP_FILEOPENFLAG_WRITE,
899 callback.GetCallback()));
900 CHECK_CALLBACK_BEHAVIOR(callback);
901 ASSERT_EQ(PP_OK, callback.result());
903 TestCompletionCallback callback_1(instance_->pp_instance(), PP_REQUIRED);
904 int32_t write_offset_1 = 0;
905 const char* buf_1 = "mnopqrstuvw";
906 int32_t rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1),
907 callback_1.GetCallback());
908 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
910 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
911 int32_t read_offset_2 = 4;
912 char buf_2[3];
913 callback_2.WaitForResult(file_io.Read(read_offset_2, buf_2, sizeof(buf_2),
914 callback_2.GetCallback()));
915 CHECK_CALLBACK_BEHAVIOR(callback_2);
916 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
917 callback_1.WaitForResult(rv_1);
918 CHECK_CALLBACK_BEHAVIOR(callback_1);
920 // Cannot query while a write is pending.
921 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1),
922 callback_1.GetCallback());
923 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
924 PP_FileInfo info;
925 callback_2.WaitForResult(file_io.Query(&info, callback_2.GetCallback()));
926 CHECK_CALLBACK_BEHAVIOR(callback_2);
927 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
928 callback_1.WaitForResult(rv_1);
929 CHECK_CALLBACK_BEHAVIOR(callback_1);
931 // Cannot touch while a write is pending.
932 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1),
933 callback_1.GetCallback());
934 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
935 callback_2.WaitForResult(file_io.Touch(1234.0, 5678.0,
936 callback_2.GetCallback()));
937 CHECK_CALLBACK_BEHAVIOR(callback_2);
938 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
939 callback_1.WaitForResult(rv_1);
940 CHECK_CALLBACK_BEHAVIOR(callback_1);
942 // Cannot set length while a write is pending.
943 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1),
944 callback_1.GetCallback());
945 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
946 callback_2.WaitForResult(file_io.SetLength(123, callback_2.GetCallback()));
947 CHECK_CALLBACK_BEHAVIOR(callback_2);
948 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
949 callback_1.WaitForResult(rv_1);
950 CHECK_CALLBACK_BEHAVIOR(callback_1);
952 PASS();
955 std::string TestFileIO::TestWillWriteWillSetLength() {
956 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
958 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
959 pp::FileRef file_ref(file_system, "/file_will_write");
960 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
961 CHECK_CALLBACK_BEHAVIOR(callback);
962 ASSERT_EQ(PP_OK, callback.result());
964 pp::FileIO file_io(instance_);
965 callback.WaitForResult(file_io.Open(file_ref,
966 PP_FILEOPENFLAG_CREATE |
967 PP_FILEOPENFLAG_TRUNCATE |
968 PP_FILEOPENFLAG_READ |
969 PP_FILEOPENFLAG_WRITE,
970 callback.GetCallback()));
971 CHECK_CALLBACK_BEHAVIOR(callback);
972 ASSERT_EQ(PP_OK, callback.result());
974 const PPB_FileIOTrusted* trusted = static_cast<const PPB_FileIOTrusted*>(
975 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE));
976 ASSERT_TRUE(trusted);
978 // Get file descriptor. This is only supported in-process for now, so don't
979 // test out of process.
980 const PPB_Testing_Dev* testing_interface = GetTestingInterface();
981 if (testing_interface && !testing_interface->IsOutOfProcess()) {
982 int32_t fd = trusted->GetOSFileDescriptor(file_io.pp_resource());
983 ASSERT_TRUE(fd >= 0);
986 // Calling WillWrite.
987 callback.WaitForResult(trusted->WillWrite(
988 file_io.pp_resource(), 0, 9,
989 callback.GetCallback().pp_completion_callback()));
990 CHECK_CALLBACK_BEHAVIOR(callback);
991 ASSERT_EQ(9, callback.result());
993 // Writing the actual data.
994 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
995 "test_test", callback_type());
996 ASSERT_EQ(PP_OK, rv);
998 std::string read_buffer;
999 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
1000 callback_type());
1001 ASSERT_EQ(PP_OK, rv);
1002 ASSERT_EQ(std::string("test_test"), read_buffer);
1004 // Calling WillSetLength.
1005 callback.WaitForResult(trusted->WillSetLength(
1006 file_io.pp_resource(), 4,
1007 callback.GetCallback().pp_completion_callback()));
1008 CHECK_CALLBACK_BEHAVIOR(callback);
1009 ASSERT_EQ(PP_OK, rv);
1011 // Calling actual SetLength.
1012 callback.WaitForResult(file_io.SetLength(4, callback.GetCallback()));
1013 CHECK_CALLBACK_BEHAVIOR(callback);
1014 ASSERT_EQ(PP_OK, rv);
1016 read_buffer.clear();
1017 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
1018 callback_type());
1019 ASSERT_EQ(PP_OK, rv);
1020 ASSERT_EQ(std::string("test"), read_buffer);
1022 PASS();
1025 std::string TestFileIO::TestRequestOSFileHandle() {
1026 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1028 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
1029 pp::FileRef file_ref(file_system, "/file_os_fd");
1031 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
1032 if (callback.result() != PP_OK)
1033 return ReportError("FileSystem::Open", callback.result());
1035 pp::FileIO_Private file_io(instance_);
1036 callback.WaitForResult(file_io.Open(file_ref,
1037 PP_FILEOPENFLAG_CREATE |
1038 PP_FILEOPENFLAG_TRUNCATE |
1039 PP_FILEOPENFLAG_READ |
1040 PP_FILEOPENFLAG_WRITE,
1041 callback.GetCallback()));
1042 if (callback.result() != PP_OK)
1043 return ReportError("FileIO::Open", callback.result());
1045 PP_FileHandle handle = PP_kInvalidFileHandle;
1046 callback.WaitForResult(
1047 file_io.RequestOSFileHandle(&handle, callback.GetCallback()));
1048 if (callback.result() != PP_OK)
1049 return ReportError("FileIO::RequestOSFileHandle", callback.result());
1051 if (handle == PP_kInvalidFileHandle)
1052 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1053 #if defined(PPAPI_OS_WIN)
1054 int fd = _open_osfhandle(reinterpret_cast<intptr_t>(handle),
1055 _O_RDWR | _O_BINARY);
1056 #else
1057 int fd = handle;
1058 #endif
1059 if (fd < 0)
1060 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1062 // Check write(2) for the native FD.
1063 const std::string msg = "foobar";
1064 ssize_t cnt = write(fd, msg.data(), msg.size());
1065 if (cnt < 0)
1066 return ReportError("write for native FD returned error", errno);
1067 if (cnt != static_cast<ssize_t>(msg.size()))
1068 return ReportError("write for native FD count mismatch", cnt);
1070 // Check lseek(2) for the native FD.
1071 off_t off = lseek(fd, 0, SEEK_CUR);
1072 if (off == static_cast<off_t>(-1))
1073 return ReportError("lseek for native FD returned error", errno);
1074 if (off != static_cast<off_t>(msg.size()))
1075 return ReportError("lseek for native FD offset mismatch", off);
1077 off = lseek(fd, 0, SEEK_SET);
1078 if (off == static_cast<off_t>(-1))
1079 return ReportError("lseek for native FD returned error", errno);
1080 if (off != 0)
1081 return ReportError("lseek for native FD offset mismatch", off);
1083 // Check read(2) for the native FD.
1084 std::string buf(msg.size(), '\0');
1085 cnt = read(fd, &buf[0], msg.size());
1086 if (cnt < 0)
1087 return ReportError("read for native FD returned error", errno);
1088 if (cnt != static_cast<ssize_t>(msg.size()))
1089 return ReportError("read for native FD count mismatch", cnt);
1090 if (msg != buf)
1091 return ReportMismatch("read for native FD", buf, msg);
1093 // TODO(hamaji): Test CreateFileMapping for windows.
1094 #if !defined(PPAPI_OS_WIN)
1095 // Check mmap(2) for read.
1096 char* mapped = reinterpret_cast<char*>(
1097 mmap(NULL, msg.size(), PROT_READ, MAP_PRIVATE, fd, 0));
1098 if (mapped == MAP_FAILED)
1099 return ReportError("mmap(r) for native FD returned errno", errno);
1100 // Make sure the buffer is cleared.
1101 buf = std::string(msg.size(), '\0');
1102 memcpy(&buf[0], mapped, msg.size());
1103 if (msg != buf)
1104 return ReportMismatch("mmap(r) for native FD", buf, msg);
1105 int r = munmap(mapped, msg.size());
1106 if (r < 0)
1107 return ReportError("munmap for native FD returned error", errno);
1109 // Check mmap(2) for write.
1110 mapped = reinterpret_cast<char*>(
1111 mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
1112 if (mapped == MAP_FAILED)
1113 return ReportError("mmap(w) for native FD returned errno", errno);
1114 // s/foo/baz/
1115 strcpy(mapped, "baz");
1117 r = munmap(mapped, msg.size());
1118 if (r < 0)
1119 return ReportError("munmap for native FD returned error", errno);
1120 #endif
1122 #if defined(PPAPI_OS_WIN)
1123 int r = _close(fd);
1124 #else
1125 r = close(handle);
1126 #endif
1127 if (r < 0)
1128 return ReportError("close for native FD returned error", errno);
1130 // TODO(hamaji): Check if the file is actually updated?
1132 PASS();
1135 std::string TestFileIO::MatchOpenExpectations(pp::FileSystem* file_system,
1136 size_t open_flags,
1137 size_t expectations) {
1138 std::string bad_argument =
1139 "TestFileIO::MatchOpenExpectations has invalid input arguments.";
1140 bool invalid_combination = !!(expectations & INVALID_FLAG_COMBINATION);
1141 if (invalid_combination) {
1142 if (expectations != INVALID_FLAG_COMBINATION)
1143 return bad_argument;
1144 } else {
1145 // Validate that one and only one of <some_expectation> and
1146 // DONT_<some_expectation> is specified.
1147 for (size_t remains = expectations, end = END_OF_OPEN_EXPECATION_PAIRS;
1148 end != 0; remains >>= 2, end >>= 2) {
1149 if (!!(remains & 1) == !!(remains & 2))
1150 return bad_argument;
1153 bool create_if_doesnt_exist = !!(expectations & CREATE_IF_DOESNT_EXIST);
1154 bool open_if_exists = !!(expectations & OPEN_IF_EXISTS);
1155 bool truncate_if_exists = !!(expectations & TRUNCATE_IF_EXISTS);
1157 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1158 pp::FileRef existent_file_ref(
1159 *file_system, "/match_open_expectation_existent_non_empty_file");
1160 pp::FileRef nonexistent_file_ref(
1161 *file_system, "/match_open_expectation_nonexistent_file");
1163 // Setup files for test.
1165 callback.WaitForResult(existent_file_ref.Delete(callback.GetCallback()));
1166 CHECK_CALLBACK_BEHAVIOR(callback);
1167 ASSERT_TRUE(callback.result() == PP_OK ||
1168 callback.result() == PP_ERROR_FILENOTFOUND);
1169 callback.WaitForResult(nonexistent_file_ref.Delete(callback.GetCallback()));
1170 CHECK_CALLBACK_BEHAVIOR(callback);
1171 ASSERT_TRUE(callback.result() == PP_OK ||
1172 callback.result() == PP_ERROR_FILENOTFOUND);
1174 pp::FileIO existent_file_io(instance_);
1175 callback.WaitForResult(existent_file_io.Open(
1176 existent_file_ref,
1177 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE,
1178 callback.GetCallback()));
1179 CHECK_CALLBACK_BEHAVIOR(callback);
1180 ASSERT_EQ(PP_OK, callback.result());
1181 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &existent_file_io,
1182 0, "foobar", callback_type());
1183 ASSERT_EQ(PP_OK, rv);
1186 pp::FileIO existent_file_io(instance_);
1187 callback.WaitForResult(existent_file_io.Open(existent_file_ref, open_flags,
1188 callback.GetCallback()));
1189 CHECK_CALLBACK_BEHAVIOR(callback);
1190 if ((invalid_combination && callback.result() == PP_OK) ||
1191 (!invalid_combination &&
1192 ((callback.result() == PP_OK) != open_if_exists))) {
1193 return ReportOpenError(open_flags);
1196 if (!invalid_combination && open_if_exists) {
1197 PP_FileInfo info;
1198 callback.WaitForResult(existent_file_io.Query(&info,
1199 callback.GetCallback()));
1200 CHECK_CALLBACK_BEHAVIOR(callback);
1201 ASSERT_EQ(PP_OK, callback.result());
1202 if (truncate_if_exists != (info.size == 0))
1203 return ReportOpenError(open_flags);
1206 pp::FileIO nonexistent_file_io(instance_);
1207 callback.WaitForResult(nonexistent_file_io.Open(nonexistent_file_ref,
1208 open_flags,
1209 callback.GetCallback()));
1210 CHECK_CALLBACK_BEHAVIOR(callback);
1211 if ((invalid_combination && callback.result() == PP_OK) ||
1212 (!invalid_combination &&
1213 ((callback.result() == PP_OK) != create_if_doesnt_exist))) {
1214 return ReportOpenError(open_flags);
1217 return std::string();
1220 // TODO(viettrungluu): Test Close(). crbug.com/69457