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