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 24using pp::flash::FileModuleLocal; 25 26namespace { 27 28void 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 36bool 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 51bool 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 82bool DirEntryEqual(FileModuleLocal::DirEntry i, 83 FileModuleLocal::DirEntry j) { 84 return i.name == j.name && i.is_dir == j.is_dir; 85} 86 87bool 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 96REGISTER_TEST_CASE(FlashFile); 97 98TestFlashFile::TestFlashFile(TestingInstance* instance) 99 : TestCase(instance) { 100} 101 102TestFlashFile::~TestFlashFile() { 103} 104 105bool TestFlashFile::Init() { 106 return FileModuleLocal::IsAvailable(); 107} 108 109void 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 119void 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 126std::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 154std::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 186std::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 224std::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(info.type, PP_FILETYPE_DIRECTORY); 232 233 PASS(); 234} 235 236std::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(info.type, PP_FILETYPE_REGULAR); 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(info.type, PP_FILETYPE_DIRECTORY); 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 267std::string TestFlashFile::TestGetDirContents() { 268 SetUp(); 269 std::vector<FileModuleLocal::DirEntry> result; 270 ASSERT_TRUE(FileModuleLocal::GetDirContents(instance_, std::string(), 271 &result)); 272 ASSERT_EQ(result.size(), 1); 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 304std::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 327std::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