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 "chrome/browser/chromeos/drive/file_system_util.h" 6 7 #include "base/file_util.h" 8 #include "base/files/file_path.h" 9 #include "base/files/scoped_temp_dir.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "chrome/common/chrome_constants.h" 13 #include "chrome/test/base/testing_browser_process.h" 14 #include "chrome/test/base/testing_profile.h" 15 #include "chrome/test/base/testing_profile_manager.h" 16 #include "content/public/test/test_browser_thread_bundle.h" 17 #include "content/public/test/test_file_system_options.h" 18 #include "google_apis/drive/test_util.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 #include "webkit/browser/fileapi/external_mount_points.h" 21 #include "webkit/browser/fileapi/file_system_backend.h" 22 #include "webkit/browser/fileapi/file_system_context.h" 23 #include "webkit/browser/fileapi/file_system_url.h" 24 #include "webkit/browser/fileapi/isolated_context.h" 25 26 namespace drive { 27 namespace util { 28 29 namespace { 30 31 // Sets up ProfileManager for testing and marks the current thread as UI by 32 // TestBrowserThreadBundle. We need the thread since Profile objects must be 33 // touched from UI and hence has CHECK/DCHECKs for it. 34 class ProfileRelatedFileSystemUtilTest : public testing::Test { 35 protected: 36 ProfileRelatedFileSystemUtilTest() 37 : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) { 38 } 39 40 virtual void SetUp() OVERRIDE { 41 ASSERT_TRUE(testing_profile_manager_.SetUp()); 42 } 43 44 Profile* CreateProfileWithName(const std::string& name) { 45 return testing_profile_manager_.CreateTestingProfile( 46 chrome::kProfileDirPrefix + name); 47 } 48 49 private: 50 content::TestBrowserThreadBundle thread_bundle_; 51 TestingProfileManager testing_profile_manager_; 52 }; 53 54 } // namespace 55 56 TEST(FileSystemUtilTest, FilePathToDriveURL) { 57 base::FilePath path; 58 59 // Path with alphabets and numbers. 60 path = GetDriveMyDriveRootPath().AppendASCII("foo/bar012.txt"); 61 EXPECT_EQ(path, DriveURLToFilePath(FilePathToDriveURL(path))); 62 63 // Path with symbols. 64 path = GetDriveMyDriveRootPath().AppendASCII( 65 " !\"#$%&'()*+,-.:;<=>?@[\\]^_`{|}~"); 66 EXPECT_EQ(path, DriveURLToFilePath(FilePathToDriveURL(path))); 67 68 // Path with '%'. 69 path = GetDriveMyDriveRootPath().AppendASCII("%19%20%21.txt"); 70 EXPECT_EQ(path, DriveURLToFilePath(FilePathToDriveURL(path))); 71 72 // Path with multi byte characters. 73 base::string16 utf16_string; 74 utf16_string.push_back(0x307b); // HIRAGANA_LETTER_HO 75 utf16_string.push_back(0x3052); // HIRAGANA_LETTER_GE 76 path = GetDriveMyDriveRootPath().Append( 77 base::FilePath::FromUTF8Unsafe(base::UTF16ToUTF8(utf16_string) + ".txt")); 78 EXPECT_EQ(path, DriveURLToFilePath(FilePathToDriveURL(path))); 79 } 80 81 TEST_F(ProfileRelatedFileSystemUtilTest, GetDriveMountPointPath) { 82 Profile* profile = CreateProfileWithName("hash1"); 83 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("/special/drive-hash1"), 84 GetDriveMountPointPath(profile)); 85 } 86 87 TEST_F(ProfileRelatedFileSystemUtilTest, ExtractProfileFromPath) { 88 Profile* profile1 = CreateProfileWithName("hash1"); 89 Profile* profile2 = CreateProfileWithName("hash2"); 90 EXPECT_EQ(profile1, ExtractProfileFromPath( 91 base::FilePath::FromUTF8Unsafe("/special/drive-hash1"))); 92 EXPECT_EQ(profile2, ExtractProfileFromPath( 93 base::FilePath::FromUTF8Unsafe("/special/drive-hash2/root/xxx"))); 94 EXPECT_EQ(NULL, ExtractProfileFromPath( 95 base::FilePath::FromUTF8Unsafe("/special/non-drive-path"))); 96 } 97 98 TEST(FileSystemUtilTest, IsUnderDriveMountPoint) { 99 EXPECT_FALSE(IsUnderDriveMountPoint( 100 base::FilePath::FromUTF8Unsafe("/wherever/foo.txt"))); 101 EXPECT_FALSE(IsUnderDriveMountPoint( 102 base::FilePath::FromUTF8Unsafe("/special/foo.txt"))); 103 EXPECT_FALSE(IsUnderDriveMountPoint( 104 base::FilePath::FromUTF8Unsafe("special/drive/foo.txt"))); 105 106 EXPECT_TRUE(IsUnderDriveMountPoint( 107 base::FilePath::FromUTF8Unsafe("/special/drive"))); 108 EXPECT_TRUE(IsUnderDriveMountPoint( 109 base::FilePath::FromUTF8Unsafe("/special/drive/foo.txt"))); 110 EXPECT_TRUE(IsUnderDriveMountPoint( 111 base::FilePath::FromUTF8Unsafe("/special/drive/subdir/foo.txt"))); 112 EXPECT_TRUE(IsUnderDriveMountPoint( 113 base::FilePath::FromUTF8Unsafe("/special/drive-xxx/foo.txt"))); 114 } 115 116 TEST(FileSystemUtilTest, ExtractDrivePath) { 117 EXPECT_EQ(base::FilePath(), 118 ExtractDrivePath( 119 base::FilePath::FromUTF8Unsafe("/wherever/foo.txt"))); 120 EXPECT_EQ(base::FilePath(), 121 ExtractDrivePath( 122 base::FilePath::FromUTF8Unsafe("/special/foo.txt"))); 123 124 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive"), 125 ExtractDrivePath( 126 base::FilePath::FromUTF8Unsafe("/special/drive"))); 127 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/foo.txt"), 128 ExtractDrivePath( 129 base::FilePath::FromUTF8Unsafe("/special/drive/foo.txt"))); 130 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/subdir/foo.txt"), 131 ExtractDrivePath(base::FilePath::FromUTF8Unsafe( 132 "/special/drive/subdir/foo.txt"))); 133 EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/foo.txt"), 134 ExtractDrivePath( 135 base::FilePath::FromUTF8Unsafe("/special/drive-xxx/foo.txt"))); 136 } 137 138 TEST(FileSystemUtilTest, ExtractDrivePathFromFileSystemUrl) { 139 TestingProfile profile; 140 141 // Set up file system context for testing. 142 base::ScopedTempDir temp_dir_; 143 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 144 145 base::MessageLoop message_loop; 146 scoped_refptr<fileapi::ExternalMountPoints> mount_points = 147 fileapi::ExternalMountPoints::CreateRefCounted(); 148 scoped_refptr<fileapi::FileSystemContext> context( 149 new fileapi::FileSystemContext( 150 base::MessageLoopProxy::current().get(), 151 base::MessageLoopProxy::current().get(), 152 mount_points.get(), 153 NULL, // special_storage_policy 154 NULL, // quota_manager_proxy, 155 ScopedVector<fileapi::FileSystemBackend>(), 156 std::vector<fileapi::URLRequestAutoMountHandler>(), 157 temp_dir_.path(), // partition_path 158 content::CreateAllowFileAccessOptions())); 159 160 // Type:"external" + virtual_path:"drive/foo/bar" resolves to "drive/foo/bar". 161 const std::string& drive_mount_name = 162 GetDriveMountPointPath(&profile).BaseName().AsUTF8Unsafe(); 163 mount_points->RegisterFileSystem( 164 drive_mount_name, 165 fileapi::kFileSystemTypeDrive, 166 fileapi::FileSystemMountOption(), 167 GetDriveMountPointPath(&profile)); 168 EXPECT_EQ( 169 base::FilePath::FromUTF8Unsafe("drive/foo/bar"), 170 ExtractDrivePathFromFileSystemUrl(context->CrackURL(GURL( 171 "filesystem:chrome-extension://dummy-id/external/" + 172 drive_mount_name + "/foo/bar")))); 173 174 // Virtual mount name should not affect the extracted path. 175 mount_points->RevokeFileSystem(drive_mount_name); 176 mount_points->RegisterFileSystem( 177 "drive2", 178 fileapi::kFileSystemTypeDrive, 179 fileapi::FileSystemMountOption(), 180 GetDriveMountPointPath(&profile)); 181 EXPECT_EQ( 182 base::FilePath::FromUTF8Unsafe("drive/foo/bar"), 183 ExtractDrivePathFromFileSystemUrl(context->CrackURL(GURL( 184 "filesystem:chrome-extension://dummy-id/external/drive2/foo/bar")))); 185 186 // Type:"external" + virtual_path:"Downloads/foo" is not a Drive path. 187 mount_points->RegisterFileSystem( 188 "Downloads", 189 fileapi::kFileSystemTypeNativeLocal, 190 fileapi::FileSystemMountOption(), 191 temp_dir_.path()); 192 EXPECT_EQ( 193 base::FilePath(), 194 ExtractDrivePathFromFileSystemUrl(context->CrackURL(GURL( 195 "filesystem:chrome-extension://dummy-id/external/Downloads/foo")))); 196 197 // Type:"isolated" + virtual_path:"isolated_id/name" mapped on a Drive path. 198 std::string isolated_name; 199 std::string isolated_id = 200 fileapi::IsolatedContext::GetInstance()->RegisterFileSystemForPath( 201 fileapi::kFileSystemTypeNativeForPlatformApp, 202 std::string(), 203 GetDriveMountPointPath(&profile).AppendASCII("bar/buz"), 204 &isolated_name); 205 EXPECT_EQ( 206 base::FilePath::FromUTF8Unsafe("drive/bar/buz"), 207 ExtractDrivePathFromFileSystemUrl(context->CrackURL(GURL( 208 "filesystem:chrome-extension://dummy-id/isolated/" + 209 isolated_id + "/" + isolated_name)))); 210 } 211 212 TEST(FileSystemUtilTest, EscapeUnescapeCacheFileName) { 213 const std::string kUnescapedFileName( 214 "tmp:`~!@#$%^&*()-_=+[{|]}\\\\;\',<.>/?"); 215 const std::string kEscapedFileName( 216 "tmp:`~!@#$%25^&*()-_=+[{|]}\\\\;\',<%2E>%2F?"); 217 EXPECT_EQ(kEscapedFileName, EscapeCacheFileName(kUnescapedFileName)); 218 EXPECT_EQ(kUnescapedFileName, UnescapeCacheFileName(kEscapedFileName)); 219 } 220 221 TEST(FileSystemUtilTest, NormalizeFileName) { 222 EXPECT_EQ("", NormalizeFileName("")); 223 EXPECT_EQ("foo", NormalizeFileName("foo")); 224 // Slash 225 EXPECT_EQ("foo_zzz", NormalizeFileName("foo/zzz")); 226 EXPECT_EQ("___", NormalizeFileName("///")); 227 // Japanese hiragana "hi" + semi-voiced-mark is normalized to "pi". 228 EXPECT_EQ("\xE3\x81\xB4", NormalizeFileName("\xE3\x81\xB2\xE3\x82\x9A")); 229 // Dot 230 EXPECT_EQ("_", NormalizeFileName(".")); 231 EXPECT_EQ("_", NormalizeFileName("..")); 232 EXPECT_EQ("_", NormalizeFileName("...")); 233 EXPECT_EQ(".bashrc", NormalizeFileName(".bashrc")); 234 EXPECT_EQ("._", NormalizeFileName("./")); 235 } 236 237 TEST(FileSystemUtilTest, GetCacheRootPath) { 238 TestingProfile profile; 239 base::FilePath profile_path = profile.GetPath(); 240 EXPECT_EQ(profile_path.AppendASCII("GCache/v1"), 241 util::GetCacheRootPath(&profile)); 242 } 243 244 TEST(FileSystemUtilTest, GDocFile) { 245 base::ScopedTempDir temp_dir; 246 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 247 248 GURL url("https://docs.google.com/document/d/" 249 "1YsCnrMxxgp7LDdtlFDt-WdtEIth89vA9inrILtvK-Ug/edit"); 250 std::string resource_id("1YsCnrMxxgp7LDdtlFDt-WdtEIth89vA9inrILtvK-Ug"); 251 252 // Read and write gdoc. 253 base::FilePath file = temp_dir.path().AppendASCII("test.gdoc"); 254 EXPECT_TRUE(CreateGDocFile(file, url, resource_id)); 255 EXPECT_TRUE(HasGDocFileExtension(file)); 256 EXPECT_EQ(url, ReadUrlFromGDocFile(file)); 257 EXPECT_EQ(resource_id, ReadResourceIdFromGDocFile(file)); 258 259 // Read and write gsheet. 260 file = temp_dir.path().AppendASCII("test.gsheet"); 261 EXPECT_TRUE(CreateGDocFile(file, url, resource_id)); 262 EXPECT_TRUE(HasGDocFileExtension(file)); 263 EXPECT_EQ(url, ReadUrlFromGDocFile(file)); 264 EXPECT_EQ(resource_id, ReadResourceIdFromGDocFile(file)); 265 266 // Read and write gslides. 267 file = temp_dir.path().AppendASCII("test.gslides"); 268 EXPECT_TRUE(CreateGDocFile(file, url, resource_id)); 269 EXPECT_TRUE(HasGDocFileExtension(file)); 270 EXPECT_EQ(url, ReadUrlFromGDocFile(file)); 271 EXPECT_EQ(resource_id, ReadResourceIdFromGDocFile(file)); 272 273 // Read and write gdraw. 274 file = temp_dir.path().AppendASCII("test.gdraw"); 275 EXPECT_TRUE(CreateGDocFile(file, url, resource_id)); 276 EXPECT_TRUE(HasGDocFileExtension(file)); 277 EXPECT_EQ(url, ReadUrlFromGDocFile(file)); 278 EXPECT_EQ(resource_id, ReadResourceIdFromGDocFile(file)); 279 280 // Read and write gtable. 281 file = temp_dir.path().AppendASCII("test.gtable"); 282 EXPECT_TRUE(CreateGDocFile(file, url, resource_id)); 283 EXPECT_TRUE(HasGDocFileExtension(file)); 284 EXPECT_EQ(url, ReadUrlFromGDocFile(file)); 285 EXPECT_EQ(resource_id, ReadResourceIdFromGDocFile(file)); 286 287 // Read and write glink. 288 file = temp_dir.path().AppendASCII("test.glink"); 289 EXPECT_TRUE(CreateGDocFile(file, url, resource_id)); 290 EXPECT_TRUE(HasGDocFileExtension(file)); 291 EXPECT_EQ(url, ReadUrlFromGDocFile(file)); 292 EXPECT_EQ(resource_id, ReadResourceIdFromGDocFile(file)); 293 294 // Non GDoc file. 295 file = temp_dir.path().AppendASCII("test.txt"); 296 std::string data = "Hello world!"; 297 EXPECT_TRUE(google_apis::test_util::WriteStringToFile(file, data)); 298 EXPECT_FALSE(HasGDocFileExtension(file)); 299 EXPECT_TRUE(ReadUrlFromGDocFile(file).is_empty()); 300 EXPECT_TRUE(ReadResourceIdFromGDocFile(file).empty()); 301 } 302 303 } // namespace util 304 } // namespace drive 305