| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "components/reading_list/ios/reading_list_store.h" | |
| 6 | |
| 7 #include <map> | |
| 8 #include <set> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/memory/ptr_util.h" | |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "base/run_loop.h" | |
| 14 #include "base/test/simple_test_clock.h" | |
| 15 #include "components/reading_list/ios/reading_list_model_impl.h" | |
| 16 #include "components/sync/model/fake_model_type_change_processor.h" | |
| 17 #include "components/sync/model/model_type_store_test_util.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // Tests that the transition from |entryA| to |entryB| is possible (|possible| | |
| 23 // is true) or not. | |
| 24 void ExpectAB(const sync_pb::ReadingListSpecifics& entryA, | |
| 25 const sync_pb::ReadingListSpecifics& entryB, | |
| 26 bool possible) { | |
| 27 EXPECT_EQ(ReadingListStore::CompareEntriesForSync(entryA, entryB), possible); | |
| 28 std::unique_ptr<ReadingListEntry> a = | |
| 29 ReadingListEntry::FromReadingListSpecifics(entryA, | |
| 30 base::Time::FromTimeT(10)); | |
| 31 std::unique_ptr<ReadingListEntry> b = | |
| 32 ReadingListEntry::FromReadingListSpecifics(entryB, | |
| 33 base::Time::FromTimeT(10)); | |
| 34 a->MergeWithEntry(*b); | |
| 35 std::unique_ptr<sync_pb::ReadingListSpecifics> mergedEntry = | |
| 36 a->AsReadingListSpecifics(); | |
| 37 if (possible) { | |
| 38 // If transition is possible, the merge should be B. | |
| 39 EXPECT_EQ(entryB.SerializeAsString(), mergedEntry->SerializeAsString()); | |
| 40 } else { | |
| 41 // If transition is not possible, the transition shold be possible to the | |
| 42 // merged state. | |
| 43 EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, *mergedEntry)); | |
| 44 EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryB, *mergedEntry)); | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 base::Time AdvanceAndGetTime(base::SimpleTestClock* clock) { | |
| 49 clock->Advance(base::TimeDelta::FromMilliseconds(10)); | |
| 50 return clock->Now(); | |
| 51 } | |
| 52 | |
| 53 } // namespace | |
| 54 | |
| 55 class FakeModelTypeChangeProcessorObserver { | |
| 56 public: | |
| 57 virtual void Put(const std::string& client_tag, | |
| 58 std::unique_ptr<syncer::EntityData> entity_data, | |
| 59 syncer::MetadataChangeList* metadata_change_list) = 0; | |
| 60 | |
| 61 virtual void Delete(const std::string& client_tag, | |
| 62 syncer::MetadataChangeList* metadata_change_list) = 0; | |
| 63 }; | |
| 64 | |
| 65 class TestModelTypeChangeProcessor | |
| 66 : public syncer::FakeModelTypeChangeProcessor { | |
| 67 public: | |
| 68 void SetObserver(FakeModelTypeChangeProcessorObserver* observer) { | |
| 69 observer_ = observer; | |
| 70 } | |
| 71 | |
| 72 void Put(const std::string& client_tag, | |
| 73 std::unique_ptr<syncer::EntityData> entity_data, | |
| 74 syncer::MetadataChangeList* metadata_change_list) override { | |
| 75 observer_->Put(client_tag, std::move(entity_data), metadata_change_list); | |
| 76 } | |
| 77 | |
| 78 void Delete(const std::string& client_tag, | |
| 79 syncer::MetadataChangeList* metadata_change_list) override { | |
| 80 observer_->Delete(client_tag, metadata_change_list); | |
| 81 } | |
| 82 | |
| 83 private: | |
| 84 FakeModelTypeChangeProcessorObserver* observer_; | |
| 85 }; | |
| 86 | |
| 87 class ReadingListStoreTest : public testing::Test, | |
| 88 public FakeModelTypeChangeProcessorObserver, | |
| 89 public ReadingListStoreDelegate { | |
| 90 protected: | |
| 91 ReadingListStoreTest() | |
| 92 : store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()) { | |
| 93 ClearState(); | |
| 94 reading_list_store_ = base::MakeUnique<ReadingListStore>( | |
| 95 base::Bind(&syncer::ModelTypeStoreTestUtil::MoveStoreToCallback, | |
| 96 base::Passed(&store_)), | |
| 97 base::Bind(&ReadingListStoreTest::CreateModelTypeChangeProcessor, | |
| 98 base::Unretained(this))); | |
| 99 auto clock = base::MakeUnique<base::SimpleTestClock>(); | |
| 100 clock_ = clock.get(); | |
| 101 model_ = base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr, | |
| 102 std::move(clock)); | |
| 103 reading_list_store_->SetReadingListModel(model_.get(), this, clock_); | |
| 104 | |
| 105 base::RunLoop().RunUntilIdle(); | |
| 106 } | |
| 107 | |
| 108 std::unique_ptr<syncer::ModelTypeChangeProcessor> | |
| 109 CreateModelTypeChangeProcessor(syncer::ModelType type, | |
| 110 syncer::ModelTypeSyncBridge* service) { | |
| 111 auto processor = base::MakeUnique<TestModelTypeChangeProcessor>(); | |
| 112 processor->SetObserver(this); | |
| 113 return std::move(processor); | |
| 114 } | |
| 115 | |
| 116 void Put(const std::string& storage_key, | |
| 117 std::unique_ptr<syncer::EntityData> entity_data, | |
| 118 syncer::MetadataChangeList* metadata_changes) override { | |
| 119 put_multimap_.insert(std::make_pair(storage_key, std::move(entity_data))); | |
| 120 put_called_++; | |
| 121 } | |
| 122 | |
| 123 void Delete(const std::string& storage_key, | |
| 124 syncer::MetadataChangeList* metadata_changes) override { | |
| 125 delete_set_.insert(storage_key); | |
| 126 delete_called_++; | |
| 127 } | |
| 128 | |
| 129 void AssertCounts(int put_called, | |
| 130 int delete_called, | |
| 131 int sync_add_called, | |
| 132 int sync_remove_called, | |
| 133 int sync_merge_called) { | |
| 134 EXPECT_EQ(put_called, put_called_); | |
| 135 EXPECT_EQ(delete_called, delete_called_); | |
| 136 EXPECT_EQ(sync_add_called, sync_add_called_); | |
| 137 EXPECT_EQ(sync_remove_called, sync_remove_called_); | |
| 138 EXPECT_EQ(sync_merge_called, sync_merge_called_); | |
| 139 } | |
| 140 | |
| 141 void ClearState() { | |
| 142 delete_called_ = 0; | |
| 143 put_called_ = 0; | |
| 144 delete_set_.clear(); | |
| 145 put_multimap_.clear(); | |
| 146 sync_add_called_ = 0; | |
| 147 sync_remove_called_ = 0; | |
| 148 sync_merge_called_ = 0; | |
| 149 sync_added_.clear(); | |
| 150 sync_removed_.clear(); | |
| 151 sync_merged_.clear(); | |
| 152 } | |
| 153 | |
| 154 // These three mathods handle callbacks from a ReadingListStore. | |
| 155 void StoreLoaded(std::unique_ptr<ReadingListEntries> entries) override {} | |
| 156 | |
| 157 // Handle sync events. | |
| 158 void SyncAddEntry(std::unique_ptr<ReadingListEntry> entry) override { | |
| 159 sync_add_called_++; | |
| 160 sync_added_[entry->URL().spec()] = entry->IsRead(); | |
| 161 } | |
| 162 | |
| 163 void SyncRemoveEntry(const GURL& gurl) override { | |
| 164 sync_remove_called_++; | |
| 165 sync_removed_.insert(gurl.spec()); | |
| 166 } | |
| 167 | |
| 168 ReadingListEntry* SyncMergeEntry( | |
| 169 std::unique_ptr<ReadingListEntry> entry) override { | |
| 170 sync_merge_called_++; | |
| 171 sync_merged_[entry->URL().spec()] = entry->IsRead(); | |
| 172 return model_->SyncMergeEntry(std::move(entry)); | |
| 173 } | |
| 174 | |
| 175 // In memory model type store needs a MessageLoop. | |
| 176 base::MessageLoop message_loop_; | |
| 177 | |
| 178 std::unique_ptr<syncer::ModelTypeStore> store_; | |
| 179 std::unique_ptr<ReadingListModelImpl> model_; | |
| 180 base::SimpleTestClock* clock_; | |
| 181 std::unique_ptr<ReadingListStore> reading_list_store_; | |
| 182 int put_called_; | |
| 183 int delete_called_; | |
| 184 int sync_add_called_; | |
| 185 int sync_remove_called_; | |
| 186 int sync_merge_called_; | |
| 187 std::map<std::string, std::unique_ptr<syncer::EntityData>> put_multimap_; | |
| 188 std::set<std::string> delete_set_; | |
| 189 std::map<std::string, bool> sync_added_; | |
| 190 std::set<std::string> sync_removed_; | |
| 191 std::map<std::string, bool> sync_merged_; | |
| 192 }; | |
| 193 | |
| 194 TEST_F(ReadingListStoreTest, CheckEmpties) { | |
| 195 EXPECT_EQ(0ul, model_->size()); | |
| 196 } | |
| 197 | |
| 198 TEST_F(ReadingListStoreTest, SaveOneRead) { | |
| 199 ReadingListEntry entry(GURL("http://read.example.com/"), "read title", | |
| 200 AdvanceAndGetTime(clock_)); | |
| 201 entry.SetRead(true, AdvanceAndGetTime(clock_)); | |
| 202 AdvanceAndGetTime(clock_); | |
| 203 reading_list_store_->SaveEntry(entry); | |
| 204 AssertCounts(1, 0, 0, 0, 0); | |
| 205 syncer::EntityData* data = put_multimap_["http://read.example.com/"].get(); | |
| 206 const sync_pb::ReadingListSpecifics& specifics = | |
| 207 data->specifics.reading_list(); | |
| 208 EXPECT_EQ(specifics.title(), "read title"); | |
| 209 EXPECT_EQ(specifics.url(), "http://read.example.com/"); | |
| 210 EXPECT_EQ(specifics.status(), sync_pb::ReadingListSpecifics::READ); | |
| 211 } | |
| 212 | |
| 213 TEST_F(ReadingListStoreTest, SaveOneUnread) { | |
| 214 ReadingListEntry entry(GURL("http://unread.example.com/"), "unread title", | |
| 215 AdvanceAndGetTime(clock_)); | |
| 216 reading_list_store_->SaveEntry(entry); | |
| 217 AssertCounts(1, 0, 0, 0, 0); | |
| 218 syncer::EntityData* data = put_multimap_["http://unread.example.com/"].get(); | |
| 219 const sync_pb::ReadingListSpecifics& specifics = | |
| 220 data->specifics.reading_list(); | |
| 221 EXPECT_EQ(specifics.title(), "unread title"); | |
| 222 EXPECT_EQ(specifics.url(), "http://unread.example.com/"); | |
| 223 EXPECT_EQ(specifics.status(), sync_pb::ReadingListSpecifics::UNSEEN); | |
| 224 } | |
| 225 | |
| 226 TEST_F(ReadingListStoreTest, SyncMergeOneEntry) { | |
| 227 syncer::EntityDataMap remote_input; | |
| 228 ReadingListEntry entry(GURL("http://read.example.com/"), "read title", | |
| 229 AdvanceAndGetTime(clock_)); | |
| 230 entry.SetRead(true, AdvanceAndGetTime(clock_)); | |
| 231 std::unique_ptr<sync_pb::ReadingListSpecifics> specifics = | |
| 232 entry.AsReadingListSpecifics(); | |
| 233 | |
| 234 syncer::EntityData data; | |
| 235 data.client_tag_hash = "http://read.example.com/"; | |
| 236 *data.specifics.mutable_reading_list() = *specifics; | |
| 237 | |
| 238 remote_input["http://read.example.com/"] = data.PassToPtr(); | |
| 239 | |
| 240 std::unique_ptr<syncer::MetadataChangeList> metadata_changes( | |
| 241 reading_list_store_->CreateMetadataChangeList()); | |
| 242 auto error = reading_list_store_->MergeSyncData(std::move(metadata_changes), | |
| 243 remote_input); | |
| 244 AssertCounts(0, 0, 1, 0, 0); | |
| 245 EXPECT_EQ(sync_added_.size(), 1u); | |
| 246 EXPECT_EQ(sync_added_.count("http://read.example.com/"), 1u); | |
| 247 EXPECT_EQ(sync_added_["http://read.example.com/"], true); | |
| 248 } | |
| 249 | |
| 250 TEST_F(ReadingListStoreTest, ApplySyncChangesOneAdd) { | |
| 251 syncer::EntityDataMap remote_input; | |
| 252 ReadingListEntry entry(GURL("http://read.example.com/"), "read title", | |
| 253 AdvanceAndGetTime(clock_)); | |
| 254 entry.SetRead(true, AdvanceAndGetTime(clock_)); | |
| 255 std::unique_ptr<sync_pb::ReadingListSpecifics> specifics = | |
| 256 entry.AsReadingListSpecifics(); | |
| 257 syncer::EntityData data; | |
| 258 data.client_tag_hash = "http://read.example.com/"; | |
| 259 *data.specifics.mutable_reading_list() = *specifics; | |
| 260 | |
| 261 syncer::EntityChangeList add_changes; | |
| 262 | |
| 263 add_changes.push_back(syncer::EntityChange::CreateAdd( | |
| 264 "http://read.example.com/", data.PassToPtr())); | |
| 265 auto error = reading_list_store_->ApplySyncChanges( | |
| 266 reading_list_store_->CreateMetadataChangeList(), add_changes); | |
| 267 AssertCounts(0, 0, 1, 0, 0); | |
| 268 EXPECT_EQ(sync_added_.size(), 1u); | |
| 269 EXPECT_EQ(sync_added_.count("http://read.example.com/"), 1u); | |
| 270 EXPECT_EQ(sync_added_["http://read.example.com/"], true); | |
| 271 } | |
| 272 | |
| 273 TEST_F(ReadingListStoreTest, ApplySyncChangesOneMerge) { | |
| 274 syncer::EntityDataMap remote_input; | |
| 275 AdvanceAndGetTime(clock_); | |
| 276 model_->AddEntry(GURL("http://unread.example.com/"), "unread title", | |
| 277 reading_list::ADDED_VIA_CURRENT_APP); | |
| 278 | |
| 279 ReadingListEntry new_entry(GURL("http://unread.example.com/"), "unread title", | |
| 280 AdvanceAndGetTime(clock_)); | |
| 281 new_entry.SetRead(true, AdvanceAndGetTime(clock_)); | |
| 282 std::unique_ptr<sync_pb::ReadingListSpecifics> specifics = | |
| 283 new_entry.AsReadingListSpecifics(); | |
| 284 syncer::EntityData data; | |
| 285 data.client_tag_hash = "http://unread.example.com/"; | |
| 286 *data.specifics.mutable_reading_list() = *specifics; | |
| 287 | |
| 288 syncer::EntityChangeList add_changes; | |
| 289 add_changes.push_back(syncer::EntityChange::CreateAdd( | |
| 290 "http://unread.example.com/", data.PassToPtr())); | |
| 291 auto error = reading_list_store_->ApplySyncChanges( | |
| 292 reading_list_store_->CreateMetadataChangeList(), add_changes); | |
| 293 AssertCounts(1, 0, 0, 0, 1); | |
| 294 EXPECT_EQ(sync_merged_.size(), 1u); | |
| 295 EXPECT_EQ(sync_merged_.count("http://unread.example.com/"), 1u); | |
| 296 EXPECT_EQ(sync_merged_["http://unread.example.com/"], true); | |
| 297 } | |
| 298 | |
| 299 TEST_F(ReadingListStoreTest, ApplySyncChangesOneIgnored) { | |
| 300 // Read entry but with unread URL as it must update the other one. | |
| 301 ReadingListEntry old_entry(GURL("http://unread.example.com/"), | |
| 302 "old unread title", AdvanceAndGetTime(clock_)); | |
| 303 old_entry.SetRead(true, AdvanceAndGetTime(clock_)); | |
| 304 | |
| 305 syncer::EntityDataMap remote_input; | |
| 306 AdvanceAndGetTime(clock_); | |
| 307 model_->AddEntry(GURL("http://unread.example.com/"), "new unread title", | |
| 308 reading_list::ADDED_VIA_CURRENT_APP); | |
| 309 AssertCounts(0, 0, 0, 0, 0); | |
| 310 | |
| 311 std::unique_ptr<sync_pb::ReadingListSpecifics> specifics = | |
| 312 old_entry.AsReadingListSpecifics(); | |
| 313 syncer::EntityData data; | |
| 314 data.client_tag_hash = "http://unread.example.com/"; | |
| 315 *data.specifics.mutable_reading_list() = *specifics; | |
| 316 | |
| 317 syncer::EntityChangeList add_changes; | |
| 318 add_changes.push_back(syncer::EntityChange::CreateAdd( | |
| 319 "http://unread.example.com/", data.PassToPtr())); | |
| 320 auto error = reading_list_store_->ApplySyncChanges( | |
| 321 reading_list_store_->CreateMetadataChangeList(), add_changes); | |
| 322 AssertCounts(1, 0, 0, 0, 1); | |
| 323 EXPECT_EQ(sync_merged_.size(), 1u); | |
| 324 } | |
| 325 | |
| 326 TEST_F(ReadingListStoreTest, ApplySyncChangesOneRemove) { | |
| 327 syncer::EntityChangeList delete_changes; | |
| 328 delete_changes.push_back( | |
| 329 syncer::EntityChange::CreateDelete("http://read.example.com/")); | |
| 330 auto error = reading_list_store_->ApplySyncChanges( | |
| 331 reading_list_store_->CreateMetadataChangeList(), delete_changes); | |
| 332 AssertCounts(0, 0, 0, 1, 0); | |
| 333 EXPECT_EQ(sync_removed_.size(), 1u); | |
| 334 EXPECT_EQ(sync_removed_.count("http://read.example.com/"), 1u); | |
| 335 } | |
| 336 | |
| 337 TEST_F(ReadingListStoreTest, CompareEntriesForSync) { | |
| 338 sync_pb::ReadingListSpecifics entryA; | |
| 339 sync_pb::ReadingListSpecifics entryB; | |
| 340 entryA.set_entry_id("http://foo.bar/"); | |
| 341 entryB.set_entry_id("http://foo.bar/"); | |
| 342 entryA.set_url("http://foo.bar/"); | |
| 343 entryB.set_url("http://foo.bar/"); | |
| 344 entryA.set_title("Foo Bar"); | |
| 345 entryB.set_title("Foo Bar"); | |
| 346 entryA.set_status(sync_pb::ReadingListSpecifics::UNREAD); | |
| 347 entryB.set_status(sync_pb::ReadingListSpecifics::UNREAD); | |
| 348 entryA.set_creation_time_us(10); | |
| 349 entryB.set_creation_time_us(10); | |
| 350 entryA.set_first_read_time_us(50); | |
| 351 entryB.set_first_read_time_us(50); | |
| 352 entryA.set_update_time_us(100); | |
| 353 entryB.set_update_time_us(100); | |
| 354 entryA.set_update_title_time_us(110); | |
| 355 entryB.set_update_title_time_us(110); | |
| 356 // Equal entries can be submitted. | |
| 357 ExpectAB(entryA, entryB, true); | |
| 358 ExpectAB(entryB, entryA, true); | |
| 359 | |
| 360 // Try to update each field. | |
| 361 | |
| 362 // You cannot change the URL of an entry. | |
| 363 entryA.set_url("http://foo.foo/"); | |
| 364 EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryA, entryB)); | |
| 365 EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA)); | |
| 366 entryA.set_url("http://foo.bar/"); | |
| 367 | |
| 368 // You can set a title to a title later in alphabetical order if the | |
| 369 // update_title_time is the same. If a title has been more recently updated, | |
| 370 // the only possible transition is to this one. | |
| 371 entryA.set_title(""); | |
| 372 ExpectAB(entryA, entryB, true); | |
| 373 ExpectAB(entryB, entryA, false); | |
| 374 entryA.set_update_title_time_us(109); | |
| 375 ExpectAB(entryA, entryB, true); | |
| 376 ExpectAB(entryB, entryA, false); | |
| 377 entryA.set_update_title_time_us(110); | |
| 378 | |
| 379 entryA.set_title("Foo Aar"); | |
| 380 ExpectAB(entryA, entryB, true); | |
| 381 ExpectAB(entryB, entryA, false); | |
| 382 entryA.set_update_title_time_us(109); | |
| 383 ExpectAB(entryA, entryB, true); | |
| 384 ExpectAB(entryB, entryA, false); | |
| 385 entryA.set_update_title_time_us(110); | |
| 386 | |
| 387 entryA.set_title("Foo Ba"); | |
| 388 ExpectAB(entryA, entryB, true); | |
| 389 ExpectAB(entryB, entryA, false); | |
| 390 entryA.set_update_title_time_us(109); | |
| 391 ExpectAB(entryA, entryB, true); | |
| 392 ExpectAB(entryB, entryA, false); | |
| 393 entryA.set_update_title_time_us(110); | |
| 394 | |
| 395 entryA.set_title("Foo Bas"); | |
| 396 ExpectAB(entryA, entryB, false); | |
| 397 ExpectAB(entryB, entryA, true); | |
| 398 entryA.set_update_title_time_us(109); | |
| 399 ExpectAB(entryA, entryB, true); | |
| 400 ExpectAB(entryB, entryA, false); | |
| 401 entryA.set_update_title_time_us(110); | |
| 402 entryA.set_title("Foo Bar"); | |
| 403 | |
| 404 // Update times. | |
| 405 entryA.set_creation_time_us(9); | |
| 406 ExpectAB(entryA, entryB, true); | |
| 407 ExpectAB(entryB, entryA, false); | |
| 408 entryA.set_first_read_time_us(51); | |
| 409 ExpectAB(entryA, entryB, true); | |
| 410 ExpectAB(entryB, entryA, false); | |
| 411 entryA.set_first_read_time_us(49); | |
| 412 ExpectAB(entryA, entryB, true); | |
| 413 ExpectAB(entryB, entryA, false); | |
| 414 entryA.set_first_read_time_us(0); | |
| 415 ExpectAB(entryA, entryB, true); | |
| 416 ExpectAB(entryB, entryA, false); | |
| 417 entryA.set_first_read_time_us(50); | |
| 418 entryB.set_first_read_time_us(0); | |
| 419 ExpectAB(entryA, entryB, true); | |
| 420 ExpectAB(entryB, entryA, false); | |
| 421 entryB.set_first_read_time_us(50); | |
| 422 entryA.set_creation_time_us(10); | |
| 423 entryA.set_first_read_time_us(51); | |
| 424 ExpectAB(entryA, entryB, true); | |
| 425 ExpectAB(entryB, entryA, false); | |
| 426 entryA.set_first_read_time_us(0); | |
| 427 ExpectAB(entryA, entryB, true); | |
| 428 ExpectAB(entryB, entryA, false); | |
| 429 entryA.set_first_read_time_us(50); | |
| 430 | |
| 431 entryA.set_update_time_us(99); | |
| 432 ExpectAB(entryA, entryB, true); | |
| 433 ExpectAB(entryB, entryA, false); | |
| 434 sync_pb::ReadingListSpecifics::ReadingListEntryStatus status_oder[3] = { | |
| 435 sync_pb::ReadingListSpecifics::UNSEEN, | |
| 436 sync_pb::ReadingListSpecifics::UNREAD, | |
| 437 sync_pb::ReadingListSpecifics::READ}; | |
| 438 for (int index_a = 0; index_a < 3; index_a++) { | |
| 439 entryA.set_status(status_oder[index_a]); | |
| 440 for (int index_b = 0; index_b < 3; index_b++) { | |
| 441 entryB.set_status(status_oder[index_b]); | |
| 442 ExpectAB(entryA, entryB, true); | |
| 443 ExpectAB(entryB, entryA, false); | |
| 444 } | |
| 445 } | |
| 446 entryA.set_update_time_us(100); | |
| 447 for (int index_a = 0; index_a < 3; index_a++) { | |
| 448 entryA.set_status(status_oder[index_a]); | |
| 449 entryB.set_status(status_oder[index_a]); | |
| 450 ExpectAB(entryA, entryB, true); | |
| 451 ExpectAB(entryB, entryA, true); | |
| 452 for (int index_b = index_a + 1; index_b < 3; index_b++) { | |
| 453 entryB.set_status(status_oder[index_b]); | |
| 454 ExpectAB(entryA, entryB, true); | |
| 455 ExpectAB(entryB, entryA, false); | |
| 456 } | |
| 457 } | |
| 458 } | |
| OLD | NEW |