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/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/stl_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "chrome/browser/media_galleries/fileapi/iphoto_data_provider.h"
20 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
21 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
22 #include "chrome/test/base/in_process_browser_test.h"
23 #include "content/public/browser/browser_thread.h"
30 class TestIPhotoDataProvider : public IPhotoDataProvider {
32 TestIPhotoDataProvider(const base::FilePath& xml_library_path,
33 const base::Closure& callback)
34 : IPhotoDataProvider(xml_library_path),
37 ~TestIPhotoDataProvider() override {}
40 void OnLibraryChanged(const base::FilePath& path, bool error) override {
41 IPhotoDataProvider::OnLibraryChanged(path, error);
45 base::Closure callback_;
47 DISALLOW_COPY_AND_ASSIGN(TestIPhotoDataProvider);
50 class IPhotoDataProviderTest : public InProcessBrowserTest {
52 IPhotoDataProviderTest() {}
53 virtual ~IPhotoDataProviderTest() {}
56 virtual void SetUp() override {
57 ASSERT_TRUE(library_dir_.CreateUniqueTempDir());
58 WriteLibraryInternal();
59 // The ImportedMediaGalleryRegistry is created on which ever thread calls
60 // GetInstance() first. It shouldn't matter what thread creates, however
61 // in practice it is always created on the UI thread, so this calls
62 // GetInstance here to mirror those real conditions.
63 ImportedMediaGalleryRegistry::GetInstance();
64 InProcessBrowserTest::SetUp();
68 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
70 quit_closure_ = loop.QuitClosure();
71 MediaFileSystemBackend::MediaTaskRunner()->PostTask(
73 base::Bind(&IPhotoDataProviderTest::StartTestOnMediaTaskRunner,
74 base::Unretained(this)));
78 void WriteLibrary(const base::Closure& callback) {
79 SetLibraryChangeCallback(callback);
80 WriteLibraryInternal();
83 void SetLibraryChangeCallback(const base::Closure& callback) {
84 EXPECT_TRUE(library_changed_callback_.is_null());
85 library_changed_callback_ = callback;
88 IPhotoDataProvider* data_provider() const {
89 return ImportedMediaGalleryRegistry::IPhotoDataProvider();
92 const base::FilePath& library_dir() const {
93 return library_dir_.path();
96 base::FilePath XmlFile() const {
97 return library_dir_.path().AppendASCII("library.xml");
100 // Start the test. The data provider is refreshed before calling StartTest
101 // and the result of the refresh is passed in.
102 virtual void StartTest(bool parse_success) = 0;
105 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
106 ImportedMediaGalleryRegistry* imported_registry =
107 ImportedMediaGalleryRegistry::GetInstance();
108 imported_registry->iphoto_data_provider_.reset();
109 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
113 // Override to provide a full library string.
114 virtual std::string GetLibraryString() {
115 return "<plist><dict>\n</dict></plist>\n";
119 void StartTestOnMediaTaskRunner() {
120 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
121 ImportedMediaGalleryRegistry* imported_registry =
122 ImportedMediaGalleryRegistry::GetInstance();
123 imported_registry->iphoto_data_provider_.reset(
124 new TestIPhotoDataProvider(
126 base::Bind(&IPhotoDataProviderTest::OnLibraryChanged,
127 base::Unretained(this))));
128 data_provider()->RefreshData(base::Bind(&IPhotoDataProviderTest::StartTest,
129 base::Unretained(this)));
132 void OnLibraryChanged() {
133 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
134 if (!library_changed_callback_.is_null()) {
135 library_changed_callback_.Run();
136 library_changed_callback_.Reset();
140 void WriteLibraryInternal() {
141 std::string xml = GetLibraryString();
142 ASSERT_EQ(static_cast<int>(xml.size()),
143 base::WriteFile(XmlFile(), xml.c_str(), xml.size()));
146 base::ScopedTempDir library_dir_;
148 base::Closure library_changed_callback_;
150 base::Closure quit_closure_;
152 DISALLOW_COPY_AND_ASSIGN(IPhotoDataProviderTest);
155 class IPhotoDataProviderBasicTest : public IPhotoDataProviderTest {
157 IPhotoDataProviderBasicTest() {}
158 virtual ~IPhotoDataProviderBasicTest() {}
160 std::string GetLibraryString() override {
161 return "<plist><dict>\n"
162 "<key>List of Albums</key>\n"
165 " <key>AlbumId</key>"
166 " <integer>14</integer>"
167 " <key>AlbumName</key>"
168 " <string>Album1</string>"
169 " <key>KeyList</key>"
171 " <string>1</string>"
172 " <string>3</string>" // [3] and [4] are name dupes
173 " <string>4</string>"
177 " <key>AlbumId</key>"
178 " <integer>15</integer>"
179 " <key>AlbumName</key>"
180 " <string>Album2</string>"
181 " <key>KeyList</key>"
183 " <string>2</string>"
187 " <key>AlbumId</key>"
188 " <integer>16</integer>"
189 " <key>AlbumName</key>"
190 " <string>Album5</string>"
191 " <key>KeyList</key>"
193 " <string>5</string>" // A name dupe of [2], but in another album.
197 "<key>Master Image List</key>\n"
201 " <key>MediaType</key>"
202 " <string>Image</string>"
203 " <key>Caption</key>"
204 " <string>caption</string>"
206 " <string>guid1</string>"
207 " <key>ImagePath</key>"
208 " <string>/vol/path1.jpg</string>"
209 " <key>ThumbPath</key>"
210 " <string>/vol/thumb1.jpg</string>"
214 " <key>MediaType</key>"
215 " <string>Image</string>"
216 " <key>Caption</key>"
217 " <string>caption2</string>"
219 " <string>guid2</string>"
220 " <key>ImagePath</key>"
221 " <string>/vol/path2.jpg</string>"
222 " <key>ThumbPath</key>"
223 " <string>/vol/thumb2.jpg</string>"
227 " <key>MediaType</key>"
228 " <string>Image</string>"
229 " <key>Caption</key>"
230 " <string>caption3</string>"
232 " <string>guid3</string>"
233 " <key>ImagePath</key>"
234 " <string>/vol/path3.jpg</string>"
235 " <key>ThumbPath</key>"
236 " <string>/vol/thumb3.jpg</string>"
238 " <key>4</key>\n" // A name duplicate of [3] in another path.
240 " <key>MediaType</key>"
241 " <string>Image</string>"
242 " <key>Caption</key>"
243 " <string>caption</string>"
245 " <string>guid3</string>"
246 " <key>ImagePath</key>"
247 " <string>/vol/dupe/path3.jpg</string>"
248 " <key>ThumbPath</key>"
249 " <string>/vol/dupe/thumb3.jpg</string>"
251 " <key>5</key>\n" // A name duplicate of [2] in another path.
253 " <key>MediaType</key>"
254 " <string>Image</string>"
255 " <key>Caption</key>"
256 " <string>caption5</string>"
258 " <string>guid2</string>"
259 " <key>ImagePath</key>"
260 " <string>/vol/dupe/path2.jpg</string>"
261 " <key>ThumbPath</key>"
262 " <string>/vol/dupe/thumb2.jpg</string>"
263 " <key>OriginalPath</key>" \
264 " <string>/original/vol/another2.jpg</string>" \
270 void StartTest(bool parse_success) override {
271 EXPECT_TRUE(parse_success);
273 std::vector<std::string> names = data_provider()->GetAlbumNames();
274 EXPECT_EQ(3U, names.size());
275 EXPECT_EQ("Album1", names[0]);
277 EXPECT_EQ(FilePath("/vol/path1.jpg").value(),
278 data_provider()->GetPhotoLocationInAlbum(
279 "Album1", "path1.jpg").value());
280 EXPECT_EQ(FilePath("/vol/path3.jpg").value(),
281 data_provider()->GetPhotoLocationInAlbum(
282 "Album1", "path3.jpg").value());
283 EXPECT_EQ(FilePath("/vol/dupe/path3.jpg").value(),
284 data_provider()->GetPhotoLocationInAlbum(
285 "Album1", "path3(4).jpg").value());
286 EXPECT_EQ(FilePath().value(),
287 data_provider()->GetPhotoLocationInAlbum(
288 "Album1", "path5.jpg").value());
290 // path2.jpg is name-duped, but in different albums, and so should not
292 EXPECT_EQ(FilePath("/vol/dupe/path2.jpg").value(),
293 data_provider()->GetPhotoLocationInAlbum(
294 "Album5", "path2.jpg").value());
295 EXPECT_EQ(FilePath("/vol/path2.jpg").value(),
296 data_provider()->GetPhotoLocationInAlbum(
297 "Album2", "path2.jpg").value());
299 std::map<std::string, base::FilePath> photos =
300 data_provider()->GetAlbumContents("nonexistent");
301 EXPECT_EQ(0U, photos.size());
302 photos = data_provider()->GetAlbumContents("Album1");
303 EXPECT_EQ(3U, photos.size());
304 EXPECT_TRUE(ContainsKey(photos, "path1.jpg"));
305 EXPECT_FALSE(ContainsKey(photos, "path2.jpg"));
306 EXPECT_TRUE(ContainsKey(photos, "path3.jpg"));
307 EXPECT_TRUE(ContainsKey(photos, "path3(4).jpg"));
308 EXPECT_EQ(FilePath("/vol/path1.jpg").value(), photos["path1.jpg"].value());
309 EXPECT_EQ(FilePath("/vol/path3.jpg").value(),
310 photos["path3.jpg"].value());
311 EXPECT_EQ(FilePath("/vol/dupe/path3.jpg").value(),
312 photos["path3(4).jpg"].value());
314 photos = data_provider()->GetAlbumContents("Album2");
315 EXPECT_EQ(1U, photos.size());
316 EXPECT_TRUE(ContainsKey(photos, "path2.jpg"));
318 EXPECT_FALSE(data_provider()->HasOriginals("Album1"));
319 EXPECT_TRUE(data_provider()->HasOriginals("Album5"));
320 std::map<std::string, base::FilePath> originals =
321 data_provider()->GetOriginals("Album1");
322 EXPECT_EQ(0U, originals.size());
323 originals = data_provider()->GetOriginals("Album5");
324 EXPECT_EQ(1U, originals.size());
325 EXPECT_TRUE(ContainsKey(originals, "path2.jpg"));
326 EXPECT_FALSE(ContainsKey(originals, "path1.jpg"));
327 EXPECT_EQ(FilePath("/original/vol/another2.jpg").value(),
328 originals["path2.jpg"].value());
329 base::FilePath original_path =
330 data_provider()->GetOriginalPhotoLocation("Album5", "path2.jpg");
331 EXPECT_EQ(FilePath("/original/vol/another2.jpg").value(),
332 original_path.value());
338 DISALLOW_COPY_AND_ASSIGN(IPhotoDataProviderBasicTest);
341 class IPhotoDataProviderRefreshTest : public IPhotoDataProviderTest {
343 IPhotoDataProviderRefreshTest() {}
344 virtual ~IPhotoDataProviderRefreshTest() {}
346 std::string another_album;
348 std::string GetLibraryString() override {
349 return "<plist><dict>\n"
350 "<key>List of Albums</key>\n"
353 " <key>AlbumId</key>"
354 " <integer>14</integer>"
355 " <key>AlbumName</key>"
356 " <string>Album1</string>"
357 " <key>KeyList</key>"
359 " <string>1</string>"
364 "<key>Master Image List</key>\n"
368 " <key>MediaType</key>"
369 " <string>Image</string>"
370 " <key>Caption1</key>"
371 " <string>caption</string>"
373 " <string>guid1</string>"
374 " <key>ImagePath</key>"
375 " <string>/vol/path1.jpg</string>"
376 " <key>ThumbPath</key>"
377 " <string>/vol/thumb1.jpg</string>"
383 void StartTest(bool parse_success) override {
384 EXPECT_TRUE(parse_success);
386 EXPECT_EQ(FilePath("/vol/path1.jpg"),
387 data_provider()->GetPhotoLocationInAlbum("Album1", "path1.jpg"));
388 std::vector<std::string> names = data_provider()->GetAlbumNames();
389 EXPECT_EQ(1U, names.size());
390 EXPECT_EQ("Album1", names[0]);
394 " <key>AlbumId</key>"
395 " <integer>14</integer>"
396 " <key>AlbumName</key>"
397 " <string>Another Album</string>"
398 " <key>KeyList</key>"
400 " <string>1</string>"
404 WriteLibrary(base::Bind(&IPhotoDataProviderRefreshTest::CheckAfterWrite,
405 base::Unretained(this)));
408 void CheckAfterWrite() {
409 // No change -- data has not been parsed.
410 EXPECT_EQ(FilePath("/vol/path1.jpg"),
411 data_provider()->GetPhotoLocationInAlbum("Album1", "path1.jpg"));
412 std::vector<std::string> names = data_provider()->GetAlbumNames();
413 EXPECT_EQ(1U, names.size());
414 EXPECT_EQ("Album1", names[0]);
416 data_provider()->RefreshData(
417 base::Bind(&IPhotoDataProviderRefreshTest::CheckRefresh,
418 base::Unretained(this)));
421 void CheckRefresh(bool is_valid) {
422 EXPECT_TRUE(is_valid);
424 EXPECT_EQ(FilePath("/vol/path1.jpg"),
425 data_provider()->GetPhotoLocationInAlbum("Album1", "path1.jpg"));
426 std::vector<std::string> names = data_provider()->GetAlbumNames();
427 EXPECT_EQ(2U, names.size());
428 if (names.size() == 2U) {
429 EXPECT_EQ("Album1", names[0]);
430 EXPECT_EQ("Another Album", names[1]);
437 DISALLOW_COPY_AND_ASSIGN(IPhotoDataProviderRefreshTest);
440 class IPhotoDataProviderInvalidTest : public IPhotoDataProviderTest {
442 IPhotoDataProviderInvalidTest() {}
443 virtual ~IPhotoDataProviderInvalidTest() {}
445 void StartTest(bool parse_success) override {
446 EXPECT_TRUE(parse_success);
448 SetLibraryChangeCallback(
449 base::Bind(&IPhotoDataProvider::RefreshData,
450 base::Unretained(data_provider()),
451 base::Bind(&IPhotoDataProviderInvalidTest::CheckInvalid,
452 base::Unretained(this))));
453 EXPECT_EQ(1L, base::WriteFile(XmlFile(), " ", 1));
456 void CheckInvalid(bool is_valid) {
457 EXPECT_FALSE(is_valid);
462 DISALLOW_COPY_AND_ASSIGN(IPhotoDataProviderInvalidTest);
465 IN_PROC_BROWSER_TEST_F(IPhotoDataProviderBasicTest, BasicTest) {
469 IN_PROC_BROWSER_TEST_F(IPhotoDataProviderRefreshTest, RefreshTest) {
473 IN_PROC_BROWSER_TEST_F(IPhotoDataProviderInvalidTest, InvalidTest) {
477 } // namespace iphoto