Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / media_galleries / fileapi / itunes_data_provider_browsertest.cc
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.
4
5 #include <string>
6 #include <vector>
7
8 #include "base/bind.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.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"
23 #include "url/gurl.h"
24
25 namespace itunes {
26
27 namespace {
28
29 struct LibraryEntry {
30   LibraryEntry(const std::string& artist, const std::string& album,
31                const base::FilePath& location)
32       : artist(artist),
33         album(album),
34         location(location) {
35   }
36   std::string artist;
37   std::string album;
38   base::FilePath location;
39 };
40
41 // 'c' with combinding cedilla.
42 const char kDeNormalizedName[] = {
43     'c', static_cast<unsigned char>(0xCC), static_cast<unsigned char>(0xA7), 0};
44 // 'c' with cedilla.
45 const char kNormalizedName[] = {
46     static_cast<unsigned char>(0xC3), static_cast<unsigned char>(0xA7), 0};
47
48 }  // namespace
49
50 class TestITunesDataProvider : public ITunesDataProvider {
51  public:
52   TestITunesDataProvider(const base::FilePath& xml_library_path,
53                          const base::Closure& callback)
54       : ITunesDataProvider(xml_library_path),
55         callback_(callback) {
56   }
57   virtual ~TestITunesDataProvider() {}
58
59  private:
60   virtual void OnLibraryChanged(const base::FilePath& path,
61                                 bool error) OVERRIDE {
62     ITunesDataProvider::OnLibraryChanged(path, error);
63     callback_.Run();
64   }
65
66   base::Closure callback_;
67
68   DISALLOW_COPY_AND_ASSIGN(TestITunesDataProvider);
69 };
70
71 class ITunesDataProviderTest : public InProcessBrowserTest {
72  public:
73   ITunesDataProviderTest() {}
74   virtual ~ITunesDataProviderTest() {}
75
76  protected:
77   virtual void SetUp() OVERRIDE {
78     ASSERT_TRUE(library_dir_.CreateUniqueTempDir());
79     WriteLibraryInternal(SetUpLibrary());
80     // The ImportedMediaGalleryRegistry is created on which ever thread calls
81     // GetInstance() first.  It shouldn't matter what thread creates, however
82     // in practice it is always created on the UI thread, so this calls
83     // GetInstance here to mirror those real conditions.
84     ImportedMediaGalleryRegistry::GetInstance();
85     InProcessBrowserTest::SetUp();
86   }
87
88   void RunTest() {
89     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
90     base::RunLoop loop;
91     quit_closure_ = loop.QuitClosure();
92     MediaFileSystemBackend::MediaTaskRunner()->PostTask(
93         FROM_HERE,
94         base::Bind(&ITunesDataProviderTest::StartTestOnMediaTaskRunner,
95                    base::Unretained(this)));
96     loop.Run();
97   }
98
99   void WriteLibrary(const std::vector<LibraryEntry>& entries,
100                     const base::Closure& callback) {
101     SetLibraryChangeCallback(callback);
102     WriteLibraryInternal(entries);
103   }
104
105   void SetLibraryChangeCallback(const base::Closure& callback) {
106     EXPECT_TRUE(library_changed_callback_.is_null());
107     library_changed_callback_ = callback;
108   }
109
110   ITunesDataProvider* data_provider() const {
111     return ImportedMediaGalleryRegistry::ITunesDataProvider();
112   }
113
114   const base::FilePath& library_dir() const {
115     return library_dir_.path();
116   }
117
118   base::FilePath XmlFile() const {
119     return library_dir_.path().AppendASCII("library.xml");
120   }
121
122   void ExpectTrackLocation(const std::string& artist, const std::string& album,
123                            const std::string& track_name) {
124     base::FilePath track =
125         library_dir().AppendASCII(track_name).NormalizePathSeparators();
126     EXPECT_EQ(track.value(),
127               data_provider()->GetTrackLocation(
128                   artist, album, track_name).NormalizePathSeparators().value());
129   }
130
131   void ExpectNoTrack(const std::string& artist, const std::string& album,
132                      const std::string& track_name) {
133     EXPECT_TRUE(data_provider()->GetTrackLocation(
134           artist, album, track_name).empty()) << track_name;
135   }
136
137
138   // Get the initial set of library entries, called by SetUp.  If no entries
139   // are returned the xml file is not created.
140   virtual std::vector<LibraryEntry> SetUpLibrary() {
141     return std::vector<LibraryEntry>();
142   }
143
144   // Start the test. The data provider is refreshed before calling StartTest
145   // and the result of the refresh is passed in.
146   virtual void StartTest(bool parse_success) = 0;
147
148   void TestDone() {
149     DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
150     ImportedMediaGalleryRegistry* imported_registry =
151         ImportedMediaGalleryRegistry::GetInstance();
152     imported_registry->itunes_data_provider_.reset();
153     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
154                                      quit_closure_);
155   }
156
157  private:
158   void StartTestOnMediaTaskRunner() {
159     DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
160     ImportedMediaGalleryRegistry* imported_registry =
161         ImportedMediaGalleryRegistry::GetInstance();
162     imported_registry->itunes_data_provider_.reset(
163         new TestITunesDataProvider(
164             XmlFile(),
165             base::Bind(&ITunesDataProviderTest::OnLibraryChanged,
166                        base::Unretained(this))));
167     data_provider()->RefreshData(base::Bind(&ITunesDataProviderTest::StartTest,
168                                             base::Unretained(this)));
169   };
170
171   void OnLibraryChanged() {
172     DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
173     if (!library_changed_callback_.is_null()) {
174       library_changed_callback_.Run();
175       library_changed_callback_.Reset();
176     }
177   }
178
179   void WriteLibraryInternal(const std::vector<LibraryEntry>& entries) {
180     if (!entries.size())
181       return;
182     std::string xml = "<plist><dict><key>Tracks</key><dict>\n";
183     for (size_t i = 0; i < entries.size(); ++i) {
184       std::string separator;
185 #if defined(OS_WIN)
186       separator = "/";
187 #endif
188       GURL location("file://localhost" + separator +
189                     entries[i].location.AsUTF8Unsafe());
190       std::string entry_string = base::StringPrintf(
191           "<key>%" PRIuS "</key><dict>\n"
192           "  <key>Track ID</key><integer>%" PRIuS "</integer>\n"
193           "  <key>Location</key><string>%s</string>\n"
194           "  <key>Artist</key><string>%s</string>\n"
195           "  <key>Album</key><string>%s</string>\n"
196           "</dict>\n",
197           i + 1, i + 1, location.spec().c_str(), entries[i].artist.c_str(),
198           entries[i].album.c_str());
199       xml += entry_string;
200     }
201     xml += "</dict></dict></plist>\n";
202     ASSERT_EQ(static_cast<int>(xml.size()),
203               base::WriteFile(XmlFile(), xml.c_str(), xml.size()));
204   }
205
206   base::ScopedTempDir library_dir_;
207
208   base::Closure library_changed_callback_;
209
210   base::Closure quit_closure_;
211
212   DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderTest);
213 };
214
215 class ITunesDataProviderBasicTest : public ITunesDataProviderTest {
216  public:
217   ITunesDataProviderBasicTest() {}
218   virtual ~ITunesDataProviderBasicTest() {}
219
220   virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
221     base::FilePath track = library_dir().AppendASCII("Track.mp3");
222     std::vector<LibraryEntry> entries;
223     entries.push_back(LibraryEntry("Artist", "Album", track));
224     return entries;
225   }
226
227   virtual void StartTest(bool parse_success) OVERRIDE {
228     EXPECT_TRUE(parse_success);
229
230     // KnownArtist
231     EXPECT_TRUE(data_provider()->KnownArtist("Artist"));
232     EXPECT_FALSE(data_provider()->KnownArtist("Artist2"));
233
234     // KnownAlbum
235     EXPECT_TRUE(data_provider()->KnownAlbum("Artist", "Album"));
236     EXPECT_FALSE(data_provider()->KnownAlbum("Artist", "Album2"));
237     EXPECT_FALSE(data_provider()->KnownAlbum("Artist2", "Album"));
238
239     // GetTrackLocation
240     ExpectTrackLocation("Artist", "Album", "Track.mp3");
241     ExpectNoTrack("Artist", "Album", "Track2.mp3");
242     ExpectNoTrack("Artist", "Album2", "Track.mp3");
243     ExpectNoTrack("Artist2", "Album", "Track.mp3");
244
245     // GetArtistNames
246     std::set<ITunesDataProvider::ArtistName> artists =
247       data_provider()->GetArtistNames();
248     ASSERT_EQ(1U, artists.size());
249     EXPECT_EQ("Artist", *artists.begin());
250
251     // GetAlbumNames
252     std::set<ITunesDataProvider::AlbumName> albums =
253         data_provider()->GetAlbumNames("Artist");
254     ASSERT_EQ(1U, albums.size());
255     EXPECT_EQ("Album", *albums.begin());
256
257     albums = data_provider()->GetAlbumNames("Artist2");
258     EXPECT_EQ(0U, albums.size());
259
260     // GetAlbum
261     base::FilePath track =
262         library_dir().AppendASCII("Track.mp3").NormalizePathSeparators();
263     ITunesDataProvider::Album album =
264         data_provider()->GetAlbum("Artist", "Album");
265     ASSERT_EQ(1U, album.size());
266     EXPECT_EQ(track.BaseName().AsUTF8Unsafe(), album.begin()->first);
267     EXPECT_EQ(track.value(),
268               album.begin()->second.NormalizePathSeparators().value());
269
270     album = data_provider()->GetAlbum("Artist", "Album2");
271     EXPECT_EQ(0U, album.size());
272
273     album = data_provider()->GetAlbum("Artist2", "Album");
274     EXPECT_EQ(0U, album.size());
275
276     TestDone();
277   }
278
279  private:
280   DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderBasicTest);
281 };
282
283 class ITunesDataProviderRefreshTest : public ITunesDataProviderTest {
284  public:
285   ITunesDataProviderRefreshTest() {}
286   virtual ~ITunesDataProviderRefreshTest() {}
287
288   virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
289     base::FilePath track = library_dir().AppendASCII("Track.mp3");
290     std::vector<LibraryEntry> entries;
291     entries.push_back(LibraryEntry("Artist", "Album", track));
292     return entries;
293   }
294
295   virtual void StartTest(bool parse_success) OVERRIDE {
296     EXPECT_TRUE(parse_success);
297
298     // Initial contents.
299     ExpectTrackLocation("Artist", "Album", "Track.mp3");
300     ExpectNoTrack("Artist2", "Album2", "Track2.mp3");
301
302     // New file.
303     base::FilePath track2 = library_dir().AppendASCII("Track2.mp3");
304     std::vector<LibraryEntry> entries;
305     entries.push_back(LibraryEntry("Artist2", "Album2", track2));
306     WriteLibrary(entries,
307                  base::Bind(&ITunesDataProviderRefreshTest::CheckAfterWrite,
308                             base::Unretained(this)));
309   }
310
311   void CheckAfterWrite() {
312     // Content the same.
313     ExpectTrackLocation("Artist", "Album", "Track.mp3");
314     ExpectNoTrack("Artist2", "Album2", "Track2.mp3");
315
316     data_provider()->RefreshData(
317         base::Bind(&ITunesDataProviderRefreshTest::CheckRefresh,
318                    base::Unretained(this)));
319   }
320
321   void CheckRefresh(bool is_valid) {
322     EXPECT_TRUE(is_valid);
323
324     ExpectTrackLocation("Artist2", "Album2", "Track2.mp3");
325     ExpectNoTrack("Artist", "Album", "Track.mp3");
326     TestDone();
327   }
328
329  private:
330   DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderRefreshTest);
331 };
332
333 class ITunesDataProviderInvalidTest : public ITunesDataProviderTest {
334  public:
335   ITunesDataProviderInvalidTest() {}
336   virtual ~ITunesDataProviderInvalidTest() {}
337
338   virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
339     base::FilePath track = library_dir().AppendASCII("Track.mp3");
340     std::vector<LibraryEntry> entries;
341     entries.push_back(LibraryEntry("Artist", "Album", track));
342     return entries;
343   }
344
345   virtual void StartTest(bool parse_success) OVERRIDE {
346     EXPECT_TRUE(parse_success);
347
348     SetLibraryChangeCallback(
349         base::Bind(&ITunesDataProvider::RefreshData,
350                    base::Unretained(data_provider()),
351                    base::Bind(&ITunesDataProviderInvalidTest::CheckInvalid,
352                               base::Unretained(this))));
353     ASSERT_EQ(1L, base::WriteFile(XmlFile(), " ", 1));
354   }
355
356   void CheckInvalid(bool is_valid) {
357     EXPECT_FALSE(is_valid);
358     TestDone();
359   }
360
361  private:
362   DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderInvalidTest);
363 };
364
365 class ITunesDataProviderUniqueNameTest : public ITunesDataProviderTest {
366  public:
367   ITunesDataProviderUniqueNameTest() {}
368   virtual ~ITunesDataProviderUniqueNameTest() {}
369
370   virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
371     base::FilePath track = library_dir().AppendASCII("Track.mp3");
372     std::vector<LibraryEntry> entries;
373     // Dupe album names should get uniquified with the track id, which in the
374     // test framework is the vector index.
375     entries.push_back(LibraryEntry("Artist", "Album", track));
376     entries.push_back(LibraryEntry("Artist", "Album", track));
377     entries.push_back(LibraryEntry("Artist", "Album2", track));
378     return entries;
379   }
380
381   virtual void StartTest(bool parse_success) OVERRIDE {
382     EXPECT_TRUE(parse_success);
383
384     base::FilePath track =
385         library_dir().AppendASCII("Track.mp3").NormalizePathSeparators();
386     EXPECT_EQ(track.value(),
387               data_provider()->GetTrackLocation(
388                   "Artist", "Album",
389                   "Track (1).mp3").NormalizePathSeparators().value());
390     EXPECT_EQ(track.value(),
391               data_provider()->GetTrackLocation(
392                   "Artist", "Album",
393                   "Track (2).mp3").NormalizePathSeparators().value());
394     EXPECT_EQ(track.value(),
395               data_provider()->GetTrackLocation(
396                   "Artist", "Album2",
397                   "Track.mp3").NormalizePathSeparators().value());
398
399     TestDone();
400   }
401
402  private:
403   DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderUniqueNameTest);
404 };
405
406 class ITunesDataProviderEscapeTest : public ITunesDataProviderTest {
407  // Albums and tracks that aren't the same, but become the same after
408  // replacing bad characters are not handled properly, but that case should
409  // never happen in practice.
410  public:
411   ITunesDataProviderEscapeTest() {}
412   virtual ~ITunesDataProviderEscapeTest() {}
413
414   virtual std::vector<LibraryEntry> SetUpLibrary() OVERRIDE {
415     base::FilePath track = library_dir().AppendASCII("Track:1.mp3");
416     std::vector<LibraryEntry> entries;
417     entries.push_back(LibraryEntry("Artist:/name", "Album:name/", track));
418     entries.push_back(LibraryEntry("Artist/name", "Album:name", track));
419     entries.push_back(LibraryEntry("Artist/name", "Album:name", track));
420     entries.push_back(LibraryEntry(kDeNormalizedName, kNormalizedName, track));
421     return entries;
422   }
423
424   virtual void StartTest(bool parse_success) OVERRIDE {
425     EXPECT_TRUE(parse_success);
426
427     base::FilePath track =
428         library_dir().AppendASCII("Track:1.mp3").NormalizePathSeparators();
429     EXPECT_EQ(track.value(),
430               data_provider()->GetTrackLocation(
431                   "Artist__name", "Album_name_",
432                   "Track_1.mp3").NormalizePathSeparators().value());
433     EXPECT_EQ(track.value(),
434               data_provider()->GetTrackLocation(
435                   "Artist_name", "Album_name",
436                   "Track_1 (2).mp3").NormalizePathSeparators().value());
437     EXPECT_EQ(track.value(),
438               data_provider()->GetTrackLocation(
439                   "Artist_name", "Album_name",
440                   "Track_1 (3).mp3").NormalizePathSeparators().value());
441     EXPECT_EQ(track.value(),
442               data_provider()->GetTrackLocation(
443                   kNormalizedName, kNormalizedName,
444                   "Track_1.mp3").NormalizePathSeparators().value());
445
446     TestDone();
447   }
448
449  private:
450   DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderEscapeTest);
451 };
452
453 IN_PROC_BROWSER_TEST_F(ITunesDataProviderBasicTest, BasicTest) {
454   RunTest();
455 }
456
457 IN_PROC_BROWSER_TEST_F(ITunesDataProviderRefreshTest, RefreshTest) {
458   RunTest();
459 }
460
461 IN_PROC_BROWSER_TEST_F(ITunesDataProviderInvalidTest, InvalidTest) {
462   RunTest();
463 }
464
465 IN_PROC_BROWSER_TEST_F(ITunesDataProviderUniqueNameTest, UniqueNameTest) {
466   RunTest();
467 }
468
469 IN_PROC_BROWSER_TEST_F(ITunesDataProviderEscapeTest, EscapeTest) {
470   RunTest();
471 }
472
473 }  // namespace itunes