proto_value_conversions_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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. #include "components/sync/protocol/proto_value_conversions.h"
  5. #include <string>
  6. #include "base/strings/string_number_conversions.h"
  7. #include "base/time/time.h"
  8. #include "base/values.h"
  9. #include "components/sync/base/model_type.h"
  10. #include "components/sync/base/unique_position.h"
  11. #include "components/sync/protocol/app_setting_specifics.pb.h"
  12. #include "components/sync/protocol/app_specifics.pb.h"
  13. #include "components/sync/protocol/autofill_specifics.pb.h"
  14. #include "components/sync/protocol/bookmark_specifics.pb.h"
  15. #include "components/sync/protocol/contact_info_specifics.pb.h"
  16. #include "components/sync/protocol/data_type_progress_marker.pb.h"
  17. #include "components/sync/protocol/device_info_specifics.pb.h"
  18. #include "components/sync/protocol/encryption.pb.h"
  19. #include "components/sync/protocol/entity_specifics.pb.h"
  20. #include "components/sync/protocol/extension_setting_specifics.pb.h"
  21. #include "components/sync/protocol/extension_specifics.pb.h"
  22. #include "components/sync/protocol/managed_user_setting_specifics.pb.h"
  23. #include "components/sync/protocol/nigori_specifics.pb.h"
  24. #include "components/sync/protocol/os_preference_specifics.pb.h"
  25. #include "components/sync/protocol/os_priority_preference_specifics.pb.h"
  26. #include "components/sync/protocol/password_specifics.pb.h"
  27. #include "components/sync/protocol/preference_specifics.pb.h"
  28. #include "components/sync/protocol/priority_preference_specifics.pb.h"
  29. #include "components/sync/protocol/search_engine_specifics.pb.h"
  30. #include "components/sync/protocol/session_specifics.pb.h"
  31. #include "components/sync/protocol/sharing_message_specifics.pb.h"
  32. #include "components/sync/protocol/sync.pb.h"
  33. #include "components/sync/protocol/sync_entity.pb.h"
  34. #include "components/sync/protocol/theme_specifics.pb.h"
  35. #include "components/sync/protocol/typed_url_specifics.pb.h"
  36. #include "testing/gmock/include/gmock/gmock.h"
  37. #include "testing/gtest/include/gtest/gtest.h"
  38. namespace syncer {
  39. namespace {
  40. using testing::Not;
  41. // Keep this file in sync with the .proto files in this directory.
  42. #define DEFINE_SPECIFICS_TO_VALUE_TEST(Key) \
  43. TEST(ProtoValueConversionsTest, Proto_##Key##_SpecificsToValue) { \
  44. sync_pb::EntitySpecifics specifics; \
  45. specifics.mutable_##Key(); \
  46. std::unique_ptr<base::DictionaryValue> value( \
  47. EntitySpecificsToValue(specifics)); \
  48. EXPECT_EQ(1, static_cast<int>(value->DictSize())); \
  49. }
  50. // We'd also like to check if we changed any field in our messages. However,
  51. // that's hard to do: sizeof could work, but it's platform-dependent.
  52. // default_instance().ByteSize() won't change for most changes, since most of
  53. // our fields are optional. So we just settle for comments in the proto files.
  54. DEFINE_SPECIFICS_TO_VALUE_TEST(encrypted)
  55. static_assert(40 == syncer::GetNumModelTypes(),
  56. "When adding a new field, add a DEFINE_SPECIFICS_TO_VALUE_TEST "
  57. "for your field below, and optionally a test for the specific "
  58. "conversions.");
  59. DEFINE_SPECIFICS_TO_VALUE_TEST(app)
  60. DEFINE_SPECIFICS_TO_VALUE_TEST(app_list)
  61. DEFINE_SPECIFICS_TO_VALUE_TEST(app_setting)
  62. DEFINE_SPECIFICS_TO_VALUE_TEST(arc_package)
  63. DEFINE_SPECIFICS_TO_VALUE_TEST(autofill)
  64. DEFINE_SPECIFICS_TO_VALUE_TEST(autofill_offer)
  65. DEFINE_SPECIFICS_TO_VALUE_TEST(autofill_profile)
  66. DEFINE_SPECIFICS_TO_VALUE_TEST(autofill_wallet)
  67. DEFINE_SPECIFICS_TO_VALUE_TEST(bookmark)
  68. DEFINE_SPECIFICS_TO_VALUE_TEST(contact_info)
  69. DEFINE_SPECIFICS_TO_VALUE_TEST(device_info)
  70. DEFINE_SPECIFICS_TO_VALUE_TEST(dictionary)
  71. DEFINE_SPECIFICS_TO_VALUE_TEST(extension)
  72. DEFINE_SPECIFICS_TO_VALUE_TEST(extension_setting)
  73. DEFINE_SPECIFICS_TO_VALUE_TEST(history)
  74. DEFINE_SPECIFICS_TO_VALUE_TEST(history_delete_directive)
  75. DEFINE_SPECIFICS_TO_VALUE_TEST(managed_user_setting)
  76. DEFINE_SPECIFICS_TO_VALUE_TEST(nigori)
  77. DEFINE_SPECIFICS_TO_VALUE_TEST(os_preference)
  78. DEFINE_SPECIFICS_TO_VALUE_TEST(os_priority_preference)
  79. DEFINE_SPECIFICS_TO_VALUE_TEST(password)
  80. DEFINE_SPECIFICS_TO_VALUE_TEST(preference)
  81. DEFINE_SPECIFICS_TO_VALUE_TEST(printer)
  82. DEFINE_SPECIFICS_TO_VALUE_TEST(printers_authorization_server)
  83. DEFINE_SPECIFICS_TO_VALUE_TEST(priority_preference)
  84. DEFINE_SPECIFICS_TO_VALUE_TEST(reading_list)
  85. DEFINE_SPECIFICS_TO_VALUE_TEST(search_engine)
  86. DEFINE_SPECIFICS_TO_VALUE_TEST(security_event)
  87. DEFINE_SPECIFICS_TO_VALUE_TEST(send_tab_to_self)
  88. DEFINE_SPECIFICS_TO_VALUE_TEST(session)
  89. DEFINE_SPECIFICS_TO_VALUE_TEST(sharing_message)
  90. DEFINE_SPECIFICS_TO_VALUE_TEST(theme)
  91. DEFINE_SPECIFICS_TO_VALUE_TEST(typed_url)
  92. DEFINE_SPECIFICS_TO_VALUE_TEST(user_consent)
  93. DEFINE_SPECIFICS_TO_VALUE_TEST(user_event)
  94. DEFINE_SPECIFICS_TO_VALUE_TEST(wallet_metadata)
  95. DEFINE_SPECIFICS_TO_VALUE_TEST(web_app)
  96. DEFINE_SPECIFICS_TO_VALUE_TEST(wifi_configuration)
  97. DEFINE_SPECIFICS_TO_VALUE_TEST(workspace_desk)
  98. TEST(ProtoValueConversionsTest, AutofillWalletSpecificsToValue) {
  99. sync_pb::AutofillWalletSpecifics specifics;
  100. specifics.mutable_masked_card()->set_name_on_card("Igloo");
  101. specifics.mutable_address()->set_recipient_name("John");
  102. specifics.mutable_customer_data()->set_id("123456");
  103. specifics.mutable_cloud_token_data()->set_masked_card_id("1111");
  104. specifics.set_type(sync_pb::AutofillWalletSpecifics::UNKNOWN);
  105. std::unique_ptr<base::DictionaryValue> value =
  106. AutofillWalletSpecificsToValue(specifics);
  107. EXPECT_FALSE(value->Get("masked_card", nullptr));
  108. EXPECT_FALSE(value->Get("address", nullptr));
  109. EXPECT_FALSE(value->Get("customer_data", nullptr));
  110. EXPECT_FALSE(value->Get("cloud_token_data", nullptr));
  111. specifics.set_type(sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD);
  112. value = AutofillWalletSpecificsToValue(specifics);
  113. EXPECT_TRUE(value->Get("masked_card", nullptr));
  114. EXPECT_FALSE(value->Get("address", nullptr));
  115. EXPECT_FALSE(value->Get("customer_data", nullptr));
  116. EXPECT_FALSE(value->Get("cloud_token_data", nullptr));
  117. specifics.set_type(sync_pb::AutofillWalletSpecifics::POSTAL_ADDRESS);
  118. value = AutofillWalletSpecificsToValue(specifics);
  119. EXPECT_FALSE(value->Get("masked_card", nullptr));
  120. EXPECT_TRUE(value->Get("address", nullptr));
  121. EXPECT_FALSE(value->Get("customer_data", nullptr));
  122. EXPECT_FALSE(value->Get("cloud_token_data", nullptr));
  123. specifics.set_type(sync_pb::AutofillWalletSpecifics::CUSTOMER_DATA);
  124. value = AutofillWalletSpecificsToValue(specifics);
  125. EXPECT_FALSE(value->Get("masked_card", nullptr));
  126. EXPECT_FALSE(value->Get("address", nullptr));
  127. EXPECT_TRUE(value->Get("customer_data", nullptr));
  128. EXPECT_FALSE(value->Get("cloud_token_data", nullptr));
  129. specifics.set_type(
  130. sync_pb::AutofillWalletSpecifics::CREDIT_CARD_CLOUD_TOKEN_DATA);
  131. value = AutofillWalletSpecificsToValue(specifics);
  132. EXPECT_FALSE(value->Get("masked_card", nullptr));
  133. EXPECT_FALSE(value->Get("address", nullptr));
  134. EXPECT_FALSE(value->Get("customer_data", nullptr));
  135. EXPECT_TRUE(value->Get("cloud_token_data", nullptr));
  136. }
  137. TEST(ProtoValueConversionsTest, BookmarkSpecificsData) {
  138. const base::Time creation_time(base::Time::Now());
  139. const std::string icon_url = "http://www.google.com/favicon.ico";
  140. sync_pb::BookmarkSpecifics specifics;
  141. specifics.set_creation_time_us(creation_time.ToInternalValue());
  142. specifics.set_icon_url(icon_url);
  143. sync_pb::MetaInfo* meta_1 = specifics.add_meta_info();
  144. meta_1->set_key("key1");
  145. meta_1->set_value("value1");
  146. sync_pb::MetaInfo* meta_2 = specifics.add_meta_info();
  147. meta_2->set_key("key2");
  148. meta_2->set_value("value2");
  149. std::unique_ptr<base::DictionaryValue> value(
  150. BookmarkSpecificsToValue(specifics));
  151. EXPECT_FALSE(value->DictEmpty());
  152. std::string encoded_time;
  153. EXPECT_TRUE(value->GetString("creation_time_us", &encoded_time));
  154. EXPECT_EQ(base::NumberToString(creation_time.ToInternalValue()),
  155. encoded_time);
  156. std::string encoded_icon_url;
  157. EXPECT_TRUE(value->GetString("icon_url", &encoded_icon_url));
  158. EXPECT_EQ(icon_url, encoded_icon_url);
  159. base::ListValue* meta_info_list;
  160. ASSERT_TRUE(value->GetList("meta_info", &meta_info_list));
  161. EXPECT_EQ(2u, meta_info_list->GetListDeprecated().size());
  162. const base::Value* meta_info_value;
  163. const base::DictionaryValue* meta_info;
  164. std::string meta_key;
  165. std::string meta_value;
  166. meta_info_value = &meta_info_list->GetListDeprecated()[0];
  167. ASSERT_TRUE(meta_info_value->is_dict());
  168. meta_info = &base::Value::AsDictionaryValue(*meta_info_value);
  169. EXPECT_TRUE(meta_info->GetString("key", &meta_key));
  170. EXPECT_TRUE(meta_info->GetString("value", &meta_value));
  171. EXPECT_EQ("key1", meta_key);
  172. EXPECT_EQ("value1", meta_value);
  173. meta_info_value = &meta_info_list->GetListDeprecated()[1];
  174. ASSERT_TRUE(meta_info_value->is_dict());
  175. meta_info = &base::Value::AsDictionaryValue(*meta_info_value);
  176. EXPECT_TRUE(meta_info->GetString("key", &meta_key));
  177. EXPECT_TRUE(meta_info->GetString("value", &meta_value));
  178. EXPECT_EQ("key2", meta_key);
  179. EXPECT_EQ("value2", meta_value);
  180. }
  181. TEST(ProtoValueConversionsTest, UniquePositionToValue) {
  182. sync_pb::SyncEntity entity;
  183. entity.mutable_unique_position()->set_custom_compressed_v1("test");
  184. std::unique_ptr<base::DictionaryValue> value =
  185. SyncEntityToValue(entity, {.include_specifics = false});
  186. std::string unique_position;
  187. EXPECT_TRUE(value->GetString("unique_position", &unique_position));
  188. std::string expected_unique_position =
  189. UniquePosition::FromProto(entity.unique_position()).ToDebugString();
  190. EXPECT_EQ(expected_unique_position, unique_position);
  191. }
  192. TEST(ProtoValueConversionsTest, SyncEntityToValueIncludeSpecifics) {
  193. sync_pb::SyncEntity entity;
  194. entity.mutable_specifics();
  195. std::unique_ptr<base::DictionaryValue> value =
  196. SyncEntityToValue(entity, {.include_specifics = true});
  197. EXPECT_TRUE(value->GetDictionary("specifics", nullptr));
  198. value = SyncEntityToValue(entity, {.include_specifics = false});
  199. EXPECT_FALSE(value->GetDictionary("specifics", nullptr));
  200. }
  201. namespace {
  202. // Returns whether the given value has specifics under the entries in the given
  203. // path.
  204. bool ValueHasSpecifics(const base::DictionaryValue& value,
  205. const std::string& path) {
  206. const base::ListValue* entities_list = nullptr;
  207. if (!value.GetList(path, &entities_list))
  208. return false;
  209. const base::Value& entry_dictionary_value =
  210. entities_list->GetListDeprecated()[0];
  211. if (!entry_dictionary_value.is_dict())
  212. return false;
  213. const base::DictionaryValue& entry_dictionary =
  214. base::Value::AsDictionaryValue(entry_dictionary_value);
  215. const base::DictionaryValue* specifics_dictionary = nullptr;
  216. return entry_dictionary.GetDictionary("specifics", &specifics_dictionary);
  217. }
  218. MATCHER(ValueHasNonEmptyGetUpdateTriggers, "") {
  219. const base::DictionaryValue& value = arg;
  220. const base::ListValue* entities_list = nullptr;
  221. if (!value.GetList("get_updates.from_progress_marker", &entities_list)) {
  222. *result_listener << "no from_progress_marker list";
  223. return false;
  224. }
  225. const base::Value& entry_dictionary_value = entities_list->GetList().front();
  226. if (!entry_dictionary_value.is_dict()) {
  227. *result_listener << "from_progress_marker does not contain a dictionary";
  228. return false;
  229. }
  230. const base::DictionaryValue& entry_dictionary =
  231. base::Value::AsDictionaryValue(entry_dictionary_value);
  232. const base::DictionaryValue* get_update_triggers_dictionary = nullptr;
  233. if (!entry_dictionary.GetDictionary("get_update_triggers",
  234. &get_update_triggers_dictionary)) {
  235. *result_listener << "no get_update_triggers dictionary";
  236. return false;
  237. }
  238. return !get_update_triggers_dictionary->GetDict().empty();
  239. }
  240. } // namespace
  241. // Create a ClientToServerMessage with an EntitySpecifics. Converting it to
  242. // a value should respect the |include_specifics| flag.
  243. TEST(ProtoValueConversionsTest, ClientToServerMessageToValue) {
  244. sync_pb::ClientToServerMessage message;
  245. sync_pb::CommitMessage* commit_message = message.mutable_commit();
  246. sync_pb::SyncEntity* entity = commit_message->add_entries();
  247. entity->mutable_specifics();
  248. std::unique_ptr<base::DictionaryValue> value_with_specifics(
  249. ClientToServerMessageToValue(message, {.include_specifics = true}));
  250. EXPECT_FALSE(value_with_specifics->DictEmpty());
  251. EXPECT_TRUE(
  252. ValueHasSpecifics(*(value_with_specifics.get()), "commit.entries"));
  253. std::unique_ptr<base::DictionaryValue> value_without_specifics(
  254. ClientToServerMessageToValue(message, {.include_specifics = false}));
  255. EXPECT_FALSE(value_without_specifics->DictEmpty());
  256. EXPECT_FALSE(
  257. ValueHasSpecifics(*(value_without_specifics.get()), "commit.entries"));
  258. }
  259. TEST(ProtoValueConversionsTest, ClientToServerMessageToValueGUTriggers) {
  260. sync_pb::ClientToServerMessage message;
  261. sync_pb::GetUpdateTriggers* get_update_triggers =
  262. message.mutable_get_updates()
  263. ->add_from_progress_marker()
  264. ->mutable_get_update_triggers();
  265. get_update_triggers->set_client_dropped_hints(false);
  266. get_update_triggers->set_server_dropped_hints(false);
  267. get_update_triggers->set_datatype_refresh_nudges(0);
  268. get_update_triggers->set_local_modification_nudges(0);
  269. get_update_triggers->set_initial_sync_in_progress(false);
  270. get_update_triggers->set_sync_for_resolve_conflict_in_progress(false);
  271. std::unique_ptr<base::DictionaryValue> value_with_full_gu_triggers(
  272. ClientToServerMessageToValue(message,
  273. {.include_full_get_update_triggers = true}));
  274. EXPECT_FALSE(value_with_full_gu_triggers->DictEmpty());
  275. EXPECT_THAT(*value_with_full_gu_triggers,
  276. ValueHasNonEmptyGetUpdateTriggers());
  277. std::unique_ptr<base::DictionaryValue> value_without_full_gu_triggers(
  278. ClientToServerMessageToValue(
  279. message, {.include_full_get_update_triggers = false}));
  280. EXPECT_FALSE(value_without_full_gu_triggers->DictEmpty());
  281. EXPECT_THAT(*value_without_full_gu_triggers,
  282. Not(ValueHasNonEmptyGetUpdateTriggers()));
  283. }
  284. // Create a ClientToServerResponse with an EntitySpecifics. Converting it to
  285. // a value should respect the |include_specifics| flag.
  286. TEST(ProtoValueConversionsTest, ClientToServerResponseToValue) {
  287. sync_pb::ClientToServerResponse message;
  288. sync_pb::GetUpdatesResponse* response = message.mutable_get_updates();
  289. sync_pb::SyncEntity* entity = response->add_entries();
  290. entity->mutable_specifics();
  291. std::unique_ptr<base::DictionaryValue> value_with_specifics(
  292. ClientToServerResponseToValue(message, {.include_specifics = true}));
  293. EXPECT_FALSE(value_with_specifics->DictEmpty());
  294. EXPECT_TRUE(
  295. ValueHasSpecifics(*(value_with_specifics.get()), "get_updates.entries"));
  296. std::unique_ptr<base::DictionaryValue> value_without_specifics(
  297. ClientToServerResponseToValue(message, {.include_specifics = false}));
  298. EXPECT_FALSE(value_without_specifics->DictEmpty());
  299. EXPECT_FALSE(ValueHasSpecifics(*(value_without_specifics.get()),
  300. "get_updates.entries"));
  301. }
  302. } // namespace
  303. } // namespace syncer