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