- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / tests / test_file_ref.cc
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.
4
5 #include "ppapi/tests/test_file_ref.h"
6
7 #include <stdio.h>
8
9 #include <sstream>
10 #include <vector>
11
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"
26
27 REGISTER_TEST_CASE(FileRef);
28
29 namespace {
30
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?";
37
38 typedef std::vector<pp::DirectoryEntry> DirEntries;
39
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.";
45 }
46
47 }  // namespace
48
49 bool TestFileRef::Init() {
50   return CheckTestingInterface() && EnsureRunningOverHTTP();
51 }
52
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);
57
58   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
59
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());
64
65   pp::URLResponseInfo response_info(loader.GetResponseInfo());
66   ASSERT_FALSE(response_info.is_null());
67   ASSERT_EQ(200, response_info.GetStatusCode());
68
69   *file_ref_ext = pp::FileRef(response_info.GetBodyAsFileRef());
70   ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, file_ref_ext->GetFileSystemType());
71   PASS();
72 }
73
74 int32_t TestFileRef::DeleteDirectoryRecursively(pp::FileRef* dir) {
75   if (!dir)
76     return PP_ERROR_BADARGUMENT;
77
78   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
79   TestCompletionCallbackWithOutput<DirEntries> output_callback(
80       instance_->pp_instance(), callback_type());
81
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)
86     return rv;
87
88   DirEntries entries = output_callback.output();
89   for (DirEntries::const_iterator it = entries.begin();
90        it != entries.end();
91        ++it) {
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)
96         return rv;
97     } else {
98       callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
99       rv = callback.result();
100       if (rv != PP_OK && rv != PP_ERROR_FILENOTFOUND)
101         return rv;
102     }
103   }
104   callback.WaitForResult(dir->Delete(callback.GetCallback()));
105   return callback.result();
106 }
107
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);
121 }
122
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();
133
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: " +
142           invalid_paths[j];
143     }
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: " +
147           invalid_paths[j];
148     }
149   }
150   PASS();
151 }
152
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);
158
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.";
162
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.";
166
167   pp::FileRef file_ref_ext;
168   std::string result = MakeExternalFileRef(&file_ref_ext);
169   if (!result.empty())
170     return result;
171   PASS();
172 }
173
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);
179
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);
184
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);
189
190   // Test the "/" case.
191   pp::FileRef file_ref_slash(file_system_temp, "/");
192   name = file_ref_slash.GetName().AsString();
193   if (name != "/")
194     return ReportMismatch("FileRef::GetName", name, "/");
195
196   pp::URLRequestInfo request(instance_);
197   request.SetURL("test_url_loader_data/hello.txt");
198   request.SetStreamToFile(true);
199
200   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
201
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());
206
207   pp::URLResponseInfo response_info(loader.GetResponseInfo());
208   ASSERT_FALSE(response_info.is_null());
209   ASSERT_EQ(200, response_info.GetStatusCode());
210
211   pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
212   name = file_ref_ext.GetName().AsString();
213   ASSERT_FALSE(name.empty());
214
215   PASS();
216 }
217
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);
223
224   pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
225   ASSERT_EQ(kPersFilePath, file_ref_pers.GetPath().AsString());
226
227   pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
228   ASSERT_EQ(kTempFilePath, file_ref_temp.GetPath().AsString());
229
230   pp::URLRequestInfo request(instance_);
231   request.SetURL("test_url_loader_data/hello.txt");
232   request.SetStreamToFile(true);
233
234   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
235
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());
240
241   pp::URLResponseInfo response_info(loader.GetResponseInfo());
242   ASSERT_FALSE(response_info.is_null());
243   ASSERT_EQ(200, response_info.GetStatusCode());
244
245   pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
246   ASSERT_TRUE(file_ref_ext.GetPath().is_undefined());
247
248   PASS();
249 }
250
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);
256
257   pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
258   ASSERT_EQ(kParentPath, file_ref_pers.GetParent().GetPath().AsString());
259
260   pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
261   ASSERT_EQ(kParentPath, file_ref_temp.GetParent().GetPath().AsString());
262
263   // Test the "/" case.
264   pp::FileRef file_ref_slash(file_system_temp, "/");
265   ASSERT_EQ("/", file_ref_slash.GetParent().GetPath().AsString());
266
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());
270
271   pp::URLRequestInfo request(instance_);
272   request.SetURL("test_url_loader_data/hello.txt");
273   request.SetStreamToFile(true);
274
275   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
276
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());
281
282   pp::URLResponseInfo response_info(loader.GetResponseInfo());
283   ASSERT_FALSE(response_info.is_null());
284   ASSERT_EQ(200, response_info.GetStatusCode());
285
286   pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
287   ASSERT_TRUE(file_ref_ext.GetParent().is_null());
288
289   PASS();
290 }
291
292 std::string TestFileRef::TestMakeDirectory() {
293   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
294
295   // Open.
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());
300
301   // MakeDirectory.
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());
306
307   // MakeDirectory aborted.
308   int32_t rv = PP_ERROR_FAILED;
309   {
310     rv = pp::FileRef(file_system, "/test_dir_make_abort")
311         .MakeDirectory(callback.GetCallback());
312   }
313   callback.WaitForAbortResult(rv);
314   CHECK_CALLBACK_BEHAVIOR(callback);
315
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());
322
323   // MakeDirectoryIncludingAncestors aborted.
324   {
325     rv = pp::FileRef(file_system, "/dir_make_abort_1/dir_make_abort_2")
326         .MakeDirectoryIncludingAncestors(callback.GetCallback());
327   }
328   callback.WaitForAbortResult(rv);
329   CHECK_CALLBACK_BEHAVIOR(callback);
330
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());
336
337   PASS();
338 }
339
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());
346
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());
357
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());
362
363   // Touch.
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());
372
373   // Touch aborted.
374   int32_t rv = PP_ERROR_FAILED;
375   {
376     rv = pp::FileRef(file_system, "/file_touch_abort")
377         .Touch(last_access_time, last_modified_time, callback.GetCallback());
378   }
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());
384   } else {
385     // Touch ran synchronously and should have failed because the file does not
386     // exist.
387     ASSERT_EQ(PP_ERROR_FILENOTFOUND, callback.result());
388   }
389
390   // Query.
391   PP_FileInfo info;
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);
398
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);
402
403   // Cancellation test.
404   // TODO(viettrungluu): this test causes a bunch of LOG(WARNING)s; investigate.
405   // TODO(viettrungluu): check |info| for late writes.
406   {
407     rv = pp::FileRef(file_system, "/file_touch").Touch(
408         last_access_time, last_modified_time, callback.GetCallback());
409   }
410   callback.WaitForAbortResult(rv);
411   CHECK_CALLBACK_BEHAVIOR(callback);
412
413   PASS();
414 }
415
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());
422
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());
429
430   callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
431   CHECK_CALLBACK_BEHAVIOR(callback);
432   ASSERT_EQ(PP_OK, callback.result());
433
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());
438
439   callback.WaitForResult(dir_ref.Delete(callback.GetCallback()));
440   CHECK_CALLBACK_BEHAVIOR(callback);
441   ASSERT_EQ(PP_OK, callback.result());
442
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());
448
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());
454
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());
459
460   // Delete aborted.
461   int32_t rv = PP_ERROR_FAILED;
462   {
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());
471   }
472   callback.WaitForAbortResult(rv);
473   CHECK_CALLBACK_BEHAVIOR(callback);
474
475   PASS();
476 }
477
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());
484
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());
491
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());
497
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());
502
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());
508
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());
514
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());
521
522   // Rename aborted.
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");
528   {
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());
536
537     rv = file_ref_abort.Rename(target_file_ref_abort, callback.GetCallback());
538   }
539   callback.WaitForAbortResult(rv);
540   CHECK_CALLBACK_BEHAVIOR(callback);
541
542   PASS();
543 }
544
545 std::string TestFileRef::TestQuery() {
546   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
547
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());
552
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());
559
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());
564
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());
570
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);
577
578   // Query a file ref on an external filesystem.
579   pp::FileRef file_ref_ext;
580   std::string result = MakeExternalFileRef(&file_ref_ext);
581   if (!result.empty())
582     return result;
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());
588
589   info = out_callback.output();
590   ASSERT_EQ(PP_FILETYPE_REGULAR, info.type);
591   ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, info.system_type);
592
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);
597
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());
604
605   PASS();
606 }
607
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());
614
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());
621
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());
630
631   // FileRef::ReadDirectoryEntries only works out-of-process.
632   if (testing_interface_->IsOutOfProcess()) {
633     TestCompletionCallbackWithOutput<DirEntries>
634         output_callback(instance_->pp_instance(), callback_type());
635
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());
640
641     DirEntries entries = output_callback.output();
642     ASSERT_EQ(1, entries.size());
643     ASSERT_EQ(kTerribleName, entries.front().file_ref().GetName().AsString());
644   }
645
646   PASS();
647 }
648
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());
656
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_";
661
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);
665
666   callback.WaitForResult(test_dir.MakeDirectory(callback.GetCallback()));
667   CHECK_CALLBACK_BEHAVIOR(callback);
668   ASSERT_EQ(PP_OK, callback.result());
669
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());
676
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());
682
683     expected_file_names.insert(buffer.str());
684   }
685
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());
692
693     callback.WaitForResult(file_ref.MakeDirectory(callback.GetCallback()));
694     CHECK_CALLBACK_BEHAVIOR(callback);
695     ASSERT_EQ(PP_OK, callback.result());
696
697     expected_dir_names.insert(buffer.str());
698   }
699
700   // Test that |ReadDirectoryEntries()| is able to fetch all
701   // directories and files that we created.
702   {
703     TestCompletionCallbackWithOutput<DirEntries> output_callback(
704         instance_->pp_instance(), callback_type());
705
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());
710
711     DirEntries entries = output_callback.output();
712     size_t sum = expected_file_names.size() + expected_dir_names.size();
713     ASSERT_EQ(sum, entries.size());
714
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);
725       } else {
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);
732       }
733     }
734     ASSERT_TRUE(expected_file_names.empty());
735     ASSERT_TRUE(expected_dir_names.empty());
736   }
737
738   // Test cancellation of asynchronous |ReadDirectoryEntries()|.
739   TestCompletionCallbackWithOutput<DirEntries> output_callback(
740       instance_->pp_instance(), callback_type());
741   {
742     rv = pp::FileRef(file_system, test_dir_name)
743         .ReadDirectoryEntries(output_callback.GetCallback());
744   }
745   output_callback.WaitForAbortResult(rv);
746   CHECK_CALLBACK_BEHAVIOR(output_callback);
747
748
749   PASS();
750 }