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.
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/format_macros.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/run_loop.h"
17 #include "base/strings/stringprintf.h"
18 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
19 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
20 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
21 #include "chrome/test/base/in_process_browser_test.h"
22 #include "content/public/browser/browser_thread.h"
30 LibraryEntry(const std::string
& artist
, const std::string
& album
,
31 const base::FilePath
& location
)
38 base::FilePath location
;
43 class TestITunesDataProvider
: public ITunesDataProvider
{
45 TestITunesDataProvider(const base::FilePath
& xml_library_path
,
46 const base::Closure
& callback
)
47 : ITunesDataProvider(xml_library_path
),
50 virtual ~TestITunesDataProvider() {}
53 virtual void OnLibraryChanged(const base::FilePath
& path
,
54 bool error
) OVERRIDE
{
55 ITunesDataProvider::OnLibraryChanged(path
, error
);
59 base::Closure callback_
;
61 DISALLOW_COPY_AND_ASSIGN(TestITunesDataProvider
);
64 class ITunesDataProviderTest
: public InProcessBrowserTest
{
66 ITunesDataProviderTest() {}
67 virtual ~ITunesDataProviderTest() {}
70 virtual void SetUp() OVERRIDE
{
71 ASSERT_TRUE(library_dir_
.CreateUniqueTempDir());
72 WriteLibraryInternal(SetUpLibrary());
73 // The ImportedMediaGalleryRegistry is created on which ever thread calls
74 // GetInstance() first. It shouldn't matter what thread creates, however
75 // in practice it is always created on the UI thread, so this calls
76 // GetInstance here to mirror those real conditions.
77 ImportedMediaGalleryRegistry::GetInstance();
78 InProcessBrowserTest::SetUp();
82 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
84 quit_closure_
= loop
.QuitClosure();
85 MediaFileSystemBackend::MediaTaskRunner()->PostTask(
87 base::Bind(&ITunesDataProviderTest::StartTestOnMediaTaskRunner
,
88 base::Unretained(this)));
92 void WriteLibrary(const std::vector
<LibraryEntry
>& entries
,
93 const base::Closure
& callback
) {
94 SetLibraryChangeCallback(callback
);
95 WriteLibraryInternal(entries
);
98 void SetLibraryChangeCallback(const base::Closure
& callback
) {
99 EXPECT_TRUE(library_changed_callback_
.is_null());
100 library_changed_callback_
= callback
;
103 ITunesDataProvider
* data_provider() const {
104 return ImportedMediaGalleryRegistry::ITunesDataProvider();
107 const base::FilePath
& library_dir() const {
108 return library_dir_
.path();
111 base::FilePath
XmlFile() const {
112 return library_dir_
.path().AppendASCII("library.xml");
115 void ExpectTrackLocation(const std::string
& artist
, const std::string
& album
,
116 const std::string
& track_name
) {
117 base::FilePath track
=
118 library_dir().AppendASCII(track_name
).NormalizePathSeparators();
119 EXPECT_EQ(track
.value(),
120 data_provider()->GetTrackLocation(
121 artist
, album
, track_name
).NormalizePathSeparators().value());
124 void ExpectNoTrack(const std::string
& artist
, const std::string
& album
,
125 const std::string
& track_name
) {
126 EXPECT_TRUE(data_provider()->GetTrackLocation(
127 artist
, album
, track_name
).empty()) << track_name
;
131 // Get the initial set of library entries, called by SetUp. If no entries
132 // are returned the xml file is not created.
133 virtual std::vector
<LibraryEntry
> SetUpLibrary() {
134 return std::vector
<LibraryEntry
>();
137 // Start the test. The data provider is refreshed before calling StartTest
138 // and the result of the refresh is passed in.
139 virtual void StartTest(bool parse_success
) = 0;
142 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
143 ImportedMediaGalleryRegistry
* imported_registry
=
144 ImportedMediaGalleryRegistry::GetInstance();
145 imported_registry
->itunes_data_provider_
.reset();
146 content::BrowserThread::PostTask(content::BrowserThread::UI
, FROM_HERE
,
151 void StartTestOnMediaTaskRunner() {
152 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
153 ImportedMediaGalleryRegistry
* imported_registry
=
154 ImportedMediaGalleryRegistry::GetInstance();
155 imported_registry
->itunes_data_provider_
.reset(
156 new TestITunesDataProvider(
158 base::Bind(&ITunesDataProviderTest::OnLibraryChanged
,
159 base::Unretained(this))));
160 data_provider()->RefreshData(base::Bind(&ITunesDataProviderTest::StartTest
,
161 base::Unretained(this)));
164 void OnLibraryChanged() {
165 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
166 if (!library_changed_callback_
.is_null()) {
167 library_changed_callback_
.Run();
168 library_changed_callback_
.Reset();
172 void WriteLibraryInternal(const std::vector
<LibraryEntry
>& entries
) {
175 std::string xml
= "<plist><dict><key>Tracks</key><dict>\n";
176 for (size_t i
= 0; i
< entries
.size(); ++i
) {
177 std::string separator
;
181 GURL
location("file://localhost" + separator
+
182 entries
[i
].location
.AsUTF8Unsafe());
183 std::string entry_string
= base::StringPrintf(
184 "<key>%" PRIuS
"</key><dict>\n"
185 " <key>Track ID</key><integer>%" PRIuS
"</integer>\n"
186 " <key>Location</key><string>%s</string>\n"
187 " <key>Artist</key><string>%s</string>\n"
188 " <key>Album</key><string>%s</string>\n"
190 i
+ 1, i
+ 1, location
.spec().c_str(), entries
[i
].artist
.c_str(),
191 entries
[i
].album
.c_str());
194 xml
+= "</dict></dict></plist>\n";
195 ASSERT_EQ(static_cast<int>(xml
.size()),
196 file_util::WriteFile(XmlFile(), xml
.c_str(), xml
.size()));
199 base::ScopedTempDir library_dir_
;
201 base::Closure library_changed_callback_
;
203 base::Closure quit_closure_
;
205 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderTest
);
208 class ITunesDataProviderBasicTest
: public ITunesDataProviderTest
{
210 ITunesDataProviderBasicTest() {}
211 virtual ~ITunesDataProviderBasicTest() {}
213 virtual std::vector
<LibraryEntry
> SetUpLibrary() OVERRIDE
{
214 base::FilePath track
= library_dir().AppendASCII("Track.mp3");
215 std::vector
<LibraryEntry
> entries
;
216 entries
.push_back(LibraryEntry("Artist", "Album", track
));
220 virtual void StartTest(bool parse_success
) OVERRIDE
{
221 EXPECT_TRUE(parse_success
);
224 EXPECT_TRUE(data_provider()->KnownArtist("Artist"));
225 EXPECT_FALSE(data_provider()->KnownArtist("Artist2"));
228 EXPECT_TRUE(data_provider()->KnownAlbum("Artist", "Album"));
229 EXPECT_FALSE(data_provider()->KnownAlbum("Artist", "Album2"));
230 EXPECT_FALSE(data_provider()->KnownAlbum("Artist2", "Album"));
233 ExpectTrackLocation("Artist", "Album", "Track.mp3");
234 ExpectNoTrack("Artist", "Album", "Track2.mp3");
235 ExpectNoTrack("Artist", "Album2", "Track.mp3");
236 ExpectNoTrack("Artist2", "Album", "Track.mp3");
239 std::set
<ITunesDataProvider::ArtistName
> artists
=
240 data_provider()->GetArtistNames();
241 ASSERT_EQ(1U, artists
.size());
242 EXPECT_EQ("Artist", *artists
.begin());
245 std::set
<ITunesDataProvider::AlbumName
> albums
=
246 data_provider()->GetAlbumNames("Artist");
247 ASSERT_EQ(1U, albums
.size());
248 EXPECT_EQ("Album", *albums
.begin());
250 albums
= data_provider()->GetAlbumNames("Artist2");
251 EXPECT_EQ(0U, albums
.size());
254 base::FilePath track
=
255 library_dir().AppendASCII("Track.mp3").NormalizePathSeparators();
256 ITunesDataProvider::Album album
=
257 data_provider()->GetAlbum("Artist", "Album");
258 ASSERT_EQ(1U, album
.size());
259 EXPECT_EQ(track
.BaseName().AsUTF8Unsafe(), album
.begin()->first
);
260 EXPECT_EQ(track
.value(),
261 album
.begin()->second
.NormalizePathSeparators().value());
263 album
= data_provider()->GetAlbum("Artist", "Album2");
264 EXPECT_EQ(0U, album
.size());
266 album
= data_provider()->GetAlbum("Artist2", "Album");
267 EXPECT_EQ(0U, album
.size());
273 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderBasicTest
);
276 class ITunesDataProviderRefreshTest
: public ITunesDataProviderTest
{
278 ITunesDataProviderRefreshTest() {}
279 virtual ~ITunesDataProviderRefreshTest() {}
281 virtual std::vector
<LibraryEntry
> SetUpLibrary() OVERRIDE
{
282 base::FilePath track
= library_dir().AppendASCII("Track.mp3");
283 std::vector
<LibraryEntry
> entries
;
284 entries
.push_back(LibraryEntry("Artist", "Album", track
));
288 virtual void StartTest(bool parse_success
) OVERRIDE
{
289 EXPECT_TRUE(parse_success
);
292 ExpectTrackLocation("Artist", "Album", "Track.mp3");
293 ExpectNoTrack("Artist2", "Album2", "Track2.mp3");
296 base::FilePath track2
= library_dir().AppendASCII("Track2.mp3");
297 std::vector
<LibraryEntry
> entries
;
298 entries
.push_back(LibraryEntry("Artist2", "Album2", track2
));
299 WriteLibrary(entries
,
300 base::Bind(&ITunesDataProviderRefreshTest::CheckAfterWrite
,
301 base::Unretained(this)));
304 void CheckAfterWrite() {
306 ExpectTrackLocation("Artist", "Album", "Track.mp3");
307 ExpectNoTrack("Artist2", "Album2", "Track2.mp3");
309 data_provider()->RefreshData(
310 base::Bind(&ITunesDataProviderRefreshTest::CheckRefresh
,
311 base::Unretained(this)));
314 void CheckRefresh(bool is_valid
) {
315 EXPECT_TRUE(is_valid
);
317 ExpectTrackLocation("Artist2", "Album2", "Track2.mp3");
318 ExpectNoTrack("Artist", "Album", "Track.mp3");
323 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderRefreshTest
);
326 class ITunesDataProviderInvalidTest
: public ITunesDataProviderTest
{
328 ITunesDataProviderInvalidTest() {}
329 virtual ~ITunesDataProviderInvalidTest() {}
331 virtual std::vector
<LibraryEntry
> SetUpLibrary() OVERRIDE
{
332 base::FilePath track
= library_dir().AppendASCII("Track.mp3");
333 std::vector
<LibraryEntry
> entries
;
334 entries
.push_back(LibraryEntry("Artist", "Album", track
));
338 virtual void StartTest(bool parse_success
) OVERRIDE
{
339 EXPECT_TRUE(parse_success
);
341 SetLibraryChangeCallback(
342 base::Bind(&ITunesDataProvider::RefreshData
,
343 base::Unretained(data_provider()),
344 base::Bind(&ITunesDataProviderInvalidTest::CheckInvalid
,
345 base::Unretained(this))));
346 ASSERT_EQ(1L, file_util::WriteFile(XmlFile(), " ", 1));
349 void CheckInvalid(bool is_valid
) {
350 EXPECT_FALSE(is_valid
);
355 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderInvalidTest
);
358 class ITunesDataProviderUniqueNameTest
: public ITunesDataProviderTest
{
360 ITunesDataProviderUniqueNameTest() {}
361 virtual ~ITunesDataProviderUniqueNameTest() {}
363 virtual std::vector
<LibraryEntry
> SetUpLibrary() OVERRIDE
{
364 base::FilePath track
= library_dir().AppendASCII("Track.mp3");
365 std::vector
<LibraryEntry
> entries
;
366 // Dupe album names should get uniquified with the track id, which in the
367 // test framework is the vector index.
368 entries
.push_back(LibraryEntry("Artist", "Album", track
));
369 entries
.push_back(LibraryEntry("Artist", "Album", track
));
370 entries
.push_back(LibraryEntry("Artist", "Album2", track
));
374 virtual void StartTest(bool parse_success
) OVERRIDE
{
375 EXPECT_TRUE(parse_success
);
377 base::FilePath track
=
378 library_dir().AppendASCII("Track.mp3").NormalizePathSeparators();
379 EXPECT_EQ(track
.value(),
380 data_provider()->GetTrackLocation(
382 "Track (1).mp3").NormalizePathSeparators().value());
383 EXPECT_EQ(track
.value(),
384 data_provider()->GetTrackLocation(
386 "Track (2).mp3").NormalizePathSeparators().value());
387 EXPECT_EQ(track
.value(),
388 data_provider()->GetTrackLocation(
390 "Track.mp3").NormalizePathSeparators().value());
396 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderUniqueNameTest
);
399 class ITunesDataProviderEscapeTest
: public ITunesDataProviderTest
{
400 // Albums and tracks that aren't the same, but become the same after
401 // replacing bad characters are not handled properly, but that case should
402 // never happen in practice.
404 ITunesDataProviderEscapeTest() {}
405 virtual ~ITunesDataProviderEscapeTest() {}
407 virtual std::vector
<LibraryEntry
> SetUpLibrary() OVERRIDE
{
408 base::FilePath track
= library_dir().AppendASCII("Track:1.mp3");
409 std::vector
<LibraryEntry
> entries
;
410 entries
.push_back(LibraryEntry("Artist:/name", "Album:name/", track
));
411 entries
.push_back(LibraryEntry("Artist/name", "Album:name", track
));
412 entries
.push_back(LibraryEntry("Artist/name", "Album:name", track
));
416 virtual void StartTest(bool parse_success
) OVERRIDE
{
417 EXPECT_TRUE(parse_success
);
419 base::FilePath track
=
420 library_dir().AppendASCII("Track:1.mp3").NormalizePathSeparators();
421 EXPECT_EQ(track
.value(),
422 data_provider()->GetTrackLocation(
423 "Artist__name", "Album_name_",
424 "Track_1.mp3").NormalizePathSeparators().value());
425 EXPECT_EQ(track
.value(),
426 data_provider()->GetTrackLocation(
427 "Artist_name", "Album_name",
428 "Track_1 (2).mp3").NormalizePathSeparators().value());
429 EXPECT_EQ(track
.value(),
430 data_provider()->GetTrackLocation(
431 "Artist_name", "Album_name",
432 "Track_1 (3).mp3").NormalizePathSeparators().value());
438 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderEscapeTest
);
441 IN_PROC_BROWSER_TEST_F(ITunesDataProviderBasicTest
, BasicTest
) {
445 IN_PROC_BROWSER_TEST_F(ITunesDataProviderRefreshTest
, RefreshTest
) {
449 IN_PROC_BROWSER_TEST_F(ITunesDataProviderInvalidTest
, InvalidTest
) {
453 IN_PROC_BROWSER_TEST_F(ITunesDataProviderUniqueNameTest
, UniqueNameTest
) {
457 IN_PROC_BROWSER_TEST_F(ITunesDataProviderEscapeTest
, EscapeTest
) {
461 } // namespace itunes