1 // Copyright (c) 2011 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_ref.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/c/ppb_file_io.h"
14 #include "ppapi/c/dev/ppb_testing_dev.h"
15 #include "ppapi/cpp/directory_entry.h"
16 #include "ppapi/cpp/file_io.h"
17 #include "ppapi/cpp/file_ref.h"
18 #include "ppapi/cpp/file_system.h"
19 #include "ppapi/cpp/instance.h"
20 #include "ppapi/cpp/module.h"
21 #include "ppapi/cpp/url_loader.h"
22 #include "ppapi/cpp/url_request_info.h"
23 #include "ppapi/cpp/url_response_info.h"
24 #include "ppapi/tests/test_utils.h"
25 #include "ppapi/tests/testing_instance.h"
27 REGISTER_TEST_CASE(FileRef);
31 const char* kPersFileName = "persistent";
32 const char* kTempFileName = "temporary";
33 const char* kParentPath = "/foo/bar";
34 const char* kPersFilePath = "/foo/bar/persistent";
35 const char* kTempFilePath = "/foo/bar/temporary";
36 const char* kTerribleName = "!@#$%^&*()-_=+{}[] ;:'\"|`~\t\n\r\b?";
38 typedef std::vector<pp::DirectoryEntry> DirEntries;
40 std::string ReportMismatch(const std::string& method_name,
41 const std::string& returned_result,
42 const std::string& expected_result) {
43 return method_name + " returned '" + returned_result + "'; '" +
44 expected_result + "' expected.";
49 bool TestFileRef::Init() {
50 return CheckTestingInterface() && EnsureRunningOverHTTP();
53 std::string TestFileRef::MakeExternalFileRef(pp::FileRef* file_ref_ext) {
54 pp::URLRequestInfo request(instance_);
55 request.SetURL("test_url_loader_data/hello.txt");
56 request.SetStreamToFile(true);
58 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
60 pp::URLLoader loader(instance_);
61 callback.WaitForResult(loader.Open(request, callback.GetCallback()));
62 CHECK_CALLBACK_BEHAVIOR(callback);
63 ASSERT_EQ(PP_OK, callback.result());
65 pp::URLResponseInfo response_info(loader.GetResponseInfo());
66 ASSERT_FALSE(response_info.is_null());
67 ASSERT_EQ(200, response_info.GetStatusCode());
69 *file_ref_ext = pp::FileRef(response_info.GetBodyAsFileRef());
70 ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, file_ref_ext->GetFileSystemType());
74 int32_t TestFileRef::DeleteDirectoryRecursively(pp::FileRef* dir) {
76 return PP_ERROR_BADARGUMENT;
78 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
79 TestCompletionCallbackWithOutput<DirEntries> output_callback(
80 instance_->pp_instance(), callback_type());
82 output_callback.WaitForResult(
83 dir->ReadDirectoryEntries(output_callback.GetCallback()));
84 int32_t rv = output_callback.result();
85 if (rv != PP_OK && rv != PP_ERROR_FILENOTFOUND)
88 DirEntries entries = output_callback.output();
89 for (DirEntries::const_iterator it = entries.begin();
92 pp::FileRef file_ref = it->file_ref();
93 if (it->file_type() == PP_FILETYPE_DIRECTORY) {
94 rv = DeleteDirectoryRecursively(&file_ref);
95 if (rv != PP_OK && rv != PP_ERROR_FILENOTFOUND)
98 callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
99 rv = callback.result();
100 if (rv != PP_OK && rv != PP_ERROR_FILENOTFOUND)
104 callback.WaitForResult(dir->Delete(callback.GetCallback()));
105 return callback.result();
108 void TestFileRef::RunTests(const std::string& filter) {
109 RUN_CALLBACK_TEST(TestFileRef, Create, filter);
110 RUN_CALLBACK_TEST(TestFileRef, GetFileSystemType, filter);
111 RUN_CALLBACK_TEST(TestFileRef, GetName, filter);
112 RUN_CALLBACK_TEST(TestFileRef, GetPath, filter);
113 RUN_CALLBACK_TEST(TestFileRef, GetParent, filter);
114 RUN_CALLBACK_TEST(TestFileRef, MakeDirectory, filter);
115 RUN_CALLBACK_TEST(TestFileRef, QueryAndTouchFile, filter);
116 RUN_CALLBACK_TEST(TestFileRef, DeleteFileAndDirectory, filter);
117 RUN_CALLBACK_TEST(TestFileRef, RenameFileAndDirectory, filter);
118 RUN_CALLBACK_TEST(TestFileRef, Query, filter);
119 RUN_CALLBACK_TEST(TestFileRef, FileNameEscaping, filter);
120 RUN_CALLBACK_TEST(TestFileRef, ReadDirectoryEntries, filter);
123 std::string TestFileRef::TestCreate() {
124 std::vector<std::string> invalid_paths;
125 invalid_paths.push_back("invalid_path"); // no '/' at the first character
126 invalid_paths.push_back(std::string()); // empty path
127 // The following are directory traversal checks
128 invalid_paths.push_back("..");
129 invalid_paths.push_back("/../invalid_path");
130 invalid_paths.push_back("/../../invalid_path");
131 invalid_paths.push_back("/invalid/../../path");
132 const size_t num_invalid_paths = invalid_paths.size();
134 pp::FileSystem file_system_pers(
135 instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
136 pp::FileSystem file_system_temp(
137 instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
138 for (size_t j = 0; j < num_invalid_paths; ++j) {
139 pp::FileRef file_ref_pers(file_system_pers, invalid_paths[j].c_str());
140 if (file_ref_pers.pp_resource() != 0) {
141 return "file_ref_pers expected to be invalid for path: " +
144 pp::FileRef file_ref_temp(file_system_temp, invalid_paths[j].c_str());
145 if (file_ref_temp.pp_resource() != 0) {
146 return "file_ref_temp expected to be invalid for path: " +
153 std::string TestFileRef::TestGetFileSystemType() {
154 pp::FileSystem file_system_pers(
155 instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
156 pp::FileSystem file_system_temp(
157 instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
159 pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
160 if (file_ref_pers.GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALPERSISTENT)
161 return "file_ref_pers expected to be persistent.";
163 pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
164 if (file_ref_temp.GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALTEMPORARY)
165 return "file_ref_temp expected to be temporary.";
167 pp::FileRef file_ref_ext;
168 std::string result = MakeExternalFileRef(&file_ref_ext);
174 std::string TestFileRef::TestGetName() {
175 pp::FileSystem file_system_pers(
176 instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
177 pp::FileSystem file_system_temp(
178 instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
180 pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
181 std::string name = file_ref_pers.GetName().AsString();
182 if (name != kPersFileName)
183 return ReportMismatch("FileRef::GetName", name, kPersFileName);
185 pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
186 name = file_ref_temp.GetName().AsString();
187 if (name != kTempFileName)
188 return ReportMismatch("FileRef::GetName", name, kTempFileName);
190 // Test the "/" case.
191 pp::FileRef file_ref_slash(file_system_temp, "/");
192 name = file_ref_slash.GetName().AsString();
194 return ReportMismatch("FileRef::GetName", name, "/");
196 pp::URLRequestInfo request(instance_);
197 request.SetURL("test_url_loader_data/hello.txt");
198 request.SetStreamToFile(true);
200 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
202 pp::URLLoader loader(instance_);
203 callback.WaitForResult(loader.Open(request, callback.GetCallback()));
204 CHECK_CALLBACK_BEHAVIOR(callback);
205 ASSERT_EQ(PP_OK, callback.result());
207 pp::URLResponseInfo response_info(loader.GetResponseInfo());
208 ASSERT_FALSE(response_info.is_null());
209 ASSERT_EQ(200, response_info.GetStatusCode());
211 pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
212 name = file_ref_ext.GetName().AsString();
213 ASSERT_FALSE(name.empty());
218 std::string TestFileRef::TestGetPath() {
219 pp::FileSystem file_system_pers(
220 instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
221 pp::FileSystem file_system_temp(
222 instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
224 pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
225 ASSERT_EQ(kPersFilePath, file_ref_pers.GetPath().AsString());
227 pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
228 ASSERT_EQ(kTempFilePath, file_ref_temp.GetPath().AsString());
230 pp::URLRequestInfo request(instance_);
231 request.SetURL("test_url_loader_data/hello.txt");
232 request.SetStreamToFile(true);
234 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
236 pp::URLLoader loader(instance_);
237 callback.WaitForResult(loader.Open(request, callback.GetCallback()));
238 CHECK_CALLBACK_BEHAVIOR(callback);
239 ASSERT_EQ(PP_OK, callback.result());
241 pp::URLResponseInfo response_info(loader.GetResponseInfo());
242 ASSERT_FALSE(response_info.is_null());
243 ASSERT_EQ(200, response_info.GetStatusCode());
245 pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
246 ASSERT_TRUE(file_ref_ext.GetPath().is_undefined());
251 std::string TestFileRef::TestGetParent() {
252 pp::FileSystem file_system_pers(
253 instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
254 pp::FileSystem file_system_temp(
255 instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
257 pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
258 ASSERT_EQ(kParentPath, file_ref_pers.GetParent().GetPath().AsString());
260 pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
261 ASSERT_EQ(kParentPath, file_ref_temp.GetParent().GetPath().AsString());
263 // Test the "/" case.
264 pp::FileRef file_ref_slash(file_system_temp, "/");
265 ASSERT_EQ("/", file_ref_slash.GetParent().GetPath().AsString());
267 // Test the "/foo" case (the parent is "/").
268 pp::FileRef file_ref_with_root_parent(file_system_temp, "/foo");
269 ASSERT_EQ("/", file_ref_with_root_parent.GetParent().GetPath().AsString());
271 pp::URLRequestInfo request(instance_);
272 request.SetURL("test_url_loader_data/hello.txt");
273 request.SetStreamToFile(true);
275 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
277 pp::URLLoader loader(instance_);
278 callback.WaitForResult(loader.Open(request, callback.GetCallback()));
279 CHECK_CALLBACK_BEHAVIOR(callback);
280 ASSERT_EQ(PP_OK, callback.result());
282 pp::URLResponseInfo response_info(loader.GetResponseInfo());
283 ASSERT_FALSE(response_info.is_null());
284 ASSERT_EQ(200, response_info.GetStatusCode());
286 pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
287 ASSERT_TRUE(file_ref_ext.GetParent().is_null());
292 std::string TestFileRef::TestMakeDirectory() {
293 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
296 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
297 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
298 CHECK_CALLBACK_BEHAVIOR(callback);
299 ASSERT_EQ(PP_OK, callback.result());
302 pp::FileRef dir_ref(file_system, "/test_dir_make_directory");
303 callback.WaitForResult(dir_ref.MakeDirectory(callback.GetCallback()));
304 CHECK_CALLBACK_BEHAVIOR(callback);
305 ASSERT_EQ(PP_OK, callback.result());
307 // MakeDirectory aborted.
308 int32_t rv = PP_ERROR_FAILED;
310 rv = pp::FileRef(file_system, "/test_dir_make_abort")
311 .MakeDirectory(callback.GetCallback());
313 callback.WaitForAbortResult(rv);
314 CHECK_CALLBACK_BEHAVIOR(callback);
316 // MakeDirectoryIncludingAncestors.
317 dir_ref = pp::FileRef(file_system, "/dir_make_dir_1/dir_make_dir_2");
318 callback.WaitForResult(
319 dir_ref.MakeDirectoryIncludingAncestors(callback.GetCallback()));
320 CHECK_CALLBACK_BEHAVIOR(callback);
321 ASSERT_EQ(PP_OK, callback.result());
323 // MakeDirectoryIncludingAncestors aborted.
325 rv = pp::FileRef(file_system, "/dir_make_abort_1/dir_make_abort_2")
326 .MakeDirectoryIncludingAncestors(callback.GetCallback());
328 callback.WaitForAbortResult(rv);
329 CHECK_CALLBACK_BEHAVIOR(callback);
331 // MakeDirectory with nested path should fail.
332 dir_ref = pp::FileRef(file_system, "/dir_make_dir_3/dir_make_dir_4");
333 callback.WaitForResult(dir_ref.MakeDirectory(callback.GetCallback()));
334 CHECK_CALLBACK_BEHAVIOR(callback);
335 ASSERT_NE(PP_OK, callback.result());
340 std::string TestFileRef::TestQueryAndTouchFile() {
341 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
342 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
343 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
344 CHECK_CALLBACK_BEHAVIOR(callback);
345 ASSERT_EQ(PP_OK, callback.result());
347 pp::FileRef file_ref(file_system, "/file_touch");
348 pp::FileIO file_io(instance_);
349 callback.WaitForResult(
350 file_io.Open(file_ref,
351 PP_FILEOPENFLAG_CREATE |
352 PP_FILEOPENFLAG_TRUNCATE |
353 PP_FILEOPENFLAG_WRITE,
354 callback.GetCallback()));
355 CHECK_CALLBACK_BEHAVIOR(callback);
356 ASSERT_EQ(PP_OK, callback.result());
358 // Write some data to have a non-zero file size.
359 callback.WaitForResult(file_io.Write(0, "test", 4, callback.GetCallback()));
360 CHECK_CALLBACK_BEHAVIOR(callback);
361 ASSERT_EQ(4, callback.result());
364 const PP_Time last_access_time = 123 * 24 * 3600.0;
365 // last_modified_time's granularity is 2 seconds
366 // See note in test_file_io.cc for why we use this time.
367 const PP_Time last_modified_time = 100 * 24 * 3600.0;
368 callback.WaitForResult(file_ref.Touch(last_access_time, last_modified_time,
369 callback.GetCallback()));
370 CHECK_CALLBACK_BEHAVIOR(callback);
371 ASSERT_EQ(PP_OK, callback.result());
374 int32_t rv = PP_ERROR_FAILED;
376 rv = pp::FileRef(file_system, "/file_touch_abort")
377 .Touch(last_access_time, last_modified_time, callback.GetCallback());
379 callback.WaitForResult(rv);
380 CHECK_CALLBACK_BEHAVIOR(callback);
381 if (rv == PP_OK_COMPLETIONPENDING) {
382 // Touch tried to run asynchronously and should have been aborted.
383 ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
385 // Touch ran synchronously and should have failed because the file does not
387 ASSERT_EQ(PP_ERROR_FILENOTFOUND, callback.result());
392 callback.WaitForResult(file_io.Query(&info, callback.GetCallback()));
393 CHECK_CALLBACK_BEHAVIOR(callback);
394 ASSERT_EQ(PP_OK, callback.result());
395 ASSERT_EQ(4, info.size);
396 ASSERT_EQ(PP_FILETYPE_REGULAR, info.type);
397 ASSERT_EQ(PP_FILESYSTEMTYPE_LOCALTEMPORARY, info.system_type);
399 // Disabled due to DST-related failure: crbug.com/314579
400 // ASSERT_EQ(last_access_time, info.last_access_time);
401 // ASSERT_EQ(last_modified_time, info.last_modified_time);
403 // Cancellation test.
404 // TODO(viettrungluu): this test causes a bunch of LOG(WARNING)s; investigate.
405 // TODO(viettrungluu): check |info| for late writes.
407 rv = pp::FileRef(file_system, "/file_touch").Touch(
408 last_access_time, last_modified_time, callback.GetCallback());
410 callback.WaitForAbortResult(rv);
411 CHECK_CALLBACK_BEHAVIOR(callback);
416 std::string TestFileRef::TestDeleteFileAndDirectory() {
417 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
418 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
419 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
420 CHECK_CALLBACK_BEHAVIOR(callback);
421 ASSERT_EQ(PP_OK, callback.result());
423 pp::FileRef file_ref(file_system, "/file_delete");
424 pp::FileIO file_io(instance_);
425 callback.WaitForResult(
426 file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE, callback.GetCallback()));
427 CHECK_CALLBACK_BEHAVIOR(callback);
428 ASSERT_EQ(PP_OK, callback.result());
430 callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
431 CHECK_CALLBACK_BEHAVIOR(callback);
432 ASSERT_EQ(PP_OK, callback.result());
434 pp::FileRef dir_ref(file_system, "/dir_delete");
435 callback.WaitForResult(dir_ref.MakeDirectory(callback.GetCallback()));
436 CHECK_CALLBACK_BEHAVIOR(callback);
437 ASSERT_EQ(PP_OK, callback.result());
439 callback.WaitForResult(dir_ref.Delete(callback.GetCallback()));
440 CHECK_CALLBACK_BEHAVIOR(callback);
441 ASSERT_EQ(PP_OK, callback.result());
443 pp::FileRef nested_dir_ref(file_system, "/dir_delete_1/dir_delete_2");
444 callback.WaitForResult(
445 nested_dir_ref.MakeDirectoryIncludingAncestors(callback.GetCallback()));
446 CHECK_CALLBACK_BEHAVIOR(callback);
447 ASSERT_EQ(PP_OK, callback.result());
449 // Attempt to delete the parent directory (should fail; it's non-empty).
450 pp::FileRef parent_dir_ref = nested_dir_ref.GetParent();
451 callback.WaitForResult(parent_dir_ref.Delete(callback.GetCallback()));
452 CHECK_CALLBACK_BEHAVIOR(callback);
453 ASSERT_EQ(PP_ERROR_FAILED, callback.result());
455 pp::FileRef nonexistent_file_ref(file_system, "/nonexistent_file_delete");
456 callback.WaitForResult(nonexistent_file_ref.Delete(callback.GetCallback()));
457 CHECK_CALLBACK_BEHAVIOR(callback);
458 ASSERT_EQ(PP_ERROR_FILENOTFOUND, callback.result());
461 int32_t rv = PP_ERROR_FAILED;
463 pp::FileRef file_ref_abort(file_system, "/file_delete_abort");
464 pp::FileIO file_io_abort(instance_);
465 callback.WaitForResult(
466 file_io_abort.Open(file_ref_abort, PP_FILEOPENFLAG_CREATE,
467 callback.GetCallback()));
468 CHECK_CALLBACK_BEHAVIOR(callback);
469 ASSERT_EQ(PP_OK, callback.result());
470 rv = file_ref_abort.Delete(callback.GetCallback());
472 callback.WaitForAbortResult(rv);
473 CHECK_CALLBACK_BEHAVIOR(callback);
478 std::string TestFileRef::TestRenameFileAndDirectory() {
479 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
480 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
481 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
482 CHECK_CALLBACK_BEHAVIOR(callback);
483 ASSERT_EQ(PP_OK, callback.result());
485 pp::FileRef file_ref(file_system, "/file_rename");
486 pp::FileIO file_io(instance_);
487 callback.WaitForResult(
488 file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE, callback.GetCallback()));
489 CHECK_CALLBACK_BEHAVIOR(callback);
490 ASSERT_EQ(PP_OK, callback.result());
492 pp::FileRef target_file_ref(file_system, "/target_file_rename");
493 callback.WaitForResult(
494 file_ref.Rename(target_file_ref, callback.GetCallback()));
495 CHECK_CALLBACK_BEHAVIOR(callback);
496 ASSERT_EQ(PP_OK, callback.result());
498 pp::FileRef dir_ref(file_system, "/dir_rename");
499 callback.WaitForResult(dir_ref.MakeDirectory(callback.GetCallback()));
500 CHECK_CALLBACK_BEHAVIOR(callback);
501 ASSERT_EQ(PP_OK, callback.result());
503 pp::FileRef target_dir_ref(file_system, "/target_dir_rename");
504 callback.WaitForResult(
505 dir_ref.Rename(target_dir_ref, callback.GetCallback()));
506 CHECK_CALLBACK_BEHAVIOR(callback);
507 ASSERT_EQ(PP_OK, callback.result());
509 pp::FileRef nested_dir_ref(file_system, "/dir_rename_1/dir_rename_2");
510 callback.WaitForResult(
511 nested_dir_ref.MakeDirectoryIncludingAncestors(callback.GetCallback()));
512 CHECK_CALLBACK_BEHAVIOR(callback);
513 ASSERT_EQ(PP_OK, callback.result());
515 // Try to rename nested directory to the parent name. Should fail.
516 pp::FileRef target_nested_dir_ref(file_system, "/dir_rename_1");
517 callback.WaitForResult(
518 nested_dir_ref.Rename(target_nested_dir_ref, callback.GetCallback()));
519 CHECK_CALLBACK_BEHAVIOR(callback);
520 ASSERT_EQ(PP_ERROR_FAILED, callback.result());
523 // TODO(viettrungluu): Figure out what we want to do if the target file
524 // resource is destroyed before completion.
525 int32_t rv = PP_ERROR_FAILED;
526 pp::FileRef target_file_ref_abort(file_system,
527 "/target_file_rename_abort");
529 pp::FileRef file_ref_abort(file_system, "/file_rename_abort");
530 pp::FileIO file_io_abort(instance_);
531 callback.WaitForResult(
532 file_io_abort.Open(file_ref_abort, PP_FILEOPENFLAG_CREATE,
533 callback.GetCallback()));
534 CHECK_CALLBACK_BEHAVIOR(callback);
535 ASSERT_EQ(PP_OK, callback.result());
537 rv = file_ref_abort.Rename(target_file_ref_abort, callback.GetCallback());
539 callback.WaitForAbortResult(rv);
540 CHECK_CALLBACK_BEHAVIOR(callback);
545 std::string TestFileRef::TestQuery() {
546 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
548 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
549 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
550 CHECK_CALLBACK_BEHAVIOR(callback);
551 ASSERT_EQ(PP_OK, callback.result());
553 pp::FileRef file_ref(file_system, "/file");
554 pp::FileIO file_io(instance_);
555 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE,
556 callback.GetCallback()));
557 CHECK_CALLBACK_BEHAVIOR(callback);
558 ASSERT_EQ(PP_OK, callback.result());
560 // We touch the file so we can easily check access and modified time.
561 callback.WaitForResult(file_io.Touch(0, 0, callback.GetCallback()));
562 CHECK_CALLBACK_BEHAVIOR(callback);
563 ASSERT_EQ(PP_OK, callback.result());
565 TestCompletionCallbackWithOutput<PP_FileInfo> out_callback(
566 instance_->pp_instance(), callback_type());
567 out_callback.WaitForResult(file_ref.Query(out_callback.GetCallback()));
568 CHECK_CALLBACK_BEHAVIOR(out_callback);
569 ASSERT_EQ(PP_OK, out_callback.result());
571 PP_FileInfo info = out_callback.output();
572 ASSERT_EQ(0, info.size);
573 ASSERT_EQ(PP_FILETYPE_REGULAR, info.type);
574 ASSERT_EQ(PP_FILESYSTEMTYPE_LOCALTEMPORARY, info.system_type);
575 ASSERT_DOUBLE_EQ(0.0, info.last_access_time);
576 ASSERT_DOUBLE_EQ(0.0, info.last_modified_time);
578 // Query a file ref on an external filesystem.
579 pp::FileRef file_ref_ext;
580 std::string result = MakeExternalFileRef(&file_ref_ext);
583 out_callback.WaitForResult(file_ref_ext.Query(out_callback.GetCallback()));
584 CHECK_CALLBACK_BEHAVIOR(out_callback);
585 if (out_callback.result() != PP_OK)
586 return ReportError("Query() result", out_callback.result());
587 ASSERT_EQ(PP_OK, out_callback.result());
589 info = out_callback.output();
590 ASSERT_EQ(PP_FILETYPE_REGULAR, info.type);
591 ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, info.system_type);
593 // We can't touch the file, so just sanity check the times.
594 ASSERT_TRUE(info.creation_time >= 0.0);
595 ASSERT_TRUE(info.last_modified_time >= 0.0);
596 ASSERT_TRUE(info.last_access_time >= 0.0);
598 // Query a file ref for a file that doesn't exist.
599 pp::FileRef missing_file_ref(file_system, "/missing_file");
600 out_callback.WaitForResult(missing_file_ref.Query(
601 out_callback.GetCallback()));
602 CHECK_CALLBACK_BEHAVIOR(out_callback);
603 ASSERT_EQ(PP_ERROR_FILENOTFOUND, out_callback.result());
608 std::string TestFileRef::TestFileNameEscaping() {
609 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
610 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
611 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
612 CHECK_CALLBACK_BEHAVIOR(callback);
613 ASSERT_EQ(PP_OK, callback.result());
615 std::string test_dir_path = "/dir_for_escaping_test";
616 // Create a directory in which to test.
617 pp::FileRef test_dir_ref(file_system, test_dir_path.c_str());
618 callback.WaitForResult(test_dir_ref.MakeDirectory(callback.GetCallback()));
619 CHECK_CALLBACK_BEHAVIOR(callback);
620 ASSERT_EQ(PP_OK, callback.result());
622 // Create the file with the terrible name.
623 std::string full_file_path = test_dir_path + "/" + kTerribleName;
624 pp::FileRef file_ref(file_system, full_file_path.c_str());
625 pp::FileIO file_io(instance_);
626 callback.WaitForResult(
627 file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE, callback.GetCallback()));
628 CHECK_CALLBACK_BEHAVIOR(callback);
629 ASSERT_EQ(PP_OK, callback.result());
631 // FileRef::ReadDirectoryEntries only works out-of-process.
632 if (testing_interface_->IsOutOfProcess()) {
633 TestCompletionCallbackWithOutput<DirEntries>
634 output_callback(instance_->pp_instance(), callback_type());
636 output_callback.WaitForResult(
637 test_dir_ref.ReadDirectoryEntries(output_callback.GetCallback()));
638 CHECK_CALLBACK_BEHAVIOR(output_callback);
639 ASSERT_EQ(PP_OK, output_callback.result());
641 DirEntries entries = output_callback.output();
642 ASSERT_EQ(1, entries.size());
643 ASSERT_EQ(kTerribleName, entries.front().file_ref().GetName().AsString());
649 std::string TestFileRef::TestReadDirectoryEntries() {
650 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
651 pp::FileSystem file_system(
652 instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
653 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
654 CHECK_CALLBACK_BEHAVIOR(callback);
655 ASSERT_EQ(PP_OK, callback.result());
657 // Setup testing directories and files.
658 const char* test_dir_name = "/test_get_next_file";
659 const char* file_prefix = "file_";
660 const char* dir_prefix = "dir_";
662 pp::FileRef test_dir(file_system, test_dir_name);
663 int32_t rv = DeleteDirectoryRecursively(&test_dir);
664 ASSERT_TRUE(rv == PP_OK || rv == PP_ERROR_FILENOTFOUND);
666 callback.WaitForResult(test_dir.MakeDirectory(callback.GetCallback()));
667 CHECK_CALLBACK_BEHAVIOR(callback);
668 ASSERT_EQ(PP_OK, callback.result());
670 static const int kNumFiles = 3;
671 std::set<std::string> expected_file_names;
672 for (int i = 1; i <= kNumFiles; ++i) {
673 std::ostringstream buffer;
674 buffer << test_dir_name << '/' << file_prefix << i;
675 pp::FileRef file_ref(file_system, buffer.str().c_str());
677 pp::FileIO file_io(instance_);
678 callback.WaitForResult(
679 file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE, callback.GetCallback()));
680 CHECK_CALLBACK_BEHAVIOR(callback);
681 ASSERT_EQ(PP_OK, callback.result());
683 expected_file_names.insert(buffer.str());
686 static const int kNumDirectories = 3;
687 std::set<std::string> expected_dir_names;
688 for (int i = 1; i <= kNumDirectories; ++i) {
689 std::ostringstream buffer;
690 buffer << test_dir_name << '/' << dir_prefix << i;
691 pp::FileRef file_ref(file_system, buffer.str().c_str());
693 callback.WaitForResult(file_ref.MakeDirectory(callback.GetCallback()));
694 CHECK_CALLBACK_BEHAVIOR(callback);
695 ASSERT_EQ(PP_OK, callback.result());
697 expected_dir_names.insert(buffer.str());
700 // Test that |ReadDirectoryEntries()| is able to fetch all
701 // directories and files that we created.
703 TestCompletionCallbackWithOutput<DirEntries> output_callback(
704 instance_->pp_instance(), callback_type());
706 output_callback.WaitForResult(
707 test_dir.ReadDirectoryEntries(output_callback.GetCallback()));
708 CHECK_CALLBACK_BEHAVIOR(output_callback);
709 ASSERT_EQ(PP_OK, output_callback.result());
711 DirEntries entries = output_callback.output();
712 size_t sum = expected_file_names.size() + expected_dir_names.size();
713 ASSERT_EQ(sum, entries.size());
715 for (DirEntries::const_iterator it = entries.begin();
716 it != entries.end(); ++it) {
717 pp::FileRef file_ref = it->file_ref();
718 std::string file_path = file_ref.GetPath().AsString();
719 std::set<std::string>::iterator found =
720 expected_file_names.find(file_path);
721 if (found != expected_file_names.end()) {
722 if (it->file_type() != PP_FILETYPE_REGULAR)
723 return file_path + " should have been a regular file.";
724 expected_file_names.erase(found);
726 found = expected_dir_names.find(file_path);
727 if (found == expected_dir_names.end())
728 return "Unexpected file path: " + file_path;
729 if (it->file_type() != PP_FILETYPE_DIRECTORY)
730 return file_path + " should have been a directory.";
731 expected_dir_names.erase(found);
734 ASSERT_TRUE(expected_file_names.empty());
735 ASSERT_TRUE(expected_dir_names.empty());
738 // Test cancellation of asynchronous |ReadDirectoryEntries()|.
739 TestCompletionCallbackWithOutput<DirEntries> output_callback(
740 instance_->pp_instance(), callback_type());
742 rv = pp::FileRef(file_system, test_dir_name)
743 .ReadDirectoryEntries(output_callback.GetCallback());
745 output_callback.WaitForAbortResult(rv);
746 CHECK_CALLBACK_BEHAVIOR(output_callback);