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/private/ppb_testing_private.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
, "/dir_make_dir");
303 callback
.WaitForResult(
304 dir_ref
.MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
305 CHECK_CALLBACK_BEHAVIOR(callback
);
306 ASSERT_EQ(PP_OK
, callback
.result());
308 // Make a directory on the existing path without exclusive flag.
309 callback
.WaitForResult(
310 dir_ref
.MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
311 CHECK_CALLBACK_BEHAVIOR(callback
);
312 ASSERT_EQ(PP_OK
, callback
.result());
314 // Making a directory should be aborted.
315 int32_t rv
= PP_ERROR_FAILED
;
317 rv
= pp::FileRef(file_system
, "/dir_make_dir_abort")
318 .MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback());
320 callback
.WaitForAbortResult(rv
);
321 CHECK_CALLBACK_BEHAVIOR(callback
);
323 // Make nested directories.
324 dir_ref
= pp::FileRef(file_system
, "/dir_make_nested_dir_1/dir");
325 callback
.WaitForResult(
326 dir_ref
.MakeDirectory(PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS
,
327 callback
.GetCallback()));
328 CHECK_CALLBACK_BEHAVIOR(callback
);
329 ASSERT_EQ(PP_OK
, callback
.result());
331 dir_ref
= pp::FileRef(file_system
, "/dir_make_nested_dir_2/dir");
332 callback
.WaitForResult(
333 dir_ref
.MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
334 CHECK_CALLBACK_BEHAVIOR(callback
);
335 ASSERT_EQ(PP_ERROR_FILENOTFOUND
, callback
.result());
337 // Ensure there is no directory on the path to test exclusive cases.
338 dir_ref
= pp::FileRef(file_system
, "/dir_make_dir_exclusive");
339 rv
= DeleteDirectoryRecursively(&dir_ref
);
340 ASSERT_TRUE(rv
== PP_OK
|| rv
== PP_ERROR_FILENOTFOUND
);
342 // Make a directory exclusively.
343 callback
.WaitForResult(
344 dir_ref
.MakeDirectory(PP_MAKEDIRECTORYFLAG_EXCLUSIVE
,
345 callback
.GetCallback()));
346 CHECK_CALLBACK_BEHAVIOR(callback
);
347 ASSERT_EQ(PP_OK
, callback
.result());
349 callback
.WaitForResult(
350 dir_ref
.MakeDirectory(PP_MAKEDIRECTORYFLAG_EXCLUSIVE
,
351 callback
.GetCallback()));
352 CHECK_CALLBACK_BEHAVIOR(callback
);
353 ASSERT_EQ(PP_ERROR_FILEEXISTS
, callback
.result());
358 std::string
TestFileRef::TestQueryAndTouchFile() {
359 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
360 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
361 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
362 CHECK_CALLBACK_BEHAVIOR(callback
);
363 ASSERT_EQ(PP_OK
, callback
.result());
365 pp::FileRef
file_ref(file_system
, "/file_touch");
366 pp::FileIO
file_io(instance_
);
367 callback
.WaitForResult(
368 file_io
.Open(file_ref
,
369 PP_FILEOPENFLAG_CREATE
|
370 PP_FILEOPENFLAG_TRUNCATE
|
371 PP_FILEOPENFLAG_WRITE
,
372 callback
.GetCallback()));
373 CHECK_CALLBACK_BEHAVIOR(callback
);
374 ASSERT_EQ(PP_OK
, callback
.result());
376 // Write some data to have a non-zero file size.
377 callback
.WaitForResult(file_io
.Write(0, "test", 4, callback
.GetCallback()));
378 CHECK_CALLBACK_BEHAVIOR(callback
);
379 ASSERT_EQ(4, callback
.result());
382 const PP_Time last_access_time
= 123 * 24 * 3600.0;
383 // last_modified_time's granularity is 2 seconds
384 // See note in test_file_io.cc for why we use this time.
385 const PP_Time last_modified_time
= 100 * 24 * 3600.0;
386 callback
.WaitForResult(file_ref
.Touch(last_access_time
, last_modified_time
,
387 callback
.GetCallback()));
388 CHECK_CALLBACK_BEHAVIOR(callback
);
389 ASSERT_EQ(PP_OK
, callback
.result());
392 int32_t rv
= PP_ERROR_FAILED
;
394 rv
= pp::FileRef(file_system
, "/file_touch_abort")
395 .Touch(last_access_time
, last_modified_time
, callback
.GetCallback());
397 callback
.WaitForResult(rv
);
398 CHECK_CALLBACK_BEHAVIOR(callback
);
399 if (rv
== PP_OK_COMPLETIONPENDING
) {
400 // Touch tried to run asynchronously and should have been aborted.
401 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
403 // Touch ran synchronously and should have failed because the file does not
405 ASSERT_EQ(PP_ERROR_FILENOTFOUND
, callback
.result());
410 callback
.WaitForResult(file_io
.Query(&info
, callback
.GetCallback()));
411 CHECK_CALLBACK_BEHAVIOR(callback
);
412 ASSERT_EQ(PP_OK
, callback
.result());
413 ASSERT_EQ(4, info
.size
);
414 ASSERT_EQ(PP_FILETYPE_REGULAR
, info
.type
);
415 ASSERT_EQ(PP_FILESYSTEMTYPE_LOCALTEMPORARY
, info
.system_type
);
417 // Disabled due to DST-related failure: crbug.com/314579
418 // ASSERT_EQ(last_access_time, info.last_access_time);
419 // ASSERT_EQ(last_modified_time, info.last_modified_time);
421 // Cancellation test.
422 // TODO(viettrungluu): this test causes a bunch of LOG(WARNING)s; investigate.
423 // TODO(viettrungluu): check |info| for late writes.
425 rv
= pp::FileRef(file_system
, "/file_touch").Touch(
426 last_access_time
, last_modified_time
, callback
.GetCallback());
428 callback
.WaitForAbortResult(rv
);
429 CHECK_CALLBACK_BEHAVIOR(callback
);
434 std::string
TestFileRef::TestDeleteFileAndDirectory() {
435 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
436 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
437 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
438 CHECK_CALLBACK_BEHAVIOR(callback
);
439 ASSERT_EQ(PP_OK
, callback
.result());
441 pp::FileRef
file_ref(file_system
, "/file_delete");
442 pp::FileIO
file_io(instance_
);
443 callback
.WaitForResult(
444 file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
, callback
.GetCallback()));
445 CHECK_CALLBACK_BEHAVIOR(callback
);
446 ASSERT_EQ(PP_OK
, callback
.result());
448 callback
.WaitForResult(file_ref
.Delete(callback
.GetCallback()));
449 CHECK_CALLBACK_BEHAVIOR(callback
);
450 ASSERT_EQ(PP_OK
, callback
.result());
452 pp::FileRef
dir_ref(file_system
, "/dir_delete");
453 callback
.WaitForResult(dir_ref
.MakeDirectory(
454 PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
455 CHECK_CALLBACK_BEHAVIOR(callback
);
456 ASSERT_EQ(PP_OK
, callback
.result());
458 callback
.WaitForResult(dir_ref
.Delete(callback
.GetCallback()));
459 CHECK_CALLBACK_BEHAVIOR(callback
);
460 ASSERT_EQ(PP_OK
, callback
.result());
462 pp::FileRef
nested_dir_ref(file_system
, "/dir_delete_1/dir_delete_2");
463 callback
.WaitForResult(
464 nested_dir_ref
.MakeDirectory(PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS
,
465 callback
.GetCallback()));
466 CHECK_CALLBACK_BEHAVIOR(callback
);
467 ASSERT_EQ(PP_OK
, callback
.result());
469 // Attempt to delete the parent directory (should fail; it's non-empty).
470 pp::FileRef parent_dir_ref
= nested_dir_ref
.GetParent();
471 callback
.WaitForResult(parent_dir_ref
.Delete(callback
.GetCallback()));
472 CHECK_CALLBACK_BEHAVIOR(callback
);
473 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
475 pp::FileRef
nonexistent_file_ref(file_system
, "/nonexistent_file_delete");
476 callback
.WaitForResult(nonexistent_file_ref
.Delete(callback
.GetCallback()));
477 CHECK_CALLBACK_BEHAVIOR(callback
);
478 ASSERT_EQ(PP_ERROR_FILENOTFOUND
, callback
.result());
481 int32_t rv
= PP_ERROR_FAILED
;
483 pp::FileRef
file_ref_abort(file_system
, "/file_delete_abort");
484 pp::FileIO
file_io_abort(instance_
);
485 callback
.WaitForResult(
486 file_io_abort
.Open(file_ref_abort
, PP_FILEOPENFLAG_CREATE
,
487 callback
.GetCallback()));
488 CHECK_CALLBACK_BEHAVIOR(callback
);
489 ASSERT_EQ(PP_OK
, callback
.result());
490 rv
= file_ref_abort
.Delete(callback
.GetCallback());
492 callback
.WaitForAbortResult(rv
);
493 CHECK_CALLBACK_BEHAVIOR(callback
);
498 std::string
TestFileRef::TestRenameFileAndDirectory() {
499 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
500 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
501 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
502 CHECK_CALLBACK_BEHAVIOR(callback
);
503 ASSERT_EQ(PP_OK
, callback
.result());
505 pp::FileRef
file_ref(file_system
, "/file_rename");
506 pp::FileIO
file_io(instance_
);
507 callback
.WaitForResult(
508 file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
, callback
.GetCallback()));
509 CHECK_CALLBACK_BEHAVIOR(callback
);
510 ASSERT_EQ(PP_OK
, callback
.result());
512 pp::FileRef
target_file_ref(file_system
, "/target_file_rename");
513 callback
.WaitForResult(
514 file_ref
.Rename(target_file_ref
, callback
.GetCallback()));
515 CHECK_CALLBACK_BEHAVIOR(callback
);
516 ASSERT_EQ(PP_OK
, callback
.result());
518 pp::FileRef
dir_ref(file_system
, "/dir_rename");
519 callback
.WaitForResult(dir_ref
.MakeDirectory(
520 PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
521 CHECK_CALLBACK_BEHAVIOR(callback
);
522 ASSERT_EQ(PP_OK
, callback
.result());
524 pp::FileRef
target_dir_ref(file_system
, "/target_dir_rename");
525 callback
.WaitForResult(
526 dir_ref
.Rename(target_dir_ref
, callback
.GetCallback()));
527 CHECK_CALLBACK_BEHAVIOR(callback
);
528 ASSERT_EQ(PP_OK
, callback
.result());
530 pp::FileRef
nested_dir_ref(file_system
, "/dir_rename_1/dir_rename_2");
531 callback
.WaitForResult(
532 nested_dir_ref
.MakeDirectory(PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS
,
533 callback
.GetCallback()));
534 CHECK_CALLBACK_BEHAVIOR(callback
);
535 ASSERT_EQ(PP_OK
, callback
.result());
537 // Try to rename nested directory to the parent name. Should fail.
538 pp::FileRef
target_nested_dir_ref(file_system
, "/dir_rename_1");
539 callback
.WaitForResult(
540 nested_dir_ref
.Rename(target_nested_dir_ref
, callback
.GetCallback()));
541 CHECK_CALLBACK_BEHAVIOR(callback
);
542 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
545 // TODO(viettrungluu): Figure out what we want to do if the target file
546 // resource is destroyed before completion.
547 int32_t rv
= PP_ERROR_FAILED
;
548 pp::FileRef
target_file_ref_abort(file_system
,
549 "/target_file_rename_abort");
551 pp::FileRef
file_ref_abort(file_system
, "/file_rename_abort");
552 pp::FileIO
file_io_abort(instance_
);
553 callback
.WaitForResult(
554 file_io_abort
.Open(file_ref_abort
, PP_FILEOPENFLAG_CREATE
,
555 callback
.GetCallback()));
556 CHECK_CALLBACK_BEHAVIOR(callback
);
557 ASSERT_EQ(PP_OK
, callback
.result());
559 rv
= file_ref_abort
.Rename(target_file_ref_abort
, callback
.GetCallback());
561 callback
.WaitForAbortResult(rv
);
562 CHECK_CALLBACK_BEHAVIOR(callback
);
567 std::string
TestFileRef::TestQuery() {
568 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
570 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
571 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
572 CHECK_CALLBACK_BEHAVIOR(callback
);
573 ASSERT_EQ(PP_OK
, callback
.result());
575 pp::FileRef
file_ref(file_system
, "/file");
576 pp::FileIO
file_io(instance_
);
577 callback
.WaitForResult(file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
,
578 callback
.GetCallback()));
579 CHECK_CALLBACK_BEHAVIOR(callback
);
580 ASSERT_EQ(PP_OK
, callback
.result());
582 // We touch the file so we can easily check access and modified time.
583 callback
.WaitForResult(file_io
.Touch(0, 0, callback
.GetCallback()));
584 CHECK_CALLBACK_BEHAVIOR(callback
);
585 ASSERT_EQ(PP_OK
, callback
.result());
587 TestCompletionCallbackWithOutput
<PP_FileInfo
> out_callback(
588 instance_
->pp_instance(), callback_type());
589 out_callback
.WaitForResult(file_ref
.Query(out_callback
.GetCallback()));
590 CHECK_CALLBACK_BEHAVIOR(out_callback
);
591 ASSERT_EQ(PP_OK
, out_callback
.result());
593 PP_FileInfo info
= out_callback
.output();
594 ASSERT_EQ(0, info
.size
);
595 ASSERT_EQ(PP_FILETYPE_REGULAR
, info
.type
);
596 ASSERT_EQ(PP_FILESYSTEMTYPE_LOCALTEMPORARY
, info
.system_type
);
597 ASSERT_DOUBLE_EQ(0.0, info
.last_access_time
);
598 ASSERT_DOUBLE_EQ(0.0, info
.last_modified_time
);
600 // Query a file ref on an external filesystem.
601 pp::FileRef file_ref_ext
;
602 std::string result
= MakeExternalFileRef(&file_ref_ext
);
605 out_callback
.WaitForResult(file_ref_ext
.Query(out_callback
.GetCallback()));
606 CHECK_CALLBACK_BEHAVIOR(out_callback
);
607 if (out_callback
.result() != PP_OK
)
608 return ReportError("Query() result", out_callback
.result());
609 ASSERT_EQ(PP_OK
, out_callback
.result());
611 info
= out_callback
.output();
612 ASSERT_EQ(PP_FILETYPE_REGULAR
, info
.type
);
613 ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL
, info
.system_type
);
615 // We can't touch the file, so just sanity check the times.
616 ASSERT_TRUE(info
.creation_time
>= 0.0);
617 ASSERT_TRUE(info
.last_modified_time
>= 0.0);
618 ASSERT_TRUE(info
.last_access_time
>= 0.0);
620 // Query a file ref for a file that doesn't exist.
621 pp::FileRef
missing_file_ref(file_system
, "/missing_file");
622 out_callback
.WaitForResult(missing_file_ref
.Query(
623 out_callback
.GetCallback()));
624 CHECK_CALLBACK_BEHAVIOR(out_callback
);
625 ASSERT_EQ(PP_ERROR_FILENOTFOUND
, out_callback
.result());
630 std::string
TestFileRef::TestFileNameEscaping() {
631 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
632 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
633 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
634 CHECK_CALLBACK_BEHAVIOR(callback
);
635 ASSERT_EQ(PP_OK
, callback
.result());
637 std::string test_dir_path
= "/dir_for_escaping_test";
638 // Create a directory in which to test.
639 pp::FileRef
test_dir_ref(file_system
, test_dir_path
.c_str());
640 callback
.WaitForResult(test_dir_ref
.MakeDirectory(
641 PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
642 CHECK_CALLBACK_BEHAVIOR(callback
);
643 ASSERT_EQ(PP_OK
, callback
.result());
645 // Create the file with the terrible name.
646 std::string full_file_path
= test_dir_path
+ "/" + kTerribleName
;
647 pp::FileRef
file_ref(file_system
, full_file_path
.c_str());
648 pp::FileIO
file_io(instance_
);
649 callback
.WaitForResult(
650 file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
, callback
.GetCallback()));
651 CHECK_CALLBACK_BEHAVIOR(callback
);
652 ASSERT_EQ(PP_OK
, callback
.result());
654 // FileRef::ReadDirectoryEntries only works out-of-process.
655 if (testing_interface_
->IsOutOfProcess()) {
656 TestCompletionCallbackWithOutput
<DirEntries
>
657 output_callback(instance_
->pp_instance(), callback_type());
659 output_callback
.WaitForResult(
660 test_dir_ref
.ReadDirectoryEntries(output_callback
.GetCallback()));
661 CHECK_CALLBACK_BEHAVIOR(output_callback
);
662 ASSERT_EQ(PP_OK
, output_callback
.result());
664 DirEntries entries
= output_callback
.output();
665 ASSERT_EQ(1, entries
.size());
666 ASSERT_EQ(kTerribleName
, entries
.front().file_ref().GetName().AsString());
672 std::string
TestFileRef::TestReadDirectoryEntries() {
673 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
674 pp::FileSystem
file_system(
675 instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
676 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
677 CHECK_CALLBACK_BEHAVIOR(callback
);
678 ASSERT_EQ(PP_OK
, callback
.result());
680 // Setup testing directories and files.
681 const char* test_dir_name
= "/test_get_next_file";
682 const char* file_prefix
= "file_";
683 const char* dir_prefix
= "dir_";
685 pp::FileRef
test_dir(file_system
, test_dir_name
);
686 int32_t rv
= DeleteDirectoryRecursively(&test_dir
);
687 ASSERT_TRUE(rv
== PP_OK
|| rv
== PP_ERROR_FILENOTFOUND
);
689 callback
.WaitForResult(test_dir
.MakeDirectory(
690 PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
691 CHECK_CALLBACK_BEHAVIOR(callback
);
692 ASSERT_EQ(PP_OK
, callback
.result());
694 static const int kNumFiles
= 3;
695 std::set
<std::string
> expected_file_names
;
696 for (int i
= 1; i
<= kNumFiles
; ++i
) {
697 std::ostringstream buffer
;
698 buffer
<< test_dir_name
<< '/' << file_prefix
<< i
;
699 pp::FileRef
file_ref(file_system
, buffer
.str().c_str());
701 pp::FileIO
file_io(instance_
);
702 callback
.WaitForResult(
703 file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
, callback
.GetCallback()));
704 CHECK_CALLBACK_BEHAVIOR(callback
);
705 ASSERT_EQ(PP_OK
, callback
.result());
707 expected_file_names
.insert(buffer
.str());
710 static const int kNumDirectories
= 3;
711 std::set
<std::string
> expected_dir_names
;
712 for (int i
= 1; i
<= kNumDirectories
; ++i
) {
713 std::ostringstream buffer
;
714 buffer
<< test_dir_name
<< '/' << dir_prefix
<< i
;
715 pp::FileRef
file_ref(file_system
, buffer
.str().c_str());
717 callback
.WaitForResult(file_ref
.MakeDirectory(
718 PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
719 CHECK_CALLBACK_BEHAVIOR(callback
);
720 ASSERT_EQ(PP_OK
, callback
.result());
722 expected_dir_names
.insert(buffer
.str());
725 // Test that |ReadDirectoryEntries()| is able to fetch all
726 // directories and files that we created.
728 TestCompletionCallbackWithOutput
<DirEntries
> output_callback(
729 instance_
->pp_instance(), callback_type());
731 output_callback
.WaitForResult(
732 test_dir
.ReadDirectoryEntries(output_callback
.GetCallback()));
733 CHECK_CALLBACK_BEHAVIOR(output_callback
);
734 ASSERT_EQ(PP_OK
, output_callback
.result());
736 DirEntries entries
= output_callback
.output();
737 size_t sum
= expected_file_names
.size() + expected_dir_names
.size();
738 ASSERT_EQ(sum
, entries
.size());
740 for (DirEntries::const_iterator it
= entries
.begin();
741 it
!= entries
.end(); ++it
) {
742 pp::FileRef file_ref
= it
->file_ref();
743 std::string file_path
= file_ref
.GetPath().AsString();
744 std::set
<std::string
>::iterator found
=
745 expected_file_names
.find(file_path
);
746 if (found
!= expected_file_names
.end()) {
747 if (it
->file_type() != PP_FILETYPE_REGULAR
)
748 return file_path
+ " should have been a regular file.";
749 expected_file_names
.erase(found
);
751 found
= expected_dir_names
.find(file_path
);
752 if (found
== expected_dir_names
.end())
753 return "Unexpected file path: " + file_path
;
754 if (it
->file_type() != PP_FILETYPE_DIRECTORY
)
755 return file_path
+ " should have been a directory.";
756 expected_dir_names
.erase(found
);
759 ASSERT_TRUE(expected_file_names
.empty());
760 ASSERT_TRUE(expected_dir_names
.empty());
763 // Test cancellation of asynchronous |ReadDirectoryEntries()|.
764 TestCompletionCallbackWithOutput
<DirEntries
> output_callback(
765 instance_
->pp_instance(), callback_type());
767 rv
= pp::FileRef(file_system
, test_dir_name
)
768 .ReadDirectoryEntries(output_callback
.GetCallback());
770 output_callback
.WaitForAbortResult(rv
);
771 CHECK_CALLBACK_BEHAVIOR(output_callback
);