Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / native_media_file_util_unittest.cc
blob9bce4b25b824702abae5d4c3c6c7355469c9c26c
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.
5 #include <set>
6 #include <string>
8 #include "base/bind.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/format_macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
17 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
18 #include "content/public/test/mock_special_storage_policy.h"
19 #include "content/public/test/test_browser_thread.h"
20 #include "content/public/test/test_file_system_options.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_operation_runner.h"
25 #include "storage/browser/fileapi/file_system_url.h"
26 #include "storage/browser/fileapi/isolated_context.h"
27 #include "storage/browser/fileapi/native_file_util.h"
28 #include "testing/gtest/include/gtest/gtest.h"
30 #define FPL(x) FILE_PATH_LITERAL(x)
32 using storage::FileSystemOperation;
33 using storage::FileSystemURL;
35 namespace {
37 typedef FileSystemOperation::FileEntryList FileEntryList;
39 struct FilteringTestCase {
40 const base::FilePath::CharType* path;
41 bool is_directory;
42 bool visible;
43 bool media_file;
44 const char* content;
47 const FilteringTestCase kFilteringTestCases[] = {
48 // Directory should always be visible.
49 { FPL("hoge"), true, true, false, NULL },
50 { FPL("fuga.jpg"), true, true, false, NULL },
51 { FPL("piyo.txt"), true, true, false, NULL },
52 { FPL("moga.cod"), true, true, false, NULL },
54 // File should be visible if it's a supported media file.
55 // File without extension.
56 { FPL("foo"), false, false, false, "abc" },
57 // Supported media file.
58 { FPL("bar.jpg"), false, true, true, "\xFF\xD8\xFF" },
59 // Unsupported masquerading file.
60 { FPL("sna.jpg"), false, true, false, "abc" },
61 // Non-media file.
62 { FPL("baz.txt"), false, false, false, "abc" },
63 // Unsupported media file.
64 { FPL("foobar.cod"), false, false, false, "abc" },
67 void ExpectEqHelper(const std::string& test_name,
68 base::File::Error expected,
69 base::File::Error actual) {
70 EXPECT_EQ(expected, actual) << test_name;
73 void ExpectMetadataEqHelper(const std::string& test_name,
74 base::File::Error expected,
75 bool expected_is_directory,
76 base::File::Error actual,
77 const base::File::Info& file_info) {
78 EXPECT_EQ(expected, actual) << test_name;
79 if (actual == base::File::FILE_OK)
80 EXPECT_EQ(expected_is_directory, file_info.is_directory) << test_name;
83 void DidReadDirectory(std::set<base::FilePath::StringType>* content,
84 bool* completed,
85 base::File::Error error,
86 const FileEntryList& file_list,
87 bool has_more) {
88 EXPECT_TRUE(!*completed);
89 *completed = !has_more;
90 for (FileEntryList::const_iterator itr = file_list.begin();
91 itr != file_list.end(); ++itr)
92 EXPECT_TRUE(content->insert(itr->name).second);
95 void PopulateDirectoryWithTestCases(const base::FilePath& dir,
96 const FilteringTestCase* test_cases,
97 size_t n) {
98 for (size_t i = 0; i < n; ++i) {
99 base::FilePath path = dir.Append(test_cases[i].path);
100 if (test_cases[i].is_directory) {
101 ASSERT_TRUE(base::CreateDirectory(path));
102 } else {
103 ASSERT_TRUE(test_cases[i].content != NULL);
104 int len = strlen(test_cases[i].content);
105 ASSERT_EQ(len, base::WriteFile(path, test_cases[i].content, len));
110 } // namespace
112 class NativeMediaFileUtilTest : public testing::Test {
113 public:
114 NativeMediaFileUtilTest()
115 : io_thread_(content::BrowserThread::IO, &message_loop_) {
118 void SetUp() override {
119 ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
120 ASSERT_TRUE(base::CreateDirectory(root_path()));
122 scoped_refptr<storage::SpecialStoragePolicy> storage_policy =
123 new content::MockSpecialStoragePolicy();
125 ScopedVector<storage::FileSystemBackend> additional_providers;
126 additional_providers.push_back(new MediaFileSystemBackend(
127 data_dir_.path(), base::ThreadTaskRunnerHandle::Get().get()));
129 file_system_context_ = new storage::FileSystemContext(
130 base::ThreadTaskRunnerHandle::Get().get(),
131 base::ThreadTaskRunnerHandle::Get().get(),
132 storage::ExternalMountPoints::CreateRefCounted().get(),
133 storage_policy.get(), NULL, additional_providers.Pass(),
134 std::vector<storage::URLRequestAutoMountHandler>(), data_dir_.path(),
135 content::CreateAllowFileAccessOptions());
137 filesystem_id_ = isolated_context()->RegisterFileSystemForPath(
138 storage::kFileSystemTypeNativeMedia, std::string(), root_path(), NULL);
140 isolated_context()->AddReference(filesystem_id_);
143 void TearDown() override {
144 isolated_context()->RemoveReference(filesystem_id_);
145 file_system_context_ = NULL;
148 protected:
149 storage::FileSystemContext* file_system_context() {
150 return file_system_context_.get();
153 FileSystemURL CreateURL(const base::FilePath::CharType* test_case_path) {
154 return file_system_context_->CreateCrackedFileSystemURL(
155 origin(),
156 storage::kFileSystemTypeIsolated,
157 GetVirtualPath(test_case_path));
160 storage::IsolatedContext* isolated_context() {
161 return storage::IsolatedContext::GetInstance();
164 base::FilePath root_path() {
165 return data_dir_.path().Append(FPL("Media Directory"));
168 base::FilePath GetVirtualPath(
169 const base::FilePath::CharType* test_case_path) {
170 return base::FilePath::FromUTF8Unsafe(filesystem_id_).
171 Append(FPL("Media Directory")).
172 Append(base::FilePath(test_case_path));
175 GURL origin() {
176 return GURL("http://example.com");
179 storage::FileSystemType type() { return storage::kFileSystemTypeNativeMedia; }
181 storage::FileSystemOperationRunner* operation_runner() {
182 return file_system_context_->operation_runner();
185 private:
186 base::MessageLoop message_loop_;
187 content::TestBrowserThread io_thread_;
189 base::ScopedTempDir data_dir_;
190 scoped_refptr<storage::FileSystemContext> file_system_context_;
192 std::string filesystem_id_;
194 DISALLOW_COPY_AND_ASSIGN(NativeMediaFileUtilTest);
197 TEST_F(NativeMediaFileUtilTest, DirectoryExistsAndFileExistsFiltering) {
198 PopulateDirectoryWithTestCases(root_path(),
199 kFilteringTestCases,
200 arraysize(kFilteringTestCases));
202 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
203 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
205 base::File::Error expectation =
206 kFilteringTestCases[i].visible ?
207 base::File::FILE_OK :
208 base::File::FILE_ERROR_NOT_FOUND;
210 std::string test_name =
211 base::StringPrintf("DirectoryExistsAndFileExistsFiltering %" PRIuS, i);
212 if (kFilteringTestCases[i].is_directory) {
213 operation_runner()->DirectoryExists(
214 url, base::Bind(&ExpectEqHelper, test_name, expectation));
215 } else {
216 operation_runner()->FileExists(
217 url, base::Bind(&ExpectEqHelper, test_name, expectation));
219 base::MessageLoop::current()->RunUntilIdle();
223 TEST_F(NativeMediaFileUtilTest, ReadDirectoryFiltering) {
224 PopulateDirectoryWithTestCases(root_path(),
225 kFilteringTestCases,
226 arraysize(kFilteringTestCases));
228 std::set<base::FilePath::StringType> content;
229 FileSystemURL url = CreateURL(FPL(""));
230 bool completed = false;
231 operation_runner()->ReadDirectory(
232 url, base::Bind(&DidReadDirectory, &content, &completed));
233 base::MessageLoop::current()->RunUntilIdle();
234 EXPECT_TRUE(completed);
235 EXPECT_EQ(6u, content.size());
237 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
238 base::FilePath::StringType name =
239 base::FilePath(kFilteringTestCases[i].path).BaseName().value();
240 std::set<base::FilePath::StringType>::const_iterator found =
241 content.find(name);
242 EXPECT_EQ(kFilteringTestCases[i].visible, found != content.end());
246 TEST_F(NativeMediaFileUtilTest, CreateDirectoryFiltering) {
247 // Run the loop twice. The second loop attempts to create directories that are
248 // pre-existing. Though the result should be the same.
249 for (int loop_count = 0; loop_count < 2; ++loop_count) {
250 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
251 if (kFilteringTestCases[i].is_directory) {
252 FileSystemURL root_url = CreateURL(FPL(""));
253 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
255 std::string test_name = base::StringPrintf(
256 "CreateFileAndCreateDirectoryFiltering run %d, test %" PRIuS,
257 loop_count, i);
258 base::File::Error expectation =
259 kFilteringTestCases[i].visible ?
260 base::File::FILE_OK :
261 base::File::FILE_ERROR_SECURITY;
262 operation_runner()->CreateDirectory(
263 url, false, false,
264 base::Bind(&ExpectEqHelper, test_name, expectation));
266 base::MessageLoop::current()->RunUntilIdle();
271 TEST_F(NativeMediaFileUtilTest, CopySourceFiltering) {
272 base::FilePath dest_path = root_path().AppendASCII("dest");
273 FileSystemURL dest_url = CreateURL(FPL("dest"));
275 // Run the loop twice. The first run has no source files. The second run does.
276 for (int loop_count = 0; loop_count < 2; ++loop_count) {
277 if (loop_count == 1) {
278 PopulateDirectoryWithTestCases(root_path(),
279 kFilteringTestCases,
280 arraysize(kFilteringTestCases));
282 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
283 // Always start with an empty destination directory.
284 // Copying to a non-empty destination directory is an invalid operation.
285 ASSERT_TRUE(base::DeleteFile(dest_path, true));
286 ASSERT_TRUE(base::CreateDirectory(dest_path));
288 FileSystemURL root_url = CreateURL(FPL(""));
289 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
291 std::string test_name = base::StringPrintf(
292 "CopySourceFiltering run %d test %" PRIuS, loop_count, i);
293 base::File::Error expectation = base::File::FILE_OK;
294 if (loop_count == 0 || !kFilteringTestCases[i].visible) {
295 // If the source does not exist or is not visible.
296 expectation = base::File::FILE_ERROR_NOT_FOUND;
297 } else if (!kFilteringTestCases[i].is_directory) {
298 // Cannot copy a visible file to a directory.
299 expectation = base::File::FILE_ERROR_INVALID_OPERATION;
301 operation_runner()->Copy(
302 url, dest_url, storage::FileSystemOperation::OPTION_NONE,
303 storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT,
304 storage::FileSystemOperationRunner::CopyProgressCallback(),
305 base::Bind(&ExpectEqHelper, test_name, expectation));
306 base::MessageLoop::current()->RunUntilIdle();
311 TEST_F(NativeMediaFileUtilTest, CopyDestFiltering) {
312 // Run the loop twice. The first run has no destination files.
313 // The second run does.
314 for (int loop_count = 0; loop_count < 2; ++loop_count) {
315 if (loop_count == 1) {
316 // Reset the test directory between the two loops to remove old
317 // directories and create new ones that should pre-exist.
318 ASSERT_TRUE(base::DeleteFile(root_path(), true));
319 ASSERT_TRUE(base::CreateDirectory(root_path()));
320 PopulateDirectoryWithTestCases(root_path(),
321 kFilteringTestCases,
322 arraysize(kFilteringTestCases));
325 // Always create a dummy source data file.
326 base::FilePath src_path = root_path().AppendASCII("foo.jpg");
327 FileSystemURL src_url = CreateURL(FPL("foo.jpg"));
328 static const char kDummyData[] = "dummy";
329 ASSERT_TRUE(base::WriteFile(src_path, kDummyData, strlen(kDummyData)));
331 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
332 if (loop_count == 0 && kFilteringTestCases[i].is_directory) {
333 // These directories do not exist in this case, so Copy() will not
334 // treat them as directories. Thus invalidating these test cases.
335 continue;
337 FileSystemURL root_url = CreateURL(FPL(""));
338 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
340 std::string test_name = base::StringPrintf(
341 "CopyDestFiltering run %d test %" PRIuS, loop_count, i);
342 base::File::Error expectation;
343 if (loop_count == 0) {
344 // The destination path is a file here. The directory case has been
345 // handled above.
346 // If the destination path does not exist and is not visible, then
347 // creating it would be a security violation.
348 expectation =
349 kFilteringTestCases[i].visible ?
350 base::File::FILE_OK :
351 base::File::FILE_ERROR_SECURITY;
352 } else {
353 if (!kFilteringTestCases[i].visible) {
354 // If the destination path exist and is not visible, then to the copy
355 // operation, it looks like the file needs to be created, which is a
356 // security violation.
357 expectation = base::File::FILE_ERROR_SECURITY;
358 } else if (kFilteringTestCases[i].is_directory) {
359 // Cannot copy a file to a directory.
360 expectation = base::File::FILE_ERROR_INVALID_OPERATION;
361 } else {
362 // Copying from a file to a visible file that exists is ok.
363 expectation = base::File::FILE_OK;
366 operation_runner()->Copy(
367 src_url, url, storage::FileSystemOperation::OPTION_NONE,
368 storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT,
369 storage::FileSystemOperationRunner::CopyProgressCallback(),
370 base::Bind(&ExpectEqHelper, test_name, expectation));
371 base::MessageLoop::current()->RunUntilIdle();
376 TEST_F(NativeMediaFileUtilTest, MoveSourceFiltering) {
377 base::FilePath dest_path = root_path().AppendASCII("dest");
378 FileSystemURL dest_url = CreateURL(FPL("dest"));
380 // Run the loop twice. The first run has no source files. The second run does.
381 for (int loop_count = 0; loop_count < 2; ++loop_count) {
382 if (loop_count == 1) {
383 PopulateDirectoryWithTestCases(root_path(),
384 kFilteringTestCases,
385 arraysize(kFilteringTestCases));
387 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
388 // Always start with an empty destination directory.
389 // Moving to a non-empty destination directory is an invalid operation.
390 ASSERT_TRUE(base::DeleteFile(dest_path, true));
391 ASSERT_TRUE(base::CreateDirectory(dest_path));
393 FileSystemURL root_url = CreateURL(FPL(""));
394 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
396 std::string test_name = base::StringPrintf(
397 "MoveSourceFiltering run %d test %" PRIuS, loop_count, i);
398 base::File::Error expectation = base::File::FILE_OK;
399 if (loop_count == 0 || !kFilteringTestCases[i].visible) {
400 // If the source does not exist or is not visible.
401 expectation = base::File::FILE_ERROR_NOT_FOUND;
402 } else if (!kFilteringTestCases[i].is_directory) {
403 // Cannot move a visible file to a directory.
404 expectation = base::File::FILE_ERROR_INVALID_OPERATION;
406 operation_runner()->Move(
407 url,
408 dest_url,
409 storage::FileSystemOperation::OPTION_NONE,
410 base::Bind(&ExpectEqHelper, test_name, expectation));
411 base::MessageLoop::current()->RunUntilIdle();
416 TEST_F(NativeMediaFileUtilTest, MoveDestFiltering) {
417 // Run the loop twice. The first run has no destination files.
418 // The second run does.
419 for (int loop_count = 0; loop_count < 2; ++loop_count) {
420 if (loop_count == 1) {
421 // Reset the test directory between the two loops to remove old
422 // directories and create new ones that should pre-exist.
423 ASSERT_TRUE(base::DeleteFile(root_path(), true));
424 ASSERT_TRUE(base::CreateDirectory(root_path()));
425 PopulateDirectoryWithTestCases(root_path(),
426 kFilteringTestCases,
427 arraysize(kFilteringTestCases));
430 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
431 if (loop_count == 0 && kFilteringTestCases[i].is_directory) {
432 // These directories do not exist in this case, so Copy() will not
433 // treat them as directories. Thus invalidating these test cases.
434 continue;
437 // Create the source file for every test case because it might get moved.
438 base::FilePath src_path = root_path().AppendASCII("foo.jpg");
439 FileSystemURL src_url = CreateURL(FPL("foo.jpg"));
440 static const char kDummyData[] = "dummy";
441 ASSERT_TRUE(
442 base::WriteFile(src_path, kDummyData, strlen(kDummyData)));
444 FileSystemURL root_url = CreateURL(FPL(""));
445 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
447 std::string test_name = base::StringPrintf(
448 "MoveDestFiltering run %d test %" PRIuS, loop_count, i);
449 base::File::Error expectation;
450 if (loop_count == 0) {
451 // The destination path is a file here. The directory case has been
452 // handled above.
453 // If the destination path does not exist and is not visible, then
454 // creating it would be a security violation.
455 expectation =
456 kFilteringTestCases[i].visible ?
457 base::File::FILE_OK :
458 base::File::FILE_ERROR_SECURITY;
459 } else {
460 if (!kFilteringTestCases[i].visible) {
461 // If the destination path exist and is not visible, then to the move
462 // operation, it looks like the file needs to be created, which is a
463 // security violation.
464 expectation = base::File::FILE_ERROR_SECURITY;
465 } else if (kFilteringTestCases[i].is_directory) {
466 // Cannot move a file to a directory.
467 expectation = base::File::FILE_ERROR_INVALID_OPERATION;
468 } else {
469 // Moving from a file to a visible file that exists is ok.
470 expectation = base::File::FILE_OK;
473 operation_runner()->Move(
474 src_url,
475 url,
476 storage::FileSystemOperation::OPTION_NONE,
477 base::Bind(&ExpectEqHelper, test_name, expectation));
478 base::MessageLoop::current()->RunUntilIdle();
483 TEST_F(NativeMediaFileUtilTest, GetMetadataFiltering) {
484 // Run the loop twice. The first run has no files. The second run does.
485 for (int loop_count = 0; loop_count < 2; ++loop_count) {
486 if (loop_count == 1) {
487 PopulateDirectoryWithTestCases(root_path(),
488 kFilteringTestCases,
489 arraysize(kFilteringTestCases));
491 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
492 FileSystemURL root_url = CreateURL(FPL(""));
493 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
495 std::string test_name = base::StringPrintf(
496 "GetMetadataFiltering run %d test %" PRIuS, loop_count, i);
497 base::File::Error expectation = base::File::FILE_OK;
498 if (loop_count == 0 || !kFilteringTestCases[i].visible) {
499 // Cannot get metadata from files that do not exist or are not visible.
500 expectation = base::File::FILE_ERROR_NOT_FOUND;
502 operation_runner()->GetMetadata(
503 url,
504 base::Bind(&ExpectMetadataEqHelper,
505 test_name,
506 expectation,
507 kFilteringTestCases[i].is_directory));
508 base::MessageLoop::current()->RunUntilIdle();
513 TEST_F(NativeMediaFileUtilTest, RemoveFileFiltering) {
514 // Run the loop twice. The first run has no files. The second run does.
515 for (int loop_count = 0; loop_count < 2; ++loop_count) {
516 if (loop_count == 1) {
517 PopulateDirectoryWithTestCases(root_path(),
518 kFilteringTestCases,
519 arraysize(kFilteringTestCases));
521 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
522 FileSystemURL root_url = CreateURL(FPL(""));
523 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
525 std::string test_name = base::StringPrintf(
526 "RemoveFiltering run %d test %" PRIuS, loop_count, i);
527 base::File::Error expectation = base::File::FILE_OK;
528 if (loop_count == 0 || !kFilteringTestCases[i].visible) {
529 // Cannot remove files that do not exist or are not visible.
530 expectation = base::File::FILE_ERROR_NOT_FOUND;
531 } else if (kFilteringTestCases[i].is_directory) {
532 expectation = base::File::FILE_ERROR_NOT_A_FILE;
534 operation_runner()->RemoveFile(
535 url, base::Bind(&ExpectEqHelper, test_name, expectation));
536 base::MessageLoop::current()->RunUntilIdle();
541 void CreateSnapshotCallback(
542 base::File::Error* error,
543 base::File::Error result,
544 const base::File::Info&,
545 const base::FilePath&,
546 const scoped_refptr<storage::ShareableFileReference>&) {
547 *error = result;
550 TEST_F(NativeMediaFileUtilTest, CreateSnapshot) {
551 PopulateDirectoryWithTestCases(root_path(),
552 kFilteringTestCases,
553 arraysize(kFilteringTestCases));
554 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
555 if (kFilteringTestCases[i].is_directory ||
556 !kFilteringTestCases[i].visible) {
557 continue;
559 FileSystemURL root_url = CreateURL(FPL(""));
560 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
561 base::File::Error expected_error, error;
562 if (kFilteringTestCases[i].media_file)
563 expected_error = base::File::FILE_OK;
564 else
565 expected_error = base::File::FILE_ERROR_SECURITY;
566 error = base::File::FILE_ERROR_FAILED;
567 operation_runner()->CreateSnapshotFile(url,
568 base::Bind(CreateSnapshotCallback, &error));
569 base::MessageLoop::current()->RunUntilIdle();
570 ASSERT_EQ(expected_error, error);