Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: components/reading_list/ios/reading_list_store_unittest.cc

Issue 2763233003: Move ReadingList model to components/reading_list/core (Closed)
Patch Set: feedback Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/reading_list/ios/reading_list_store_delegate.h ('k') | ios/chrome/app/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « components/reading_list/ios/reading_list_store_delegate.h ('k') | ios/chrome/app/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698