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