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