test_file_ref.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  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. #include "ppapi/tests/test_file_ref.h"
  5. #include <stddef.h>
  6. #include <stdio.h>
  7. #include <sstream>
  8. #include <vector>
  9. #include "ppapi/c/pp_errors.h"
  10. #include "ppapi/c/ppb_file_io.h"
  11. #include "ppapi/c/private/ppb_testing_private.h"
  12. #include "ppapi/cpp/dev/file_chooser_dev.h"
  13. #include "ppapi/cpp/directory_entry.h"
  14. #include "ppapi/cpp/file_io.h"
  15. #include "ppapi/cpp/file_ref.h"
  16. #include "ppapi/cpp/file_system.h"
  17. #include "ppapi/cpp/instance.h"
  18. #include "ppapi/cpp/module.h"
  19. #include "ppapi/cpp/url_loader.h"
  20. #include "ppapi/cpp/url_request_info.h"
  21. #include "ppapi/cpp/url_response_info.h"
  22. #include "ppapi/tests/test_utils.h"
  23. #include "ppapi/tests/testing_instance.h"
  24. REGISTER_TEST_CASE(FileRef);
  25. namespace {
  26. const char* kPersFileName = "persistent";
  27. const char* kTempFileName = "temporary";
  28. const char* kParentPath = "/foo/bar";
  29. const char* kPersFilePath = "/foo/bar/persistent";
  30. const char* kTempFilePath = "/foo/bar/temporary";
  31. const char* kTerribleName = "!@#$%^&*()-_=+{}[] ;:'\"|`~\t\n\r\b?";
  32. typedef std::vector<pp::DirectoryEntry> DirEntries;
  33. std::string ReportMismatch(const std::string& method_name,
  34. const std::string& returned_result,
  35. const std::string& expected_result) {
  36. return method_name + " returned '" + returned_result + "'; '" +
  37. expected_result + "' expected.";
  38. }
  39. } // namespace
  40. bool TestFileRef::Init() {
  41. return CheckTestingInterface() && EnsureRunningOverHTTP();
  42. }
  43. std::string TestFileRef::MakeExternalFileRef(pp::FileRef* file_ref_ext) {
  44. pp::FileChooser_Dev file_chooser(instance(), PP_FILECHOOSERMODE_OPEN, "*");
  45. ASSERT_FALSE(file_chooser.is_null());
  46. TestCompletionCallbackWithOutput<std::vector<pp::FileRef> >
  47. filechooser_callback(instance_->pp_instance(), callback_type());
  48. filechooser_callback.WaitForResult(
  49. file_chooser.Show(filechooser_callback.GetCallback()));
  50. const std::vector<pp::FileRef>& output_ref = filechooser_callback.output();
  51. ASSERT_EQ(1u, output_ref.size());
  52. *file_ref_ext = output_ref[0];
  53. ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, file_ref_ext->GetFileSystemType());
  54. PASS();
  55. }
  56. int32_t TestFileRef::DeleteDirectoryRecursively(pp::FileRef* dir) {
  57. if (!dir)
  58. return PP_ERROR_BADARGUMENT;
  59. TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  60. TestCompletionCallbackWithOutput<DirEntries> output_callback(
  61. instance_->pp_instance(), callback_type());
  62. output_callback.WaitForResult(
  63. dir->ReadDirectoryEntries(output_callback.GetCallback()));
  64. int32_t rv = output_callback.result();
  65. if (rv != PP_OK && rv != PP_ERROR_FILENOTFOUND)
  66. return rv;
  67. DirEntries entries = output_callback.output();
  68. for (DirEntries::const_iterator it = entries.begin();
  69. it != entries.end();
  70. ++it) {
  71. pp::FileRef file_ref = it->file_ref();
  72. if (it->file_type() == PP_FILETYPE_DIRECTORY) {
  73. rv = DeleteDirectoryRecursively(&file_ref);
  74. if (rv != PP_OK && rv != PP_ERROR_FILENOTFOUND)
  75. return rv;
  76. } else {
  77. callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
  78. rv = callback.result();
  79. if (rv != PP_OK && rv != PP_ERROR_FILENOTFOUND)
  80. return rv;
  81. }
  82. }
  83. callback.WaitForResult(dir->Delete(callback.GetCallback()));
  84. return callback.result();
  85. }
  86. void TestFileRef::RunTests(const std::string& filter) {
  87. RUN_CALLBACK_TEST(TestFileRef, Create, filter);
  88. RUN_CALLBACK_TEST(TestFileRef, GetFileSystemType, filter);
  89. RUN_CALLBACK_TEST(TestFileRef, GetName, filter);
  90. RUN_CALLBACK_TEST(TestFileRef, GetPath, filter);
  91. RUN_CALLBACK_TEST(TestFileRef, GetParent, filter);
  92. RUN_CALLBACK_TEST(TestFileRef, MakeDirectory, filter);
  93. RUN_CALLBACK_TEST(TestFileRef, QueryAndTouchFile, filter);
  94. RUN_CALLBACK_TEST(TestFileRef, DeleteFileAndDirectory, filter);
  95. RUN_CALLBACK_TEST(TestFileRef, RenameFileAndDirectory, filter);
  96. RUN_CALLBACK_TEST(TestFileRef, Query, filter);
  97. RUN_CALLBACK_TEST(TestFileRef, FileNameEscaping, filter);
  98. RUN_CALLBACK_TEST(TestFileRef, ReadDirectoryEntries, filter);
  99. }
  100. std::string TestFileRef::TestCreate() {
  101. std::vector<std::string> invalid_paths;
  102. invalid_paths.push_back("invalid_path"); // no '/' at the first character
  103. invalid_paths.push_back(std::string()); // empty path
  104. // The following are directory traversal checks
  105. invalid_paths.push_back("..");
  106. invalid_paths.push_back("/../invalid_path");
  107. invalid_paths.push_back("/../../invalid_path");
  108. invalid_paths.push_back("/invalid/../../path");
  109. const size_t num_invalid_paths = invalid_paths.size();
  110. pp::FileSystem file_system_pers(
  111. instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
  112. pp::FileSystem file_system_temp(
  113. instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  114. for (size_t j = 0; j < num_invalid_paths; ++j) {
  115. pp::FileRef file_ref_pers(file_system_pers, invalid_paths[j].c_str());
  116. if (file_ref_pers.pp_resource() != 0) {
  117. return "file_ref_pers expected to be invalid for path: " +
  118. invalid_paths[j];
  119. }
  120. pp::FileRef file_ref_temp(file_system_temp, invalid_paths[j].c_str());
  121. if (file_ref_temp.pp_resource() != 0) {
  122. return "file_ref_temp expected to be invalid for path: " +
  123. invalid_paths[j];
  124. }
  125. }
  126. PASS();
  127. }
  128. std::string TestFileRef::TestGetFileSystemType() {
  129. pp::FileSystem file_system_pers(
  130. instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
  131. pp::FileSystem file_system_temp(
  132. instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  133. pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
  134. if (file_ref_pers.GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALPERSISTENT)
  135. return "file_ref_pers expected to be persistent.";
  136. pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
  137. if (file_ref_temp.GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALTEMPORARY)
  138. return "file_ref_temp expected to be temporary.";
  139. pp::FileRef file_ref_ext;
  140. std::string result = MakeExternalFileRef(&file_ref_ext);
  141. if (!result.empty())
  142. return result;
  143. PASS();
  144. }
  145. std::string TestFileRef::TestGetName() {
  146. pp::FileSystem file_system_pers(
  147. instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
  148. pp::FileSystem file_system_temp(
  149. instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  150. pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
  151. std::string name = file_ref_pers.GetName().AsString();
  152. if (name != kPersFileName)
  153. return ReportMismatch("FileRef::GetName", name, kPersFileName);
  154. pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
  155. name = file_ref_temp.GetName().AsString();
  156. if (name != kTempFileName)
  157. return ReportMismatch("FileRef::GetName", name, kTempFileName);
  158. // Test the "/" case.
  159. pp::FileRef file_ref_slash(file_system_temp, "/");
  160. name = file_ref_slash.GetName().AsString();
  161. if (name != "/")
  162. return ReportMismatch("FileRef::GetName", name, "/");
  163. pp::FileRef file_ref_ext;
  164. std::string result = MakeExternalFileRef(&file_ref_ext);
  165. if (!result.empty())
  166. return result;
  167. name = file_ref_ext.GetName().AsString();
  168. ASSERT_FALSE(name.empty());
  169. PASS();
  170. }
  171. std::string TestFileRef::TestGetPath() {
  172. pp::FileSystem file_system_pers(
  173. instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
  174. pp::FileSystem file_system_temp(
  175. instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  176. pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
  177. ASSERT_EQ(kPersFilePath, file_ref_pers.GetPath().AsString());
  178. pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
  179. ASSERT_EQ(kTempFilePath, file_ref_temp.GetPath().AsString());
  180. pp::FileRef file_ref_ext;
  181. std::string result = MakeExternalFileRef(&file_ref_ext);
  182. if (!result.empty())
  183. return result;
  184. ASSERT_TRUE(file_ref_ext.GetPath().is_undefined());
  185. PASS();
  186. }
  187. std::string TestFileRef::TestGetParent() {
  188. pp::FileSystem file_system_pers(
  189. instance_, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
  190. pp::FileSystem file_system_temp(
  191. instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  192. pp::FileRef file_ref_pers(file_system_pers, kPersFilePath);
  193. ASSERT_EQ(kParentPath, file_ref_pers.GetParent().GetPath().AsString());
  194. pp::FileRef file_ref_temp(file_system_temp, kTempFilePath);
  195. ASSERT_EQ(kParentPath, file_ref_temp.GetParent().GetPath().AsString());
  196. // Test the "/" case.
  197. pp::FileRef file_ref_slash(file_system_temp, "/");
  198. ASSERT_EQ("/", file_ref_slash.GetParent().GetPath().AsString());
  199. // Test the "/foo" case (the parent is "/").
  200. pp::FileRef file_ref_with_root_parent(file_system_temp, "/foo");
  201. ASSERT_EQ("/", file_ref_with_root_parent.GetParent().GetPath().AsString());
  202. pp::FileRef file_ref_ext;
  203. std::string result = MakeExternalFileRef(&file_ref_ext);
  204. if (!result.empty())
  205. return result;
  206. ASSERT_TRUE(file_ref_ext.GetParent().is_null());
  207. PASS();
  208. }
  209. std::string TestFileRef::TestMakeDirectory() {
  210. TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  211. // Open.
  212. pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  213. callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
  214. CHECK_CALLBACK_BEHAVIOR(callback);
  215. ASSERT_EQ(PP_OK, callback.result());
  216. // Make a directory.
  217. pp::FileRef dir_ref(file_system, "/dir_make_dir");
  218. callback.WaitForResult(
  219. dir_ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
  220. CHECK_CALLBACK_BEHAVIOR(callback);
  221. ASSERT_EQ(PP_OK, callback.result());
  222. // Make a directory on the existing path without exclusive flag.
  223. callback.WaitForResult(
  224. dir_ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
  225. CHECK_CALLBACK_BEHAVIOR(callback);
  226. ASSERT_EQ(PP_OK, callback.result());
  227. // Making a directory should be aborted.
  228. int32_t rv = PP_ERROR_FAILED;
  229. {
  230. rv = pp::FileRef(file_system, "/dir_make_dir_abort")
  231. .MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback());
  232. }
  233. callback.WaitForAbortResult(rv);
  234. CHECK_CALLBACK_BEHAVIOR(callback);
  235. // Make nested directories.
  236. dir_ref = pp::FileRef(file_system, "/dir_make_nested_dir_1/dir");
  237. callback.WaitForResult(
  238. dir_ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS,
  239. callback.GetCallback()));
  240. CHECK_CALLBACK_BEHAVIOR(callback);
  241. ASSERT_EQ(PP_OK, callback.result());
  242. dir_ref = pp::FileRef(file_system, "/dir_make_nested_dir_2/dir");
  243. callback.WaitForResult(
  244. dir_ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
  245. CHECK_CALLBACK_BEHAVIOR(callback);
  246. ASSERT_EQ(PP_ERROR_FILENOTFOUND, callback.result());
  247. // Ensure there is no directory on the path to test exclusive cases.
  248. dir_ref = pp::FileRef(file_system, "/dir_make_dir_exclusive");
  249. rv = DeleteDirectoryRecursively(&dir_ref);
  250. ASSERT_TRUE(rv == PP_OK || rv == PP_ERROR_FILENOTFOUND);
  251. // Make a directory exclusively.
  252. callback.WaitForResult(
  253. dir_ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_EXCLUSIVE,
  254. callback.GetCallback()));
  255. CHECK_CALLBACK_BEHAVIOR(callback);
  256. ASSERT_EQ(PP_OK, callback.result());
  257. callback.WaitForResult(
  258. dir_ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_EXCLUSIVE,
  259. callback.GetCallback()));
  260. CHECK_CALLBACK_BEHAVIOR(callback);
  261. ASSERT_EQ(PP_ERROR_FILEEXISTS, callback.result());
  262. PASS();
  263. }
  264. std::string TestFileRef::TestQueryAndTouchFile() {
  265. TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  266. pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  267. callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
  268. CHECK_CALLBACK_BEHAVIOR(callback);
  269. ASSERT_EQ(PP_OK, callback.result());
  270. pp::FileRef file_ref(file_system, "/file_touch");
  271. pp::FileIO file_io(instance_);
  272. callback.WaitForResult(
  273. file_io.Open(file_ref,
  274. PP_FILEOPENFLAG_CREATE |
  275. PP_FILEOPENFLAG_TRUNCATE |
  276. PP_FILEOPENFLAG_WRITE,
  277. callback.GetCallback()));
  278. CHECK_CALLBACK_BEHAVIOR(callback);
  279. ASSERT_EQ(PP_OK, callback.result());
  280. // Write some data to have a non-zero file size.
  281. callback.WaitForResult(file_io.Write(0, "test", 4, callback.GetCallback()));
  282. CHECK_CALLBACK_BEHAVIOR(callback);
  283. ASSERT_EQ(4, callback.result());
  284. // Touch.
  285. const PP_Time last_access_time = 123 * 24 * 3600.0;
  286. // last_modified_time's granularity is 2 seconds
  287. // See note in test_file_io.cc for why we use this time.
  288. const PP_Time last_modified_time = 100 * 24 * 3600.0;
  289. callback.WaitForResult(file_ref.Touch(last_access_time, last_modified_time,
  290. callback.GetCallback()));
  291. CHECK_CALLBACK_BEHAVIOR(callback);
  292. ASSERT_EQ(PP_OK, callback.result());
  293. // Touch aborted.
  294. int32_t rv = PP_ERROR_FAILED;
  295. {
  296. rv = pp::FileRef(file_system, "/file_touch_abort")
  297. .Touch(last_access_time, last_modified_time, callback.GetCallback());
  298. }
  299. callback.WaitForResult(rv);
  300. CHECK_CALLBACK_BEHAVIOR(callback);
  301. if (rv == PP_OK_COMPLETIONPENDING) {
  302. // Touch tried to run asynchronously and should have been aborted.
  303. ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
  304. } else {
  305. // Touch ran synchronously and should have failed because the file does not
  306. // exist.
  307. ASSERT_EQ(PP_ERROR_FILENOTFOUND, callback.result());
  308. }
  309. // Query.
  310. PP_FileInfo info;
  311. callback.WaitForResult(file_io.Query(&info, callback.GetCallback()));
  312. CHECK_CALLBACK_BEHAVIOR(callback);
  313. ASSERT_EQ(PP_OK, callback.result());
  314. ASSERT_EQ(4, info.size);
  315. ASSERT_EQ(PP_FILETYPE_REGULAR, info.type);
  316. ASSERT_EQ(PP_FILESYSTEMTYPE_LOCALTEMPORARY, info.system_type);
  317. // Disabled due to DST-related failure: crbug.com/314579
  318. // ASSERT_EQ(last_access_time, info.last_access_time);
  319. // ASSERT_EQ(last_modified_time, info.last_modified_time);
  320. // Cancellation test.
  321. // TODO(viettrungluu): this test causes a bunch of LOG(WARNING)s; investigate.
  322. // TODO(viettrungluu): check |info| for late writes.
  323. {
  324. rv = pp::FileRef(file_system, "/file_touch").Touch(
  325. last_access_time, last_modified_time, callback.GetCallback());
  326. }
  327. callback.WaitForAbortResult(rv);
  328. CHECK_CALLBACK_BEHAVIOR(callback);
  329. PASS();
  330. }
  331. std::string TestFileRef::TestDeleteFileAndDirectory() {
  332. TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  333. pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  334. callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
  335. CHECK_CALLBACK_BEHAVIOR(callback);
  336. ASSERT_EQ(PP_OK, callback.result());
  337. pp::FileRef file_ref(file_system, "/file_delete");
  338. pp::FileIO file_io(instance_);
  339. callback.WaitForResult(
  340. file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE, callback.GetCallback()));
  341. CHECK_CALLBACK_BEHAVIOR(callback);
  342. ASSERT_EQ(PP_OK, callback.result());
  343. callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
  344. CHECK_CALLBACK_BEHAVIOR(callback);
  345. ASSERT_EQ(PP_OK, callback.result());
  346. pp::FileRef dir_ref(file_system, "/dir_delete");
  347. callback.WaitForResult(dir_ref.MakeDirectory(
  348. PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
  349. CHECK_CALLBACK_BEHAVIOR(callback);
  350. ASSERT_EQ(PP_OK, callback.result());
  351. callback.WaitForResult(dir_ref.Delete(callback.GetCallback()));
  352. CHECK_CALLBACK_BEHAVIOR(callback);
  353. ASSERT_EQ(PP_OK, callback.result());
  354. pp::FileRef nested_dir_ref(file_system, "/dir_delete_1/dir_delete_2");
  355. callback.WaitForResult(
  356. nested_dir_ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS,
  357. callback.GetCallback()));
  358. CHECK_CALLBACK_BEHAVIOR(callback);
  359. ASSERT_EQ(PP_OK, callback.result());
  360. // Attempt to delete the parent directory (should fail; it's non-empty).
  361. pp::FileRef parent_dir_ref = nested_dir_ref.GetParent();
  362. callback.WaitForResult(parent_dir_ref.Delete(callback.GetCallback()));
  363. CHECK_CALLBACK_BEHAVIOR(callback);
  364. ASSERT_EQ(PP_ERROR_FAILED, callback.result());
  365. pp::FileRef nonexistent_file_ref(file_system, "/nonexistent_file_delete");
  366. callback.WaitForResult(nonexistent_file_ref.Delete(callback.GetCallback()));
  367. CHECK_CALLBACK_BEHAVIOR(callback);
  368. ASSERT_EQ(PP_ERROR_FILENOTFOUND, callback.result());
  369. // Delete aborted.
  370. int32_t rv = PP_ERROR_FAILED;
  371. {
  372. pp::FileRef file_ref_abort(file_system, "/file_delete_abort");
  373. pp::FileIO file_io_abort(instance_);
  374. callback.WaitForResult(
  375. file_io_abort.Open(file_ref_abort, PP_FILEOPENFLAG_CREATE,
  376. callback.GetCallback()));
  377. CHECK_CALLBACK_BEHAVIOR(callback);
  378. ASSERT_EQ(PP_OK, callback.result());
  379. rv = file_ref_abort.Delete(callback.GetCallback());
  380. }
  381. callback.WaitForAbortResult(rv);
  382. CHECK_CALLBACK_BEHAVIOR(callback);
  383. PASS();
  384. }
  385. std::string TestFileRef::TestRenameFileAndDirectory() {
  386. TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  387. pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  388. callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
  389. CHECK_CALLBACK_BEHAVIOR(callback);
  390. ASSERT_EQ(PP_OK, callback.result());
  391. pp::FileRef file_ref(file_system, "/file_rename");
  392. pp::FileIO file_io(instance_);
  393. callback.WaitForResult(
  394. file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE, callback.GetCallback()));
  395. CHECK_CALLBACK_BEHAVIOR(callback);
  396. ASSERT_EQ(PP_OK, callback.result());
  397. pp::FileRef target_file_ref(file_system, "/target_file_rename");
  398. callback.WaitForResult(
  399. file_ref.Rename(target_file_ref, callback.GetCallback()));
  400. CHECK_CALLBACK_BEHAVIOR(callback);
  401. ASSERT_EQ(PP_OK, callback.result());
  402. pp::FileRef dir_ref(file_system, "/dir_rename");
  403. callback.WaitForResult(dir_ref.MakeDirectory(
  404. PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
  405. CHECK_CALLBACK_BEHAVIOR(callback);
  406. ASSERT_EQ(PP_OK, callback.result());
  407. pp::FileRef target_dir_ref(file_system, "/target_dir_rename");
  408. callback.WaitForResult(
  409. dir_ref.Rename(target_dir_ref, callback.GetCallback()));
  410. CHECK_CALLBACK_BEHAVIOR(callback);
  411. ASSERT_EQ(PP_OK, callback.result());
  412. pp::FileRef nested_dir_ref(file_system, "/dir_rename_1/dir_rename_2");
  413. callback.WaitForResult(
  414. nested_dir_ref.MakeDirectory(PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS,
  415. callback.GetCallback()));
  416. CHECK_CALLBACK_BEHAVIOR(callback);
  417. ASSERT_EQ(PP_OK, callback.result());
  418. // Try to rename nested directory to the parent name. Should fail.
  419. pp::FileRef target_nested_dir_ref(file_system, "/dir_rename_1");
  420. callback.WaitForResult(
  421. nested_dir_ref.Rename(target_nested_dir_ref, callback.GetCallback()));
  422. CHECK_CALLBACK_BEHAVIOR(callback);
  423. ASSERT_EQ(PP_ERROR_FAILED, callback.result());
  424. // Rename aborted.
  425. // TODO(viettrungluu): Figure out what we want to do if the target file
  426. // resource is destroyed before completion.
  427. int32_t rv = PP_ERROR_FAILED;
  428. pp::FileRef target_file_ref_abort(file_system,
  429. "/target_file_rename_abort");
  430. {
  431. pp::FileRef file_ref_abort(file_system, "/file_rename_abort");
  432. pp::FileIO file_io_abort(instance_);
  433. callback.WaitForResult(
  434. file_io_abort.Open(file_ref_abort, PP_FILEOPENFLAG_CREATE,
  435. callback.GetCallback()));
  436. CHECK_CALLBACK_BEHAVIOR(callback);
  437. ASSERT_EQ(PP_OK, callback.result());
  438. rv = file_ref_abort.Rename(target_file_ref_abort, callback.GetCallback());
  439. }
  440. callback.WaitForAbortResult(rv);
  441. CHECK_CALLBACK_BEHAVIOR(callback);
  442. PASS();
  443. }
  444. std::string TestFileRef::TestQuery() {
  445. TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  446. pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  447. callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
  448. CHECK_CALLBACK_BEHAVIOR(callback);
  449. ASSERT_EQ(PP_OK, callback.result());
  450. pp::FileRef file_ref(file_system, "/file");
  451. pp::FileIO file_io(instance_);
  452. callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE,
  453. callback.GetCallback()));
  454. CHECK_CALLBACK_BEHAVIOR(callback);
  455. ASSERT_EQ(PP_OK, callback.result());
  456. // We touch the file so we can easily check access and modified time.
  457. callback.WaitForResult(file_io.Touch(0, 0, callback.GetCallback()));
  458. CHECK_CALLBACK_BEHAVIOR(callback);
  459. ASSERT_EQ(PP_OK, callback.result());
  460. TestCompletionCallbackWithOutput<PP_FileInfo> out_callback(
  461. instance_->pp_instance(), callback_type());
  462. out_callback.WaitForResult(file_ref.Query(out_callback.GetCallback()));
  463. CHECK_CALLBACK_BEHAVIOR(out_callback);
  464. ASSERT_EQ(PP_OK, out_callback.result());
  465. PP_FileInfo info = out_callback.output();
  466. ASSERT_EQ(0, info.size);
  467. ASSERT_EQ(PP_FILETYPE_REGULAR, info.type);
  468. ASSERT_EQ(PP_FILESYSTEMTYPE_LOCALTEMPORARY, info.system_type);
  469. ASSERT_DOUBLE_EQ(0.0, info.last_access_time);
  470. ASSERT_DOUBLE_EQ(0.0, info.last_modified_time);
  471. // Query a file ref on an external filesystem.
  472. pp::FileRef file_ref_ext;
  473. std::string result = MakeExternalFileRef(&file_ref_ext);
  474. if (!result.empty())
  475. return result;
  476. out_callback.WaitForResult(file_ref_ext.Query(out_callback.GetCallback()));
  477. CHECK_CALLBACK_BEHAVIOR(out_callback);
  478. if (out_callback.result() != PP_OK)
  479. return ReportError("Query() result", out_callback.result());
  480. ASSERT_EQ(PP_OK, out_callback.result());
  481. info = out_callback.output();
  482. ASSERT_EQ(PP_FILETYPE_REGULAR, info.type);
  483. ASSERT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, info.system_type);
  484. // We can't touch the file, so just sanity check the times.
  485. ASSERT_TRUE(info.creation_time >= 0.0);
  486. ASSERT_TRUE(info.last_modified_time >= 0.0);
  487. ASSERT_TRUE(info.last_access_time >= 0.0);
  488. // Query a file ref for a file that doesn't exist.
  489. pp::FileRef missing_file_ref(file_system, "/missing_file");
  490. out_callback.WaitForResult(missing_file_ref.Query(
  491. out_callback.GetCallback()));
  492. CHECK_CALLBACK_BEHAVIOR(out_callback);
  493. ASSERT_EQ(PP_ERROR_FILENOTFOUND, out_callback.result());
  494. PASS();
  495. }
  496. std::string TestFileRef::TestFileNameEscaping() {
  497. TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  498. pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  499. callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
  500. CHECK_CALLBACK_BEHAVIOR(callback);
  501. ASSERT_EQ(PP_OK, callback.result());
  502. std::string test_dir_path = "/dir_for_escaping_test";
  503. // Create a directory in which to test.
  504. pp::FileRef test_dir_ref(file_system, test_dir_path.c_str());
  505. callback.WaitForResult(test_dir_ref.MakeDirectory(
  506. PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
  507. CHECK_CALLBACK_BEHAVIOR(callback);
  508. ASSERT_EQ(PP_OK, callback.result());
  509. // Create the file with the terrible name.
  510. std::string full_file_path = test_dir_path + "/" + kTerribleName;
  511. pp::FileRef file_ref(file_system, full_file_path.c_str());
  512. pp::FileIO file_io(instance_);
  513. callback.WaitForResult(
  514. file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE, callback.GetCallback()));
  515. CHECK_CALLBACK_BEHAVIOR(callback);
  516. ASSERT_EQ(PP_OK, callback.result());
  517. // FileRef::ReadDirectoryEntries only works out-of-process.
  518. if (testing_interface_->IsOutOfProcess()) {
  519. TestCompletionCallbackWithOutput<DirEntries>
  520. output_callback(instance_->pp_instance(), callback_type());
  521. output_callback.WaitForResult(
  522. test_dir_ref.ReadDirectoryEntries(output_callback.GetCallback()));
  523. CHECK_CALLBACK_BEHAVIOR(output_callback);
  524. ASSERT_EQ(PP_OK, output_callback.result());
  525. DirEntries entries = output_callback.output();
  526. ASSERT_EQ(1, entries.size());
  527. ASSERT_EQ(kTerribleName, entries.front().file_ref().GetName().AsString());
  528. }
  529. PASS();
  530. }
  531. std::string TestFileRef::TestReadDirectoryEntries() {
  532. TestCompletionCallback callback(instance_->pp_instance(), callback_type());
  533. pp::FileSystem file_system(
  534. instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
  535. callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
  536. CHECK_CALLBACK_BEHAVIOR(callback);
  537. ASSERT_EQ(PP_OK, callback.result());
  538. // Setup testing directories and files.
  539. const char* test_dir_name = "/test_get_next_file";
  540. const char* file_prefix = "file_";
  541. const char* dir_prefix = "dir_";
  542. pp::FileRef test_dir(file_system, test_dir_name);
  543. int32_t rv = DeleteDirectoryRecursively(&test_dir);
  544. ASSERT_TRUE(rv == PP_OK || rv == PP_ERROR_FILENOTFOUND);
  545. callback.WaitForResult(test_dir.MakeDirectory(
  546. PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
  547. CHECK_CALLBACK_BEHAVIOR(callback);
  548. ASSERT_EQ(PP_OK, callback.result());
  549. static const int kNumFiles = 3;
  550. std::set<std::string> expected_file_names;
  551. for (int i = 1; i <= kNumFiles; ++i) {
  552. std::ostringstream buffer;
  553. buffer << test_dir_name << '/' << file_prefix << i;
  554. pp::FileRef file_ref(file_system, buffer.str().c_str());
  555. pp::FileIO file_io(instance_);
  556. callback.WaitForResult(
  557. file_io.Open(file_ref, PP_FILEOPENFLAG_CREATE, callback.GetCallback()));
  558. CHECK_CALLBACK_BEHAVIOR(callback);
  559. ASSERT_EQ(PP_OK, callback.result());
  560. expected_file_names.insert(buffer.str());
  561. }
  562. static const int kNumDirectories = 3;
  563. std::set<std::string> expected_dir_names;
  564. for (int i = 1; i <= kNumDirectories; ++i) {
  565. std::ostringstream buffer;
  566. buffer << test_dir_name << '/' << dir_prefix << i;
  567. pp::FileRef file_ref(file_system, buffer.str().c_str());
  568. callback.WaitForResult(file_ref.MakeDirectory(
  569. PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
  570. CHECK_CALLBACK_BEHAVIOR(callback);
  571. ASSERT_EQ(PP_OK, callback.result());
  572. expected_dir_names.insert(buffer.str());
  573. }
  574. // Test that |ReadDirectoryEntries()| is able to fetch all
  575. // directories and files that we created.
  576. {
  577. TestCompletionCallbackWithOutput<DirEntries> output_callback(
  578. instance_->pp_instance(), callback_type());
  579. output_callback.WaitForResult(
  580. test_dir.ReadDirectoryEntries(output_callback.GetCallback()));
  581. CHECK_CALLBACK_BEHAVIOR(output_callback);
  582. ASSERT_EQ(PP_OK, output_callback.result());
  583. DirEntries entries = output_callback.output();
  584. size_t sum = expected_file_names.size() + expected_dir_names.size();
  585. ASSERT_EQ(sum, entries.size());
  586. for (DirEntries::const_iterator it = entries.begin();
  587. it != entries.end(); ++it) {
  588. pp::FileRef file_ref = it->file_ref();
  589. std::string file_path = file_ref.GetPath().AsString();
  590. std::set<std::string>::iterator found =
  591. expected_file_names.find(file_path);
  592. if (found != expected_file_names.end()) {
  593. if (it->file_type() != PP_FILETYPE_REGULAR)
  594. return file_path + " should have been a regular file.";
  595. expected_file_names.erase(found);
  596. } else {
  597. found = expected_dir_names.find(file_path);
  598. if (found == expected_dir_names.end())
  599. return "Unexpected file path: " + file_path;
  600. if (it->file_type() != PP_FILETYPE_DIRECTORY)
  601. return file_path + " should have been a directory.";
  602. expected_dir_names.erase(found);
  603. }
  604. }
  605. ASSERT_TRUE(expected_file_names.empty());
  606. ASSERT_TRUE(expected_dir_names.empty());
  607. }
  608. // Test cancellation of asynchronous |ReadDirectoryEntries()|.
  609. TestCompletionCallbackWithOutput<DirEntries> output_callback(
  610. instance_->pp_instance(), callback_type());
  611. {
  612. rv = pp::FileRef(file_system, test_dir_name)
  613. .ReadDirectoryEntries(output_callback.GetCallback());
  614. }
  615. output_callback.WaitForAbortResult(rv);
  616. CHECK_CALLBACK_BEHAVIOR(output_callback);
  617. PASS();
  618. }