Home | History | Annotate | Download | only in media_galleries
      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 "base/logging.h"
      6 #include "chrome/common/media_galleries/iphoto_library.h"
      7 #include "chrome/utility/media_galleries/iphoto_library_parser.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 
     10 #define SIMPLE_HEADER()                          \
     11     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \
     12     "<plist version=\"1.0\">"                    \
     13     "  <dict>"                                   \
     14     "    <key>Archive Path</key>"                \
     15     "    <string>/Users/username/px</string>"
     16 
     17 #define ALBUMS_HEADER()             \
     18     "    <key>List of Albums</key>" \
     19     "    <array>"
     20 
     21 #define ALBUMS_FOOTER() \
     22     "    </array>"
     23 
     24 #define SIMPLE_ALBUM(id, name, photo1, photo2)         \
     25     "    <dict>"                                       \
     26     "      <key>AlbumId</key>"                         \
     27     "      <integer>" #id "</integer>"                 \
     28     "      <key>AlbumName</key>"                       \
     29     "      <string>" name "</string>"                  \
     30     "      <key>KeyList</key>"                         \
     31     "      <array>"                                    \
     32     "      <string>" #photo1 "</string>"               \
     33     "      <string>" #photo2 "</string>"               \
     34     "      </array>"                                   \
     35     "    </dict>"
     36 
     37 #define IMAGE_LIST_HEADER()           \
     38     "   <key>Master Image List</key>" \
     39     "   <dict>"
     40 
     41 #define IMAGE_LIST_FOOTER() \
     42     "   </dict>"
     43 
     44 #define SIMPLE_PHOTO(id, guid, path, caption) \
     45     "  <key>" #id "</key>"                    \
     46     "  <dict>"                                \
     47     "    <key>MediaType</key>"                \
     48     "    <string>Image</string>"              \
     49     "    <key>Caption</key>"                  \
     50     "    <string>" caption "</string>"        \
     51     "    <key>GUID</key>"                     \
     52     "    <string>" #guid "</string>"          \
     53     "    <key>ModDateAsTimerInterval</key>"   \
     54     "    <string>386221543.0000</string>"     \
     55     "    <key>DateAsTimerInterval</key>"      \
     56     "    <string>386221543.0000</string>"     \
     57     "    <key>DateAsTimerIntervalGMT</key>"   \
     58     "    <string>385123456.00</string>"       \
     59     "    <key>ImagePath</key>"                \
     60     "    <string>" path "</string>"           \
     61     "    <key>OriginalPath</key>"             \
     62     "    <string>/original" path "</string>"  \
     63     "    <key>ThumbPath</key>"                \
     64     "    <string>" path "</string>"           \
     65     "  </dict>"
     66 
     67 #define SIMPLE_FOOTER()  \
     68     "  </dict>"          \
     69     "</plist>"
     70 
     71  // Mismatched key/string tag at ImagePath.
     72 #define MALFORMED_PHOTO1(id, guid, path, caption) \
     73     "  <key>" #id "</key>"             \
     74     "  <dict>"                         \
     75     "    <key>MediaType</key>"         \
     76     "    <string>Image</string>"       \
     77     "    <key>Caption<key>"            \
     78     "    <string>" caption "</string>" \
     79     "    <key>GUID</key>"              \
     80     "    <string>" #guid "</string>"   \
     81     "    <key>ImagePath</string>"      \
     82     "    <string>" path "</string>"    \
     83     "    <key>ThumbPath</key>"         \
     84     "    <string>" path "</string>"    \
     85     "  </dict>"
     86 
     87 // Missing "<" delimiter at ImagePath.
     88 #define MALFORMED_PHOTO2(id, guid, path, caption) \
     89     "  <key>" #id "</key>"             \
     90     "  <dict>"                         \
     91     "    <key>MediaType</key>"         \
     92     "    <string>Image</string>"       \
     93     "    <key>Caption<key>"            \
     94     "    <string>" caption "</string>" \
     95     "    <key>GUID</key>"              \
     96     "    <string>" #guid "</string>"   \
     97     "    <key>ImagePath/key>"          \
     98     "    <string>" path "</string>"    \
     99     "    <key>ThumbPath</key>"         \
    100     "    <string>" path "</string>"    \
    101     "  </dict>"
    102 
    103 namespace iphoto {
    104 
    105 namespace {
    106 
    107 void ComparePhoto(const parser::Photo& a, const parser::Photo& b) {
    108   EXPECT_EQ(a.id, b.id);
    109   EXPECT_EQ(a.location.value(), b.location.value());
    110   EXPECT_EQ(a.original_location.value(), b.original_location.value());
    111 }
    112 
    113 void CompareAlbum(const parser::Album& a, const parser::Album& b) {
    114   EXPECT_EQ(a.size(), b.size());
    115 
    116   parser::Album::const_iterator a_it;
    117   parser::Album::const_iterator b_it;
    118   for (a_it = a.begin(), b_it = b.begin();
    119        a_it != a.end() && b_it != b.end();
    120        ++a_it, ++b_it) {
    121     EXPECT_EQ(*a_it, *b_it);
    122   }
    123 }
    124 
    125 void CompareAlbums(const parser::Albums& a, const parser::Albums& b) {
    126   EXPECT_EQ(a.size(), b.size());
    127 
    128   parser::Albums::const_iterator a_it;
    129   parser::Albums::const_iterator b_it;
    130   for (a_it = a.begin(), b_it = b.begin();
    131        a_it != a.end() && b_it != b.end();
    132        ++a_it, ++b_it) {
    133     EXPECT_EQ(a_it->first, b_it->first);
    134     CompareAlbum(a_it->second, b_it->second);
    135   }
    136 }
    137 
    138 void CompareLibrary(const parser::Library& a, const parser::Library& b) {
    139   CompareAlbums(a.albums, b.albums);
    140 
    141   std::set<parser::Photo>::const_iterator a_it;
    142   std::set<parser::Photo>::const_iterator b_it;
    143   for (a_it = a.all_photos.begin(), b_it = b.all_photos.begin();
    144        a_it != a.all_photos.end() && b_it != b.all_photos.end();
    145        ++a_it, ++b_it) {
    146     ComparePhoto(*a_it, *b_it);
    147   }
    148 }
    149 
    150 class IPhotoLibraryParserTest : public testing::Test {
    151  public:
    152   IPhotoLibraryParserTest() {}
    153 
    154   void TestParser(bool expected_result, const std::string& xml) {
    155     IPhotoLibraryParser parser;
    156 
    157     EXPECT_EQ(expected_result, parser.Parse(xml));
    158     if (!expected_result)
    159       return;
    160 
    161     CompareLibrary(expected_library_, parser.library());
    162   }
    163 
    164   void AddExpectedPhoto(uint32 id,
    165                         const std::string& location,
    166                         const std::string& album) {
    167     parser::Photo photo(id, base::FilePath::FromUTF8Unsafe(location),
    168                         base::FilePath::FromUTF8Unsafe("/original" + location));
    169     if (!album.empty())
    170       expected_library_.albums[album].insert(id);
    171     expected_library_.all_photos.insert(photo);
    172   }
    173 
    174  private:
    175   parser::Library expected_library_;
    176 
    177   DISALLOW_COPY_AND_ASSIGN(IPhotoLibraryParserTest);
    178 };
    179 
    180 TEST_F(IPhotoLibraryParserTest, EmptyLibrary) {
    181   TestParser(false, "");
    182 }
    183 
    184 TEST_F(IPhotoLibraryParserTest, MinimalXML) {
    185   AddExpectedPhoto(1, "/dir/Photo With Space.jpg", "");
    186   TestParser(
    187       true,
    188       SIMPLE_HEADER()
    189       IMAGE_LIST_HEADER()
    190       SIMPLE_PHOTO(1, 1, "/dir/Photo With Space.jpg", "Photo 1")
    191       IMAGE_LIST_FOOTER()
    192       SIMPLE_FOOTER());
    193 }
    194 
    195 TEST_F(IPhotoLibraryParserTest, MultiplePhotos) {
    196   AddExpectedPhoto(1, "/dir/SongA1.jpg", "");
    197   AddExpectedPhoto(2, "/dir/SongA2.jpg", "");
    198   AddExpectedPhoto(3, "/dir/SongA3.jpg", "");
    199   AddExpectedPhoto(4, "/dir/SongB1.jpg", "");
    200   AddExpectedPhoto(5, "/dir/SongB2.jpg", "");
    201   AddExpectedPhoto(6, "/dir2/SongB1.jpg", "");
    202   AddExpectedPhoto(7, "/dir2/SongB2.jpg", "");
    203   TestParser(
    204       true,
    205       SIMPLE_HEADER()
    206       IMAGE_LIST_HEADER()
    207       SIMPLE_PHOTO(1, 1, "/dir/SongA1.jpg", "Photo 1")
    208       SIMPLE_PHOTO(2, 2, "/dir/SongA2.jpg", "Photo 2")
    209       SIMPLE_PHOTO(3, 3, "/dir/SongA3.jpg", "Photo 3")
    210       SIMPLE_PHOTO(4, 4, "/dir/SongB1.jpg", "Photo 4")
    211       SIMPLE_PHOTO(5, 5, "/dir/SongB2.jpg", "Photo 5")
    212       SIMPLE_PHOTO(6, 6, "/dir2/SongB1.jpg", "Photo 6")
    213       SIMPLE_PHOTO(7, 7, "/dir2/SongB2.jpg", "Photo 7")
    214       IMAGE_LIST_FOOTER()
    215       SIMPLE_FOOTER());
    216 }
    217 
    218 TEST_F(IPhotoLibraryParserTest, Albums) {
    219   AddExpectedPhoto(1, "/dir/PhotoA1.jpg", "Album 1");
    220   AddExpectedPhoto(2, "/dir/PhotoA2.jpg", "Album 1");
    221   AddExpectedPhoto(3, "/dir/PhotoA3.jpg", "Album 2");
    222   AddExpectedPhoto(4, "/dir/PhotoB1.jpg", "Album 2");
    223   AddExpectedPhoto(5, "/dir/PhotoB2.jpg", "Album 3");
    224   AddExpectedPhoto(6, "/dir2/PhotoB1.jpg", "Album 3");
    225   AddExpectedPhoto(7, "/dir2/PhotoB2.jpg", "");
    226   TestParser(
    227       true,
    228       SIMPLE_HEADER()
    229       ALBUMS_HEADER()
    230       SIMPLE_ALBUM(10, "Album 1", 1, 2)
    231       SIMPLE_ALBUM(11, "Album 2", 3, 4)
    232       SIMPLE_ALBUM(11, "Album/3", 5, 6)
    233       ALBUMS_FOOTER()
    234       IMAGE_LIST_HEADER()
    235       SIMPLE_PHOTO(1, 1, "/dir/PhotoA1.jpg", "Photo 1")
    236       SIMPLE_PHOTO(2, 2, "/dir/PhotoA2.jpg", "Photo 2")
    237       SIMPLE_PHOTO(3, 3, "/dir/PhotoA3.jpg", "Photo 3")
    238       SIMPLE_PHOTO(4, 4, "/dir/PhotoB1.jpg", "Photo 4")
    239       SIMPLE_PHOTO(5, 5, "/dir/PhotoB2.jpg", "Photo 5")
    240       SIMPLE_PHOTO(6, 6, "/dir2/PhotoB1.jpg", "Photo 6")
    241       SIMPLE_PHOTO(7, 7, "/dir2/PhotoB2.jpg", "Photo 7")
    242       IMAGE_LIST_FOOTER()
    243       SIMPLE_FOOTER());
    244 }
    245 
    246 TEST_F(IPhotoLibraryParserTest, MalformedStructure) {
    247   TestParser(
    248       false,
    249       SIMPLE_HEADER()
    250       ALBUMS_HEADER()
    251       ALBUMS_HEADER()
    252       ALBUMS_FOOTER()
    253       SIMPLE_FOOTER());
    254 
    255   TestParser(
    256       false,
    257       SIMPLE_HEADER()
    258       ALBUMS_HEADER()
    259       ALBUMS_FOOTER()
    260       IMAGE_LIST_HEADER()
    261       IMAGE_LIST_HEADER()
    262       SIMPLE_PHOTO(1, 1, "/bad.jpg", "p1")
    263       IMAGE_LIST_FOOTER()
    264       IMAGE_LIST_FOOTER()
    265       SIMPLE_FOOTER());
    266 
    267   TestParser(
    268       false,
    269       SIMPLE_HEADER()
    270       ALBUMS_HEADER()
    271       ALBUMS_FOOTER()
    272       IMAGE_LIST_HEADER()
    273       ALBUMS_HEADER()
    274       SIMPLE_PHOTO(1, 1, "/bad.jpg", "p1")
    275       IMAGE_LIST_FOOTER()
    276       SIMPLE_FOOTER());
    277 }
    278 
    279 TEST_F(IPhotoLibraryParserTest, MalformedSyntax) {
    280   TestParser(
    281       false,
    282       SIMPLE_HEADER()
    283       ALBUMS_HEADER()
    284       ALBUMS_FOOTER()
    285       IMAGE_LIST_HEADER()
    286       MALFORMED_PHOTO1(1, 1, "/bad.jpg", "p1")
    287       IMAGE_LIST_FOOTER()
    288       SIMPLE_FOOTER());
    289 
    290   TestParser(
    291       false,
    292       SIMPLE_HEADER()
    293       ALBUMS_HEADER()
    294       ALBUMS_FOOTER()
    295       IMAGE_LIST_HEADER()
    296       MALFORMED_PHOTO2(1, 1, "/bad.jpg", "p1")
    297       IMAGE_LIST_FOOTER()
    298       SIMPLE_FOOTER());
    299 }
    300 
    301 TEST_F(IPhotoLibraryParserTest, DuplicateAlbumNames) {
    302   AddExpectedPhoto(1, "/dir/PhotoA1.jpg", "Album 1");
    303   AddExpectedPhoto(2, "/dir/PhotoA2.jpg", "Album 1");
    304   AddExpectedPhoto(3, "/dir/PhotoA3.jpg", "Album 1(11)");
    305   AddExpectedPhoto(4, "/dir/PhotoB1.jpg", "Album 1(11)");
    306   TestParser(
    307       true,
    308       SIMPLE_HEADER()
    309       ALBUMS_HEADER()
    310       SIMPLE_ALBUM(10, "Album 1", 1, 2)
    311       SIMPLE_ALBUM(11, "Album 1", 3, 4)
    312       ALBUMS_FOOTER()
    313       IMAGE_LIST_HEADER()
    314       SIMPLE_PHOTO(1, 1, "/dir/PhotoA1.jpg", "Photo 1")
    315       SIMPLE_PHOTO(2, 2, "/dir/PhotoA2.jpg", "Photo 2")
    316       SIMPLE_PHOTO(3, 3, "/dir/PhotoA3.jpg", "Photo 3")
    317       SIMPLE_PHOTO(4, 4, "/dir/PhotoB1.jpg", "Photo 4")
    318       IMAGE_LIST_FOOTER()
    319       SIMPLE_FOOTER());
    320 }
    321 
    322 }  // namespace
    323 
    324 }  // namespace iphoto
    325