| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 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 #include "sync/syncable/parent_child_index.h" | |
| 6 | |
| 7 #include <list> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/stl_util.h" | |
| 11 #include "base/strings/string_number_conversions.h" | |
| 12 #include "sync/syncable/entry_kernel.h" | |
| 13 #include "sync/syncable/syncable_util.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 | |
| 16 namespace syncer { | |
| 17 namespace syncable { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 static const std::string kCacheGuid = "8HhNIHlEOCGQbIAALr9QEg=="; | |
| 22 | |
| 23 } // namespace | |
| 24 | |
| 25 class ParentChildIndexTest : public testing::Test { | |
| 26 public: | |
| 27 void TearDown() override { | |
| 28 // To make memory management easier, we take ownership of all EntryKernels | |
| 29 // returned by our factory methods and delete them here. | |
| 30 STLDeleteElements(&owned_entry_kernels_); | |
| 31 } | |
| 32 | |
| 33 // Unfortunately, we can't use the regular Entry factory methods, because the | |
| 34 // ParentChildIndex deals in EntryKernels. | |
| 35 | |
| 36 static syncable::Id GetBookmarkRootId() { | |
| 37 return syncable::Id::CreateFromServerId("bookmark_folder"); | |
| 38 } | |
| 39 | |
| 40 static syncable::Id GetBookmarkId(int n) { | |
| 41 return syncable::Id::CreateFromServerId("b" + base::IntToString(n)); | |
| 42 } | |
| 43 | |
| 44 static syncable::Id GetClientUniqueId(int n) { | |
| 45 return syncable::Id::CreateFromServerId("c" + base::IntToString(n)); | |
| 46 } | |
| 47 | |
| 48 EntryKernel* MakeRoot() { | |
| 49 // Mimics the root node. | |
| 50 EntryKernel* root = new EntryKernel(); | |
| 51 root->put(META_HANDLE, 1); | |
| 52 root->put(BASE_VERSION, -1); | |
| 53 root->put(SERVER_VERSION, 0); | |
| 54 root->put(IS_DIR, true); | |
| 55 root->put(ID, syncable::Id::GetRoot()); | |
| 56 root->put(PARENT_ID, syncable::Id::GetRoot()); | |
| 57 | |
| 58 owned_entry_kernels_.push_back(root); | |
| 59 return root; | |
| 60 } | |
| 61 | |
| 62 EntryKernel* MakeTypeRoot(ModelType model_type, const syncable::Id& id) { | |
| 63 // Mimics a server-created bookmark folder. | |
| 64 EntryKernel* folder = new EntryKernel; | |
| 65 folder->put(META_HANDLE, 1); | |
| 66 folder->put(BASE_VERSION, 9); | |
| 67 folder->put(SERVER_VERSION, 9); | |
| 68 folder->put(IS_DIR, true); | |
| 69 folder->put(ID, id); | |
| 70 folder->put(PARENT_ID, syncable::Id::GetRoot()); | |
| 71 folder->put(UNIQUE_SERVER_TAG, ModelTypeToRootTag(model_type)); | |
| 72 | |
| 73 // Ensure that GetModelType() returns a correct value. | |
| 74 sync_pb::EntitySpecifics specifics; | |
| 75 AddDefaultFieldValue(model_type, &specifics); | |
| 76 folder->put(SPECIFICS, specifics); | |
| 77 | |
| 78 owned_entry_kernels_.push_back(folder); | |
| 79 return folder; | |
| 80 } | |
| 81 | |
| 82 EntryKernel* MakeBookmarkRoot() { | |
| 83 return MakeTypeRoot(BOOKMARKS, GetBookmarkRootId()); | |
| 84 } | |
| 85 | |
| 86 EntryKernel* MakeBookmark(int n, int pos, bool is_dir) { | |
| 87 // Mimics a regular bookmark or folder. | |
| 88 EntryKernel* bm = new EntryKernel(); | |
| 89 bm->put(META_HANDLE, n); | |
| 90 bm->put(BASE_VERSION, 10); | |
| 91 bm->put(SERVER_VERSION, 10); | |
| 92 bm->put(IS_DIR, is_dir); | |
| 93 bm->put(ID, GetBookmarkId(n)); | |
| 94 bm->put(PARENT_ID, GetBookmarkRootId()); | |
| 95 | |
| 96 bm->put(UNIQUE_BOOKMARK_TAG, | |
| 97 syncable::GenerateSyncableBookmarkHash(kCacheGuid, | |
| 98 bm->ref(ID).GetServerId())); | |
| 99 | |
| 100 UniquePosition unique_pos = | |
| 101 UniquePosition::FromInt64(pos, bm->ref(UNIQUE_BOOKMARK_TAG)); | |
| 102 bm->put(UNIQUE_POSITION, unique_pos); | |
| 103 bm->put(SERVER_UNIQUE_POSITION, unique_pos); | |
| 104 | |
| 105 owned_entry_kernels_.push_back(bm); | |
| 106 return bm; | |
| 107 } | |
| 108 | |
| 109 EntryKernel* MakeUniqueClientItem(ModelType model_type, | |
| 110 int n, | |
| 111 const syncable::Id& parent_id) { | |
| 112 EntryKernel* item = new EntryKernel(); | |
| 113 item->put(META_HANDLE, n); | |
| 114 item->put(BASE_VERSION, 10); | |
| 115 item->put(SERVER_VERSION, 10); | |
| 116 item->put(IS_DIR, false); | |
| 117 item->put(ID, GetClientUniqueId(n)); | |
| 118 item->put(UNIQUE_CLIENT_TAG, base::IntToString(n)); | |
| 119 | |
| 120 if (!parent_id.IsNull()) { | |
| 121 item->put(PARENT_ID, parent_id); | |
| 122 } | |
| 123 | |
| 124 if (model_type != UNSPECIFIED) { | |
| 125 // Ensure that GetModelType() returns a correct value. | |
| 126 sync_pb::EntitySpecifics specifics; | |
| 127 AddDefaultFieldValue(model_type, &specifics); | |
| 128 item->put(SPECIFICS, specifics); | |
| 129 } | |
| 130 | |
| 131 owned_entry_kernels_.push_back(item); | |
| 132 return item; | |
| 133 } | |
| 134 | |
| 135 EntryKernel* MakeUniqueClientItem(int n, const syncable::Id& parent_id) { | |
| 136 return MakeUniqueClientItem(UNSPECIFIED, n, parent_id); | |
| 137 } | |
| 138 | |
| 139 EntryKernel* MakeUniqueClientItem(ModelType model_type, int n) { | |
| 140 return MakeUniqueClientItem(model_type, n, Id()); | |
| 141 } | |
| 142 | |
| 143 const syncable::Id& IndexKnownModelTypeRootId(ModelType model_type) const { | |
| 144 return index_.GetModelTypeRootId(model_type); | |
| 145 } | |
| 146 | |
| 147 ParentChildIndex index_; | |
| 148 | |
| 149 private: | |
| 150 std::list<EntryKernel*> owned_entry_kernels_; | |
| 151 }; | |
| 152 | |
| 153 TEST_F(ParentChildIndexTest, TestRootNode) { | |
| 154 EntryKernel* root = MakeRoot(); | |
| 155 EXPECT_FALSE(ParentChildIndex::ShouldInclude(root)); | |
| 156 } | |
| 157 | |
| 158 TEST_F(ParentChildIndexTest, TestBookmarkRootFolder) { | |
| 159 EntryKernel* bm_folder = MakeBookmarkRoot(); | |
| 160 EXPECT_TRUE(ParentChildIndex::ShouldInclude(bm_folder)); | |
| 161 | |
| 162 index_.Insert(bm_folder); | |
| 163 // Since BOOKMARKS is a hierarchical type, its type root folder shouldn't be | |
| 164 // tracked by ParentChildIndex. | |
| 165 EXPECT_EQ(Id(), IndexKnownModelTypeRootId(BOOKMARKS)); | |
| 166 } | |
| 167 | |
| 168 // Tests iteration over a set of siblings. | |
| 169 TEST_F(ParentChildIndexTest, ChildInsertionAndIteration) { | |
| 170 EntryKernel* bm_folder = MakeBookmarkRoot(); | |
| 171 index_.Insert(bm_folder); | |
| 172 | |
| 173 // Make some folder and non-folder entries. | |
| 174 EntryKernel* b1 = MakeBookmark(1, 1, false); | |
| 175 EntryKernel* b2 = MakeBookmark(2, 2, false); | |
| 176 EntryKernel* b3 = MakeBookmark(3, 3, true); | |
| 177 EntryKernel* b4 = MakeBookmark(4, 4, false); | |
| 178 | |
| 179 // Insert them out-of-order to test different cases. | |
| 180 index_.Insert(b3); // Only child. | |
| 181 index_.Insert(b4); // Right-most child. | |
| 182 index_.Insert(b1); // Left-most child. | |
| 183 index_.Insert(b2); // Between existing items. | |
| 184 | |
| 185 // Double-check they've been added. | |
| 186 EXPECT_TRUE(index_.Contains(b1)); | |
| 187 EXPECT_TRUE(index_.Contains(b2)); | |
| 188 EXPECT_TRUE(index_.Contains(b3)); | |
| 189 EXPECT_TRUE(index_.Contains(b4)); | |
| 190 | |
| 191 // Check the ordering. | |
| 192 const OrderedChildSet* children = index_.GetChildren(GetBookmarkRootId()); | |
| 193 ASSERT_TRUE(children); | |
| 194 ASSERT_EQ(children->size(), 4UL); | |
| 195 OrderedChildSet::const_iterator it = children->begin(); | |
| 196 EXPECT_EQ(*it, b1); | |
| 197 it++; | |
| 198 EXPECT_EQ(*it, b2); | |
| 199 it++; | |
| 200 EXPECT_EQ(*it, b3); | |
| 201 it++; | |
| 202 EXPECT_EQ(*it, b4); | |
| 203 it++; | |
| 204 EXPECT_TRUE(it == children->end()); | |
| 205 } | |
| 206 | |
| 207 // Tests iteration when hierarchy is involved. | |
| 208 TEST_F(ParentChildIndexTest, ChildInsertionAndIterationWithHierarchy) { | |
| 209 EntryKernel* bm_folder = MakeBookmarkRoot(); | |
| 210 index_.Insert(bm_folder); | |
| 211 | |
| 212 // Just below the root, we have folders f1 and f2. | |
| 213 EntryKernel* f1 = MakeBookmark(1, 1, false); | |
| 214 EntryKernel* f2 = MakeBookmark(2, 2, false); | |
| 215 EntryKernel* f3 = MakeBookmark(3, 3, false); | |
| 216 | |
| 217 // Under folder f1, we have two bookmarks. | |
| 218 EntryKernel* f1_b1 = MakeBookmark(101, 1, false); | |
| 219 f1_b1->put(PARENT_ID, GetBookmarkId(1)); | |
| 220 EntryKernel* f1_b2 = MakeBookmark(102, 2, false); | |
| 221 f1_b2->put(PARENT_ID, GetBookmarkId(1)); | |
| 222 | |
| 223 // Under folder f2, there is one bookmark. | |
| 224 EntryKernel* f2_b1 = MakeBookmark(201, 1, false); | |
| 225 f2_b1->put(PARENT_ID, GetBookmarkId(2)); | |
| 226 | |
| 227 // Under folder f3, there is nothing. | |
| 228 | |
| 229 // Insert in a strange order, because we can. | |
| 230 index_.Insert(f1_b2); | |
| 231 index_.Insert(f2); | |
| 232 index_.Insert(f2_b1); | |
| 233 index_.Insert(f1); | |
| 234 index_.Insert(f1_b1); | |
| 235 index_.Insert(f3); | |
| 236 | |
| 237 OrderedChildSet::const_iterator it; | |
| 238 | |
| 239 // Iterate over children of the bookmark root. | |
| 240 const OrderedChildSet* top_children = index_.GetChildren(GetBookmarkRootId()); | |
| 241 ASSERT_TRUE(top_children); | |
| 242 ASSERT_EQ(top_children->size(), 3UL); | |
| 243 it = top_children->begin(); | |
| 244 EXPECT_EQ(*it, f1); | |
| 245 it++; | |
| 246 EXPECT_EQ(*it, f2); | |
| 247 it++; | |
| 248 EXPECT_EQ(*it, f3); | |
| 249 it++; | |
| 250 EXPECT_TRUE(it == top_children->end()); | |
| 251 | |
| 252 // Iterate over children of the first folder. | |
| 253 const OrderedChildSet* f1_children = index_.GetChildren(GetBookmarkId(1)); | |
| 254 ASSERT_TRUE(f1_children); | |
| 255 ASSERT_EQ(f1_children->size(), 2UL); | |
| 256 it = f1_children->begin(); | |
| 257 EXPECT_EQ(*it, f1_b1); | |
| 258 it++; | |
| 259 EXPECT_EQ(*it, f1_b2); | |
| 260 it++; | |
| 261 EXPECT_TRUE(it == f1_children->end()); | |
| 262 | |
| 263 // Iterate over children of the second folder. | |
| 264 const OrderedChildSet* f2_children = index_.GetChildren(GetBookmarkId(2)); | |
| 265 ASSERT_TRUE(f2_children); | |
| 266 ASSERT_EQ(f2_children->size(), 1UL); | |
| 267 it = f2_children->begin(); | |
| 268 EXPECT_EQ(*it, f2_b1); | |
| 269 it++; | |
| 270 EXPECT_TRUE(it == f2_children->end()); | |
| 271 | |
| 272 // Check for children of the third folder. | |
| 273 const OrderedChildSet* f3_children = index_.GetChildren(GetBookmarkId(3)); | |
| 274 EXPECT_FALSE(f3_children); | |
| 275 } | |
| 276 | |
| 277 // Tests removing items. | |
| 278 TEST_F(ParentChildIndexTest, RemoveWithHierarchy) { | |
| 279 EntryKernel* bm_folder = MakeBookmarkRoot(); | |
| 280 index_.Insert(bm_folder); | |
| 281 | |
| 282 // Just below the root, we have folders f1 and f2. | |
| 283 EntryKernel* f1 = MakeBookmark(1, 1, false); | |
| 284 EntryKernel* f2 = MakeBookmark(2, 2, false); | |
| 285 EntryKernel* f3 = MakeBookmark(3, 3, false); | |
| 286 | |
| 287 // Under folder f1, we have two bookmarks. | |
| 288 EntryKernel* f1_b1 = MakeBookmark(101, 1, false); | |
| 289 f1_b1->put(PARENT_ID, GetBookmarkId(1)); | |
| 290 EntryKernel* f1_b2 = MakeBookmark(102, 2, false); | |
| 291 f1_b2->put(PARENT_ID, GetBookmarkId(1)); | |
| 292 | |
| 293 // Under folder f2, there is one bookmark. | |
| 294 EntryKernel* f2_b1 = MakeBookmark(201, 1, false); | |
| 295 f2_b1->put(PARENT_ID, GetBookmarkId(2)); | |
| 296 | |
| 297 // Under folder f3, there is nothing. | |
| 298 | |
| 299 // Insert in any order. | |
| 300 index_.Insert(f2_b1); | |
| 301 index_.Insert(f3); | |
| 302 index_.Insert(f1_b2); | |
| 303 index_.Insert(f1); | |
| 304 index_.Insert(f2); | |
| 305 index_.Insert(f1_b1); | |
| 306 | |
| 307 // Check that all are in the index. | |
| 308 EXPECT_TRUE(index_.Contains(f1)); | |
| 309 EXPECT_TRUE(index_.Contains(f2)); | |
| 310 EXPECT_TRUE(index_.Contains(f3)); | |
| 311 EXPECT_TRUE(index_.Contains(f1_b1)); | |
| 312 EXPECT_TRUE(index_.Contains(f1_b2)); | |
| 313 EXPECT_TRUE(index_.Contains(f2_b1)); | |
| 314 | |
| 315 // Remove them all in any order. | |
| 316 index_.Remove(f3); | |
| 317 EXPECT_FALSE(index_.Contains(f3)); | |
| 318 index_.Remove(f1_b2); | |
| 319 EXPECT_FALSE(index_.Contains(f1_b2)); | |
| 320 index_.Remove(f2_b1); | |
| 321 EXPECT_FALSE(index_.Contains(f2_b1)); | |
| 322 index_.Remove(f1); | |
| 323 EXPECT_FALSE(index_.Contains(f1)); | |
| 324 index_.Remove(f2); | |
| 325 EXPECT_FALSE(index_.Contains(f2)); | |
| 326 index_.Remove(f1_b1); | |
| 327 EXPECT_FALSE(index_.Contains(f1_b1)); | |
| 328 } | |
| 329 | |
| 330 // Test that involves two non-ordered items. | |
| 331 TEST_F(ParentChildIndexTest, UnorderedChildren) { | |
| 332 // Make two unique client tag items under the root node. | |
| 333 EntryKernel* u1 = MakeUniqueClientItem(1, syncable::Id::GetRoot()); | |
| 334 EntryKernel* u2 = MakeUniqueClientItem(2, syncable::Id::GetRoot()); | |
| 335 | |
| 336 EXPECT_FALSE(u1->ShouldMaintainPosition()); | |
| 337 EXPECT_FALSE(u2->ShouldMaintainPosition()); | |
| 338 | |
| 339 index_.Insert(u1); | |
| 340 index_.Insert(u2); | |
| 341 | |
| 342 const OrderedChildSet* children = index_.GetChildren(syncable::Id::GetRoot()); | |
| 343 EXPECT_EQ(children->count(u1), 1UL); | |
| 344 EXPECT_EQ(children->count(u2), 1UL); | |
| 345 EXPECT_EQ(children->size(), 2UL); | |
| 346 } | |
| 347 | |
| 348 // Test ordered and non-ordered entries under the same parent. | |
| 349 // TODO(rlarocque): We should not need to support this. | |
| 350 TEST_F(ParentChildIndexTest, OrderedAndUnorderedChildren) { | |
| 351 EntryKernel* bm_folder = MakeBookmarkRoot(); | |
| 352 index_.Insert(bm_folder); | |
| 353 | |
| 354 EntryKernel* b1 = MakeBookmark(1, 1, false); | |
| 355 EntryKernel* b2 = MakeBookmark(2, 2, false); | |
| 356 EntryKernel* u1 = MakeUniqueClientItem(1, GetBookmarkRootId()); | |
| 357 | |
| 358 index_.Insert(b1); | |
| 359 index_.Insert(u1); | |
| 360 index_.Insert(b2); | |
| 361 | |
| 362 const OrderedChildSet* children = index_.GetChildren(GetBookmarkRootId()); | |
| 363 ASSERT_TRUE(children); | |
| 364 EXPECT_EQ(3UL, children->size()); | |
| 365 | |
| 366 // Ensure that the non-positionable item is moved to the far right. | |
| 367 OrderedChildSet::const_iterator it = children->begin(); | |
| 368 EXPECT_EQ(*it, b1); | |
| 369 it++; | |
| 370 EXPECT_EQ(*it, b2); | |
| 371 it++; | |
| 372 EXPECT_EQ(*it, u1); | |
| 373 it++; | |
| 374 EXPECT_TRUE(it == children->end()); | |
| 375 } | |
| 376 | |
| 377 TEST_F(ParentChildIndexTest, NodesWithImplicitParentId) { | |
| 378 syncable::Id type_root_id = syncable::Id::CreateFromServerId("type_root"); | |
| 379 EntryKernel* type_root = MakeTypeRoot(PREFERENCES, type_root_id); | |
| 380 index_.Insert(type_root); | |
| 381 EXPECT_EQ(type_root_id, IndexKnownModelTypeRootId(PREFERENCES)); | |
| 382 | |
| 383 // Create entries without parent ID | |
| 384 EntryKernel* p1 = MakeUniqueClientItem(PREFERENCES, 1); | |
| 385 EntryKernel* p2 = MakeUniqueClientItem(PREFERENCES, 2); | |
| 386 | |
| 387 index_.Insert(p1); | |
| 388 index_.Insert(p2); | |
| 389 | |
| 390 EXPECT_TRUE(index_.Contains(p1)); | |
| 391 EXPECT_TRUE(index_.Contains(p2)); | |
| 392 | |
| 393 // Items should appear under the type root | |
| 394 const OrderedChildSet* children = index_.GetChildren(type_root); | |
| 395 ASSERT_TRUE(children); | |
| 396 EXPECT_EQ(2UL, children->size()); | |
| 397 | |
| 398 EXPECT_EQ(2UL, index_.GetSiblings(p1)->size()); | |
| 399 EXPECT_EQ(2UL, index_.GetSiblings(p2)->size()); | |
| 400 | |
| 401 index_.Remove(p1); | |
| 402 | |
| 403 EXPECT_FALSE(index_.Contains(p1)); | |
| 404 EXPECT_TRUE(index_.Contains(p2)); | |
| 405 children = index_.GetChildren(type_root_id); | |
| 406 ASSERT_TRUE(children); | |
| 407 EXPECT_EQ(1UL, children->size()); | |
| 408 | |
| 409 index_.Remove(p2); | |
| 410 | |
| 411 EXPECT_FALSE(index_.Contains(p2)); | |
| 412 children = index_.GetChildren(type_root); | |
| 413 ASSERT_EQ(nullptr, children); | |
| 414 } | |
| 415 | |
| 416 // Test that the removal isn't sensitive to the order (PurgeEntriesWithTypeIn | |
| 417 // removes items in arbitrary order). | |
| 418 TEST_F(ParentChildIndexTest, RemoveOutOfOrder) { | |
| 419 // Insert a type root and two items (with implicit parent ID). | |
| 420 syncable::Id type_root_id = syncable::Id::CreateFromServerId("type_root"); | |
| 421 EntryKernel* type_root = MakeTypeRoot(PREFERENCES, type_root_id); | |
| 422 index_.Insert(type_root); | |
| 423 EntryKernel* p1 = MakeUniqueClientItem(PREFERENCES, 1); | |
| 424 EntryKernel* p2 = MakeUniqueClientItem(PREFERENCES, 2); | |
| 425 index_.Insert(p1); | |
| 426 index_.Insert(p2); | |
| 427 | |
| 428 // Two items expected under the type root. | |
| 429 const OrderedChildSet* children = index_.GetChildren(type_root); | |
| 430 ASSERT_TRUE(children); | |
| 431 EXPECT_EQ(2UL, children->size()); | |
| 432 | |
| 433 // Remove all 3 items in arbitrary order. | |
| 434 index_.Remove(p2); | |
| 435 index_.Remove(type_root); | |
| 436 index_.Remove(p1); | |
| 437 | |
| 438 EXPECT_EQ(nullptr, index_.GetChildren(type_root)); | |
| 439 | |
| 440 // Add a new root and another two items again. | |
| 441 type_root = MakeTypeRoot(PREFERENCES, type_root_id); | |
| 442 index_.Insert(type_root); | |
| 443 | |
| 444 index_.Insert(MakeUniqueClientItem(PREFERENCES, 3)); | |
| 445 index_.Insert(MakeUniqueClientItem(PREFERENCES, 4)); | |
| 446 | |
| 447 children = index_.GetChildren(type_root); | |
| 448 ASSERT_TRUE(children); | |
| 449 // Should have 2 items. If the out of order removal cleared the implicit | |
| 450 // parent folder ID prematurely, the collection would have 3 items including | |
| 451 // p1. | |
| 452 EXPECT_EQ(2UL, children->size()); | |
| 453 } | |
| 454 | |
| 455 // Test that the insert isn't sensitive to the order (Loading entries from | |
| 456 // Sync DB is done in arbitrary order). | |
| 457 TEST_F(ParentChildIndexTest, InsertOutOfOrder) { | |
| 458 // Insert two Preferences entries with implicit parent first | |
| 459 index_.Insert(MakeUniqueClientItem(PREFERENCES, 1)); | |
| 460 index_.Insert(MakeUniqueClientItem(PREFERENCES, 2)); | |
| 461 | |
| 462 // Then insert the Preferences type root | |
| 463 syncable::Id type_root_id = syncable::Id::CreateFromServerId("type_root"); | |
| 464 index_.Insert(MakeTypeRoot(PREFERENCES, type_root_id)); | |
| 465 | |
| 466 // The index should still be able to associate Preferences entries | |
| 467 // with the root. | |
| 468 const OrderedChildSet* children = index_.GetChildren(type_root_id); | |
| 469 ASSERT_TRUE(children); | |
| 470 EXPECT_EQ(2UL, children->size()); | |
| 471 } | |
| 472 | |
| 473 // Test that if for some reason we wind up with multiple type roots, we | |
| 474 // gracefully handle it and don't allow any new entities to become invisible. | |
| 475 TEST_F(ParentChildIndexTest, MultipleTypeRoots) { | |
| 476 // Create the good Preferences type root. | |
| 477 syncable::Id type_root_id = syncable::Id::CreateFromClientString("type_root"); | |
| 478 index_.Insert(MakeTypeRoot(PREFERENCES, type_root_id)); | |
| 479 | |
| 480 // Then insert the bad Preferences type root | |
| 481 syncable::Id bad_type_root_id = syncable::Id::CreateFromServerId("bad"); | |
| 482 index_.Insert(MakeTypeRoot(PREFERENCES, bad_type_root_id)); | |
| 483 | |
| 484 // Insert two Preferences entries with implicit parent. | |
| 485 index_.Insert(MakeUniqueClientItem(PREFERENCES, 1)); | |
| 486 index_.Insert(MakeUniqueClientItem(PREFERENCES, 2)); | |
| 487 | |
| 488 // The index should still be able to associate Preferences entries | |
| 489 // with the good and bad roots. | |
| 490 const OrderedChildSet* children = index_.GetChildren(type_root_id); | |
| 491 ASSERT_TRUE(children); | |
| 492 EXPECT_EQ(2UL, children->size()); | |
| 493 const OrderedChildSet* children_bad = index_.GetChildren(bad_type_root_id); | |
| 494 ASSERT_TRUE(children_bad); | |
| 495 EXPECT_EQ(2UL, children_bad->size()); | |
| 496 } | |
| 497 | |
| 498 // Test that if for some reason we wind up with multiple type roots, we | |
| 499 // gracefully handle it and don't allow any new entities to become invisible. | |
| 500 // Same as above but with the roots created in inverse order. | |
| 501 TEST_F(ParentChildIndexTest, MultipleTypeRootsInverse) { | |
| 502 // Create the bad Preferences type root | |
| 503 syncable::Id bad_type_root_id = syncable::Id::CreateFromServerId("bad"); | |
| 504 index_.Insert(MakeTypeRoot(PREFERENCES, bad_type_root_id)); | |
| 505 | |
| 506 // Then insert the good Preferences type root. | |
| 507 syncable::Id type_root_id = syncable::Id::CreateFromClientString("type_root"); | |
| 508 index_.Insert(MakeTypeRoot(PREFERENCES, type_root_id)); | |
| 509 | |
| 510 // Insert two Preferences entries with implicit parent. | |
| 511 index_.Insert(MakeUniqueClientItem(PREFERENCES, 1)); | |
| 512 index_.Insert(MakeUniqueClientItem(PREFERENCES, 2)); | |
| 513 | |
| 514 // The index should still be able to associate Preferences entries | |
| 515 // with the good root and bad roots. | |
| 516 const OrderedChildSet* children = index_.GetChildren(type_root_id); | |
| 517 ASSERT_TRUE(children); | |
| 518 EXPECT_EQ(2UL, children->size()); | |
| 519 const OrderedChildSet* children_bad = index_.GetChildren(bad_type_root_id); | |
| 520 ASSERT_TRUE(children_bad); | |
| 521 EXPECT_EQ(2UL, children_bad->size()); | |
| 522 } | |
| 523 | |
| 524 } // namespace syncable | |
| 525 } // namespace syncer | |
| 526 | |
| OLD | NEW |