Home | History | Annotate | Download | only in protocol
      1 // Copyright (c) 2012 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 // Keep this file in sync with the .proto files in this directory.
      6 
      7 #include "sync/protocol/proto_value_conversions.h"
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/time/time.h"
     12 #include "base/values.h"
     13 #include "sync/internal_api/public/base/model_type.h"
     14 #include "sync/protocol/app_notification_specifics.pb.h"
     15 #include "sync/protocol/app_setting_specifics.pb.h"
     16 #include "sync/protocol/app_specifics.pb.h"
     17 #include "sync/protocol/autofill_specifics.pb.h"
     18 #include "sync/protocol/bookmark_specifics.pb.h"
     19 #include "sync/protocol/device_info_specifics.pb.h"
     20 #include "sync/protocol/encryption.pb.h"
     21 #include "sync/protocol/experiments_specifics.pb.h"
     22 #include "sync/protocol/extension_setting_specifics.pb.h"
     23 #include "sync/protocol/extension_specifics.pb.h"
     24 #include "sync/protocol/favicon_image_specifics.pb.h"
     25 #include "sync/protocol/favicon_tracking_specifics.pb.h"
     26 #include "sync/protocol/managed_user_setting_specifics.pb.h"
     27 #include "sync/protocol/nigori_specifics.pb.h"
     28 #include "sync/protocol/password_specifics.pb.h"
     29 #include "sync/protocol/preference_specifics.pb.h"
     30 #include "sync/protocol/priority_preference_specifics.pb.h"
     31 #include "sync/protocol/search_engine_specifics.pb.h"
     32 #include "sync/protocol/session_specifics.pb.h"
     33 #include "sync/protocol/sync.pb.h"
     34 #include "sync/protocol/theme_specifics.pb.h"
     35 #include "sync/protocol/typed_url_specifics.pb.h"
     36 #include "testing/gtest/include/gtest/gtest.h"
     37 
     38 namespace syncer {
     39 namespace {
     40 
     41 class ProtoValueConversionsTest : public testing::Test {
     42  protected:
     43   template <class T>
     44   void TestSpecificsToValue(
     45       base::DictionaryValue* (*specifics_to_value)(const T&)) {
     46     const T& specifics(T::default_instance());
     47     scoped_ptr<base::DictionaryValue> value(specifics_to_value(specifics));
     48     // We can't do much but make sure that this doesn't crash.
     49   }
     50 };
     51 
     52 TEST_F(ProtoValueConversionsTest, ProtoChangeCheck) {
     53   // If this number changes, that means we added or removed a data
     54   // type.  Don't forget to add a unit test for {New
     55   // type}SpecificsToValue below.
     56   EXPECT_EQ(30, MODEL_TYPE_COUNT);
     57 
     58   // We'd also like to check if we changed any field in our messages.
     59   // However, that's hard to do: sizeof could work, but it's
     60   // platform-dependent.  default_instance().ByteSize() won't change
     61   // for most changes, since most of our fields are optional.  So we
     62   // just settle for comments in the proto files.
     63 }
     64 
     65 TEST_F(ProtoValueConversionsTest, EncryptedDataToValue) {
     66   TestSpecificsToValue(EncryptedDataToValue);
     67 }
     68 
     69 TEST_F(ProtoValueConversionsTest, SessionHeaderToValue) {
     70   TestSpecificsToValue(SessionHeaderToValue);
     71 }
     72 
     73 TEST_F(ProtoValueConversionsTest, SessionTabToValue) {
     74   TestSpecificsToValue(SessionTabToValue);
     75 }
     76 
     77 TEST_F(ProtoValueConversionsTest, SessionWindowToValue) {
     78   TestSpecificsToValue(SessionWindowToValue);
     79 }
     80 
     81 TEST_F(ProtoValueConversionsTest, TabNavigationToValue) {
     82   TestSpecificsToValue(TabNavigationToValue);
     83 }
     84 
     85 TEST_F(ProtoValueConversionsTest, PasswordSpecificsData) {
     86   sync_pb::PasswordSpecificsData specifics;
     87   specifics.set_password_value("secret");
     88   scoped_ptr<base::DictionaryValue> value(
     89       PasswordSpecificsDataToValue(specifics));
     90   EXPECT_FALSE(value->empty());
     91   std::string password_value;
     92   EXPECT_TRUE(value->GetString("password_value", &password_value));
     93   EXPECT_EQ("<redacted>", password_value);
     94 }
     95 
     96 TEST_F(ProtoValueConversionsTest, AppListSpecificsToValue) {
     97   TestSpecificsToValue(AppListSpecificsToValue);
     98 }
     99 
    100 TEST_F(ProtoValueConversionsTest, AppNotificationToValue) {
    101   TestSpecificsToValue(AppNotificationToValue);
    102 }
    103 
    104 TEST_F(ProtoValueConversionsTest, AppSettingSpecificsToValue) {
    105   sync_pb::AppNotificationSettings specifics;
    106   specifics.set_disabled(true);
    107   specifics.set_oauth_client_id("some_id_value");
    108   scoped_ptr<base::DictionaryValue> value(AppSettingsToValue(specifics));
    109   EXPECT_FALSE(value->empty());
    110   bool disabled_value = false;
    111   std::string oauth_client_id_value;
    112   EXPECT_TRUE(value->GetBoolean("disabled", &disabled_value));
    113   EXPECT_EQ(true, disabled_value);
    114   EXPECT_TRUE(value->GetString("oauth_client_id", &oauth_client_id_value));
    115   EXPECT_EQ("some_id_value", oauth_client_id_value);
    116 }
    117 
    118 TEST_F(ProtoValueConversionsTest, AppSpecificsToValue) {
    119   TestSpecificsToValue(AppSpecificsToValue);
    120 }
    121 
    122 TEST_F(ProtoValueConversionsTest, AutofillSpecificsToValue) {
    123   TestSpecificsToValue(AutofillSpecificsToValue);
    124 }
    125 
    126 TEST_F(ProtoValueConversionsTest, AutofillProfileSpecificsToValue) {
    127   TestSpecificsToValue(AutofillProfileSpecificsToValue);
    128 }
    129 
    130 TEST_F(ProtoValueConversionsTest, BookmarkSpecificsToValue) {
    131   TestSpecificsToValue(BookmarkSpecificsToValue);
    132 }
    133 
    134 TEST_F(ProtoValueConversionsTest, BookmarkSpecificsData) {
    135   const base::Time creation_time(base::Time::Now());
    136   const std::string icon_url = "http://www.google.com/favicon.ico";
    137   sync_pb::BookmarkSpecifics specifics;
    138   specifics.set_creation_time_us(creation_time.ToInternalValue());
    139   specifics.set_icon_url(icon_url);
    140   sync_pb::MetaInfo* meta_1 = specifics.add_meta_info();
    141   meta_1->set_key("key1");
    142   meta_1->set_value("value1");
    143   sync_pb::MetaInfo* meta_2 = specifics.add_meta_info();
    144   meta_2->set_key("key2");
    145   meta_2->set_value("value2");
    146 
    147   scoped_ptr<base::DictionaryValue> value(BookmarkSpecificsToValue(specifics));
    148   EXPECT_FALSE(value->empty());
    149   std::string encoded_time;
    150   EXPECT_TRUE(value->GetString("creation_time_us", &encoded_time));
    151   EXPECT_EQ(base::Int64ToString(creation_time.ToInternalValue()), encoded_time);
    152   std::string encoded_icon_url;
    153   EXPECT_TRUE(value->GetString("icon_url", &encoded_icon_url));
    154   EXPECT_EQ(icon_url, encoded_icon_url);
    155   base::ListValue* meta_info_list;
    156   ASSERT_TRUE(value->GetList("meta_info", &meta_info_list));
    157   EXPECT_EQ(2u, meta_info_list->GetSize());
    158   base::DictionaryValue* meta_info;
    159   std::string meta_key;
    160   std::string meta_value;
    161   ASSERT_TRUE(meta_info_list->GetDictionary(0, &meta_info));
    162   EXPECT_TRUE(meta_info->GetString("key", &meta_key));
    163   EXPECT_TRUE(meta_info->GetString("value", &meta_value));
    164   EXPECT_EQ("key1", meta_key);
    165   EXPECT_EQ("value1", meta_value);
    166   ASSERT_TRUE(meta_info_list->GetDictionary(1, &meta_info));
    167   EXPECT_TRUE(meta_info->GetString("key", &meta_key));
    168   EXPECT_TRUE(meta_info->GetString("value", &meta_value));
    169   EXPECT_EQ("key2", meta_key);
    170   EXPECT_EQ("value2", meta_value);
    171 }
    172 
    173 TEST_F(ProtoValueConversionsTest, PriorityPreferenceSpecificsToValue) {
    174   TestSpecificsToValue(PriorityPreferenceSpecificsToValue);
    175 }
    176 
    177 TEST_F(ProtoValueConversionsTest, DeviceInfoSpecificsToValue) {
    178   TestSpecificsToValue(DeviceInfoSpecificsToValue);
    179 }
    180 
    181 TEST_F(ProtoValueConversionsTest, ExperimentsSpecificsToValue) {
    182   TestSpecificsToValue(ExperimentsSpecificsToValue);
    183 }
    184 
    185 TEST_F(ProtoValueConversionsTest, ExtensionSettingSpecificsToValue) {
    186   TestSpecificsToValue(ExtensionSettingSpecificsToValue);
    187 }
    188 
    189 TEST_F(ProtoValueConversionsTest, ExtensionSpecificsToValue) {
    190   TestSpecificsToValue(ExtensionSpecificsToValue);
    191 }
    192 
    193 TEST_F(ProtoValueConversionsTest, FaviconImageSpecificsToValue) {
    194   TestSpecificsToValue(FaviconImageSpecificsToValue);
    195 }
    196 
    197 TEST_F(ProtoValueConversionsTest, FaviconTrackingSpecificsToValue) {
    198   TestSpecificsToValue(FaviconTrackingSpecificsToValue);
    199 }
    200 
    201 TEST_F(ProtoValueConversionsTest, HistoryDeleteDirectiveSpecificsToValue) {
    202   TestSpecificsToValue(HistoryDeleteDirectiveSpecificsToValue);
    203 }
    204 
    205 TEST_F(ProtoValueConversionsTest, ManagedUserSettingSpecificsToValue) {
    206   TestSpecificsToValue(ManagedUserSettingSpecificsToValue);
    207 }
    208 
    209 TEST_F(ProtoValueConversionsTest, ManagedUserSpecificsToValue) {
    210   TestSpecificsToValue(ManagedUserSpecificsToValue);
    211 }
    212 
    213 TEST_F(ProtoValueConversionsTest, NigoriSpecificsToValue) {
    214   TestSpecificsToValue(NigoriSpecificsToValue);
    215 }
    216 
    217 TEST_F(ProtoValueConversionsTest, PasswordSpecificsToValue) {
    218   TestSpecificsToValue(PasswordSpecificsToValue);
    219 }
    220 
    221 TEST_F(ProtoValueConversionsTest, PreferenceSpecificsToValue) {
    222   TestSpecificsToValue(PreferenceSpecificsToValue);
    223 }
    224 
    225 TEST_F(ProtoValueConversionsTest, SearchEngineSpecificsToValue) {
    226   TestSpecificsToValue(SearchEngineSpecificsToValue);
    227 }
    228 
    229 TEST_F(ProtoValueConversionsTest, SessionSpecificsToValue) {
    230   TestSpecificsToValue(SessionSpecificsToValue);
    231 }
    232 
    233 TEST_F(ProtoValueConversionsTest, SyncedNotificationSpecificsToValue) {
    234   TestSpecificsToValue(SyncedNotificationSpecificsToValue);
    235 }
    236 
    237 TEST_F(ProtoValueConversionsTest, ThemeSpecificsToValue) {
    238   TestSpecificsToValue(ThemeSpecificsToValue);
    239 }
    240 
    241 TEST_F(ProtoValueConversionsTest, TypedUrlSpecificsToValue) {
    242   TestSpecificsToValue(TypedUrlSpecificsToValue);
    243 }
    244 
    245 TEST_F(ProtoValueConversionsTest, DictionarySpecificsToValue) {
    246   TestSpecificsToValue(DictionarySpecificsToValue);
    247 }
    248 
    249 TEST_F(ProtoValueConversionsTest, ArticleSpecificsToValue) {
    250   TestSpecificsToValue(ArticleSpecificsToValue);
    251 }
    252 
    253 // TODO(akalin): Figure out how to better test EntitySpecificsToValue.
    254 
    255 TEST_F(ProtoValueConversionsTest, EntitySpecificsToValue) {
    256   sync_pb::EntitySpecifics specifics;
    257   // Touch the extensions to make sure it shows up in the generated
    258   // value.
    259 #define SET_FIELD(key) (void)specifics.mutable_##key()
    260 
    261   SET_FIELD(app);
    262   SET_FIELD(app_list);
    263   SET_FIELD(app_notification);
    264   SET_FIELD(app_setting);
    265   SET_FIELD(article);
    266   SET_FIELD(autofill);
    267   SET_FIELD(autofill_profile);
    268   SET_FIELD(bookmark);
    269   SET_FIELD(device_info);
    270   SET_FIELD(dictionary);
    271   SET_FIELD(experiments);
    272   SET_FIELD(extension);
    273   SET_FIELD(extension_setting);
    274   SET_FIELD(favicon_image);
    275   SET_FIELD(favicon_tracking);
    276   SET_FIELD(history_delete_directive);
    277   SET_FIELD(managed_user_setting);
    278   SET_FIELD(managed_user);
    279   SET_FIELD(nigori);
    280   SET_FIELD(password);
    281   SET_FIELD(preference);
    282   SET_FIELD(priority_preference);
    283   SET_FIELD(search_engine);
    284   SET_FIELD(session);
    285   SET_FIELD(synced_notification);
    286   SET_FIELD(theme);
    287   SET_FIELD(typed_url);
    288 
    289 #undef SET_FIELD
    290 
    291   scoped_ptr<base::DictionaryValue> value(EntitySpecificsToValue(specifics));
    292   EXPECT_EQ(MODEL_TYPE_COUNT - FIRST_REAL_MODEL_TYPE -
    293             (LAST_PROXY_TYPE - FIRST_PROXY_TYPE + 1),
    294             static_cast<int>(value->size()));
    295 }
    296 
    297 namespace {
    298 // Returns whether the given value has specifics under the entries in the given
    299 // path.
    300 bool ValueHasSpecifics(const base::DictionaryValue& value,
    301                        const std::string& path) {
    302   const base::ListValue* entities_list = NULL;
    303   const base::DictionaryValue* entry_dictionary = NULL;
    304   const base::DictionaryValue* specifics_dictionary = NULL;
    305 
    306   if (!value.GetList(path, &entities_list))
    307     return false;
    308 
    309   if (!entities_list->GetDictionary(0, &entry_dictionary))
    310     return false;
    311 
    312   return entry_dictionary->GetDictionary("specifics",
    313                                          &specifics_dictionary);
    314 }
    315 }  // namespace
    316 
    317 // Create a ClientToServerMessage with an EntitySpecifics.  Converting it to
    318 // a value should respect the |include_specifics| flag.
    319 TEST_F(ProtoValueConversionsTest, ClientToServerMessageToValue) {
    320   sync_pb::ClientToServerMessage message;
    321   sync_pb::CommitMessage* commit_message = message.mutable_commit();
    322   sync_pb::SyncEntity* entity = commit_message->add_entries();
    323   entity->mutable_specifics();
    324 
    325   scoped_ptr<base::DictionaryValue> value_with_specifics(
    326       ClientToServerMessageToValue(message, true /* include_specifics */));
    327   EXPECT_FALSE(value_with_specifics->empty());
    328   EXPECT_TRUE(ValueHasSpecifics(*(value_with_specifics.get()),
    329                                 "commit.entries"));
    330 
    331   scoped_ptr<base::DictionaryValue> value_without_specifics(
    332       ClientToServerMessageToValue(message, false /* include_specifics */));
    333   EXPECT_FALSE(value_without_specifics->empty());
    334   EXPECT_FALSE(ValueHasSpecifics(*(value_without_specifics.get()),
    335                                  "commit.entries"));
    336 }
    337 
    338 // Create a ClientToServerResponse with an EntitySpecifics.  Converting it to
    339 // a value should respect the |include_specifics| flag.
    340 TEST_F(ProtoValueConversionsTest, ClientToServerResponseToValue) {
    341   sync_pb::ClientToServerResponse message;
    342   sync_pb::GetUpdatesResponse* response = message.mutable_get_updates();
    343   sync_pb::SyncEntity* entity = response->add_entries();
    344   entity->mutable_specifics();
    345 
    346   scoped_ptr<base::DictionaryValue> value_with_specifics(
    347       ClientToServerResponseToValue(message, true /* include_specifics */));
    348   EXPECT_FALSE(value_with_specifics->empty());
    349   EXPECT_TRUE(ValueHasSpecifics(*(value_with_specifics.get()),
    350                                 "get_updates.entries"));
    351 
    352   scoped_ptr<base::DictionaryValue> value_without_specifics(
    353       ClientToServerResponseToValue(message, false /* include_specifics */));
    354   EXPECT_FALSE(value_without_specifics->empty());
    355   EXPECT_FALSE(ValueHasSpecifics(*(value_without_specifics.get()),
    356                                  "get_updates.entries"));
    357 }
    358 
    359 }  // namespace
    360 }  // namespace syncer
    361