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