Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / fileapi / dragged_file_util_unittest.cc
blob38d83374baa31dfd6ac0f9e98229f65e31c95515
1 // Copyright 2013 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.
5 #include <map>
6 #include <queue>
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/files/file_enumerator.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/time/time.h"
17 #include "content/public/test/async_file_test_helper.h"
18 #include "content/public/test/test_file_system_context.h"
19 #include "content/test/fileapi_test_file_set.h"
20 #include "storage/browser/fileapi/dragged_file_util.h"
21 #include "storage/browser/fileapi/file_system_context.h"
22 #include "storage/browser/fileapi/file_system_operation_context.h"
23 #include "storage/browser/fileapi/isolated_context.h"
24 #include "storage/browser/fileapi/local_file_util.h"
25 #include "storage/browser/fileapi/native_file_util.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 using content::AsyncFileTestHelper;
29 using storage::FileSystemContext;
30 using storage::FileSystemOperationContext;
31 using storage::FileSystemType;
32 using storage::FileSystemURL;
34 namespace content {
36 namespace {
38 typedef AsyncFileTestHelper::FileEntryList FileEntryList;
40 // Used in DraggedFileUtilTest::SimulateDropFiles().
41 // Random root paths in which we create each file/directory of the
42 // RegularTestCases (so that we can simulate a drop with files/directories
43 // from multiple directories).
44 static const base::FilePath::CharType* kRootPaths[] = {
45 FILE_PATH_LITERAL("a"),
46 FILE_PATH_LITERAL("b/c"),
47 FILE_PATH_LITERAL("etc"),
50 base::FilePath GetTopLevelPath(const base::FilePath& path) {
51 std::vector<base::FilePath::StringType> components;
52 path.GetComponents(&components);
53 return base::FilePath(components[0]);
56 bool IsDirectoryEmpty(FileSystemContext* context, const FileSystemURL& url) {
57 FileEntryList entries;
58 EXPECT_EQ(base::File::FILE_OK,
59 AsyncFileTestHelper::ReadDirectory(context, url, &entries));
60 return entries.empty();
63 FileSystemURL GetEntryURL(FileSystemContext* file_system_context,
64 const FileSystemURL& dir,
65 const base::FilePath::StringType& name) {
66 return file_system_context->CreateCrackedFileSystemURL(
67 dir.origin(),
68 dir.mount_type(),
69 dir.virtual_path().Append(name));
72 base::FilePath GetRelativeVirtualPath(const FileSystemURL& root,
73 const FileSystemURL& url) {
74 if (root.virtual_path().empty())
75 return url.virtual_path();
76 base::FilePath relative;
77 const bool success = root.virtual_path().AppendRelativePath(
78 url.virtual_path(), &relative);
79 DCHECK(success);
80 return relative;
83 FileSystemURL GetOtherURL(FileSystemContext* file_system_context,
84 const FileSystemURL& root,
85 const FileSystemURL& other_root,
86 const FileSystemURL& url) {
87 return file_system_context->CreateCrackedFileSystemURL(
88 other_root.origin(),
89 other_root.mount_type(),
90 other_root.virtual_path().Append(GetRelativeVirtualPath(root, url)));
93 } // namespace
95 class DraggedFileUtilTest : public testing::Test {
96 public:
97 DraggedFileUtilTest() {}
99 void SetUp() override {
100 ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
101 ASSERT_TRUE(partition_dir_.CreateUniqueTempDir());
102 file_util_.reset(new storage::DraggedFileUtil());
104 // Register the files/directories of RegularTestCases (with random
105 // root paths) as dropped files.
106 SimulateDropFiles();
108 file_system_context_ = CreateFileSystemContextForTesting(
109 NULL /* quota_manager */,
110 partition_dir_.path());
112 isolated_context()->AddReference(filesystem_id_);
115 void TearDown() override {
116 isolated_context()->RemoveReference(filesystem_id_);
119 protected:
120 storage::IsolatedContext* isolated_context() const {
121 return storage::IsolatedContext::GetInstance();
123 const base::FilePath& root_path() const {
124 return data_dir_.path();
126 FileSystemContext* file_system_context() const {
127 return file_system_context_.get();
129 storage::FileSystemFileUtil* file_util() const { return file_util_.get(); }
130 std::string filesystem_id() const { return filesystem_id_; }
132 base::FilePath GetTestCasePlatformPath(
133 const base::FilePath::StringType& path) {
134 return toplevel_root_map_[GetTopLevelPath(base::FilePath(path))]
135 .Append(path).NormalizePathSeparators();
138 base::FilePath GetTestCaseLocalPath(const base::FilePath& path) {
139 base::FilePath relative;
140 if (data_dir_.path().AppendRelativePath(path, &relative))
141 return relative;
142 return path;
145 FileSystemURL GetFileSystemURL(const base::FilePath& path) const {
146 base::FilePath virtual_path = isolated_context()->CreateVirtualRootPath(
147 filesystem_id()).Append(path);
148 return file_system_context_->CreateCrackedFileSystemURL(
149 GURL("http://example.com"),
150 storage::kFileSystemTypeIsolated,
151 virtual_path);
154 FileSystemURL GetOtherFileSystemURL(const base::FilePath& path) const {
155 return file_system_context()->CreateCrackedFileSystemURL(
156 GURL("http://example.com"),
157 storage::kFileSystemTypeTemporary,
158 base::FilePath().AppendASCII("dest").Append(path));
161 void VerifyFilesHaveSameContent(const FileSystemURL& url1,
162 const FileSystemURL& url2) {
163 // Get the file info and the platform path for url1.
164 base::File::Info info1;
165 ASSERT_EQ(base::File::FILE_OK,
166 AsyncFileTestHelper::GetMetadata(
167 file_system_context(), url1, &info1));
168 base::FilePath platform_path1;
169 ASSERT_EQ(base::File::FILE_OK,
170 AsyncFileTestHelper::GetPlatformPath(
171 file_system_context(), url1, &platform_path1));
173 // Get the file info and the platform path for url2.
174 base::File::Info info2;
175 ASSERT_EQ(base::File::FILE_OK,
176 AsyncFileTestHelper::GetMetadata(
177 file_system_context(), url2, &info2));
178 base::FilePath platform_path2;
179 ASSERT_EQ(base::File::FILE_OK,
180 AsyncFileTestHelper::GetPlatformPath(
181 file_system_context(), url2, &platform_path2));
183 // See if file info matches with the other one.
184 EXPECT_EQ(info1.is_directory, info2.is_directory);
185 EXPECT_EQ(info1.size, info2.size);
186 EXPECT_EQ(info1.is_symbolic_link, info2.is_symbolic_link);
187 EXPECT_NE(platform_path1, platform_path2);
189 std::string content1, content2;
190 EXPECT_TRUE(base::ReadFileToString(platform_path1, &content1));
191 EXPECT_TRUE(base::ReadFileToString(platform_path2, &content2));
192 EXPECT_EQ(content1, content2);
195 void VerifyDirectoriesHaveSameContent(const FileSystemURL& root1,
196 const FileSystemURL& root2) {
197 base::FilePath root_path1 = root1.path();
198 base::FilePath root_path2 = root2.path();
200 FileEntryList entries;
201 std::queue<FileSystemURL> directories;
203 directories.push(root1);
204 std::set<base::FilePath> file_set1;
205 while (!directories.empty()) {
206 FileSystemURL dir = directories.front();
207 directories.pop();
209 ASSERT_EQ(base::File::FILE_OK,
210 AsyncFileTestHelper::ReadDirectory(
211 file_system_context(), dir, &entries));
212 for (size_t i = 0; i < entries.size(); ++i) {
213 FileSystemURL url = GetEntryURL(file_system_context(),
214 dir, entries[i].name);
215 if (entries[i].is_directory) {
216 directories.push(url);
217 continue;
219 file_set1.insert(GetRelativeVirtualPath(root1, url));
223 directories.push(root2);
224 while (!directories.empty()) {
225 FileSystemURL dir = directories.front();
226 directories.pop();
228 ASSERT_EQ(base::File::FILE_OK,
229 AsyncFileTestHelper::ReadDirectory(
230 file_system_context(), dir, &entries));
231 for (size_t i = 0; i < entries.size(); ++i) {
232 FileSystemURL url2 = GetEntryURL(file_system_context(),
233 dir, entries[i].name);
234 FileSystemURL url1 = GetOtherURL(file_system_context(),
235 root2, root1, url2);
236 if (entries[i].is_directory) {
237 directories.push(url2);
238 EXPECT_EQ(IsDirectoryEmpty(file_system_context(), url1),
239 IsDirectoryEmpty(file_system_context(), url2));
240 continue;
242 base::FilePath relative = GetRelativeVirtualPath(root2, url2);
243 EXPECT_TRUE(file_set1.find(relative) != file_set1.end());
244 VerifyFilesHaveSameContent(url1, url2);
249 scoped_ptr<storage::FileSystemOperationContext> GetOperationContext() {
250 return make_scoped_ptr(new storage::FileSystemOperationContext(
251 file_system_context())).Pass();
255 private:
256 void SimulateDropFiles() {
257 size_t root_path_index = 0;
259 storage::IsolatedContext::FileInfoSet toplevels;
260 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
261 const FileSystemTestCaseRecord& test_case =
262 kRegularFileSystemTestCases[i];
263 base::FilePath path(test_case.path);
264 base::FilePath toplevel = GetTopLevelPath(path);
266 // We create the test case files under one of the kRootPaths
267 // to simulate a drop with multiple directories.
268 if (toplevel_root_map_.find(toplevel) == toplevel_root_map_.end()) {
269 base::FilePath root = root_path().Append(
270 kRootPaths[(root_path_index++) % arraysize(kRootPaths)]);
271 toplevel_root_map_[toplevel] = root;
272 toplevels.AddPath(root.Append(path), NULL);
275 SetUpOneFileSystemTestCase(toplevel_root_map_[toplevel], test_case);
278 // Register the toplevel entries.
279 filesystem_id_ = isolated_context()->RegisterDraggedFileSystem(toplevels);
282 base::ScopedTempDir data_dir_;
283 base::ScopedTempDir partition_dir_;
284 base::MessageLoopForIO message_loop_;
285 std::string filesystem_id_;
286 scoped_refptr<FileSystemContext> file_system_context_;
287 std::map<base::FilePath, base::FilePath> toplevel_root_map_;
288 scoped_ptr<storage::DraggedFileUtil> file_util_;
289 DISALLOW_COPY_AND_ASSIGN(DraggedFileUtilTest);
292 TEST_F(DraggedFileUtilTest, BasicTest) {
293 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
294 SCOPED_TRACE(testing::Message() << "Testing RegularTestCases " << i);
295 const FileSystemTestCaseRecord& test_case =
296 kRegularFileSystemTestCases[i];
298 FileSystemURL url = GetFileSystemURL(base::FilePath(test_case.path));
300 // See if we can query the file info via the isolated FileUtil.
301 // (This should succeed since we have registered all the top-level
302 // entries of the test cases in SetUp())
303 base::File::Info info;
304 base::FilePath platform_path;
305 FileSystemOperationContext context(file_system_context());
306 ASSERT_EQ(base::File::FILE_OK,
307 file_util()->GetFileInfo(&context, url, &info, &platform_path));
309 // See if the obtained file info is correct.
310 if (!test_case.is_directory)
311 ASSERT_EQ(test_case.data_file_size, info.size);
312 ASSERT_EQ(test_case.is_directory, info.is_directory);
313 ASSERT_EQ(GetTestCasePlatformPath(test_case.path),
314 platform_path.NormalizePathSeparators());
318 TEST_F(DraggedFileUtilTest, UnregisteredPathsTest) {
319 static const FileSystemTestCaseRecord kUnregisteredCases[] = {
320 {true, FILE_PATH_LITERAL("nonexistent"), 0},
321 {true, FILE_PATH_LITERAL("nonexistent/dir foo"), 0},
322 {false, FILE_PATH_LITERAL("nonexistent/false"), 0},
323 {false, FILE_PATH_LITERAL("foo"), 30},
324 {false, FILE_PATH_LITERAL("bar"), 20},
327 for (size_t i = 0; i < arraysize(kUnregisteredCases); ++i) {
328 SCOPED_TRACE(testing::Message() << "Creating kUnregisteredCases " << i);
329 const FileSystemTestCaseRecord& test_case = kUnregisteredCases[i];
331 // Prepare the test file/directory.
332 SetUpOneFileSystemTestCase(root_path(), test_case);
334 // Make sure regular GetFileInfo succeeds.
335 base::File::Info info;
336 ASSERT_TRUE(base::GetFileInfo(root_path().Append(test_case.path), &info));
337 if (!test_case.is_directory)
338 ASSERT_EQ(test_case.data_file_size, info.size);
339 ASSERT_EQ(test_case.is_directory, info.is_directory);
342 for (size_t i = 0; i < arraysize(kUnregisteredCases); ++i) {
343 SCOPED_TRACE(testing::Message() << "Creating kUnregisteredCases " << i);
344 const FileSystemTestCaseRecord& test_case = kUnregisteredCases[i];
345 FileSystemURL url = GetFileSystemURL(base::FilePath(test_case.path));
347 // We should not be able to get the valid URL for unregistered files.
348 ASSERT_FALSE(url.is_valid());
352 TEST_F(DraggedFileUtilTest, ReadDirectoryTest) {
353 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
354 const FileSystemTestCaseRecord& test_case =
355 kRegularFileSystemTestCases[i];
356 if (!test_case.is_directory)
357 continue;
359 SCOPED_TRACE(testing::Message() << "Testing RegularTestCases " << i
360 << ": " << test_case.path);
362 // Read entries in the directory to construct the expected results map.
363 typedef std::map<base::FilePath::StringType, storage::DirectoryEntry>
364 EntryMap;
365 EntryMap expected_entry_map;
367 base::FilePath dir_path = GetTestCasePlatformPath(test_case.path);
368 base::FileEnumerator file_enum(
369 dir_path, false /* not recursive */,
370 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
371 base::FilePath current;
372 while (!(current = file_enum.Next()).empty()) {
373 base::FileEnumerator::FileInfo file_info = file_enum.GetInfo();
374 storage::DirectoryEntry entry;
375 entry.is_directory = file_info.IsDirectory();
376 entry.name = current.BaseName().value();
377 entry.size = file_info.GetSize();
378 entry.last_modified_time = file_info.GetLastModifiedTime();
379 expected_entry_map[entry.name] = entry;
381 #if defined(OS_POSIX)
382 // Creates a symlink for each file/directory.
383 // They should be ignored by ReadDirectory, so we don't add them
384 // to expected_entry_map.
385 base::CreateSymbolicLink(
386 current,
387 dir_path.Append(current.BaseName().AddExtension(
388 FILE_PATH_LITERAL("link"))));
389 #endif
392 // Perform ReadDirectory in the isolated filesystem.
393 FileSystemURL url = GetFileSystemURL(base::FilePath(test_case.path));
394 FileEntryList entries;
395 ASSERT_EQ(base::File::FILE_OK,
396 AsyncFileTestHelper::ReadDirectory(
397 file_system_context(), url, &entries));
399 EXPECT_EQ(expected_entry_map.size(), entries.size());
400 for (size_t i = 0; i < entries.size(); ++i) {
401 const storage::DirectoryEntry& entry = entries[i];
402 EntryMap::iterator found = expected_entry_map.find(entry.name);
403 EXPECT_TRUE(found != expected_entry_map.end());
404 EXPECT_EQ(found->second.name, entry.name);
405 EXPECT_EQ(found->second.is_directory, entry.is_directory);
406 EXPECT_EQ(found->second.size, entry.size);
407 EXPECT_EQ(found->second.last_modified_time.ToDoubleT(),
408 entry.last_modified_time.ToDoubleT());
413 TEST_F(DraggedFileUtilTest, GetLocalFilePathTest) {
414 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
415 const FileSystemTestCaseRecord& test_case =
416 kRegularFileSystemTestCases[i];
417 FileSystemURL url = GetFileSystemURL(base::FilePath(test_case.path));
419 FileSystemOperationContext context(file_system_context());
421 base::FilePath local_file_path;
422 EXPECT_EQ(base::File::FILE_OK,
423 file_util()->GetLocalFilePath(&context, url, &local_file_path));
424 EXPECT_EQ(GetTestCasePlatformPath(test_case.path).value(),
425 local_file_path.value());
429 TEST_F(DraggedFileUtilTest, CopyOutFileTest) {
430 FileSystemURL src_root = GetFileSystemURL(base::FilePath());
431 FileSystemURL dest_root = GetOtherFileSystemURL(base::FilePath());
433 FileEntryList entries;
434 std::queue<FileSystemURL> directories;
435 directories.push(src_root);
437 ASSERT_EQ(base::File::FILE_OK,
438 AsyncFileTestHelper::CreateDirectory(file_system_context(),
439 dest_root));
441 while (!directories.empty()) {
442 FileSystemURL dir = directories.front();
443 directories.pop();
444 ASSERT_EQ(base::File::FILE_OK,
445 AsyncFileTestHelper::ReadDirectory(file_system_context(),
446 dir, &entries));
447 for (size_t i = 0; i < entries.size(); ++i) {
448 FileSystemURL src_url = GetEntryURL(file_system_context(),
449 dir, entries[i].name);
450 FileSystemURL dest_url = GetOtherURL(file_system_context(),
451 src_root, dest_root, src_url);
453 if (entries[i].is_directory) {
454 ASSERT_EQ(base::File::FILE_OK,
455 AsyncFileTestHelper::CreateDirectory(file_system_context(),
456 dest_url));
457 directories.push(src_url);
458 continue;
460 SCOPED_TRACE(testing::Message() << "Testing file copy "
461 << src_url.path().value());
462 ASSERT_EQ(base::File::FILE_OK,
463 AsyncFileTestHelper::Copy(file_system_context(),
464 src_url, dest_url));
465 VerifyFilesHaveSameContent(src_url, dest_url);
470 TEST_F(DraggedFileUtilTest, CopyOutDirectoryTest) {
471 FileSystemURL src_root = GetFileSystemURL(base::FilePath());
472 FileSystemURL dest_root = GetOtherFileSystemURL(base::FilePath());
474 ASSERT_EQ(base::File::FILE_OK,
475 AsyncFileTestHelper::CreateDirectory(file_system_context(),
476 dest_root));
478 FileEntryList entries;
479 ASSERT_EQ(base::File::FILE_OK,
480 AsyncFileTestHelper::ReadDirectory(file_system_context(),
481 src_root, &entries));
482 for (size_t i = 0; i < entries.size(); ++i) {
483 if (!entries[i].is_directory)
484 continue;
485 FileSystemURL src_url = GetEntryURL(file_system_context(),
486 src_root, entries[i].name);
487 FileSystemURL dest_url = GetOtherURL(file_system_context(),
488 src_root, dest_root, src_url);
489 SCOPED_TRACE(testing::Message() << "Testing file copy "
490 << src_url.path().value());
491 ASSERT_EQ(base::File::FILE_OK,
492 AsyncFileTestHelper::Copy(file_system_context(),
493 src_url, dest_url));
494 VerifyDirectoriesHaveSameContent(src_url, dest_url);
498 TEST_F(DraggedFileUtilTest, TouchTest) {
499 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
500 const FileSystemTestCaseRecord& test_case =
501 kRegularFileSystemTestCases[i];
502 if (test_case.is_directory)
503 continue;
504 SCOPED_TRACE(testing::Message() << test_case.path);
505 FileSystemURL url = GetFileSystemURL(base::FilePath(test_case.path));
507 base::Time last_access_time = base::Time::FromTimeT(1000);
508 base::Time last_modified_time = base::Time::FromTimeT(2000);
510 EXPECT_EQ(base::File::FILE_OK,
511 file_util()->Touch(GetOperationContext().get(), url,
512 last_access_time,
513 last_modified_time));
515 // Verification.
516 base::File::Info info;
517 base::FilePath platform_path;
518 ASSERT_EQ(base::File::FILE_OK,
519 file_util()->GetFileInfo(GetOperationContext().get(), url,
520 &info, &platform_path));
521 EXPECT_EQ(last_access_time.ToTimeT(), info.last_accessed.ToTimeT());
522 EXPECT_EQ(last_modified_time.ToTimeT(), info.last_modified.ToTimeT());
526 TEST_F(DraggedFileUtilTest, TruncateTest) {
527 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
528 const FileSystemTestCaseRecord& test_case =
529 kRegularFileSystemTestCases[i];
530 if (test_case.is_directory)
531 continue;
533 SCOPED_TRACE(testing::Message() << test_case.path);
534 FileSystemURL url = GetFileSystemURL(base::FilePath(test_case.path));
536 // Truncate to 0.
537 base::File::Info info;
538 base::FilePath platform_path;
539 EXPECT_EQ(base::File::FILE_OK,
540 file_util()->Truncate(GetOperationContext().get(), url, 0));
541 ASSERT_EQ(base::File::FILE_OK,
542 file_util()->GetFileInfo(GetOperationContext().get(), url,
543 &info, &platform_path));
544 EXPECT_EQ(0, info.size);
546 // Truncate (extend) to 999.
547 EXPECT_EQ(base::File::FILE_OK,
548 file_util()->Truncate(GetOperationContext().get(), url, 999));
549 ASSERT_EQ(base::File::FILE_OK,
550 file_util()->GetFileInfo(GetOperationContext().get(), url,
551 &info, &platform_path));
552 EXPECT_EQ(999, info.size);
556 } // namespace content