Home | History | Annotate | Download | only in tests
      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   // 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);
    125 }
    126 
    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();
    137 
    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: " +
    146           invalid_paths[j];
    147     }
    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: " +
    151           invalid_paths[j];
    152     }
    153   }
    154   PASS();
    155 }
    156 
    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);
    162 
    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.";
    166 
    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.";
    170 
    171   pp::FileRef file_ref_ext;
    172   std::string result = MakeExternalFileRef(&file_ref_ext);
    173   if (!result.empty())
    174     return result;
    175   PASS();
    176 }
    177 
    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);
    183 
    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);
    188 
    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);
    193 
    194   // Test the "/" case.
    195   pp::FileRef file_ref_slash(file_system_temp, "/");
    196   name = file_ref_slash.GetName().AsString();
    197   if (name != "/")
    198     return ReportMismatch("FileRef::GetName", name, "/");
    199 
    200   pp::URLRequestInfo request(instance_);
    201   request.SetURL("test_url_loader_data/hello.txt");
    202   request.SetStreamToFile(true);
    203 
    204   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    205 
    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());
    210 
    211   pp::URLResponseInfo response_info(loader.GetResponseInfo());
    212   ASSERT_FALSE(response_info.is_null());
    213   ASSERT_EQ(200, response_info.GetStatusCode());
    214 
    215   pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
    216   name = file_ref_ext.GetName().AsString();
    217   ASSERT_FALSE(name.empty());
    218 
    219   PASS();
    220 }
    221 
    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);
    227 
    228   pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
    229   ASSERT_EQ(kPersFilePath, file_ref_pers.GetPath().AsString());
    230 
    231   pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
    232   ASSERT_EQ(kTempFilePath, file_ref_temp.GetPath().AsString());
    233 
    234   pp::URLRequestInfo request(instance_);
    235   request.SetURL("test_url_loader_data/hello.txt");
    236   request.SetStreamToFile(true);
    237 
    238   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    239 
    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());
    244 
    245   pp::URLResponseInfo response_info(loader.GetResponseInfo());
    246   ASSERT_FALSE(response_info.is_null());
    247   ASSERT_EQ(200, response_info.GetStatusCode());
    248 
    249   pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
    250   ASSERT_TRUE(file_ref_ext.GetPath().is_undefined());
    251 
    252   PASS();
    253 }
    254 
    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);
    260 
    261   pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
    262   ASSERT_EQ(kParentPath, file_ref_pers.GetParent().GetPath().AsString());
    263 
    264   pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
    265   ASSERT_EQ(kParentPath, file_ref_temp.GetParent().GetPath().AsString());
    266 
    267   // Test the "/" case.
    268   pp::FileRef file_ref_slash(file_system_temp, "/");
    269   ASSERT_EQ("/", file_ref_slash.GetParent().GetPath().AsString());
    270 
    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());
    274 
    275   pp::URLRequestInfo request(instance_);
    276   request.SetURL("test_url_loader_data/hello.txt");
    277   request.SetStreamToFile(true);
    278 
    279   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    280 
    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());
    285 
    286   pp::URLResponseInfo response_info(loader.GetResponseInfo());
    287   ASSERT_FALSE(response_info.is_null());
    288   ASSERT_EQ(200, response_info.GetStatusCode());
    289 
    290   pp::FileRef file_ref_ext(response_info.GetBodyAsFileRef());
    291   ASSERT_TRUE(file_ref_ext.GetParent().is_null());
    292 
    293   PASS();
    294 }
    295 
    296 std::string TestFileRef::TestMakeDirectory() {
    297   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    298 
    299   // Open.
    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());
    304 
    305   // MakeDirectory.
    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());
    310 
    311   // MakeDirectory aborted.
    312   int32_t rv = PP_ERROR_FAILED;
    313   {
    314     rv = pp::FileRef(file_system, "/test_dir_make_abort")
    315         .MakeDirectory(callback.GetCallback());
    316   }
    317   callback.WaitForAbortResult(rv);
    318   CHECK_CALLBACK_BEHAVIOR(callback);
    319 
    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());
    326 
    327   // MakeDirectoryIncludingAncestors aborted.
    328   {
    329     rv = pp::FileRef(file_system, "/dir_make_abort_1/dir_make_abort_2")
    330         .MakeDirectoryIncludingAncestors(callback.GetCallback());
    331   }
    332   callback.WaitForAbortResult(rv);
    333   CHECK_CALLBACK_BEHAVIOR(callback);
    334 
    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());
    340 
    341   PASS();
    342 }
    343 
    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());
    350 
    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());
    361 
    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());
    366 
    367   // Touch.
    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());
    376 
    377   // Touch aborted.
    378   int32_t rv = PP_ERROR_FAILED;
    379   {
    380     rv = pp::FileRef(file_system, "/file_touch_abort")
    381         .Touch(last_access_time, last_modified_time, callback.GetCallback());
    382   }
    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());
    388   } else {
    389     // Touch ran synchronously and should have failed because the file does not
    390     // exist.
    391     ASSERT_EQ(PP_ERROR_FILENOTFOUND, callback.result());
    392   }
    393 
    394   // Query.
    395   PP_FileInfo info;
    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);
    404 
    405   // Cancellation test.
    406   // TODO(viettrungluu): this test causes a bunch of LOG(WARNING)s; investigate.
    407   // TODO(viettrungluu): check |info| for late writes.
    408   {
    409     rv = pp::FileRef(file_system, "/file_touch").Touch(
    410         last_access_time, last_modified_time, callback.GetCallback());
    411   }
    412   callback.WaitForAbortResult(rv);
    413   CHECK_CALLBACK_BEHAVIOR(callback);
    414 
    415   PASS();
    416 }
    417 
    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());
    424 
    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());
    431 
    432   callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
    433   CHECK_CALLBACK_BEHAVIOR(callback);
    434   ASSERT_EQ(PP_OK, callback.result());
    435 
    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());
    440 
    441   callback.WaitForResult(dir_ref.Delete(callback.GetCallback()));
    442   CHECK_CALLBACK_BEHAVIOR(callback);
    443   ASSERT_EQ(PP_OK, callback.result());
    444 
    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());
    450 
    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());
    456 
    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());
    461 
    462   // Delete aborted.
    463   int32_t rv = PP_ERROR_FAILED;
    464   {
    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());
    473   }
    474   callback.WaitForAbortResult(rv);
    475   CHECK_CALLBACK_BEHAVIOR(callback);
    476 
    477   PASS();
    478 }
    479 
    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());
    486 
    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());
    493 
    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());
    499 
    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());
    504 
    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());
    510 
    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());
    516 
    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());
    523 
    524   // Rename aborted.
    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");
    530   {
    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());
    538 
    539     rv = file_ref_abort.Rename(target_file_ref_abort, callback.GetCallback());
    540   }
    541   callback.WaitForAbortResult(rv);
    542   CHECK_CALLBACK_BEHAVIOR(callback);
    543 
    544   PASS();
    545 }
    546 
    547 std::string TestFileRef::TestQuery() {
    548   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
    549 
    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());
    554 
    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());
    561 
    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());
    566 
    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());
    572 
    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);
    579 
    580   // Query a file ref on an external filesystem.
    581   pp::FileRef file_ref_ext;
    582   std::string result = MakeExternalFileRef(&file_ref_ext);
    583   if (!result.empty())
    584     return result;
    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());
    590 
    591   info = out_callback.output();
    592   ASSERT_EQ(PP_FILETYPE_REGULAR, info.type);
    593   ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, info.system_type);
    594 
    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);
    599 
    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());
    606 
    607   PASS();
    608 }
    609 
    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());
    616 
    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());
    623 
    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());
    632 
    633   // FileRef::ReadDirectoryEntries only works out-of-process.
    634   if (testing_interface_->IsOutOfProcess()) {
    635     TestCompletionCallbackWithOutput<DirEntries>
    636         output_callback(instance_->pp_instance(), callback_type());
    637 
    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());
    642 
    643     DirEntries entries = output_callback.output();
    644     ASSERT_EQ(1, entries.size());
    645     ASSERT_EQ(kTerribleName, entries.front().file_ref().GetName().AsString());
    646   }
    647 
    648   PASS();
    649 }
    650 
    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());
    658 
    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_";
    663 
    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);
    667 
    668   callback.WaitForResult(test_dir.MakeDirectory(callback.GetCallback()));
    669   CHECK_CALLBACK_BEHAVIOR(callback);
    670   ASSERT_EQ(PP_OK, callback.result());
    671 
    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());
    678 
    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());
    684 
    685     expected_file_names.insert(buffer.str());
    686   }
    687 
    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());
    694 
    695     callback.WaitForResult(file_ref.MakeDirectory(callback.GetCallback()));
    696     CHECK_CALLBACK_BEHAVIOR(callback);
    697     ASSERT_EQ(PP_OK, callback.result());
    698 
    699     expected_dir_names.insert(buffer.str());
    700   }
    701 
    702   // Test that |ReadDirectoryEntries()| is able to fetch all
    703   // directories and files that we created.
    704   {
    705     TestCompletionCallbackWithOutput<DirEntries> output_callback(
    706         instance_->pp_instance(), callback_type());
    707 
    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());
    712 
    713     DirEntries entries = output_callback.output();
    714     size_t sum = expected_file_names.size() + expected_dir_names.size();
    715     ASSERT_EQ(sum, entries.size());
    716 
    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);
    727       } else {
    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);
    734       }
    735     }
    736     ASSERT_TRUE(expected_file_names.empty());
    737     ASSERT_TRUE(expected_dir_names.empty());
    738   }
    739 
    740   // Test cancellation of asynchronous |ReadDirectoryEntries()|.
    741   TestCompletionCallbackWithOutput<DirEntries> output_callback(
    742       instance_->pp_instance(), callback_type());
    743   {
    744     rv = pp::FileRef(file_system, test_dir_name)
    745         .ReadDirectoryEntries(output_callback.GetCallback());
    746   }
    747   output_callback.WaitForAbortResult(rv);
    748   CHECK_CALLBACK_BEHAVIOR(output_callback);
    749 
    750 
    751   PASS();
    752 }
    753