diff options
author | noyau <noyau@chromium.org> | 2016-02-15 01:17:43 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-15 09:18:49 +0000 |
commit | 4e4654e5d078ab8e8a9ac6b5545aa6927b2ff4a4 (patch) | |
tree | a2fcf9c4a3582c480130e4adfbae8d9d3dbb8c65 /ios | |
parent | 75525faededfb3db0c284deb78a332b2231fcafa (diff) | |
download | chromium_src-4e4654e5d078ab8e8a9ac6b5545aa6927b2ff4a4.zip chromium_src-4e4654e5d078ab8e8a9ac6b5545aa6927b2ff4a4.tar.gz chromium_src-4e4654e5d078ab8e8a9ac6b5545aa6927b2ff4a4.tar.bz2 |
Reading list model API.
An API for a model to support reading lists plus an in-memory implementation for development purpose. Users of this API should only use the factory to get access to a model.
BUG=None
Review URL: https://codereview.chromium.org/1643573007
Cr-Commit-Position: refs/heads/master@{#375427}
Diffstat (limited to 'ios')
-rw-r--r-- | ios/chrome/BUILD.gn | 2 | ||||
-rw-r--r-- | ios/chrome/browser/BUILD.gn | 9 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/OWNERS | 1 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_entry.cc | 32 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_entry.h | 32 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_entry_unittest.cc | 29 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_model.cc | 21 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_model.h | 76 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_model_factory.cc | 51 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_model_factory.h | 46 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_model_memory.cc | 117 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_model_memory.h | 44 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_model_observer.h | 55 | ||||
-rw-r--r-- | ios/chrome/browser/reading_list/reading_list_model_unittest.cc | 123 | ||||
-rw-r--r-- | ios/chrome/ios_chrome.gyp | 9 | ||||
-rw-r--r-- | ios/chrome/ios_chrome_tests.gyp | 2 |
16 files changed, 649 insertions, 0 deletions
diff --git a/ios/chrome/BUILD.gn b/ios/chrome/BUILD.gn index 59a9731..f59a480 100644 --- a/ios/chrome/BUILD.gn +++ b/ios/chrome/BUILD.gn @@ -23,6 +23,8 @@ test("ios_chrome_unittests") { "browser/net/image_fetcher_unittest.mm", "browser/net/metrics_network_client_unittest.mm", "browser/net/retryable_url_fetcher_unittest.mm", + "browser/reading_list/reading_list_entry_unittest.cc", + "browser/reading_list/reading_list_model_unittest.cc", "browser/signin/chrome_identity_service_observer_bridge_unittest.mm", "browser/signin/gaia_auth_fetcher_ios_unittest.mm", "browser/snapshots/lru_cache_unittest.mm", diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn index 648375c..8469be4 100644 --- a/ios/chrome/browser/BUILD.gn +++ b/ios/chrome/browser/BUILD.gn @@ -292,6 +292,15 @@ source_set("browser") { "prefs/pref_observer_bridge.h", "prefs/pref_observer_bridge.mm", "procedural_block_types.h", + "reading_list/reading_list_entry.cc", + "reading_list/reading_list_entry.h", + "reading_list/reading_list_model.cc", + "reading_list/reading_list_model.h", + "reading_list/reading_list_model_factory.cc", + "reading_list/reading_list_model_factory.h", + "reading_list/reading_list_model_memory.cc", + "reading_list/reading_list_model_memory.h", + "reading_list/reading_list_model_observer.h", "search/search_util.cc", "search/search_util.h", "search_engines/search_engines_util.cc", diff --git a/ios/chrome/browser/reading_list/OWNERS b/ios/chrome/browser/reading_list/OWNERS new file mode 100644 index 0000000..bf1620f --- /dev/null +++ b/ios/chrome/browser/reading_list/OWNERS @@ -0,0 +1 @@ +noyau@chromium.org diff --git a/ios/chrome/browser/reading_list/reading_list_entry.cc b/ios/chrome/browser/reading_list/reading_list_entry.cc new file mode 100644 index 0000000..15c0dea --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_entry.cc @@ -0,0 +1,32 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/reading_list/reading_list_entry.h" + +ReadingListEntry::ReadingListEntry(const GURL& url, const std::string& title) + : url_(url), title_(title) { + DCHECK(!url.is_empty()); + DCHECK(url.is_valid()); +} +ReadingListEntry::ReadingListEntry(const ReadingListEntry& entry) + : url_(entry.url()), title_(entry.title()) {} +ReadingListEntry::~ReadingListEntry() {} + +const GURL& ReadingListEntry::url() const { + return url_; +} + +const std::string ReadingListEntry::title() const { + return title_; +} + +ReadingListEntry& ReadingListEntry::operator=(const ReadingListEntry& other) { + url_ = other.url_; + title_ = other.title_; + return *this; +} + +bool ReadingListEntry::operator==(const ReadingListEntry& other) const { + return url_ == other.url_; +} diff --git a/ios/chrome/browser/reading_list/reading_list_entry.h b/ios/chrome/browser/reading_list/reading_list_entry.h new file mode 100644 index 0000000..f7287b7 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_entry.h @@ -0,0 +1,32 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_H_ + +#include <string> + +#include "url/gurl.h" + +// An entry in the reading list. The URL is a unique identifier for an entry, as +// such it should not be empty and is the only thing considered when comparing +// entries. +class ReadingListEntry { + public: + ReadingListEntry(const GURL& url, const std::string& title); + ReadingListEntry(const ReadingListEntry& entry); + ~ReadingListEntry(); + + const GURL& url() const; + const std::string title() const; + + ReadingListEntry& operator=(const ReadingListEntry& other); + bool operator==(const ReadingListEntry& other) const; + + private: + GURL url_; + std::string title_; +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_H_ diff --git a/ios/chrome/browser/reading_list/reading_list_entry_unittest.cc b/ios/chrome/browser/reading_list/reading_list_entry_unittest.cc new file mode 100644 index 0000000..1bb920b --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_entry_unittest.cc @@ -0,0 +1,29 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/reading_list/reading_list_entry.h" + +#include "testing/gtest/include/gtest/gtest.h" + +TEST(ReadingListEntry, CompareIgnoreTitle) { + const ReadingListEntry e1(GURL("http://example.com"), "bar"); + const ReadingListEntry e2(GURL("http://example.com"), "foo"); + + EXPECT_EQ(e1, e2); +} + +TEST(ReadingListEntry, CompareFailureIgnoreTitle) { + const ReadingListEntry e1(GURL("http://example.com"), "bar"); + const ReadingListEntry e2(GURL("http://example.org"), "bar"); + + EXPECT_FALSE(e1 == e2); +} + +TEST(ReadingListEntry, CopyAreEquals) { + const ReadingListEntry e1(GURL("http://example.com"), "bar"); + const ReadingListEntry e2(e1); + + EXPECT_EQ(e1, e2); + EXPECT_EQ(e1.title(), e2.title()); +} diff --git a/ios/chrome/browser/reading_list/reading_list_model.cc b/ios/chrome/browser/reading_list/reading_list_model.cc new file mode 100644 index 0000000..bdc2651 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model.cc @@ -0,0 +1,21 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/reading_list/reading_list_model.h" + +ReadingListModel::ReadingListModel() {} +ReadingListModel::~ReadingListModel() {} + +// Observer methods. +void ReadingListModel::AddObserver(ReadingListModelObserver* observer) { + DCHECK(observer); + observers_.AddObserver(observer); + if (loaded()) { + observer->ReadingListModelLoaded(this); + } +} + +void ReadingListModel::RemoveObserver(ReadingListModelObserver* observer) { + observers_.RemoveObserver(observer); +} diff --git a/ios/chrome/browser/reading_list/reading_list_model.h b/ios/chrome/browser/reading_list/reading_list_model.h new file mode 100644 index 0000000..196476e --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model.h @@ -0,0 +1,76 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/observer_list.h" +#include "ios/chrome/browser/reading_list/reading_list_model_observer.h" + +class GURL; +class ReadingListEntry; +class ReadingListModel; + +namespace ios { +class ChromeBrowserState; +} + +// The reading list model contains two list of entries: one of unread urls, the +// other of read ones. This object should only be accessed from one thread +// (Usually the main thread). The observers callbacks are also sent on the main +// thread. +class ReadingListModel { + public: + // Returns true if the model finished loading. Until this returns true the + // reading list is not ready for use. + virtual bool loaded() const = 0; + + // Returns the size of read and unread entries. + virtual size_t unread_size() const = 0; + virtual size_t read_size() const = 0; + + // Returns true if there are entries in the model that were not seen by the + // user yet. Reset to true when new unread entries are added. Reset to false + // when ResetUnseenEntries is called. + virtual bool HasUnseenEntries() const = 0; + virtual void ResetUnseenEntries() = 0; + + // Returns a specific entry. + virtual const ReadingListEntry& GetUnreadEntryAtIndex(size_t index) const = 0; + virtual const ReadingListEntry& GetReadEntryAtIndex(size_t index) const = 0; + + // Adds |url| at the top of the unread entries, and removes entries with the + // same |url| from everywhere else if they exist. The addition may be + // asynchronous, and the data will be available only once the observers are + // notified. + virtual const ReadingListEntry& AddEntry(const GURL& url, + const std::string& title) = 0; + + // Removes an entry. The removal may be asynchronous, and not happen + // immediately. + virtual void RemoveEntryByUrl(const GURL& url) = 0; + + // If the |url| is in the reading list and unread, mark it read. If it is in + // the reading list and read, move it to the top of unread if it is not here + // already. This may trigger deletion of old read entries. + virtual void MarkReadByURL(const GURL& url) = 0; + + // Observer registration methods. + void AddObserver(ReadingListModelObserver* observer); + void RemoveObserver(ReadingListModelObserver* observer); + + protected: + ReadingListModel(); + virtual ~ReadingListModel(); + // The observers. + base::ObserverList<ReadingListModelObserver> observers_; + + DISALLOW_COPY_AND_ASSIGN(ReadingListModel); +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_H_ diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.cc b/ios/chrome/browser/reading_list/reading_list_model_factory.cc new file mode 100644 index 0000000..dcf6c2b --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_factory.cc @@ -0,0 +1,51 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/reading_list/reading_list_model_factory.h" + +#include <utility> + +#include "base/memory/singleton.h" +#include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/reading_list/reading_list_model_memory.h" + +// static +ReadingListModel* ReadingListModelFactory::GetForBrowserState( + ios::ChromeBrowserState* browser_state) { + return static_cast<ReadingListModelMemory*>( + GetInstance()->GetServiceForBrowserState(browser_state, true)); +} + +// static +ReadingListModel* ReadingListModelFactory::GetForBrowserStateIfExists( + ios::ChromeBrowserState* browser_state) { + return static_cast<ReadingListModelMemory*>( + GetInstance()->GetServiceForBrowserState(browser_state, false)); +} + +// static +ReadingListModelFactory* ReadingListModelFactory::GetInstance() { + return base::Singleton<ReadingListModelFactory>::get(); +} + +ReadingListModelFactory::ReadingListModelFactory() + : BrowserStateKeyedServiceFactory( + "ReadingListModel", + BrowserStateDependencyManager::GetInstance()) {} + +ReadingListModelFactory::~ReadingListModelFactory() {} + +scoped_ptr<KeyedService> ReadingListModelFactory::BuildServiceInstanceFor( + web::BrowserState* context) const { + scoped_ptr<ReadingListModelMemory> reading_list_model( + new ReadingListModelMemory()); + return std::move(reading_list_model); +} + +web::BrowserState* ReadingListModelFactory::GetBrowserStateToUse( + web::BrowserState* context) const { + return GetBrowserStateRedirectedInIncognito(context); +} diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.h b/ios/chrome/browser/reading_list/reading_list_model_factory.h new file mode 100644 index 0000000..96a6638 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_factory.h @@ -0,0 +1,46 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_FACTORY_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_FACTORY_H_ + +#include "components/keyed_service/ios/browser_state_keyed_service_factory.h" + +namespace base { +template <typename T> +struct DefaultSingletonTraits; +} // namespace base + +class ReadingListModel; + +namespace ios { +class ChromeBrowserState; +} + +// Singleton that owns the ReadingListModel and associates it with +// ios::ChromeBrowserState. +class ReadingListModelFactory : public BrowserStateKeyedServiceFactory { + public: + static ReadingListModel* GetForBrowserState( + ios::ChromeBrowserState* browser_state); + static ReadingListModel* GetForBrowserStateIfExists( + ios::ChromeBrowserState* browser_state); + static ReadingListModelFactory* GetInstance(); + + private: + friend struct base::DefaultSingletonTraits<ReadingListModelFactory>; + + ReadingListModelFactory(); + ~ReadingListModelFactory() override; + + // BrowserStateKeyedServiceFactory implementation. + scoped_ptr<KeyedService> BuildServiceInstanceFor( + web::BrowserState* context) const override; + web::BrowserState* GetBrowserStateToUse( + web::BrowserState* context) const override; + + DISALLOW_COPY_AND_ASSIGN(ReadingListModelFactory); +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_FACTORY_H_ diff --git a/ios/chrome/browser/reading_list/reading_list_model_memory.cc b/ios/chrome/browser/reading_list/reading_list_model_memory.cc new file mode 100644 index 0000000..40f9224 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_memory.cc @@ -0,0 +1,117 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/reading_list/reading_list_model_memory.h" + +#include "url/gurl.h" + +ReadingListModelMemory::ReadingListModelMemory() + : hasUnseen_(false), loaded_(true) {} +ReadingListModelMemory::~ReadingListModelMemory() {} + +void ReadingListModelMemory::Shutdown() { + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListModelBeingDeleted(this)); + loaded_ = false; +} + +bool ReadingListModelMemory::loaded() const { + return loaded_; +} + +size_t ReadingListModelMemory::unread_size() const { + DCHECK(loaded()); + return unread_.size(); +} + +size_t ReadingListModelMemory::read_size() const { + DCHECK(loaded()); + return read_.size(); +} + +bool ReadingListModelMemory::HasUnseenEntries() const { + DCHECK(loaded()); + return unread_size() && hasUnseen_; +} + +void ReadingListModelMemory::ResetUnseenEntries() { + DCHECK(loaded()); + hasUnseen_ = false; +} + +// Returns a specific entry. +const ReadingListEntry& ReadingListModelMemory::GetUnreadEntryAtIndex( + size_t index) const { + DCHECK(loaded()); + return unread_[index]; +} +const ReadingListEntry& ReadingListModelMemory::GetReadEntryAtIndex( + size_t index) const { + DCHECK(loaded()); + return read_[index]; +} + +void ReadingListModelMemory::RemoveEntryByUrl(const GURL& url) { + DCHECK(loaded()); + const ReadingListEntry entry(url, std::string()); + + auto result = std::find(unread_.begin(), unread_.end(), entry); + if (result != unread_.end()) { + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListWillRemoveUnreadEntry( + this, std::distance(unread_.begin(), result))); + unread_.erase(result); + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListDidApplyChanges(this)); + return; + } + + result = std::find(read_.begin(), read_.end(), entry); + if (result != read_.end()) { + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListWillRemoveReadEntry( + this, std::distance(read_.begin(), result))); + read_.erase(result); + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListDidApplyChanges(this)); + return; + } +} + +const ReadingListEntry& ReadingListModelMemory::AddEntry( + const GURL& url, + const std::string& title) { + DCHECK(loaded()); + RemoveEntryByUrl(url); + const ReadingListEntry entry(url, title); + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListWillAddUnreadEntry(this, entry)); + unread_.insert(unread_.begin(), entry); + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListDidApplyChanges(this)); + + hasUnseen_ = true; + return *unread_.begin(); +} + +void ReadingListModelMemory::MarkReadByURL(const GURL& url) { + DCHECK(loaded()); + const ReadingListEntry entry(url, std::string()); + + auto result = std::find(unread_.begin(), unread_.end(), entry); + if (result == unread_.end()) { + return; + } + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListWillRemoveUnreadEntry( + this, std::distance(unread_.begin(), result))); + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListWillAddReadEntry(this, entry)); + + read_.insert(read_.begin(), *result); + unread_.erase(result); + + FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, + ReadingListDidApplyChanges(this)); +} diff --git a/ios/chrome/browser/reading_list/reading_list_model_memory.h b/ios/chrome/browser/reading_list/reading_list_model_memory.h new file mode 100644 index 0000000..1dda495 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_memory.h @@ -0,0 +1,44 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_MEMORY_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_MEMORY_H_ + +#include "components/keyed_service/core/keyed_service.h" +#include "ios/chrome/browser/reading_list/reading_list_entry.h" +#include "ios/chrome/browser/reading_list/reading_list_model.h" + +// Concrete implementation of a reading list model using in memory lists. +class ReadingListModelMemory : public ReadingListModel, public KeyedService { + public: + ReadingListModelMemory(); + ~ReadingListModelMemory() override; + void Shutdown() override; + + bool loaded() const override; + size_t unread_size() const override; + size_t read_size() const override; + + bool HasUnseenEntries() const override; + void ResetUnseenEntries() override; + + // Returns a specific entry. + const ReadingListEntry& GetUnreadEntryAtIndex(size_t index) const override; + const ReadingListEntry& GetReadEntryAtIndex(size_t index) const override; + + void RemoveEntryByUrl(const GURL& url) override; + + const ReadingListEntry& AddEntry(const GURL& url, + const std::string& title) override; + + void MarkReadByURL(const GURL& url) override; + + private: + std::vector<ReadingListEntry> unread_; + std::vector<ReadingListEntry> read_; + bool hasUnseen_; + bool loaded_; +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_MEMORY_H_ diff --git a/ios/chrome/browser/reading_list/reading_list_model_observer.h b/ios/chrome/browser/reading_list/reading_list_model_observer.h new file mode 100644 index 0000000..4881d39 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_observer.h @@ -0,0 +1,55 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_OBSERVER_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_OBSERVER_H_ + +#import <set> +#import <vector> + +class ReadingListModel; +class ReadingListEntry; + +// Observer for the Reading List model. In the observer methods care should be +// taken to not modify the model. +class ReadingListModelObserver { + public: + // Invoked when the model has finished loading. Until this method is called it + // is unsafe to use the model. + virtual void ReadingListModelLoaded(const ReadingListModel* model) = 0; + + // Invoked from the destructor of the model. The model is no longer valid + // after this call. + virtual void ReadingListModelBeingDeleted(const ReadingListModel* model) {} + + // Invoked when elements are about to be removed from the read or unread list. + virtual void ReadingListWillRemoveUnreadEntry(const ReadingListModel* model, + size_t index) {} + virtual void ReadingListWillRemoveReadEntry(const ReadingListModel* model, + size_t index) {} + + // Invoked when elements are added to the read or the unread list. The new + // entries are always added at the beginning. these methods may be called + // multiple time (to process changes coming from a synchronization for + // example) and they will be executed in call order, the last call will end up + // in first position. + virtual void ReadingListWillAddUnreadEntry(const ReadingListModel* model, + const ReadingListEntry& entry) {} + + virtual void ReadingListWillAddReadEntry(const ReadingListModel* model, + const ReadingListEntry& entry) {} + + // Called after all th"e changes signaled by calls to the "Will" methods are + // done. All the "Will" methods are called as necessary, then the changes + // are applied and then this method is called. + virtual void ReadingListDidApplyChanges(ReadingListModel* model) {} + + protected: + ReadingListModelObserver() {} + virtual ~ReadingListModelObserver() {} + + DISALLOW_COPY_AND_ASSIGN(ReadingListModelObserver); +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_OBSERVER_H_ diff --git a/ios/chrome/browser/reading_list/reading_list_model_unittest.cc b/ios/chrome/browser/reading_list/reading_list_model_unittest.cc new file mode 100644 index 0000000..a863707 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_unittest.cc @@ -0,0 +1,123 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/reading_list/reading_list_model_memory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class ReadingListModelTest : public ReadingListModelObserver, + public testing::Test { + public: + ReadingListModelTest() : model_(new ReadingListModelMemory()) { + ClearCounts(); + model_->AddObserver(this); + } + ~ReadingListModelTest() override {} + + void ClearCounts() { + observer_loaded_ = observer_deleted_ = observer_remove_unread_ = + observer_remove_read_ = observer_add_unread_ = observer_add_read_ = + observer_did_apply_ = 0; + } + + void AssertObserverCount(int observer_loaded, + int observer_deleted, + int observer_remove_unread, + int observer_remove_read, + int observer_add_unread, + int observer_add_read, + int observer_did_apply) { + ASSERT_EQ(observer_loaded, observer_loaded_); + ASSERT_EQ(observer_deleted, observer_deleted_); + ASSERT_EQ(observer_remove_unread, observer_remove_unread_); + ASSERT_EQ(observer_remove_read, observer_remove_read_); + ASSERT_EQ(observer_add_unread, observer_add_unread_); + ASSERT_EQ(observer_add_read, observer_add_read_); + ASSERT_EQ(observer_did_apply, observer_did_apply_); + } + + // ReadingListModelObserver + void ReadingListModelLoaded(const ReadingListModel* model) override { + observer_loaded_ += 1; + } + void ReadingListModelBeingDeleted(const ReadingListModel* model) override { + observer_deleted_ += 1; + } + void ReadingListWillRemoveUnreadEntry(const ReadingListModel* model, + size_t index) override { + observer_remove_unread_ += 1; + } + void ReadingListWillRemoveReadEntry(const ReadingListModel* model, + size_t index) override { + observer_remove_read_ += 1; + } + void ReadingListWillAddUnreadEntry(const ReadingListModel* model, + const ReadingListEntry& entry) override { + observer_add_unread_ += 1; + } + void ReadingListWillAddReadEntry(const ReadingListModel* model, + const ReadingListEntry& entry) override { + observer_add_read_ += 1; + } + void ReadingListDidApplyChanges(ReadingListModel* model) override { + observer_did_apply_ += 1; + } + + protected: + int observer_loaded_; + int observer_deleted_; + int observer_remove_unread_; + int observer_remove_read_; + int observer_add_unread_; + int observer_add_read_; + int observer_did_apply_; + + scoped_ptr<ReadingListModelMemory> model_; +}; + +TEST_F(ReadingListModelTest, EmptyLoaded) { + EXPECT_TRUE(model_->loaded()); + AssertObserverCount(1, 0, 0, 0, 0, 0, 0); + EXPECT_EQ(0ul, model_->unread_size()); + EXPECT_EQ(0ul, model_->read_size()); + model_->Shutdown(); + EXPECT_FALSE(model_->loaded()); + AssertObserverCount(1, 1, 0, 0, 0, 0, 0); +} + +TEST_F(ReadingListModelTest, AddEntry) { + ClearCounts(); + const ReadingListEntry entry = + model_->AddEntry(GURL("http://example.com"), "sample"); + EXPECT_EQ(GURL("http://example.com"), entry.url()); + EXPECT_EQ("sample", entry.title()); + + AssertObserverCount(0, 0, 0, 0, 1, 0, 1); + EXPECT_EQ(1ul, model_->unread_size()); + EXPECT_EQ(0ul, model_->read_size()); + EXPECT_TRUE(model_->HasUnseenEntries()); + + const ReadingListEntry other_entry = model_->GetUnreadEntryAtIndex(0); + EXPECT_EQ(GURL("http://example.com"), other_entry.url()); + EXPECT_EQ("sample", other_entry.title()); +} + +TEST_F(ReadingListModelTest, ReadEntry) { + const ReadingListEntry entry = + model_->AddEntry(GURL("http://example.com"), "sample"); + + ClearCounts(); + model_->MarkReadByURL(GURL("http://example.com")); + AssertObserverCount(0, 0, 1, 0, 0, 1, 1); + EXPECT_EQ(0ul, model_->unread_size()); + EXPECT_EQ(1ul, model_->read_size()); + EXPECT_FALSE(model_->HasUnseenEntries()); + + const ReadingListEntry other_entry = model_->GetReadEntryAtIndex(0); + EXPECT_EQ(GURL("http://example.com"), other_entry.url()); + EXPECT_EQ("sample", other_entry.title()); +} + +} // namespace diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp index a1ac53d..50af6e1 100644 --- a/ios/chrome/ios_chrome.gyp +++ b/ios/chrome/ios_chrome.gyp @@ -447,6 +447,15 @@ 'browser/prefs/pref_observer_bridge.h', 'browser/prefs/pref_observer_bridge.mm', 'browser/procedural_block_types.h', + 'browser/reading_list/reading_list_entry.cc', + 'browser/reading_list/reading_list_entry.h', + 'browser/reading_list/reading_list_model.cc', + 'browser/reading_list/reading_list_model.h', + 'browser/reading_list/reading_list_model_factory.cc', + 'browser/reading_list/reading_list_model_factory.h', + 'browser/reading_list/reading_list_model_memory.cc', + 'browser/reading_list/reading_list_model_memory.h', + 'browser/reading_list/reading_list_model_observer.h', 'browser/search/search_util.cc', 'browser/search/search_util.h', 'browser/search_engines/search_engines_util.cc', diff --git a/ios/chrome/ios_chrome_tests.gyp b/ios/chrome/ios_chrome_tests.gyp index 70012fe..d72f00e 100644 --- a/ios/chrome/ios_chrome_tests.gyp +++ b/ios/chrome/ios_chrome_tests.gyp @@ -55,6 +55,8 @@ 'browser/net/image_fetcher_unittest.mm', 'browser/net/metrics_network_client_unittest.mm', 'browser/net/retryable_url_fetcher_unittest.mm', + 'browser/reading_list/reading_list_entry_unittest.cc', + 'browser/reading_list/reading_list_model_unittest.cc', 'browser/signin/chrome_identity_service_observer_bridge_unittest.mm', 'browser/signin/gaia_auth_fetcher_ios_unittest.mm', 'browser/snapshots/lru_cache_unittest.mm', |