1 // Copyright (c) 2012 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_flash_file.h" 6 7 #include <algorithm> 8 #include <vector> 9 10 #include "ppapi/c/pp_file_info.h" 11 #include "ppapi/c/ppb_file_io.h" 12 #include "ppapi/cpp/module.h" 13 #include "ppapi/cpp/private/flash_file.h" 14 #include "ppapi/tests/testing_instance.h" 15 #include "ppapi/tests/test_utils.h" 16 17 #if defined(PPAPI_OS_WIN) 18 #include <windows.h> 19 #else 20 #include <errno.h> 21 #include <unistd.h> 22 #endif 23 24 using pp::flash::FileModuleLocal; 25 26 namespace { 27 28 void CloseFileHandle(PP_FileHandle file_handle) { 29 #if defined(PPAPI_OS_WIN) 30 CloseHandle(file_handle); 31 #else 32 close(file_handle); 33 #endif 34 } 35 36 bool WriteFile(PP_FileHandle file_handle, const std::string& contents) { 37 #if defined(PPAPI_OS_WIN) 38 DWORD bytes_written = 0; 39 BOOL result = ::WriteFile(file_handle, contents.c_str(), contents.size(), 40 &bytes_written, NULL); 41 return result && bytes_written == static_cast<DWORD>(contents.size()); 42 #else 43 ssize_t bytes_written = 0; 44 do { 45 bytes_written = write(file_handle, contents.c_str(), contents.size()); 46 } while (bytes_written == -1 && errno == EINTR); 47 return bytes_written == static_cast<ssize_t>(contents.size()); 48 #endif 49 } 50 51 bool ReadFile(PP_FileHandle file_handle, std::string* contents) { 52 static const size_t kBufferSize = 1024; 53 char* buffer = new char[kBufferSize]; 54 bool result = false; 55 contents->clear(); 56 57 #if defined(PPAPI_OS_WIN) 58 SetFilePointer(file_handle, 0, NULL, FILE_BEGIN); 59 DWORD bytes_read = 0; 60 do { 61 result = !!::ReadFile(file_handle, buffer, kBufferSize, &bytes_read, NULL); 62 if (result && bytes_read > 0) 63 contents->append(buffer, bytes_read); 64 } while (result && bytes_read > 0); 65 #else 66 lseek(file_handle, 0, SEEK_SET); 67 ssize_t bytes_read = 0; 68 do { 69 do { 70 bytes_read = read(file_handle, buffer, kBufferSize); 71 } while (bytes_read == -1 && errno == EINTR); 72 result = bytes_read != -1; 73 if (bytes_read > 0) 74 contents->append(buffer, bytes_read); 75 } while (bytes_read > 0); 76 #endif 77 78 delete[] buffer; 79 return result; 80 } 81 82 bool DirEntryEqual(FileModuleLocal::DirEntry i, 83 FileModuleLocal::DirEntry j) { 84 return i.name == j.name && i.is_dir == j.is_dir; 85 } 86 87 bool DirEntryLessThan(FileModuleLocal::DirEntry i, 88 FileModuleLocal::DirEntry j) { 89 if (i.name == j.name) 90 return i.is_dir < j.is_dir; 91 return i.name < j.name; 92 } 93 94 } // namespace 95 96 REGISTER_TEST_CASE(FlashFile); 97 98 TestFlashFile::TestFlashFile(TestingInstance* instance) 99 : TestCase(instance) { 100 } 101 102 TestFlashFile::~TestFlashFile() { 103 } 104 105 bool TestFlashFile::Init() { 106 return FileModuleLocal::IsAvailable(); 107 } 108 109 void TestFlashFile::RunTests(const std::string& filter) { 110 RUN_TEST(OpenFile, filter); 111 RUN_TEST(RenameFile, filter); 112 RUN_TEST(DeleteFileOrDir, filter); 113 RUN_TEST(CreateDir, filter); 114 RUN_TEST(QueryFile, filter); 115 RUN_TEST(GetDirContents, filter); 116 RUN_TEST(CreateTemporaryFile, filter); 117 } 118 119 void TestFlashFile::SetUp() { 120 // Clear out existing test data. 121 FileModuleLocal::DeleteFileOrDir(instance_, std::string(), true); 122 // Make sure that the root directory exists. 123 FileModuleLocal::CreateDir(instance_, std::string()); 124 } 125 126 std::string TestFlashFile::TestOpenFile() { 127 SetUp(); 128 std::string filename = "abc.txt"; 129 PP_FileHandle file_handle = FileModuleLocal::OpenFile(instance_, 130 filename, 131 PP_FILEOPENFLAG_WRITE | 132 PP_FILEOPENFLAG_CREATE); 133 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 134 135 std::string contents = "This is file."; 136 std::string read_contents; 137 ASSERT_TRUE(WriteFile(file_handle, contents)); 138 ASSERT_FALSE(ReadFile(file_handle, &read_contents)); 139 CloseFileHandle(file_handle); 140 141 file_handle = FileModuleLocal::OpenFile(instance_, 142 filename, 143 PP_FILEOPENFLAG_READ); 144 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 145 146 ASSERT_FALSE(WriteFile(file_handle, contents)); 147 ASSERT_TRUE(ReadFile(file_handle, &read_contents)); 148 ASSERT_EQ(contents, read_contents); 149 CloseFileHandle(file_handle); 150 151 PASS(); 152 } 153 154 std::string TestFlashFile::TestRenameFile() { 155 SetUp(); 156 std::string filename = "abc.txt"; 157 std::string new_filename = "abc_new.txt"; 158 std::string contents = "This is file."; 159 std::string read_contents; 160 161 PP_FileHandle file_handle = FileModuleLocal::OpenFile(instance_, 162 filename, 163 PP_FILEOPENFLAG_WRITE | 164 PP_FILEOPENFLAG_CREATE); 165 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 166 ASSERT_TRUE(WriteFile(file_handle, contents)); 167 CloseFileHandle(file_handle); 168 169 ASSERT_TRUE(FileModuleLocal::RenameFile(instance_, filename, new_filename)); 170 171 file_handle = FileModuleLocal::OpenFile(instance_, 172 new_filename, 173 PP_FILEOPENFLAG_READ); 174 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 175 ASSERT_TRUE(ReadFile(file_handle, &read_contents)); 176 ASSERT_EQ(contents, read_contents); 177 CloseFileHandle(file_handle); 178 179 // Check that the old file no longer exists. 180 PP_FileInfo unused; 181 ASSERT_FALSE(FileModuleLocal::QueryFile(instance_, filename, &unused)); 182 183 PASS(); 184 } 185 186 std::string TestFlashFile::TestDeleteFileOrDir() { 187 SetUp(); 188 std::string filename = "abc.txt"; 189 std::string dirname = "def"; 190 std::string contents = "This is file."; 191 192 // Test file deletion. 193 PP_FileHandle file_handle = FileModuleLocal::OpenFile(instance_, 194 filename, 195 PP_FILEOPENFLAG_WRITE | 196 PP_FILEOPENFLAG_CREATE); 197 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 198 ASSERT_TRUE(WriteFile(file_handle, contents)); 199 CloseFileHandle(file_handle); 200 ASSERT_TRUE(FileModuleLocal::DeleteFileOrDir(instance_, filename, false)); 201 PP_FileInfo unused; 202 ASSERT_FALSE(FileModuleLocal::QueryFile(instance_, filename, &unused)); 203 204 // Test directory deletion. 205 ASSERT_TRUE(FileModuleLocal::CreateDir(instance_, dirname)); 206 ASSERT_TRUE(FileModuleLocal::DeleteFileOrDir(instance_, dirname, false)); 207 ASSERT_FALSE(FileModuleLocal::QueryFile(instance_, dirname, &unused)); 208 209 // Test recursive directory deletion. 210 ASSERT_TRUE(FileModuleLocal::CreateDir(instance_, dirname)); 211 file_handle = FileModuleLocal::OpenFile( 212 instance_, dirname + "/" + filename, 213 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE); 214 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 215 ASSERT_TRUE(WriteFile(file_handle, contents)); 216 CloseFileHandle(file_handle); 217 ASSERT_FALSE(FileModuleLocal::DeleteFileOrDir(instance_, dirname, false)); 218 ASSERT_TRUE(FileModuleLocal::DeleteFileOrDir(instance_, dirname, true)); 219 ASSERT_FALSE(FileModuleLocal::QueryFile(instance_, filename, &unused)); 220 221 PASS(); 222 } 223 224 std::string TestFlashFile::TestCreateDir() { 225 SetUp(); 226 std::string dirname = "abc"; 227 PP_FileInfo info; 228 ASSERT_FALSE(FileModuleLocal::QueryFile(instance_, dirname, &info)); 229 ASSERT_TRUE(FileModuleLocal::CreateDir(instance_, dirname)); 230 ASSERT_TRUE(FileModuleLocal::QueryFile(instance_, dirname, &info)); 231 ASSERT_EQ(PP_FILETYPE_DIRECTORY, info.type); 232 233 PASS(); 234 } 235 236 std::string TestFlashFile::TestQueryFile() { 237 std::string filename = "abc.txt"; 238 std::string dirname = "def"; 239 std::string contents = "This is file."; 240 PP_FileInfo info; 241 242 // Test querying a file. 243 PP_FileHandle file_handle = FileModuleLocal::OpenFile(instance_, 244 filename, 245 PP_FILEOPENFLAG_WRITE | 246 PP_FILEOPENFLAG_CREATE); 247 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 248 ASSERT_TRUE(WriteFile(file_handle, contents)); 249 CloseFileHandle(file_handle); 250 ASSERT_TRUE(FileModuleLocal::QueryFile(instance_, filename, &info)); 251 ASSERT_EQ(static_cast<size_t>(info.size), contents.size()); 252 ASSERT_EQ(PP_FILETYPE_REGULAR, info.type); 253 // TODO(raymes): Test the other fields. 254 255 // Test querying a directory. 256 ASSERT_TRUE(FileModuleLocal::CreateDir(instance_, dirname)); 257 ASSERT_TRUE(FileModuleLocal::QueryFile(instance_, dirname, &info)); 258 ASSERT_EQ(PP_FILETYPE_DIRECTORY, info.type); 259 // TODO(raymes): Test the other fields. 260 261 // Test querying a non-existent file. 262 ASSERT_FALSE(FileModuleLocal::QueryFile(instance_, "xx", &info)); 263 264 PASS(); 265 } 266 267 std::string TestFlashFile::TestGetDirContents() { 268 SetUp(); 269 std::vector<FileModuleLocal::DirEntry> result; 270 ASSERT_TRUE(FileModuleLocal::GetDirContents(instance_, std::string(), 271 &result)); 272 ASSERT_EQ(1, result.size()); 273 ASSERT_EQ(result[0].name, ".."); 274 ASSERT_EQ(result[0].is_dir, true); 275 276 std::string filename = "abc.txt"; 277 std::string dirname = "def"; 278 std::string contents = "This is file."; 279 PP_FileHandle file_handle = FileModuleLocal::OpenFile(instance_, 280 filename, 281 PP_FILEOPENFLAG_WRITE | 282 PP_FILEOPENFLAG_CREATE); 283 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 284 ASSERT_TRUE(WriteFile(file_handle, contents)); 285 CloseFileHandle(file_handle); 286 ASSERT_TRUE(FileModuleLocal::CreateDir(instance_, dirname)); 287 288 ASSERT_TRUE( 289 FileModuleLocal::GetDirContents(instance_, std::string(), &result)); 290 FileModuleLocal::DirEntry expected[] = { { "..", true }, { filename, false }, 291 { dirname, true } }; 292 size_t expected_size = sizeof(expected) / sizeof(expected[0]); 293 294 std::sort(expected, expected + expected_size, DirEntryLessThan); 295 std::sort(result.begin(), result.end(), DirEntryLessThan); 296 297 ASSERT_EQ(expected_size, result.size()); 298 ASSERT_TRUE(std::equal(expected, expected + expected_size, result.begin(), 299 DirEntryEqual)); 300 301 PASS(); 302 } 303 304 std::string TestFlashFile::TestCreateTemporaryFile() { 305 SetUp(); 306 size_t before_create = 0; 307 ASSERT_SUBTEST_SUCCESS(GetItemCountUnderModuleLocalRoot(&before_create)); 308 309 PP_FileHandle file_handle = FileModuleLocal::CreateTemporaryFile(instance_); 310 ASSERT_NE(PP_kInvalidFileHandle, file_handle); 311 312 std::string contents = "This is a temp file."; 313 ASSERT_TRUE(WriteFile(file_handle, contents)); 314 std::string read_contents; 315 ASSERT_TRUE(ReadFile(file_handle, &read_contents)); 316 ASSERT_EQ(contents, read_contents); 317 318 CloseFileHandle(file_handle); 319 320 size_t after_close = 0; 321 ASSERT_SUBTEST_SUCCESS(GetItemCountUnderModuleLocalRoot(&after_close)); 322 ASSERT_EQ(before_create, after_close); 323 324 PASS(); 325 } 326 327 std::string TestFlashFile::GetItemCountUnderModuleLocalRoot( 328 size_t* item_count) { 329 std::vector<FileModuleLocal::DirEntry> contents; 330 ASSERT_TRUE( 331 FileModuleLocal::GetDirContents(instance_, std::string(), &contents)); 332 *item_count = contents.size(); 333 PASS(); 334 } 335