bookmark_codec_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. // Copyright 2014 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/bookmarks/browser/bookmark_codec.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <memory>
  8. #include "base/files/file_path.h"
  9. #include "base/files/file_util.h"
  10. #include "base/guid.h"
  11. #include "base/json/json_file_value_serializer.h"
  12. #include "base/json/json_string_value_serializer.h"
  13. #include "base/no_destructor.h"
  14. #include "base/path_service.h"
  15. #include "base/strings/string_util.h"
  16. #include "base/strings/utf_string_conversions.h"
  17. #include "base/values.h"
  18. #include "components/bookmarks/browser/bookmark_model.h"
  19. #include "components/bookmarks/test/test_bookmark_client.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. using base::ASCIIToUTF16;
  22. namespace bookmarks {
  23. namespace {
  24. const char16_t kUrl1Title[] = u"url1";
  25. const char kUrl1Url[] = "http://www.url1.com";
  26. const char16_t kUrl2Title[] = u"url2";
  27. const char kUrl2Url[] = "http://www.url2.com";
  28. const char16_t kUrl3Title[] = u"url3";
  29. const char kUrl3Url[] = "http://www.url3.com";
  30. const char16_t kUrl4Title[] = u"url4";
  31. const char kUrl4Url[] = "http://www.url4.com";
  32. const char16_t kFolder1Title[] = u"folder1";
  33. const char16_t kFolder2Title[] = u"folder2";
  34. const base::FilePath& GetTestDataDir() {
  35. static base::NoDestructor<base::FilePath> dir([]() {
  36. base::FilePath dir;
  37. base::PathService::Get(base::DIR_SOURCE_ROOT, &dir);
  38. return dir.AppendASCII("components")
  39. .AppendASCII("test")
  40. .AppendASCII("data");
  41. }());
  42. return *dir;
  43. }
  44. // Helper to get a mutable bookmark node.
  45. BookmarkNode* AsMutable(const BookmarkNode* node) {
  46. return const_cast<BookmarkNode*>(node);
  47. }
  48. // Helper to verify the two given bookmark nodes.
  49. void AssertNodesEqual(const BookmarkNode* expected,
  50. const BookmarkNode* actual) {
  51. ASSERT_TRUE(expected);
  52. ASSERT_TRUE(actual);
  53. EXPECT_EQ(expected->id(), actual->id());
  54. EXPECT_EQ(expected->guid(), actual->guid());
  55. EXPECT_EQ(expected->GetTitle(), actual->GetTitle());
  56. EXPECT_EQ(expected->type(), actual->type());
  57. EXPECT_TRUE(expected->date_added() == actual->date_added());
  58. if (expected->is_url()) {
  59. EXPECT_EQ(expected->url(), actual->url());
  60. } else {
  61. EXPECT_TRUE(expected->date_folder_modified() ==
  62. actual->date_folder_modified());
  63. ASSERT_EQ(expected->children().size(), actual->children().size());
  64. for (size_t i = 0; i < expected->children().size(); ++i) {
  65. AssertNodesEqual(expected->children()[i].get(),
  66. actual->children()[i].get());
  67. }
  68. }
  69. }
  70. // Verifies that the two given bookmark models are the same.
  71. void AssertModelsEqual(BookmarkModel* expected, BookmarkModel* actual) {
  72. ASSERT_NO_FATAL_FAILURE(AssertNodesEqual(expected->bookmark_bar_node(),
  73. actual->bookmark_bar_node()));
  74. ASSERT_NO_FATAL_FAILURE(
  75. AssertNodesEqual(expected->other_node(), actual->other_node()));
  76. ASSERT_NO_FATAL_FAILURE(
  77. AssertNodesEqual(expected->mobile_node(), actual->mobile_node()));
  78. }
  79. } // namespace
  80. class BookmarkCodecTest : public testing::Test {
  81. protected:
  82. // Helpers to create bookmark models with different data.
  83. BookmarkModel* CreateTestModel1() {
  84. std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
  85. const BookmarkNode* bookmark_bar = model->bookmark_bar_node();
  86. model->AddURL(bookmark_bar, 0, kUrl1Title, GURL(kUrl1Url));
  87. return model.release();
  88. }
  89. BookmarkModel* CreateTestModel2() {
  90. std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
  91. const BookmarkNode* bookmark_bar = model->bookmark_bar_node();
  92. model->AddURL(bookmark_bar, 0, kUrl1Title, GURL(kUrl1Url));
  93. model->AddURL(bookmark_bar, 1, kUrl2Title, GURL(kUrl2Url));
  94. return model.release();
  95. }
  96. BookmarkModel* CreateTestModel3() {
  97. std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
  98. const BookmarkNode* bookmark_bar = model->bookmark_bar_node();
  99. model->AddURL(bookmark_bar, 0, kUrl1Title, GURL(kUrl1Url));
  100. const BookmarkNode* folder1 =
  101. model->AddFolder(bookmark_bar, 1, kFolder1Title);
  102. model->AddURL(folder1, 0, kUrl2Title, GURL(kUrl2Url));
  103. return model.release();
  104. }
  105. void GetBookmarksBarChildValue(base::Value* value,
  106. size_t index,
  107. base::Value** result_value) {
  108. ASSERT_TRUE(value->is_dict());
  109. base::Value::Dict* roots =
  110. value->GetDict().FindDict(BookmarkCodec::kRootsKey);
  111. ASSERT_TRUE(roots);
  112. base::Value::Dict* bb_dict =
  113. roots->FindDict(BookmarkCodec::kBookmarkBarFolderNameKey);
  114. ASSERT_TRUE(bb_dict);
  115. base::Value::List* bb_children_list =
  116. bb_dict->FindList(BookmarkCodec::kChildrenKey);
  117. ASSERT_TRUE(bb_children_list);
  118. ASSERT_LT(index, bb_children_list->size());
  119. base::Value& child_value = (*bb_children_list)[index];
  120. ASSERT_TRUE(child_value.is_dict());
  121. *result_value = &child_value;
  122. }
  123. base::Value EncodeHelper(BookmarkModel* model,
  124. const std::string& sync_metadata_str,
  125. std::string* checksum) {
  126. BookmarkCodec encoder;
  127. // Computed and stored checksums should be empty.
  128. EXPECT_EQ("", encoder.computed_checksum());
  129. EXPECT_EQ("", encoder.stored_checksum());
  130. base::Value value(encoder.Encode(model, sync_metadata_str));
  131. const std::string& computed_checksum = encoder.computed_checksum();
  132. const std::string& stored_checksum = encoder.stored_checksum();
  133. // Computed and stored checksums should not be empty and should be equal.
  134. EXPECT_FALSE(computed_checksum.empty());
  135. EXPECT_FALSE(stored_checksum.empty());
  136. EXPECT_EQ(computed_checksum, stored_checksum);
  137. *checksum = computed_checksum;
  138. return value;
  139. }
  140. bool Decode(BookmarkCodec* codec,
  141. const base::Value& value,
  142. BookmarkModel* model,
  143. std::string* sync_metadata_str) {
  144. int64_t max_id;
  145. bool result = codec->Decode(value, AsMutable(model->bookmark_bar_node()),
  146. AsMutable(model->other_node()),
  147. AsMutable(model->mobile_node()), &max_id,
  148. sync_metadata_str);
  149. model->set_next_node_id(max_id);
  150. AsMutable(model->root_node())->SetMetaInfoMap(codec->model_meta_info_map());
  151. return result;
  152. }
  153. std::unique_ptr<BookmarkModel> DecodeHelper(
  154. const base::Value& value,
  155. const std::string& expected_stored_checksum,
  156. std::string* computed_checksum,
  157. bool expected_changes,
  158. std::string* sync_metadata_str) {
  159. BookmarkCodec decoder;
  160. // Computed and stored checksums should be empty.
  161. EXPECT_EQ("", decoder.computed_checksum());
  162. EXPECT_EQ("", decoder.stored_checksum());
  163. std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
  164. EXPECT_TRUE(Decode(&decoder, value, model.get(),
  165. /*sync_metadata_str=*/sync_metadata_str));
  166. *computed_checksum = decoder.computed_checksum();
  167. const std::string& stored_checksum = decoder.stored_checksum();
  168. // Computed and stored checksums should not be empty.
  169. EXPECT_FALSE(computed_checksum->empty());
  170. EXPECT_FALSE(stored_checksum.empty());
  171. // Stored checksum should be as expected.
  172. EXPECT_EQ(expected_stored_checksum, stored_checksum);
  173. // The two checksums should be equal if expected_changes is true; otherwise
  174. // they should be different.
  175. if (expected_changes)
  176. EXPECT_NE(*computed_checksum, stored_checksum);
  177. else
  178. EXPECT_EQ(*computed_checksum, stored_checksum);
  179. return model;
  180. }
  181. void CheckIDs(const BookmarkNode* node, std::set<int64_t>* assigned_ids) {
  182. DCHECK(node);
  183. int64_t node_id = node->id();
  184. EXPECT_TRUE(assigned_ids->find(node_id) == assigned_ids->end());
  185. assigned_ids->insert(node_id);
  186. for (const auto& child : node->children())
  187. CheckIDs(child.get(), assigned_ids);
  188. }
  189. void ExpectIDsUnique(BookmarkModel* model) {
  190. std::set<int64_t> assigned_ids;
  191. CheckIDs(model->bookmark_bar_node(), &assigned_ids);
  192. CheckIDs(model->other_node(), &assigned_ids);
  193. CheckIDs(model->mobile_node(), &assigned_ids);
  194. }
  195. };
  196. TEST_F(BookmarkCodecTest, ChecksumEncodeDecodeTest) {
  197. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  198. std::string enc_checksum;
  199. base::Value value =
  200. EncodeHelper(model_to_encode.get(), /*sync_metadata_str=*/std::string(),
  201. &enc_checksum);
  202. std::string dec_checksum;
  203. std::unique_ptr<BookmarkModel> decoded_model =
  204. DecodeHelper(value, enc_checksum, &dec_checksum, false,
  205. /*sync_metadata_str=*/nullptr);
  206. }
  207. TEST_F(BookmarkCodecTest, ChecksumEncodeIdenticalModelsTest) {
  208. // Encode two identical models and make sure the check-sums are same as long
  209. // as the data is the same.
  210. std::unique_ptr<BookmarkModel> model1(CreateTestModel1());
  211. std::string enc_checksum1;
  212. EncodeHelper(model1.get(), /*sync_metadata_str=*/std::string(),
  213. &enc_checksum1);
  214. std::unique_ptr<BookmarkModel> model2(CreateTestModel1());
  215. std::string enc_checksum2;
  216. EncodeHelper(model2.get(), /*sync_metadata_str=*/std::string(),
  217. &enc_checksum2);
  218. ASSERT_EQ(enc_checksum1, enc_checksum2);
  219. }
  220. TEST_F(BookmarkCodecTest, ChecksumManualEditTest) {
  221. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  222. std::string enc_checksum;
  223. base::Value value =
  224. EncodeHelper(model_to_encode.get(), /*sync_metadata_str=*/std::string(),
  225. &enc_checksum);
  226. // Change something in the encoded value before decoding it.
  227. base::Value* child1_value = nullptr;
  228. GetBookmarksBarChildValue(&value, 0, &child1_value);
  229. std::string* title = child1_value->FindStringKey(BookmarkCodec::kNameKey);
  230. ASSERT_TRUE(title);
  231. std::string original_title = *title;
  232. child1_value->SetStringKey(BookmarkCodec::kNameKey, original_title + "1");
  233. std::string dec_checksum;
  234. std::unique_ptr<BookmarkModel> decoded_model1 =
  235. DecodeHelper(value, enc_checksum, &dec_checksum, true,
  236. /*sync_metadata_str=*/nullptr);
  237. // Undo the change and make sure the checksum is same as original.
  238. child1_value->SetStringKey(BookmarkCodec::kNameKey, original_title);
  239. std::unique_ptr<BookmarkModel> decoded_model2 =
  240. DecodeHelper(value, enc_checksum, &dec_checksum, false,
  241. /*sync_metadata_str=*/nullptr);
  242. }
  243. // Verifies no crash if a node does not have an id.
  244. // This is a regression test for: https://crbug.com/1232410 .
  245. TEST_F(BookmarkCodecTest, DecodeWithNoId) {
  246. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  247. std::string enc_checksum;
  248. base::Value value =
  249. EncodeHelper(model_to_encode.get(), /*sync_metadata_str=*/std::string(),
  250. &enc_checksum);
  251. // Remove an id.
  252. base::Value* child1_value = nullptr;
  253. GetBookmarksBarChildValue(&value, 0, &child1_value);
  254. ASSERT_TRUE(child1_value->RemoveKey(BookmarkCodec::kIdKey));
  255. std::string dec_checksum;
  256. std::unique_ptr<BookmarkModel> decoded_model1 =
  257. DecodeHelper(value, enc_checksum, &dec_checksum, true,
  258. /*sync_metadata_str=*/nullptr);
  259. // Test succeeds if no crash.
  260. }
  261. TEST_F(BookmarkCodecTest, ChecksumManualEditIDsTest) {
  262. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel3());
  263. // The test depends on existence of multiple children under bookmark bar, so
  264. // make sure that's the case.
  265. size_t bb_child_count =
  266. model_to_encode->bookmark_bar_node()->children().size();
  267. ASSERT_GT(bb_child_count, 1u);
  268. std::string enc_checksum;
  269. base::Value value =
  270. EncodeHelper(model_to_encode.get(), /*sync_metadata_str=*/std::string(),
  271. &enc_checksum);
  272. // Change IDs for all children of bookmark bar to be 1.
  273. base::Value* child_value = nullptr;
  274. for (size_t i = 0; i < bb_child_count; ++i) {
  275. GetBookmarksBarChildValue(&value, i, &child_value);
  276. std::string* id = child_value->FindStringKey(BookmarkCodec::kIdKey);
  277. ASSERT_TRUE(id);
  278. child_value->SetStringKey(BookmarkCodec::kIdKey, "1");
  279. }
  280. std::string dec_checksum;
  281. std::unique_ptr<BookmarkModel> decoded_model =
  282. DecodeHelper(value, enc_checksum, &dec_checksum, true,
  283. /*sync_metadata_str=*/nullptr);
  284. ExpectIDsUnique(decoded_model.get());
  285. // add a few extra nodes to bookmark model and make sure IDs are still uniuqe.
  286. const BookmarkNode* bb_node = decoded_model->bookmark_bar_node();
  287. decoded_model->AddURL(bb_node, 0, u"new url1", GURL("http://newurl1.com"));
  288. decoded_model->AddURL(bb_node, 0, u"new url2", GURL("http://newurl2.com"));
  289. ExpectIDsUnique(decoded_model.get());
  290. }
  291. TEST_F(BookmarkCodecTest, PersistIDsTest) {
  292. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel3());
  293. BookmarkCodec encoder;
  294. base::Value model_value(encoder.Encode(model_to_encode.get(), std::string()));
  295. std::unique_ptr<BookmarkModel> decoded_model(
  296. TestBookmarkClient::CreateModel());
  297. BookmarkCodec decoder;
  298. ASSERT_TRUE(Decode(&decoder, model_value, decoded_model.get(),
  299. /*sync_metadata_str=*/nullptr));
  300. ASSERT_NO_FATAL_FAILURE(
  301. AssertModelsEqual(model_to_encode.get(), decoded_model.get()));
  302. // Add a couple of more items to the decoded bookmark model and make sure
  303. // ID persistence is working properly.
  304. const BookmarkNode* bookmark_bar = decoded_model->bookmark_bar_node();
  305. decoded_model->AddURL(bookmark_bar, bookmark_bar->children().size(),
  306. kUrl3Title, GURL(kUrl3Url));
  307. const BookmarkNode* folder2_node = decoded_model->AddFolder(
  308. bookmark_bar, bookmark_bar->children().size(), kFolder2Title);
  309. decoded_model->AddURL(folder2_node, 0, kUrl4Title, GURL(kUrl4Url));
  310. BookmarkCodec encoder2;
  311. base::Value model_value2(encoder2.Encode(decoded_model.get(), std::string()));
  312. std::unique_ptr<BookmarkModel> decoded_model2(
  313. TestBookmarkClient::CreateModel());
  314. BookmarkCodec decoder2;
  315. ASSERT_TRUE(Decode(&decoder2, model_value2, decoded_model2.get(),
  316. /*sync_metadata_str=*/nullptr));
  317. ASSERT_NO_FATAL_FAILURE(
  318. AssertModelsEqual(decoded_model.get(), decoded_model2.get()));
  319. }
  320. TEST_F(BookmarkCodecTest, CannotDecodeModelWithoutMobileBookmarks) {
  321. base::FilePath test_file =
  322. GetTestDataDir().AppendASCII("bookmarks/model_without_sync.json");
  323. ASSERT_TRUE(base::PathExists(test_file));
  324. JSONFileValueDeserializer deserializer(test_file);
  325. std::unique_ptr<base::Value> root =
  326. deserializer.Deserialize(nullptr, nullptr);
  327. std::unique_ptr<BookmarkModel> decoded_model(
  328. TestBookmarkClient::CreateModel());
  329. BookmarkCodec decoder;
  330. EXPECT_FALSE(Decode(&decoder, *root.get(), decoded_model.get(),
  331. /*sync_metadata_str=*/nullptr));
  332. }
  333. TEST_F(BookmarkCodecTest, EncodeAndDecodeMetaInfo) {
  334. // Add meta info and encode.
  335. std::unique_ptr<BookmarkModel> model(CreateTestModel1());
  336. model->SetNodeMetaInfo(model->root_node(), "model_info", "value1");
  337. model->SetNodeMetaInfo(model->bookmark_bar_node()->children().front().get(),
  338. "node_info", "value2");
  339. std::string checksum;
  340. base::Value value =
  341. EncodeHelper(model.get(), /*sync_metadata_str=*/std::string(), &checksum);
  342. // Decode and check for meta info.
  343. model = DecodeHelper(value, checksum, &checksum, false,
  344. /*sync_metadata_str=*/nullptr);
  345. std::string meta_value;
  346. EXPECT_TRUE(model->root_node()->GetMetaInfo("model_info", &meta_value));
  347. EXPECT_EQ("value1", meta_value);
  348. EXPECT_FALSE(model->root_node()->GetMetaInfo("other_key", &meta_value));
  349. const BookmarkNode* bbn = model->bookmark_bar_node();
  350. ASSERT_EQ(1u, bbn->children().size());
  351. const BookmarkNode* child = bbn->children().front().get();
  352. EXPECT_TRUE(child->GetMetaInfo("node_info", &meta_value));
  353. EXPECT_EQ("value2", meta_value);
  354. EXPECT_FALSE(child->GetMetaInfo("other_key", &meta_value));
  355. }
  356. // Verifies that we can still decode the old codec format after changing the
  357. // way meta info is stored.
  358. TEST_F(BookmarkCodecTest, CanDecodeMetaInfoAsString) {
  359. base::FilePath test_file =
  360. GetTestDataDir().AppendASCII("bookmarks/meta_info_as_string.json");
  361. ASSERT_TRUE(base::PathExists(test_file));
  362. JSONFileValueDeserializer deserializer(test_file);
  363. std::unique_ptr<base::Value> root =
  364. deserializer.Deserialize(nullptr, nullptr);
  365. std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
  366. BookmarkCodec decoder;
  367. ASSERT_TRUE(Decode(&decoder, *root.get(), model.get(),
  368. /*sync_metadata_str=*/nullptr));
  369. const BookmarkNode* bbn = model->bookmark_bar_node();
  370. const char kNormalKey[] = "key";
  371. const char kNestedKey[] = "nested.key";
  372. std::string meta_value;
  373. EXPECT_TRUE(bbn->children()[0]->GetMetaInfo(kNormalKey, &meta_value));
  374. EXPECT_EQ("value", meta_value);
  375. EXPECT_TRUE(bbn->children()[1]->GetMetaInfo(kNormalKey, &meta_value));
  376. EXPECT_EQ("value2", meta_value);
  377. EXPECT_TRUE(bbn->children()[0]->GetMetaInfo(kNestedKey, &meta_value));
  378. EXPECT_EQ("value3", meta_value);
  379. }
  380. TEST_F(BookmarkCodecTest, EncodeAndDecodeSyncMetadata) {
  381. std::unique_ptr<BookmarkModel> model(CreateTestModel1());
  382. // Since metadata str serialized proto, it could contain no ASCII characters.
  383. std::string sync_metadata_str("a/2'\"");
  384. std::string checksum;
  385. base::Value value = EncodeHelper(model.get(), sync_metadata_str, &checksum);
  386. std::string decoded_sync_metadata_str;
  387. // Decode and verify.
  388. DecodeHelper(value, checksum, &checksum, false, &decoded_sync_metadata_str);
  389. EXPECT_EQ(sync_metadata_str, decoded_sync_metadata_str);
  390. }
  391. TEST_F(BookmarkCodecTest, EncodeAndDecodeGuid) {
  392. std::unique_ptr<BookmarkModel> model(CreateTestModel2());
  393. ASSERT_TRUE(model->bookmark_bar_node()->children()[0]->guid().is_valid());
  394. ASSERT_TRUE(model->bookmark_bar_node()->children()[1]->guid().is_valid());
  395. ASSERT_NE(model->bookmark_bar_node()->children()[0]->guid(),
  396. model->bookmark_bar_node()->children()[1]->guid());
  397. std::string checksum;
  398. base::Value model_value =
  399. EncodeHelper(model.get(), /*sync_metadata_str=*/std::string(), &checksum);
  400. // Decode and check for GUIDs.
  401. std::unique_ptr<BookmarkModel> decoded_model =
  402. DecodeHelper(model_value, checksum, &checksum, /*expected_changes=*/false,
  403. /*sync_metadata_str=*/nullptr);
  404. ASSERT_NO_FATAL_FAILURE(AssertModelsEqual(model.get(), decoded_model.get()));
  405. EXPECT_EQ(model->bookmark_bar_node()->children()[0]->guid(),
  406. decoded_model->bookmark_bar_node()->children()[0]->guid());
  407. EXPECT_EQ(model->bookmark_bar_node()->children()[1]->guid(),
  408. decoded_model->bookmark_bar_node()->children()[1]->guid());
  409. }
  410. TEST_F(BookmarkCodecTest, ReassignEmptyGUID) {
  411. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  412. BookmarkCodec encoder;
  413. base::Value value(encoder.Encode(model_to_encode.get(), std::string()));
  414. std::unique_ptr<BookmarkModel> decoded_model1(
  415. TestBookmarkClient::CreateModel());
  416. BookmarkCodec decoder1;
  417. ASSERT_TRUE(Decode(&decoder1, value, decoded_model1.get(),
  418. /*sync_metadata_str=*/nullptr));
  419. EXPECT_FALSE(decoder1.guids_reassigned());
  420. // Change GUID of child to be empty.
  421. base::Value* child_value = nullptr;
  422. GetBookmarksBarChildValue(&value, 0, &child_value);
  423. std::string* guid_str = child_value->FindStringKey(BookmarkCodec::kGuidKey);
  424. ASSERT_TRUE(guid_str);
  425. std::string original_guid_str = *guid_str;
  426. child_value->SetStringKey(BookmarkCodec::kGuidKey, "");
  427. std::unique_ptr<BookmarkModel> decoded_model2(
  428. TestBookmarkClient::CreateModel());
  429. BookmarkCodec decoder2;
  430. ASSERT_TRUE(Decode(&decoder2, value, decoded_model2.get(),
  431. /*sync_metadata_str=*/nullptr));
  432. const base::GUID guid = base::GUID::ParseCaseInsensitive(original_guid_str);
  433. ASSERT_TRUE(guid.is_valid());
  434. EXPECT_NE(guid, decoded_model2->bookmark_bar_node()->children()[0]->guid());
  435. EXPECT_TRUE(
  436. decoded_model2->bookmark_bar_node()->children()[0]->guid().is_valid());
  437. EXPECT_TRUE(decoder2.guids_reassigned());
  438. }
  439. TEST_F(BookmarkCodecTest, ReassignMissingGUID) {
  440. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  441. BookmarkCodec encoder;
  442. base::Value value(encoder.Encode(model_to_encode.get(), std::string()));
  443. std::unique_ptr<BookmarkModel> decoded_model1(
  444. TestBookmarkClient::CreateModel());
  445. BookmarkCodec decoder1;
  446. ASSERT_TRUE(Decode(&decoder1, value, decoded_model1.get(),
  447. /*sync_metadata_str=*/nullptr));
  448. EXPECT_FALSE(decoder1.guids_reassigned());
  449. // Change GUID of child to be missing.
  450. base::Value* child_value = nullptr;
  451. GetBookmarksBarChildValue(&value, 0, &child_value);
  452. std::string* guid_str = child_value->FindStringKey(BookmarkCodec::kGuidKey);
  453. ASSERT_TRUE(guid_str);
  454. std::string original_guid_str = *guid_str;
  455. child_value->RemoveKey(BookmarkCodec::kGuidKey);
  456. std::unique_ptr<BookmarkModel> decoded_model2(
  457. TestBookmarkClient::CreateModel());
  458. BookmarkCodec decoder2;
  459. ASSERT_TRUE(Decode(&decoder2, value, decoded_model2.get(),
  460. /*sync_metadata_str=*/nullptr));
  461. const base::GUID guid = base::GUID::ParseCaseInsensitive(original_guid_str);
  462. ASSERT_TRUE(guid.is_valid());
  463. EXPECT_NE(guid, decoded_model2->bookmark_bar_node()->children()[0]->guid());
  464. EXPECT_TRUE(
  465. decoded_model2->bookmark_bar_node()->children()[0]->guid().is_valid());
  466. EXPECT_TRUE(decoder2.guids_reassigned());
  467. }
  468. TEST_F(BookmarkCodecTest, ReassignInvalidGUID) {
  469. const std::string kInvalidGuid = "0000";
  470. ASSERT_FALSE(base::GUID::ParseCaseInsensitive(kInvalidGuid).is_valid());
  471. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  472. BookmarkCodec encoder;
  473. base::Value value(encoder.Encode(model_to_encode.get(), std::string()));
  474. // Change GUID of child to be invalid.
  475. base::Value* child_value = nullptr;
  476. GetBookmarksBarChildValue(&value, 0, &child_value);
  477. child_value->SetStringKey(BookmarkCodec::kGuidKey, kInvalidGuid);
  478. std::string* guid = child_value->FindStringKey(BookmarkCodec::kGuidKey);
  479. ASSERT_TRUE(guid);
  480. ASSERT_EQ(*guid, kInvalidGuid);
  481. std::unique_ptr<BookmarkModel> decoded_model(
  482. TestBookmarkClient::CreateModel());
  483. BookmarkCodec decoder;
  484. ASSERT_TRUE(Decode(&decoder, value, decoded_model.get(),
  485. /*sync_metadata_str=*/nullptr));
  486. EXPECT_TRUE(decoder.guids_reassigned());
  487. EXPECT_TRUE(
  488. decoded_model->bookmark_bar_node()->children()[0]->guid().is_valid());
  489. }
  490. TEST_F(BookmarkCodecTest, ReassignDuplicateGUID) {
  491. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel2());
  492. BookmarkCodec encoder;
  493. base::Value value(encoder.Encode(model_to_encode.get(), std::string()));
  494. base::Value* child1_value = nullptr;
  495. GetBookmarksBarChildValue(&value, 0, &child1_value);
  496. std::string* child1_guid =
  497. child1_value->FindStringKey(BookmarkCodec::kGuidKey);
  498. ASSERT_TRUE(child1_guid);
  499. base::Value* child2_value = nullptr;
  500. GetBookmarksBarChildValue(&value, 1, &child2_value);
  501. // Change GUID of child to be duplicate.
  502. child2_value->SetStringKey(BookmarkCodec::kGuidKey, *child1_guid);
  503. std::string* child2_guid =
  504. child2_value->FindStringKey(BookmarkCodec::kGuidKey);
  505. ASSERT_TRUE(child2_guid);
  506. ASSERT_EQ(*child1_guid, *child2_guid);
  507. std::unique_ptr<BookmarkModel> decoded_model(
  508. TestBookmarkClient::CreateModel());
  509. BookmarkCodec decoder;
  510. ASSERT_TRUE(Decode(&decoder, value, decoded_model.get(),
  511. /*sync_metadata_str=*/nullptr));
  512. EXPECT_TRUE(decoder.guids_reassigned());
  513. EXPECT_NE(decoded_model->bookmark_bar_node()->children()[0]->guid(),
  514. decoded_model->bookmark_bar_node()->children()[1]->guid());
  515. }
  516. TEST_F(BookmarkCodecTest, ReassignBannedGUID) {
  517. const base::GUID kBannedGuid =
  518. base::GUID::ParseLowercase(BookmarkNode::kBannedGuidDueToPastSyncBug);
  519. ASSERT_TRUE(kBannedGuid.is_valid());
  520. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  521. BookmarkCodec encoder;
  522. base::Value value(encoder.Encode(model_to_encode.get(), std::string()));
  523. // Change GUID of child to be invalid.
  524. base::Value* child_value = nullptr;
  525. GetBookmarksBarChildValue(&value, 0, &child_value);
  526. child_value->SetStringKey(BookmarkCodec::kGuidKey,
  527. kBannedGuid.AsLowercaseString());
  528. std::unique_ptr<BookmarkModel> decoded_model(
  529. TestBookmarkClient::CreateModel());
  530. BookmarkCodec decoder;
  531. ASSERT_TRUE(Decode(&decoder, value, decoded_model.get(),
  532. /*sync_metadata_str=*/nullptr));
  533. EXPECT_TRUE(decoder.guids_reassigned());
  534. EXPECT_TRUE(
  535. decoded_model->bookmark_bar_node()->children()[0]->guid().is_valid());
  536. EXPECT_NE(decoded_model->bookmark_bar_node()->children()[0]->guid(),
  537. kBannedGuid);
  538. }
  539. TEST_F(BookmarkCodecTest, ReassignPermanentNodeDuplicateGUID) {
  540. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  541. BookmarkCodec encoder;
  542. base::Value value(encoder.Encode(model_to_encode.get(), std::string()));
  543. base::Value* child_value = nullptr;
  544. GetBookmarksBarChildValue(&value, 0, &child_value);
  545. // Change GUID of child to be the root node GUID.
  546. child_value->SetStringKey(BookmarkCodec::kGuidKey,
  547. BookmarkNode::kRootNodeGuid);
  548. std::string* child_guid = child_value->FindStringKey(BookmarkCodec::kGuidKey);
  549. ASSERT_TRUE(child_guid);
  550. ASSERT_EQ(BookmarkNode::kRootNodeGuid, *child_guid);
  551. std::unique_ptr<BookmarkModel> decoded_model(
  552. TestBookmarkClient::CreateModel());
  553. BookmarkCodec decoder;
  554. ASSERT_TRUE(Decode(&decoder, value, decoded_model.get(),
  555. /*sync_metadata_str=*/nullptr));
  556. EXPECT_TRUE(decoder.guids_reassigned());
  557. EXPECT_NE(base::GUID::ParseLowercase(BookmarkNode::kRootNodeGuid),
  558. decoded_model->bookmark_bar_node()->children()[0]->guid());
  559. }
  560. TEST_F(BookmarkCodecTest, CanonicalizeGUID) {
  561. const base::GUID kGuid = base::GUID::GenerateRandomV4();
  562. const std::string kUpperCaseGuid =
  563. base::ToUpperASCII(kGuid.AsLowercaseString());
  564. std::unique_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  565. BookmarkCodec encoder;
  566. base::Value value(encoder.Encode(model_to_encode.get(), std::string()));
  567. // Change a GUID to a capitalized form, which could have been produced by an
  568. // older version of the browser, before canonicalization was enforced.
  569. base::Value* child_value = nullptr;
  570. GetBookmarksBarChildValue(&value, 0, &child_value);
  571. child_value->SetStringKey(BookmarkCodec::kGuidKey, kUpperCaseGuid);
  572. std::unique_ptr<BookmarkModel> decoded_model2(
  573. TestBookmarkClient::CreateModel());
  574. BookmarkCodec decoder2;
  575. ASSERT_TRUE(Decode(&decoder2, value, decoded_model2.get(),
  576. /*sync_metadata_str=*/nullptr));
  577. EXPECT_EQ(kGuid, decoded_model2->bookmark_bar_node()->children()[0]->guid());
  578. }
  579. } // namespace bookmarks