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 // FileRef::Query is out-of-process only.
119 if (testing_interface_
->IsOutOfProcess())
120 RUN_CALLBACK_TEST(TestFileRef
, Query
, filter
);
121 RUN_CALLBACK_TEST(TestFileRef
, FileNameEscaping
, filter
);
122 // FileRef::ReadDirectoryEntries is out-of-process only.
123 if (testing_interface_
->IsOutOfProcess())
124 RUN_CALLBACK_TEST(TestFileRef
, ReadDirectoryEntries
, filter
);
127 std::string
TestFileRef::TestCreate() {
128 std::vector
<std::string
> invalid_paths
;
129 invalid_paths
.push_back("invalid_path"); // no '/' at the first character
130 invalid_paths
.push_back(std::string()); // empty path
131 // The following are directory traversal checks
132 invalid_paths
.push_back("..");
133 invalid_paths
.push_back("/../invalid_path");
134 invalid_paths
.push_back("/../../invalid_path");
135 invalid_paths
.push_back("/invalid/../../path");
136 const size_t num_invalid_paths
= invalid_paths
.size();
138 pp::FileSystem
file_system_pers(
139 instance_
, PP_FILESYSTEMTYPE_LOCALPERSISTENT
);
140 pp::FileSystem
file_system_temp(
141 instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
142 for (size_t j
= 0; j
< num_invalid_paths
; ++j
) {
143 pp::FileRef
file_ref_pers(file_system_pers
, invalid_paths
[j
].c_str());
144 if (file_ref_pers
.pp_resource() != 0) {
145 return "file_ref_pers expected to be invalid for path: " +
148 pp::FileRef
file_ref_temp(file_system_temp
, invalid_paths
[j
].c_str());
149 if (file_ref_temp
.pp_resource() != 0) {
150 return "file_ref_temp expected to be invalid for path: " +
157 std::string
TestFileRef::TestGetFileSystemType() {
158 pp::FileSystem
file_system_pers(
159 instance_
, PP_FILESYSTEMTYPE_LOCALPERSISTENT
);
160 pp::FileSystem
file_system_temp(
161 instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
163 pp::FileRef
file_ref_pers(file_system_pers
, kPersFilePath
);
164 if (file_ref_pers
.GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALPERSISTENT
)
165 return "file_ref_pers expected to be persistent.";
167 pp::FileRef
file_ref_temp(file_system_temp
, kTempFilePath
);
168 if (file_ref_temp
.GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALTEMPORARY
)
169 return "file_ref_temp expected to be temporary.";
171 pp::FileRef file_ref_ext
;
172 std::string result
= MakeExternalFileRef(&file_ref_ext
);
178 std::string
TestFileRef::TestGetName() {
179 pp::FileSystem
file_system_pers(
180 instance_
, PP_FILESYSTEMTYPE_LOCALPERSISTENT
);
181 pp::FileSystem
file_system_temp(
182 instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
184 pp::FileRef
file_ref_pers(file_system_pers
, kPersFilePath
);
185 std::string name
= file_ref_pers
.GetName().AsString();
186 if (name
!= kPersFileName
)
187 return ReportMismatch("FileRef::GetName", name
, kPersFileName
);
189 pp::FileRef
file_ref_temp(file_system_temp
, kTempFilePath
);
190 name
= file_ref_temp
.GetName().AsString();
191 if (name
!= kTempFileName
)
192 return ReportMismatch("FileRef::GetName", name
, kTempFileName
);
194 // Test the "/" case.
195 pp::FileRef
file_ref_slash(file_system_temp
, "/");
196 name
= file_ref_slash
.GetName().AsString();
198 return ReportMismatch("FileRef::GetName", name
, "/");
200 pp::URLRequestInfo
request(instance_
);
201 request
.SetURL("test_url_loader_data/hello.txt");
202 request
.SetStreamToFile(true);
204 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
206 pp::URLLoader
loader(instance_
);
207 callback
.WaitForResult(loader
.Open(request
, callback
.GetCallback()));
208 CHECK_CALLBACK_BEHAVIOR(callback
);
209 ASSERT_EQ(PP_OK
, callback
.result());
211 pp::URLResponseInfo
response_info(loader
.GetResponseInfo());
212 ASSERT_FALSE(response_info
.is_null());
213 ASSERT_EQ(200, response_info
.GetStatusCode());
215 pp::FileRef
file_ref_ext(response_info
.GetBodyAsFileRef());
216 name
= file_ref_ext
.GetName().AsString();
217 ASSERT_FALSE(name
.empty());
222 std::string
TestFileRef::TestGetPath() {
223 pp::FileSystem
file_system_pers(
224 instance_
, PP_FILESYSTEMTYPE_LOCALPERSISTENT
);
225 pp::FileSystem
file_system_temp(
226 instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
228 pp::FileRef
file_ref_pers(file_system_pers
, kPersFilePath
);
229 ASSERT_EQ(kPersFilePath
, file_ref_pers
.GetPath().AsString());
231 pp::FileRef
file_ref_temp(file_system_temp
, kTempFilePath
);
232 ASSERT_EQ(kTempFilePath
, file_ref_temp
.GetPath().AsString());
234 pp::URLRequestInfo
request(instance_
);
235 request
.SetURL("test_url_loader_data/hello.txt");
236 request
.SetStreamToFile(true);
238 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
240 pp::URLLoader
loader(instance_
);
241 callback
.WaitForResult(loader
.Open(request
, callback
.GetCallback()));
242 CHECK_CALLBACK_BEHAVIOR(callback
);
243 ASSERT_EQ(PP_OK
, callback
.result());
245 pp::URLResponseInfo
response_info(loader
.GetResponseInfo());
246 ASSERT_FALSE(response_info
.is_null());
247 ASSERT_EQ(200, response_info
.GetStatusCode());
249 pp::FileRef
file_ref_ext(response_info
.GetBodyAsFileRef());
250 ASSERT_TRUE(file_ref_ext
.GetPath().is_undefined());
255 std::string
TestFileRef::TestGetParent() {
256 pp::FileSystem
file_system_pers(
257 instance_
, PP_FILESYSTEMTYPE_LOCALPERSISTENT
);
258 pp::FileSystem
file_system_temp(
259 instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
261 pp::FileRef
file_ref_pers(file_system_pers
, kPersFilePath
);
262 ASSERT_EQ(kParentPath
, file_ref_pers
.GetParent().GetPath().AsString());
264 pp::FileRef
file_ref_temp(file_system_temp
, kTempFilePath
);
265 ASSERT_EQ(kParentPath
, file_ref_temp
.GetParent().GetPath().AsString());
267 // Test the "/" case.
268 pp::FileRef
file_ref_slash(file_system_temp
, "/");
269 ASSERT_EQ("/", file_ref_slash
.GetParent().GetPath().AsString());
271 // Test the "/foo" case (the parent is "/").
272 pp::FileRef
file_ref_with_root_parent(file_system_temp
, "/foo");
273 ASSERT_EQ("/", file_ref_with_root_parent
.GetParent().GetPath().AsString());
275 pp::URLRequestInfo
request(instance_
);
276 request
.SetURL("test_url_loader_data/hello.txt");
277 request
.SetStreamToFile(true);
279 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
281 pp::URLLoader
loader(instance_
);
282 callback
.WaitForResult(loader
.Open(request
, callback
.GetCallback()));
283 CHECK_CALLBACK_BEHAVIOR(callback
);
284 ASSERT_EQ(PP_OK
, callback
.result());
286 pp::URLResponseInfo
response_info(loader
.GetResponseInfo());
287 ASSERT_FALSE(response_info
.is_null());
288 ASSERT_EQ(200, response_info
.GetStatusCode());
290 pp::FileRef
file_ref_ext(response_info
.GetBodyAsFileRef());
291 ASSERT_TRUE(file_ref_ext
.GetParent().is_null());
296 std::string
TestFileRef::TestMakeDirectory() {
297 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
300 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
301 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
302 CHECK_CALLBACK_BEHAVIOR(callback
);
303 ASSERT_EQ(PP_OK
, callback
.result());
306 pp::FileRef
dir_ref(file_system
, "/test_dir_make_directory");
307 callback
.WaitForResult(dir_ref
.MakeDirectory(callback
.GetCallback()));
308 CHECK_CALLBACK_BEHAVIOR(callback
);
309 ASSERT_EQ(PP_OK
, callback
.result());
311 // MakeDirectory aborted.
312 int32_t rv
= PP_ERROR_FAILED
;
314 rv
= pp::FileRef(file_system
, "/test_dir_make_abort")
315 .MakeDirectory(callback
.GetCallback());
317 callback
.WaitForAbortResult(rv
);
318 CHECK_CALLBACK_BEHAVIOR(callback
);
320 // MakeDirectoryIncludingAncestors.
321 dir_ref
= pp::FileRef(file_system
, "/dir_make_dir_1/dir_make_dir_2");
322 callback
.WaitForResult(
323 dir_ref
.MakeDirectoryIncludingAncestors(callback
.GetCallback()));
324 CHECK_CALLBACK_BEHAVIOR(callback
);
325 ASSERT_EQ(PP_OK
, callback
.result());
327 // MakeDirectoryIncludingAncestors aborted.
329 rv
= pp::FileRef(file_system
, "/dir_make_abort_1/dir_make_abort_2")
330 .MakeDirectoryIncludingAncestors(callback
.GetCallback());
332 callback
.WaitForAbortResult(rv
);
333 CHECK_CALLBACK_BEHAVIOR(callback
);
335 // MakeDirectory with nested path should fail.
336 dir_ref
= pp::FileRef(file_system
, "/dir_make_dir_3/dir_make_dir_4");
337 callback
.WaitForResult(dir_ref
.MakeDirectory(callback
.GetCallback()));
338 CHECK_CALLBACK_BEHAVIOR(callback
);
339 ASSERT_NE(PP_OK
, callback
.result());
344 std::string
TestFileRef::TestQueryAndTouchFile() {
345 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
346 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
347 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
348 CHECK_CALLBACK_BEHAVIOR(callback
);
349 ASSERT_EQ(PP_OK
, callback
.result());
351 pp::FileRef
file_ref(file_system
, "/file_touch");
352 pp::FileIO
file_io(instance_
);
353 callback
.WaitForResult(
354 file_io
.Open(file_ref
,
355 PP_FILEOPENFLAG_CREATE
|
356 PP_FILEOPENFLAG_TRUNCATE
|
357 PP_FILEOPENFLAG_WRITE
,
358 callback
.GetCallback()));
359 CHECK_CALLBACK_BEHAVIOR(callback
);
360 ASSERT_EQ(PP_OK
, callback
.result());
362 // Write some data to have a non-zero file size.
363 callback
.WaitForResult(file_io
.Write(0, "test", 4, callback
.GetCallback()));
364 CHECK_CALLBACK_BEHAVIOR(callback
);
365 ASSERT_EQ(4, callback
.result());
368 const PP_Time last_access_time
= 123 * 24 * 3600.0;
369 // last_modified_time's granularity is 2 seconds
370 // See note in test_file_io.cc for why we use this time.
371 const PP_Time last_modified_time
= 100 * 24 * 3600.0;
372 callback
.WaitForResult(file_ref
.Touch(last_access_time
, last_modified_time
,
373 callback
.GetCallback()));
374 CHECK_CALLBACK_BEHAVIOR(callback
);
375 ASSERT_EQ(PP_OK
, callback
.result());
378 int32_t rv
= PP_ERROR_FAILED
;
380 rv
= pp::FileRef(file_system
, "/file_touch_abort")
381 .Touch(last_access_time
, last_modified_time
, callback
.GetCallback());
383 callback
.WaitForResult(rv
);
384 CHECK_CALLBACK_BEHAVIOR(callback
);
385 if (rv
== PP_OK_COMPLETIONPENDING
) {
386 // Touch tried to run asynchronously and should have been aborted.
387 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
389 // Touch ran synchronously and should have failed because the file does not
391 ASSERT_EQ(PP_ERROR_FILENOTFOUND
, callback
.result());
396 callback
.WaitForResult(file_io
.Query(&info
, callback
.GetCallback()));
397 CHECK_CALLBACK_BEHAVIOR(callback
);
398 ASSERT_EQ(PP_OK
, callback
.result());
399 ASSERT_EQ(4, info
.size
);
400 ASSERT_EQ(PP_FILETYPE_REGULAR
, info
.type
);
401 ASSERT_EQ(PP_FILESYSTEMTYPE_LOCALTEMPORARY
, info
.system_type
);
402 ASSERT_EQ(last_access_time
, info
.last_access_time
);
403 ASSERT_EQ(last_modified_time
, info
.last_modified_time
);
405 // Cancellation test.
406 // TODO(viettrungluu): this test causes a bunch of LOG(WARNING)s; investigate.
407 // TODO(viettrungluu): check |info| for late writes.
409 rv
= pp::FileRef(file_system
, "/file_touch").Touch(
410 last_access_time
, last_modified_time
, callback
.GetCallback());
412 callback
.WaitForAbortResult(rv
);
413 CHECK_CALLBACK_BEHAVIOR(callback
);
418 std::string
TestFileRef::TestDeleteFileAndDirectory() {
419 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
420 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
421 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
422 CHECK_CALLBACK_BEHAVIOR(callback
);
423 ASSERT_EQ(PP_OK
, callback
.result());
425 pp::FileRef
file_ref(file_system
, "/file_delete");
426 pp::FileIO
file_io(instance_
);
427 callback
.WaitForResult(
428 file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
, callback
.GetCallback()));
429 CHECK_CALLBACK_BEHAVIOR(callback
);
430 ASSERT_EQ(PP_OK
, callback
.result());
432 callback
.WaitForResult(file_ref
.Delete(callback
.GetCallback()));
433 CHECK_CALLBACK_BEHAVIOR(callback
);
434 ASSERT_EQ(PP_OK
, callback
.result());
436 pp::FileRef
dir_ref(file_system
, "/dir_delete");
437 callback
.WaitForResult(dir_ref
.MakeDirectory(callback
.GetCallback()));
438 CHECK_CALLBACK_BEHAVIOR(callback
);
439 ASSERT_EQ(PP_OK
, callback
.result());
441 callback
.WaitForResult(dir_ref
.Delete(callback
.GetCallback()));
442 CHECK_CALLBACK_BEHAVIOR(callback
);
443 ASSERT_EQ(PP_OK
, callback
.result());
445 pp::FileRef
nested_dir_ref(file_system
, "/dir_delete_1/dir_delete_2");
446 callback
.WaitForResult(
447 nested_dir_ref
.MakeDirectoryIncludingAncestors(callback
.GetCallback()));
448 CHECK_CALLBACK_BEHAVIOR(callback
);
449 ASSERT_EQ(PP_OK
, callback
.result());
451 // Attempt to delete the parent directory (should fail; it's non-empty).
452 pp::FileRef parent_dir_ref
= nested_dir_ref
.GetParent();
453 callback
.WaitForResult(parent_dir_ref
.Delete(callback
.GetCallback()));
454 CHECK_CALLBACK_BEHAVIOR(callback
);
455 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
457 pp::FileRef
nonexistent_file_ref(file_system
, "/nonexistent_file_delete");
458 callback
.WaitForResult(nonexistent_file_ref
.Delete(callback
.GetCallback()));
459 CHECK_CALLBACK_BEHAVIOR(callback
);
460 ASSERT_EQ(PP_ERROR_FILENOTFOUND
, callback
.result());
463 int32_t rv
= PP_ERROR_FAILED
;
465 pp::FileRef
file_ref_abort(file_system
, "/file_delete_abort");
466 pp::FileIO
file_io_abort(instance_
);
467 callback
.WaitForResult(
468 file_io_abort
.Open(file_ref_abort
, PP_FILEOPENFLAG_CREATE
,
469 callback
.GetCallback()));
470 CHECK_CALLBACK_BEHAVIOR(callback
);
471 ASSERT_EQ(PP_OK
, callback
.result());
472 rv
= file_ref_abort
.Delete(callback
.GetCallback());
474 callback
.WaitForAbortResult(rv
);
475 CHECK_CALLBACK_BEHAVIOR(callback
);
480 std::string
TestFileRef::TestRenameFileAndDirectory() {
481 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
482 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
483 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
484 CHECK_CALLBACK_BEHAVIOR(callback
);
485 ASSERT_EQ(PP_OK
, callback
.result());
487 pp::FileRef
file_ref(file_system
, "/file_rename");
488 pp::FileIO
file_io(instance_
);
489 callback
.WaitForResult(
490 file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
, callback
.GetCallback()));
491 CHECK_CALLBACK_BEHAVIOR(callback
);
492 ASSERT_EQ(PP_OK
, callback
.result());
494 pp::FileRef
target_file_ref(file_system
, "/target_file_rename");
495 callback
.WaitForResult(
496 file_ref
.Rename(target_file_ref
, callback
.GetCallback()));
497 CHECK_CALLBACK_BEHAVIOR(callback
);
498 ASSERT_EQ(PP_OK
, callback
.result());
500 pp::FileRef
dir_ref(file_system
, "/dir_rename");
501 callback
.WaitForResult(dir_ref
.MakeDirectory(callback
.GetCallback()));
502 CHECK_CALLBACK_BEHAVIOR(callback
);
503 ASSERT_EQ(PP_OK
, callback
.result());
505 pp::FileRef
target_dir_ref(file_system
, "/target_dir_rename");
506 callback
.WaitForResult(
507 dir_ref
.Rename(target_dir_ref
, callback
.GetCallback()));
508 CHECK_CALLBACK_BEHAVIOR(callback
);
509 ASSERT_EQ(PP_OK
, callback
.result());
511 pp::FileRef
nested_dir_ref(file_system
, "/dir_rename_1/dir_rename_2");
512 callback
.WaitForResult(
513 nested_dir_ref
.MakeDirectoryIncludingAncestors(callback
.GetCallback()));
514 CHECK_CALLBACK_BEHAVIOR(callback
);
515 ASSERT_EQ(PP_OK
, callback
.result());
517 // Try to rename nested directory to the parent name. Should fail.
518 pp::FileRef
target_nested_dir_ref(file_system
, "/dir_rename_1");
519 callback
.WaitForResult(
520 nested_dir_ref
.Rename(target_nested_dir_ref
, callback
.GetCallback()));
521 CHECK_CALLBACK_BEHAVIOR(callback
);
522 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
525 // TODO(viettrungluu): Figure out what we want to do if the target file
526 // resource is destroyed before completion.
527 int32_t rv
= PP_ERROR_FAILED
;
528 pp::FileRef
target_file_ref_abort(file_system
,
529 "/target_file_rename_abort");
531 pp::FileRef
file_ref_abort(file_system
, "/file_rename_abort");
532 pp::FileIO
file_io_abort(instance_
);
533 callback
.WaitForResult(
534 file_io_abort
.Open(file_ref_abort
, PP_FILEOPENFLAG_CREATE
,
535 callback
.GetCallback()));
536 CHECK_CALLBACK_BEHAVIOR(callback
);
537 ASSERT_EQ(PP_OK
, callback
.result());
539 rv
= file_ref_abort
.Rename(target_file_ref_abort
, callback
.GetCallback());
541 callback
.WaitForAbortResult(rv
);
542 CHECK_CALLBACK_BEHAVIOR(callback
);
547 std::string
TestFileRef::TestQuery() {
548 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
550 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
551 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
552 CHECK_CALLBACK_BEHAVIOR(callback
);
553 ASSERT_EQ(PP_OK
, callback
.result());
555 pp::FileRef
file_ref(file_system
, "/file");
556 pp::FileIO
file_io(instance_
);
557 callback
.WaitForResult(file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
,
558 callback
.GetCallback()));
559 CHECK_CALLBACK_BEHAVIOR(callback
);
560 ASSERT_EQ(PP_OK
, callback
.result());
562 // We touch the file so we can easily check access and modified time.
563 callback
.WaitForResult(file_io
.Touch(0, 0, callback
.GetCallback()));
564 CHECK_CALLBACK_BEHAVIOR(callback
);
565 ASSERT_EQ(PP_OK
, callback
.result());
567 TestCompletionCallbackWithOutput
<PP_FileInfo
> out_callback(
568 instance_
->pp_instance(), callback_type());
569 out_callback
.WaitForResult(file_ref
.Query(out_callback
.GetCallback()));
570 CHECK_CALLBACK_BEHAVIOR(out_callback
);
571 ASSERT_EQ(PP_OK
, out_callback
.result());
573 PP_FileInfo info
= out_callback
.output();
574 ASSERT_EQ(0, info
.size
);
575 ASSERT_EQ(PP_FILETYPE_REGULAR
, info
.type
);
576 ASSERT_EQ(PP_FILESYSTEMTYPE_LOCALTEMPORARY
, info
.system_type
);
577 ASSERT_DOUBLE_EQ(0.0, info
.last_access_time
);
578 ASSERT_DOUBLE_EQ(0.0, info
.last_modified_time
);
580 // Query a file ref on an external filesystem.
581 pp::FileRef file_ref_ext
;
582 std::string result
= MakeExternalFileRef(&file_ref_ext
);
585 out_callback
.WaitForResult(file_ref_ext
.Query(out_callback
.GetCallback()));
586 CHECK_CALLBACK_BEHAVIOR(out_callback
);
587 if (out_callback
.result() != PP_OK
)
588 return ReportError("Query() result", out_callback
.result());
589 ASSERT_EQ(PP_OK
, out_callback
.result());
591 info
= out_callback
.output();
592 ASSERT_EQ(PP_FILETYPE_REGULAR
, info
.type
);
593 ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL
, info
.system_type
);
595 // We can't touch the file, so just sanity check the times.
596 ASSERT_TRUE(info
.creation_time
>= 0.0);
597 ASSERT_TRUE(info
.last_modified_time
>= 0.0);
598 ASSERT_TRUE(info
.last_access_time
>= 0.0);
600 // Query a file ref for a file that doesn't exist.
601 pp::FileRef
missing_file_ref(file_system
, "/missing_file");
602 out_callback
.WaitForResult(missing_file_ref
.Query(
603 out_callback
.GetCallback()));
604 CHECK_CALLBACK_BEHAVIOR(out_callback
);
605 ASSERT_EQ(PP_ERROR_FILENOTFOUND
, out_callback
.result());
610 std::string
TestFileRef::TestFileNameEscaping() {
611 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
612 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
613 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
614 CHECK_CALLBACK_BEHAVIOR(callback
);
615 ASSERT_EQ(PP_OK
, callback
.result());
617 std::string test_dir_path
= "/dir_for_escaping_test";
618 // Create a directory in which to test.
619 pp::FileRef
test_dir_ref(file_system
, test_dir_path
.c_str());
620 callback
.WaitForResult(test_dir_ref
.MakeDirectory(callback
.GetCallback()));
621 CHECK_CALLBACK_BEHAVIOR(callback
);
622 ASSERT_EQ(PP_OK
, callback
.result());
624 // Create the file with the terrible name.
625 std::string full_file_path
= test_dir_path
+ "/" + kTerribleName
;
626 pp::FileRef
file_ref(file_system
, full_file_path
.c_str());
627 pp::FileIO
file_io(instance_
);
628 callback
.WaitForResult(
629 file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
, callback
.GetCallback()));
630 CHECK_CALLBACK_BEHAVIOR(callback
);
631 ASSERT_EQ(PP_OK
, callback
.result());
633 // FileRef::ReadDirectoryEntries only works out-of-process.
634 if (testing_interface_
->IsOutOfProcess()) {
635 TestCompletionCallbackWithOutput
<DirEntries
>
636 output_callback(instance_
->pp_instance(), callback_type());
638 output_callback
.WaitForResult(
639 test_dir_ref
.ReadDirectoryEntries(output_callback
.GetCallback()));
640 CHECK_CALLBACK_BEHAVIOR(output_callback
);
641 ASSERT_EQ(PP_OK
, output_callback
.result());
643 DirEntries entries
= output_callback
.output();
644 ASSERT_EQ(1, entries
.size());
645 ASSERT_EQ(kTerribleName
, entries
.front().file_ref().GetName().AsString());
651 std::string
TestFileRef::TestReadDirectoryEntries() {
652 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
653 pp::FileSystem
file_system(
654 instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
655 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
656 CHECK_CALLBACK_BEHAVIOR(callback
);
657 ASSERT_EQ(PP_OK
, callback
.result());
659 // Setup testing directories and files.
660 const char* test_dir_name
= "/test_get_next_file";
661 const char* file_prefix
= "file_";
662 const char* dir_prefix
= "dir_";
664 pp::FileRef
test_dir(file_system
, test_dir_name
);
665 int32_t rv
= DeleteDirectoryRecursively(&test_dir
);
666 ASSERT_TRUE(rv
== PP_OK
|| rv
== PP_ERROR_FILENOTFOUND
);
668 callback
.WaitForResult(test_dir
.MakeDirectory(callback
.GetCallback()));
669 CHECK_CALLBACK_BEHAVIOR(callback
);
670 ASSERT_EQ(PP_OK
, callback
.result());
672 static const int kNumFiles
= 3;
673 std::set
<std::string
> expected_file_names
;
674 for (int i
= 1; i
<= kNumFiles
; ++i
) {
675 std::ostringstream buffer
;
676 buffer
<< test_dir_name
<< '/' << file_prefix
<< i
;
677 pp::FileRef
file_ref(file_system
, buffer
.str().c_str());
679 pp::FileIO
file_io(instance_
);
680 callback
.WaitForResult(
681 file_io
.Open(file_ref
, PP_FILEOPENFLAG_CREATE
, callback
.GetCallback()));
682 CHECK_CALLBACK_BEHAVIOR(callback
);
683 ASSERT_EQ(PP_OK
, callback
.result());
685 expected_file_names
.insert(buffer
.str());
688 static const int kNumDirectories
= 3;
689 std::set
<std::string
> expected_dir_names
;
690 for (int i
= 1; i
<= kNumDirectories
; ++i
) {
691 std::ostringstream buffer
;
692 buffer
<< test_dir_name
<< '/' << dir_prefix
<< i
;
693 pp::FileRef
file_ref(file_system
, buffer
.str().c_str());
695 callback
.WaitForResult(file_ref
.MakeDirectory(callback
.GetCallback()));
696 CHECK_CALLBACK_BEHAVIOR(callback
);
697 ASSERT_EQ(PP_OK
, callback
.result());
699 expected_dir_names
.insert(buffer
.str());
702 // Test that |ReadDirectoryEntries()| is able to fetch all
703 // directories and files that we created.
705 TestCompletionCallbackWithOutput
<DirEntries
> output_callback(
706 instance_
->pp_instance(), callback_type());
708 output_callback
.WaitForResult(
709 test_dir
.ReadDirectoryEntries(output_callback
.GetCallback()));
710 CHECK_CALLBACK_BEHAVIOR(output_callback
);
711 ASSERT_EQ(PP_OK
, output_callback
.result());
713 DirEntries entries
= output_callback
.output();
714 size_t sum
= expected_file_names
.size() + expected_dir_names
.size();
715 ASSERT_EQ(sum
, entries
.size());
717 for (DirEntries::const_iterator it
= entries
.begin();
718 it
!= entries
.end(); ++it
) {
719 pp::FileRef file_ref
= it
->file_ref();
720 std::string file_path
= file_ref
.GetPath().AsString();
721 std::set
<std::string
>::iterator found
=
722 expected_file_names
.find(file_path
);
723 if (found
!= expected_file_names
.end()) {
724 if (it
->file_type() != PP_FILETYPE_REGULAR
)
725 return file_path
+ " should have been a regular file.";
726 expected_file_names
.erase(found
);
728 found
= expected_dir_names
.find(file_path
);
729 if (found
== expected_dir_names
.end())
730 return "Unexpected file path: " + file_path
;
731 if (it
->file_type() != PP_FILETYPE_DIRECTORY
)
732 return file_path
+ " should have been a directory.";
733 expected_dir_names
.erase(found
);
736 ASSERT_TRUE(expected_file_names
.empty());
737 ASSERT_TRUE(expected_dir_names
.empty());
740 // Test cancellation of asynchronous |ReadDirectoryEntries()|.
741 TestCompletionCallbackWithOutput
<DirEntries
> output_callback(
742 instance_
->pp_instance(), callback_type());
744 rv
= pp::FileRef(file_system
, test_dir_name
)
745 .ReadDirectoryEntries(output_callback
.GetCallback());
747 output_callback
.WaitForAbortResult(rv
);
748 CHECK_CALLBACK_BEHAVIOR(output_callback
);