| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/media_galleries/media_folder_finder.h" |
| |
| #include <set> |
| #include <string> |
| |
| #include "base/base_paths.h" |
| #include "base/bind.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/scoped_path_override.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "chrome/browser/media_galleries/media_scan_types.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "content/public/test/test_utils.h" |
| |
| class MediaFolderFinderTest : public testing::Test { |
| public: |
| MediaFolderFinderTest() { |
| } |
| |
| virtual ~MediaFolderFinderTest() { |
| } |
| |
| virtual void SetUp() override { |
| ASSERT_TRUE(fake_dir_.CreateUniqueTempDir()); |
| } |
| |
| virtual void TearDown() override { |
| ASSERT_EQ(NULL, media_folder_finder_.get()); |
| } |
| |
| protected: |
| void CreateMediaFolderFinder( |
| const std::vector<base::FilePath> roots, |
| bool expected_success, |
| const MediaFolderFinder::MediaFolderFinderResults& expected_results) { |
| EXPECT_EQ(NULL, media_folder_finder_.get()); |
| received_results_ = false; |
| expected_success_ = expected_success; |
| expected_results_ = expected_results; |
| media_folder_finder_.reset( |
| new MediaFolderFinder(base::Bind(&MediaFolderFinderTest::OnGotResults, |
| base::Unretained(this)))); |
| media_folder_finder_->SetRootsForTesting(roots); |
| } |
| |
| void StartScan() { |
| media_folder_finder_->StartScan(); |
| } |
| |
| void DeleteMediaFolderFinder() { |
| EXPECT_TRUE(media_folder_finder_.get() != NULL); |
| media_folder_finder_.reset(); |
| } |
| |
| bool received_results() const { |
| return received_results_; |
| } |
| |
| const base::FilePath& fake_dir() const { |
| return fake_dir_.path(); |
| } |
| |
| void CreateTestDir(const base::FilePath& parent_dir) { |
| if (parent_dir == fake_dir()) |
| return; |
| |
| ASSERT_TRUE(fake_dir().IsParent(parent_dir)); |
| ASSERT_TRUE(base::CreateDirectory(parent_dir)); |
| } |
| |
| void CreateTestFile(const base::FilePath& parent_dir, |
| MediaGalleryScanFileType type, |
| size_t count, |
| bool big, |
| MediaFolderFinder::MediaFolderFinderResults* results) { |
| CreateTestDir(parent_dir); |
| |
| std::string extension; |
| size_t filesize; |
| MediaGalleryScanResult& result = (*results)[parent_dir]; |
| switch (type) { |
| case MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE: |
| extension = "jpg"; |
| filesize = 10; |
| result.image_count += count; |
| break; |
| case MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO: |
| extension = "wav"; |
| filesize = 20; |
| result.audio_count += count; |
| break; |
| case MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO: |
| extension = "avi"; |
| filesize = 30; |
| result.video_count += count; |
| break; |
| case MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN: |
| extension = "txt"; |
| filesize = 10; |
| if (IsEmptyScanResult(result)) |
| results->erase(parent_dir); |
| break; |
| default: |
| NOTREACHED(); |
| return; |
| } |
| if (big) |
| filesize *= 100000; |
| |
| for (size_t i = 0; i < count; ++i) { |
| base::FilePath test_file(parent_dir.AppendASCII("dummy." + extension)); |
| int uniquifier = |
| base::GetUniquePathNumber(test_file, base::FilePath::StringType()); |
| if (uniquifier > 0) { |
| test_file = test_file.InsertBeforeExtensionASCII( |
| base::StringPrintf(" (%d)", uniquifier)); |
| filesize += uniquifier; |
| } |
| |
| std::string dummy_data; |
| dummy_data.resize(filesize); |
| |
| int bytes_written = |
| base::WriteFile(test_file, dummy_data.c_str(), filesize); |
| ASSERT_GE(bytes_written, 0); |
| ASSERT_EQ(filesize, static_cast<size_t>(bytes_written)); |
| } |
| } |
| |
| void RunLoopUntilReceivedCallback() { |
| while (!received_results()) |
| content::RunAllBlockingPoolTasksUntilIdle(); |
| } |
| |
| private: |
| void OnGotResults( |
| bool success, |
| const MediaFolderFinder::MediaFolderFinderResults& results) { |
| received_results_ = true; |
| EXPECT_EQ(expected_success_, success); |
| std::set<base::FilePath> expected_keys = |
| GetKeysFromResults(expected_results_); |
| ASSERT_EQ(expected_keys, GetKeysFromResults(results)); |
| for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it = |
| results.begin(); |
| it != results.end(); ++it) { |
| const base::FilePath& folder = it->first; |
| const MediaGalleryScanResult& expected = it->second; |
| const MediaGalleryScanResult& actual = results.find(folder)->second; |
| EXPECT_EQ(expected.image_count, actual.image_count) |
| << " Image count for " << folder.value(); |
| EXPECT_EQ(expected.audio_count, actual.audio_count) |
| << " Audio count for " << folder.value(); |
| EXPECT_EQ(expected.video_count, actual.video_count) |
| << " Video count for " << folder.value(); |
| } |
| } |
| |
| std::set<base::FilePath> GetKeysFromResults( |
| const MediaFolderFinder::MediaFolderFinderResults& results) { |
| std::set<base::FilePath> keys; |
| for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it = |
| results.begin(); |
| it != results.end(); ++it) { |
| keys.insert(it->first); |
| } |
| return keys; |
| } |
| |
| content::TestBrowserThreadBundle thread_bundle_; |
| |
| base::ScopedTempDir fake_dir_; |
| |
| scoped_ptr<MediaFolderFinder> media_folder_finder_; |
| |
| bool expected_success_; |
| MediaFolderFinder::MediaFolderFinderResults expected_results_; |
| bool received_results_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MediaFolderFinderTest); |
| }; |
| |
| TEST_F(MediaFolderFinderTest, NoScan) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| CreateMediaFolderFinder(folders, false, expected_results); |
| DeleteMediaFolderFinder(); |
| EXPECT_TRUE(received_results()); |
| } |
| |
| TEST_F(MediaFolderFinderTest, ScanAndCancel) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| CreateMediaFolderFinder(folders, false, expected_results); |
| StartScan(); |
| DeleteMediaFolderFinder(); |
| content::RunAllBlockingPoolTasksUntilIdle(); |
| EXPECT_TRUE(received_results()); |
| } |
| |
| TEST_F(MediaFolderFinderTest, ScanNothing) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| CreateMediaFolderFinder(folders, true, expected_results); |
| StartScan(); |
| RunLoopUntilReceivedCallback(); |
| DeleteMediaFolderFinder(); |
| } |
| |
| TEST_F(MediaFolderFinderTest, EmptyScan) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| CreateMediaFolderFinder(folders, true, expected_results); |
| StartScan(); |
| RunLoopUntilReceivedCallback(); |
| DeleteMediaFolderFinder(); |
| } |
| |
| TEST_F(MediaFolderFinderTest, ScanMediaFiles) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| |
| base::FilePath dir1 = fake_dir().AppendASCII("dir1"); |
| base::FilePath dir2 = fake_dir().AppendASCII("dir2"); |
| base::FilePath dir2_3 = dir2.AppendASCII("dir2_3"); |
| base::FilePath dir2_4 = dir2.AppendASCII("dir2_4"); |
| base::FilePath dir2_4_5 = dir2_4.AppendASCII("dir2_4_5"); |
| base::FilePath dir2_4_empty = dir2_4.AppendASCII("dir2_4_empty"); |
| base::FilePath dir_empty = fake_dir().AppendASCII("dir_empty"); |
| |
| CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 2, true, |
| &expected_results); |
| CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, false, |
| &expected_results); |
| CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN, 1, false, |
| &expected_results); |
| CreateTestFile(dir2_3, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO, 4, true, |
| &expected_results); |
| CreateTestFile(dir2_3, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO, 3, false, |
| &expected_results); |
| CreateTestFile(dir2_4, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN, 5, false, |
| &expected_results); |
| CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 2, true, |
| &expected_results); |
| CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO, 4, true, |
| &expected_results); |
| CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO, 1, true, |
| &expected_results); |
| CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 5, false, |
| &expected_results); |
| CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO, 3, false, |
| &expected_results); |
| CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN, 3, true, |
| &expected_results); |
| CreateTestDir(dir2_4_empty); |
| CreateTestDir(dir_empty); |
| |
| CreateMediaFolderFinder(folders, true, expected_results); |
| StartScan(); |
| RunLoopUntilReceivedCallback(); |
| DeleteMediaFolderFinder(); |
| } |
| |
| TEST_F(MediaFolderFinderTest, SkipHiddenFiles) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| |
| base::FilePath hidden_dir = fake_dir().AppendASCII(".hidden"); |
| |
| CreateTestFile(hidden_dir, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 2, true, |
| &expected_results); |
| expected_results.erase(hidden_dir); |
| |
| CreateMediaFolderFinder(folders, true, expected_results); |
| StartScan(); |
| RunLoopUntilReceivedCallback(); |
| DeleteMediaFolderFinder(); |
| } |
| |
| TEST_F(MediaFolderFinderTest, ScanIgnoresSmallMediaFiles) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| |
| base::FilePath dir1 = fake_dir().AppendASCII("dir1"); |
| base::FilePath dir2 = fake_dir().AppendASCII("dir2"); |
| base::FilePath dir_empty = fake_dir().AppendASCII("dir_empty"); |
| |
| CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 2, true, |
| &expected_results); |
| CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO, 1, false, |
| &expected_results); |
| CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN, 1, false, |
| &expected_results); |
| CreateTestFile(dir2, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, false, |
| &expected_results); |
| CreateTestFile(dir2, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO, 3, false, |
| &expected_results); |
| CreateTestFile(dir2, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO, 5, false, |
| &expected_results); |
| CreateTestFile(dir2, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN, 1, true, |
| &expected_results); |
| CreateTestDir(dir_empty); |
| ASSERT_EQ(1U, expected_results.erase(dir2)); |
| |
| CreateMediaFolderFinder(folders, true, expected_results); |
| StartScan(); |
| RunLoopUntilReceivedCallback(); |
| DeleteMediaFolderFinder(); |
| } |
| |
| TEST_F(MediaFolderFinderTest, Overlap) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| folders.push_back(fake_dir()); |
| |
| base::FilePath dir1 = fake_dir().AppendASCII("dir1"); |
| folders.push_back(dir1); |
| folders.push_back(dir1); |
| |
| CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, true, |
| &expected_results); |
| |
| CreateMediaFolderFinder(folders, true, expected_results); |
| StartScan(); |
| RunLoopUntilReceivedCallback(); |
| DeleteMediaFolderFinder(); |
| } |
| |
| TEST_F(MediaFolderFinderTest, Prune) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| |
| #if defined(OS_WIN) |
| int pruned_dir_key = base::DIR_IE_INTERNET_CACHE; |
| #elif defined(OS_MACOSX) |
| int pruned_dir_key = chrome::DIR_USER_LIBRARY; |
| #else |
| int pruned_dir_key = base::DIR_CACHE; |
| #endif |
| |
| base::FilePath fake_pruned_dir = fake_dir().AppendASCII("dir1"); |
| base::ScopedPathOverride scoped_fake_pruned_dir_override(pruned_dir_key, |
| fake_pruned_dir); |
| |
| CreateTestFile(fake_dir(), MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, true, |
| &expected_results); |
| CreateTestFile(fake_pruned_dir, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, true, |
| &expected_results); |
| |
| base::FilePath test_dir = fake_pruned_dir.AppendASCII("dir2"); |
| CreateTestFile(test_dir, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, true, |
| &expected_results); |
| |
| // |fake_pruned_dir| and |test_dir| are pruned. |
| expected_results.erase(fake_pruned_dir); |
| expected_results.erase(test_dir); |
| |
| CreateMediaFolderFinder(folders, true, expected_results); |
| StartScan(); |
| RunLoopUntilReceivedCallback(); |
| DeleteMediaFolderFinder(); |
| } |
| |
| TEST_F(MediaFolderFinderTest, Graylist) { |
| MediaFolderFinder::MediaFolderFinderResults expected_results; |
| std::vector<base::FilePath> folders; |
| folders.push_back(fake_dir()); |
| |
| base::FilePath fake_home_dir = fake_dir().AppendASCII("dir1"); |
| base::FilePath test_dir = fake_home_dir.AppendASCII("dir2"); |
| base::ScopedPathOverride scoped_fake_home_dir_override(base::DIR_HOME, |
| fake_home_dir); |
| |
| CreateTestFile(fake_dir(), MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, true, |
| &expected_results); |
| CreateTestFile(fake_home_dir, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, true, |
| &expected_results); |
| CreateTestFile(test_dir, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, true, |
| &expected_results); |
| |
| // |fake_home_dir| and its ancestors do not show up in results. |
| expected_results.erase(fake_dir()); |
| expected_results.erase(fake_home_dir); |
| |
| CreateMediaFolderFinder(folders, true, expected_results); |
| StartScan(); |
| RunLoopUntilReceivedCallback(); |
| DeleteMediaFolderFinder(); |
| } |