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.
5 #include "chrome/browser/media_galleries/media_folder_finder.h"
10 #include "base/base_paths.h"
11 #include "base/bind.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/test/scoped_path_override.h"
16 #include "base/threading/sequenced_worker_pool.h"
17 #include "chrome/browser/media_galleries/media_scan_types.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "content/public/test/test_utils.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 class MediaFolderFinderTest
: public testing::Test
{
26 MediaFolderFinderTest() {
29 ~MediaFolderFinderTest() override
{}
31 void SetUp() override
{ ASSERT_TRUE(fake_dir_
.CreateUniqueTempDir()); }
33 void TearDown() override
{ ASSERT_EQ(NULL
, media_folder_finder_
.get()); }
36 void CreateMediaFolderFinder(
37 const std::vector
<base::FilePath
> roots
,
38 bool expected_success
,
39 const MediaFolderFinder::MediaFolderFinderResults
& expected_results
) {
40 EXPECT_EQ(NULL
, media_folder_finder_
.get());
41 received_results_
= false;
42 expected_success_
= expected_success
;
43 expected_results_
= expected_results
;
44 media_folder_finder_
.reset(
45 new MediaFolderFinder(base::Bind(&MediaFolderFinderTest::OnGotResults
,
46 base::Unretained(this))));
47 media_folder_finder_
->SetRootsForTesting(roots
);
51 media_folder_finder_
->StartScan();
54 void DeleteMediaFolderFinder() {
55 EXPECT_TRUE(media_folder_finder_
.get() != NULL
);
56 media_folder_finder_
.reset();
59 bool received_results() const {
60 return received_results_
;
63 const base::FilePath
& fake_dir() const {
64 return fake_dir_
.path();
67 void CreateTestDir(const base::FilePath
& parent_dir
) {
68 if (parent_dir
== fake_dir())
71 ASSERT_TRUE(fake_dir().IsParent(parent_dir
));
72 ASSERT_TRUE(base::CreateDirectory(parent_dir
));
75 void CreateTestFile(const base::FilePath
& parent_dir
,
76 MediaGalleryScanFileType type
,
79 MediaFolderFinder::MediaFolderFinderResults
* results
) {
80 CreateTestDir(parent_dir
);
82 std::string extension
;
84 MediaGalleryScanResult
& result
= (*results
)[parent_dir
];
86 case MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
:
89 result
.image_count
+= count
;
91 case MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO
:
94 result
.audio_count
+= count
;
96 case MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO
:
99 result
.video_count
+= count
;
101 case MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN
:
104 if (IsEmptyScanResult(result
))
105 results
->erase(parent_dir
);
114 for (size_t i
= 0; i
< count
; ++i
) {
115 base::FilePath
test_file(parent_dir
.AppendASCII("dummy." + extension
));
117 base::GetUniquePathNumber(test_file
, base::FilePath::StringType());
118 if (uniquifier
> 0) {
119 test_file
= test_file
.InsertBeforeExtensionASCII(
120 base::StringPrintf(" (%d)", uniquifier
));
121 filesize
+= uniquifier
;
124 std::string dummy_data
;
125 dummy_data
.resize(filesize
);
128 base::WriteFile(test_file
, dummy_data
.c_str(), filesize
);
129 ASSERT_GE(bytes_written
, 0);
130 ASSERT_EQ(filesize
, static_cast<size_t>(bytes_written
));
134 void RunLoopUntilReceivedCallback() {
135 while (!received_results())
136 content::RunAllBlockingPoolTasksUntilIdle();
142 const MediaFolderFinder::MediaFolderFinderResults
& results
) {
143 received_results_
= true;
144 EXPECT_EQ(expected_success_
, success
);
145 std::set
<base::FilePath
> expected_keys
=
146 GetKeysFromResults(expected_results_
);
147 ASSERT_EQ(expected_keys
, GetKeysFromResults(results
));
148 for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it
=
150 it
!= results
.end(); ++it
) {
151 const base::FilePath
& folder
= it
->first
;
152 const MediaGalleryScanResult
& expected
= it
->second
;
153 const MediaGalleryScanResult
& actual
= results
.find(folder
)->second
;
154 EXPECT_EQ(expected
.image_count
, actual
.image_count
)
155 << " Image count for " << folder
.value();
156 EXPECT_EQ(expected
.audio_count
, actual
.audio_count
)
157 << " Audio count for " << folder
.value();
158 EXPECT_EQ(expected
.video_count
, actual
.video_count
)
159 << " Video count for " << folder
.value();
163 std::set
<base::FilePath
> GetKeysFromResults(
164 const MediaFolderFinder::MediaFolderFinderResults
& results
) {
165 std::set
<base::FilePath
> keys
;
166 for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it
=
168 it
!= results
.end(); ++it
) {
169 keys
.insert(it
->first
);
174 content::TestBrowserThreadBundle thread_bundle_
;
176 base::ScopedTempDir fake_dir_
;
178 scoped_ptr
<MediaFolderFinder
> media_folder_finder_
;
180 bool expected_success_
;
181 MediaFolderFinder::MediaFolderFinderResults expected_results_
;
182 bool received_results_
;
184 DISALLOW_COPY_AND_ASSIGN(MediaFolderFinderTest
);
187 TEST_F(MediaFolderFinderTest
, NoScan
) {
188 MediaFolderFinder::MediaFolderFinderResults expected_results
;
189 std::vector
<base::FilePath
> folders
;
190 folders
.push_back(fake_dir());
191 CreateMediaFolderFinder(folders
, false, expected_results
);
192 DeleteMediaFolderFinder();
193 EXPECT_TRUE(received_results());
196 TEST_F(MediaFolderFinderTest
, ScanAndCancel
) {
197 MediaFolderFinder::MediaFolderFinderResults expected_results
;
198 std::vector
<base::FilePath
> folders
;
199 folders
.push_back(fake_dir());
200 CreateMediaFolderFinder(folders
, false, expected_results
);
202 DeleteMediaFolderFinder();
203 content::RunAllBlockingPoolTasksUntilIdle();
204 EXPECT_TRUE(received_results());
207 TEST_F(MediaFolderFinderTest
, ScanNothing
) {
208 MediaFolderFinder::MediaFolderFinderResults expected_results
;
209 std::vector
<base::FilePath
> folders
;
210 CreateMediaFolderFinder(folders
, true, expected_results
);
212 RunLoopUntilReceivedCallback();
213 DeleteMediaFolderFinder();
216 TEST_F(MediaFolderFinderTest
, EmptyScan
) {
217 MediaFolderFinder::MediaFolderFinderResults expected_results
;
218 std::vector
<base::FilePath
> folders
;
219 folders
.push_back(fake_dir());
220 CreateMediaFolderFinder(folders
, true, expected_results
);
222 RunLoopUntilReceivedCallback();
223 DeleteMediaFolderFinder();
226 TEST_F(MediaFolderFinderTest
, ScanMediaFiles
) {
227 MediaFolderFinder::MediaFolderFinderResults expected_results
;
228 std::vector
<base::FilePath
> folders
;
229 folders
.push_back(fake_dir());
231 base::FilePath dir1
= fake_dir().AppendASCII("dir1");
232 base::FilePath dir2
= fake_dir().AppendASCII("dir2");
233 base::FilePath dir2_3
= dir2
.AppendASCII("dir2_3");
234 base::FilePath dir2_4
= dir2
.AppendASCII("dir2_4");
235 base::FilePath dir2_4_5
= dir2_4
.AppendASCII("dir2_4_5");
236 base::FilePath dir2_4_empty
= dir2_4
.AppendASCII("dir2_4_empty");
237 base::FilePath dir_empty
= fake_dir().AppendASCII("dir_empty");
239 CreateTestFile(dir1
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 2, true,
241 CreateTestFile(dir1
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, false,
243 CreateTestFile(dir1
, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN
, 1, false,
245 CreateTestFile(dir2_3
, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO
, 4, true,
247 CreateTestFile(dir2_3
, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO
, 3, false,
249 CreateTestFile(dir2_4
, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN
, 5, false,
251 CreateTestFile(dir2_4_5
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 2, true,
253 CreateTestFile(dir2_4_5
, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO
, 4, true,
255 CreateTestFile(dir2_4_5
, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO
, 1, true,
257 CreateTestFile(dir2_4_5
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 5, false,
259 CreateTestFile(dir2_4_5
, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO
, 3, false,
261 CreateTestFile(dir2_4_5
, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN
, 3, true,
263 CreateTestDir(dir2_4_empty
);
264 CreateTestDir(dir_empty
);
266 CreateMediaFolderFinder(folders
, true, expected_results
);
268 RunLoopUntilReceivedCallback();
269 DeleteMediaFolderFinder();
272 TEST_F(MediaFolderFinderTest
, SkipHiddenFiles
) {
273 MediaFolderFinder::MediaFolderFinderResults expected_results
;
274 std::vector
<base::FilePath
> folders
;
275 folders
.push_back(fake_dir());
277 base::FilePath hidden_dir
= fake_dir().AppendASCII(".hidden");
279 CreateTestFile(hidden_dir
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 2, true,
281 expected_results
.erase(hidden_dir
);
283 CreateMediaFolderFinder(folders
, true, expected_results
);
285 RunLoopUntilReceivedCallback();
286 DeleteMediaFolderFinder();
289 TEST_F(MediaFolderFinderTest
, ScanIgnoresSmallMediaFiles
) {
290 MediaFolderFinder::MediaFolderFinderResults expected_results
;
291 std::vector
<base::FilePath
> folders
;
292 folders
.push_back(fake_dir());
294 base::FilePath dir1
= fake_dir().AppendASCII("dir1");
295 base::FilePath dir2
= fake_dir().AppendASCII("dir2");
296 base::FilePath dir_empty
= fake_dir().AppendASCII("dir_empty");
298 CreateTestFile(dir1
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 2, true,
300 CreateTestFile(dir1
, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO
, 1, false,
302 CreateTestFile(dir1
, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN
, 1, false,
304 CreateTestFile(dir2
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, false,
306 CreateTestFile(dir2
, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO
, 3, false,
308 CreateTestFile(dir2
, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO
, 5, false,
310 CreateTestFile(dir2
, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN
, 1, true,
312 CreateTestDir(dir_empty
);
313 ASSERT_EQ(1U, expected_results
.erase(dir2
));
315 CreateMediaFolderFinder(folders
, true, expected_results
);
317 RunLoopUntilReceivedCallback();
318 DeleteMediaFolderFinder();
321 TEST_F(MediaFolderFinderTest
, Overlap
) {
322 MediaFolderFinder::MediaFolderFinderResults expected_results
;
323 std::vector
<base::FilePath
> folders
;
324 folders
.push_back(fake_dir());
325 folders
.push_back(fake_dir());
327 base::FilePath dir1
= fake_dir().AppendASCII("dir1");
328 folders
.push_back(dir1
);
329 folders
.push_back(dir1
);
331 CreateTestFile(dir1
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, true,
334 CreateMediaFolderFinder(folders
, true, expected_results
);
336 RunLoopUntilReceivedCallback();
337 DeleteMediaFolderFinder();
340 TEST_F(MediaFolderFinderTest
, Prune
) {
341 MediaFolderFinder::MediaFolderFinderResults expected_results
;
342 std::vector
<base::FilePath
> folders
;
343 folders
.push_back(fake_dir());
346 int pruned_dir_key
= base::DIR_IE_INTERNET_CACHE
;
347 #elif defined(OS_MACOSX)
348 int pruned_dir_key
= chrome::DIR_USER_LIBRARY
;
350 int pruned_dir_key
= base::DIR_CACHE
;
353 base::FilePath fake_pruned_dir
= fake_dir().AppendASCII("dir1");
354 base::ScopedPathOverride
scoped_fake_pruned_dir_override(pruned_dir_key
,
357 CreateTestFile(fake_dir(), MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, true,
359 CreateTestFile(fake_pruned_dir
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, true,
362 base::FilePath test_dir
= fake_pruned_dir
.AppendASCII("dir2");
363 CreateTestFile(test_dir
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, true,
366 // |fake_pruned_dir| and |test_dir| are pruned.
367 expected_results
.erase(fake_pruned_dir
);
368 expected_results
.erase(test_dir
);
370 CreateMediaFolderFinder(folders
, true, expected_results
);
372 RunLoopUntilReceivedCallback();
373 DeleteMediaFolderFinder();
376 TEST_F(MediaFolderFinderTest
, Graylist
) {
377 MediaFolderFinder::MediaFolderFinderResults expected_results
;
378 std::vector
<base::FilePath
> folders
;
379 folders
.push_back(fake_dir());
381 base::FilePath fake_home_dir
= fake_dir().AppendASCII("dir1");
382 base::FilePath test_dir
= fake_home_dir
.AppendASCII("dir2");
383 base::ScopedPathOverride
scoped_fake_home_dir_override(base::DIR_HOME
,
386 CreateTestFile(fake_dir(), MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, true,
388 CreateTestFile(fake_home_dir
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, true,
390 CreateTestFile(test_dir
, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE
, 1, true,
393 // |fake_home_dir| and its ancestors do not show up in results.
394 expected_results
.erase(fake_dir());
395 expected_results
.erase(fake_home_dir
);
397 CreateMediaFolderFinder(folders
, true, expected_results
);
399 RunLoopUntilReceivedCallback();
400 DeleteMediaFolderFinder();