summaryrefslogtreecommitdiffstats
path: root/base/prefs
diff options
context:
space:
mode:
Diffstat (limited to 'base/prefs')
-rw-r--r--base/prefs/DEPS18
-rw-r--r--base/prefs/README10
-rw-r--r--base/prefs/default_pref_store.cc26
-rw-r--r--base/prefs/default_pref_store.h36
-rw-r--r--base/prefs/json_pref_store.cc344
-rw-r--r--base/prefs/json_pref_store.h93
-rw-r--r--base/prefs/json_pref_store_unittest.cc293
-rw-r--r--base/prefs/overlay_user_pref_store.cc186
-rw-r--r--base/prefs/overlay_user_pref_store.h84
-rw-r--r--base/prefs/overlay_user_pref_store_unittest.cc282
-rw-r--r--base/prefs/persistent_pref_store.h94
-rw-r--r--base/prefs/pref_notifier.h26
-rw-r--r--base/prefs/pref_store.cc13
-rw-r--r--base/prefs/pref_store.h72
-rw-r--r--base/prefs/pref_store_observer_mock.cc9
-rw-r--r--base/prefs/pref_store_observer_mock.h25
-rw-r--r--base/prefs/pref_value_map.cc151
-rw-r--r--base/prefs/pref_value_map.h87
-rw-r--r--base/prefs/pref_value_map_unittest.cc111
-rw-r--r--base/prefs/public/pref_change_registrar.cc89
-rw-r--r--base/prefs/public/pref_change_registrar.h66
-rw-r--r--base/prefs/public/pref_change_registrar_unittest.cc207
-rw-r--r--base/prefs/public/pref_service_base.h272
-rw-r--r--base/prefs/testing_pref_store.cc135
-rw-r--r--base/prefs/testing_pref_store.h84
-rw-r--r--base/prefs/value_map_pref_store.cc61
-rw-r--r--base/prefs/value_map_pref_store.h59
27 files changed, 2933 insertions, 0 deletions
diff --git a/base/prefs/DEPS b/base/prefs/DEPS
new file mode 100644
index 0000000..ab1b336
--- /dev/null
+++ b/base/prefs/DEPS
@@ -0,0 +1,18 @@
+include_rules = [
+ # Will move to base/
+ "+chrome/common/important_file_writer.h",
+]
+
+specific_include_rules = {
+ '.*_[a-z]+test\.cc': [
+ "!chrome/common/chrome_notification_types.h",
+ "!chrome/common/chrome_paths.h",
+ "!chrome/common/important_file_writer.h",
+ "!chrome/common/pref_names.h",
+ "!chrome/test/base/testing_pref_service.h",
+ "!content/public/browser/notification_details.h",
+ "!content/public/browser/notification_source.h",
+ "!content/public/browser/notification_types.h",
+ "!content/public/test/mock_notification_observer.h",
+ ],
+}
diff --git a/base/prefs/README b/base/prefs/README
new file mode 100644
index 0000000..a49604e
--- /dev/null
+++ b/base/prefs/README
@@ -0,0 +1,10 @@
+Prefs is a general-purpose key-value store for application preferences.
+
+At the moment, src/base/prefs has a bunch of dependencies back to
+src/chrome, and thus should only be used by code under src/chrome.
+
+We are working to remove these dependencies; once we do so,
+src/base/prefs will be available as a separate module, 'base_prefs',
+from src/base/base.gyp.
+
+Until that happens, please do not try to reuse outside of chrome/.
diff --git a/base/prefs/default_pref_store.cc b/base/prefs/default_pref_store.cc
new file mode 100644
index 0000000..c031221
--- /dev/null
+++ b/base/prefs/default_pref_store.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 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 "base/prefs/default_pref_store.h"
+
+using base::Value;
+
+DefaultPrefStore::DefaultPrefStore() {}
+
+void DefaultPrefStore::SetDefaultValue(const std::string& key, Value* value) {
+ CHECK(GetValue(key, NULL) == READ_NO_VALUE);
+ SetValue(key, value);
+}
+
+void DefaultPrefStore::RemoveDefaultValue(const std::string& key) {
+ CHECK(GetValue(key, NULL) == READ_OK);
+ RemoveValue(key);
+}
+
+base::Value::Type DefaultPrefStore::GetType(const std::string& key) const {
+ const Value* value;
+ return GetValue(key, &value) == READ_OK ? value->GetType() : Value::TYPE_NULL;
+}
+
+DefaultPrefStore::~DefaultPrefStore() {}
diff --git a/base/prefs/default_pref_store.h b/base/prefs/default_pref_store.h
new file mode 100644
index 0000000..90d83f0
--- /dev/null
+++ b/base/prefs/default_pref_store.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 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 BASE_PREFS_DEFAULT_PREF_STORE_H_
+#define BASE_PREFS_DEFAULT_PREF_STORE_H_
+
+#include <string>
+
+#include "base/prefs/value_map_pref_store.h"
+#include "base/values.h"
+
+// This PrefStore keeps track of default preference values set when a
+// preference is registered with the PrefService.
+class DefaultPrefStore : public ValueMapPrefStore {
+ public:
+ DefaultPrefStore();
+
+ // Stores a new |value| for |key|. Assumes ownership of |value|.
+ void SetDefaultValue(const std::string& key, Value* value);
+
+ // Removes the value for |key|.
+ void RemoveDefaultValue(const std::string& key);
+
+ // Returns the registered type for |key| or Value::TYPE_NULL if the |key|
+ // has not been registered.
+ base::Value::Type GetType(const std::string& key) const;
+
+ protected:
+ virtual ~DefaultPrefStore();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore);
+};
+
+#endif // BASE_PREFS_DEFAULT_PREF_STORE_H_
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc
new file mode 100644
index 0000000..18dc0b7
--- /dev/null
+++ b/base/prefs/json_pref_store.cc
@@ -0,0 +1,344 @@
+// Copyright (c) 2012 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 "base/prefs/json_pref_store.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop_proxy.h"
+#include "base/values.h"
+
+namespace {
+
+// Some extensions we'll tack on to copies of the Preferences files.
+const FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad");
+
+// Differentiates file loading between origin thread and passed
+// (aka file) thread.
+class FileThreadDeserializer
+ : public base::RefCountedThreadSafe<FileThreadDeserializer> {
+ public:
+ FileThreadDeserializer(JsonPrefStore* delegate,
+ base::MessageLoopProxy* file_loop_proxy)
+ : no_dir_(false),
+ error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
+ delegate_(delegate),
+ file_loop_proxy_(file_loop_proxy),
+ origin_loop_proxy_(base::MessageLoopProxy::current()) {
+ }
+
+ void Start(const FilePath& path) {
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+ file_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(&FileThreadDeserializer::ReadFileAndReport,
+ this, path));
+ }
+
+ // Deserializes JSON on the file thread.
+ void ReadFileAndReport(const FilePath& path) {
+ DCHECK(file_loop_proxy_->BelongsToCurrentThread());
+
+ value_.reset(DoReading(path, &error_, &no_dir_));
+
+ origin_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this));
+ }
+
+ // Reports deserialization result on the origin thread.
+ void ReportOnOriginThread() {
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+ delegate_->OnFileRead(value_.release(), error_, no_dir_);
+ }
+
+ static Value* DoReading(const FilePath& path,
+ PersistentPrefStore::PrefReadError* error,
+ bool* no_dir) {
+ int error_code;
+ std::string error_msg;
+ JSONFileValueSerializer serializer(path);
+ Value* value = serializer.Deserialize(&error_code, &error_msg);
+ HandleErrors(value, path, error_code, error_msg, error);
+ *no_dir = !file_util::PathExists(path.DirName());
+ return value;
+ }
+
+ static void HandleErrors(const Value* value,
+ const FilePath& path,
+ int error_code,
+ const std::string& error_msg,
+ PersistentPrefStore::PrefReadError* error);
+
+ private:
+ friend class base::RefCountedThreadSafe<FileThreadDeserializer>;
+ ~FileThreadDeserializer() {}
+
+ bool no_dir_;
+ PersistentPrefStore::PrefReadError error_;
+ scoped_ptr<Value> value_;
+ scoped_refptr<JsonPrefStore> delegate_;
+ scoped_refptr<base::MessageLoopProxy> file_loop_proxy_;
+ scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
+};
+
+// static
+void FileThreadDeserializer::HandleErrors(
+ const Value* value,
+ const FilePath& path,
+ int error_code,
+ const std::string& error_msg,
+ PersistentPrefStore::PrefReadError* error) {
+ *error = PersistentPrefStore::PREF_READ_ERROR_NONE;
+ if (!value) {
+ DVLOG(1) << "Error while loading JSON file: " << error_msg;
+ switch (error_code) {
+ case JSONFileValueSerializer::JSON_ACCESS_DENIED:
+ *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
+ break;
+ case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
+ *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
+ break;
+ case JSONFileValueSerializer::JSON_FILE_LOCKED:
+ *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
+ break;
+ case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
+ *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
+ break;
+ default:
+ *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
+ // JSON errors indicate file corruption of some sort.
+ // Since the file is corrupt, move it to the side and continue with
+ // empty preferences. This will result in them losing their settings.
+ // We keep the old file for possible support and debugging assistance
+ // as well as to detect if they're seeing these errors repeatedly.
+ // TODO(erikkay) Instead, use the last known good file.
+ FilePath bad = path.ReplaceExtension(kBadExtension);
+
+ // If they've ever had a parse error before, put them in another bucket.
+ // TODO(erikkay) if we keep this error checking for very long, we may
+ // want to differentiate between recent and long ago errors.
+ if (file_util::PathExists(bad))
+ *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT;
+ file_util::Move(path, bad);
+ break;
+ }
+ } else if (!value->IsType(Value::TYPE_DICTIONARY)) {
+ *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
+ }
+}
+
+} // namespace
+
+JsonPrefStore::JsonPrefStore(const FilePath& filename,
+ base::MessageLoopProxy* file_message_loop_proxy)
+ : path_(filename),
+ file_message_loop_proxy_(file_message_loop_proxy),
+ prefs_(new DictionaryValue()),
+ read_only_(false),
+ writer_(filename, file_message_loop_proxy),
+ error_delegate_(NULL),
+ initialized_(false),
+ read_error_(PREF_READ_ERROR_OTHER) {
+}
+
+PrefStore::ReadResult JsonPrefStore::GetValue(const std::string& key,
+ const Value** result) const {
+ Value* tmp = NULL;
+ if (prefs_->Get(key, &tmp)) {
+ if (result)
+ *result = tmp;
+ return READ_OK;
+ }
+ return READ_NO_VALUE;
+}
+
+void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+size_t JsonPrefStore::NumberOfObservers() const {
+ return observers_.size();
+}
+
+bool JsonPrefStore::IsInitializationComplete() const {
+ return initialized_;
+}
+
+PrefStore::ReadResult JsonPrefStore::GetMutableValue(const std::string& key,
+ Value** result) {
+ return prefs_->Get(key, result) ? READ_OK : READ_NO_VALUE;
+}
+
+void JsonPrefStore::SetValue(const std::string& key, Value* value) {
+ DCHECK(value);
+ scoped_ptr<Value> new_value(value);
+ Value* old_value = NULL;
+ prefs_->Get(key, &old_value);
+ if (!old_value || !value->Equals(old_value)) {
+ prefs_->Set(key, new_value.release());
+ ReportValueChanged(key);
+ }
+}
+
+void JsonPrefStore::SetValueSilently(const std::string& key, Value* value) {
+ DCHECK(value);
+ scoped_ptr<Value> new_value(value);
+ Value* old_value = NULL;
+ prefs_->Get(key, &old_value);
+ if (!old_value || !value->Equals(old_value)) {
+ prefs_->Set(key, new_value.release());
+ if (!read_only_)
+ writer_.ScheduleWrite(this);
+ }
+}
+
+void JsonPrefStore::RemoveValue(const std::string& key) {
+ if (prefs_->Remove(key, NULL))
+ ReportValueChanged(key);
+}
+
+void JsonPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+ keys_need_empty_value_.insert(key);
+}
+
+bool JsonPrefStore::ReadOnly() const {
+ return read_only_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
+ return read_error_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
+ if (path_.empty()) {
+ OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
+ return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
+ }
+
+ PrefReadError error;
+ bool no_dir;
+ Value* value = FileThreadDeserializer::DoReading(path_, &error, &no_dir);
+ OnFileRead(value, error, no_dir);
+ return error;
+}
+
+void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) {
+ initialized_ = false;
+ error_delegate_.reset(error_delegate);
+ if (path_.empty()) {
+ OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
+ return;
+ }
+
+ // Start async reading of the preferences file. It will delete itself
+ // in the end.
+ scoped_refptr<FileThreadDeserializer> deserializer(
+ new FileThreadDeserializer(this, file_message_loop_proxy_.get()));
+ deserializer->Start(path_);
+}
+
+void JsonPrefStore::CommitPendingWrite() {
+ if (writer_.HasPendingWrite() && !read_only_)
+ writer_.DoScheduledWrite();
+}
+
+void JsonPrefStore::ReportValueChanged(const std::string& key) {
+ FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+ if (!read_only_)
+ writer_.ScheduleWrite(this);
+}
+
+void JsonPrefStore::OnFileRead(Value* value_owned,
+ PersistentPrefStore::PrefReadError error,
+ bool no_dir) {
+ scoped_ptr<Value> value(value_owned);
+ read_error_ = error;
+
+ if (no_dir) {
+ FOR_EACH_OBSERVER(PrefStore::Observer,
+ observers_,
+ OnInitializationCompleted(false));
+ return;
+ }
+
+ initialized_ = true;
+
+ switch (error) {
+ case PREF_READ_ERROR_ACCESS_DENIED:
+ case PREF_READ_ERROR_FILE_OTHER:
+ case PREF_READ_ERROR_FILE_LOCKED:
+ case PREF_READ_ERROR_JSON_TYPE:
+ case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
+ read_only_ = true;
+ break;
+ case PREF_READ_ERROR_NONE:
+ DCHECK(value.get());
+ prefs_.reset(static_cast<DictionaryValue*>(value.release()));
+ break;
+ case PREF_READ_ERROR_NO_FILE:
+ // If the file just doesn't exist, maybe this is first run. In any case
+ // there's no harm in writing out default prefs in this case.
+ break;
+ case PREF_READ_ERROR_JSON_PARSE:
+ case PREF_READ_ERROR_JSON_REPEAT:
+ break;
+ default:
+ NOTREACHED() << "Unknown error: " << error;
+ }
+
+ if (error_delegate_.get() && error != PREF_READ_ERROR_NONE)
+ error_delegate_->OnError(error);
+
+ FOR_EACH_OBSERVER(PrefStore::Observer,
+ observers_,
+ OnInitializationCompleted(true));
+}
+
+JsonPrefStore::~JsonPrefStore() {
+ CommitPendingWrite();
+}
+
+bool JsonPrefStore::SerializeData(std::string* output) {
+ // TODO(tc): Do we want to prune webkit preferences that match the default
+ // value?
+ JSONStringValueSerializer serializer(output);
+ serializer.set_pretty_print(true);
+ scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren());
+
+ // Iterates |keys_need_empty_value_| and if the key exists in |prefs_|,
+ // ensure its empty ListValue or DictonaryValue is preserved.
+ for (std::set<std::string>::const_iterator
+ it = keys_need_empty_value_.begin();
+ it != keys_need_empty_value_.end();
+ ++it) {
+ const std::string& key = *it;
+
+ base::Value* value = NULL;
+ if (!prefs_->Get(key, &value))
+ continue;
+
+ if (value->IsType(base::Value::TYPE_LIST)) {
+ const base::ListValue* list = NULL;
+ if (value->GetAsList(&list) && list->empty())
+ copy->Set(key, new base::ListValue);
+ } else if (value->IsType(base::Value::TYPE_DICTIONARY)) {
+ const base::DictionaryValue* dict = NULL;
+ if (value->GetAsDictionary(&dict) && dict->empty())
+ copy->Set(key, new base::DictionaryValue);
+ }
+ }
+
+ return serializer.Serialize(*(copy.get()));
+}
diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h
new file mode 100644
index 0000000..3ed1ffb1
--- /dev/null
+++ b/base/prefs/json_pref_store.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 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 BASE_PREFS_JSON_PREF_STORE_H_
+#define BASE_PREFS_JSON_PREF_STORE_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "chrome/common/important_file_writer.h"
+
+namespace base {
+class DictionaryValue;
+class MessageLoopProxy;
+class Value;
+}
+
+class FilePath;
+
+// A writable PrefStore implementation that is used for user preferences.
+class JsonPrefStore : public PersistentPrefStore,
+ public ImportantFileWriter::DataSerializer {
+ public:
+ // |file_message_loop_proxy| is the MessageLoopProxy for a thread on which
+ // file I/O can be done.
+ JsonPrefStore(const FilePath& pref_filename,
+ base::MessageLoopProxy* file_message_loop_proxy);
+
+ // PrefStore overrides:
+ virtual ReadResult GetValue(const std::string& key,
+ const base::Value** result) const OVERRIDE;
+ virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE;
+ virtual size_t NumberOfObservers() const OVERRIDE;
+ virtual bool IsInitializationComplete() const OVERRIDE;
+
+ // PersistentPrefStore overrides:
+ virtual ReadResult GetMutableValue(const std::string& key,
+ base::Value** result) OVERRIDE;
+ virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE;
+ virtual void SetValueSilently(const std::string& key,
+ base::Value* value) OVERRIDE;
+ virtual void RemoveValue(const std::string& key) OVERRIDE;
+ virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
+ virtual bool ReadOnly() const OVERRIDE;
+ virtual PrefReadError GetReadError() const OVERRIDE;
+ virtual PrefReadError ReadPrefs() OVERRIDE;
+ virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE;
+ virtual void CommitPendingWrite() OVERRIDE;
+ virtual void ReportValueChanged(const std::string& key) OVERRIDE;
+
+ // This method is called after JSON file has been read. Method takes
+ // ownership of the |value| pointer. Note, this method is used with
+ // asynchronous file reading, so class exposes it only for the internal needs.
+ // (read: do not call it manually).
+ void OnFileRead(base::Value* value_owned, PrefReadError error, bool no_dir);
+
+ private:
+ virtual ~JsonPrefStore();
+
+ // ImportantFileWriter::DataSerializer overrides:
+ virtual bool SerializeData(std::string* output) OVERRIDE;
+
+ FilePath path_;
+ scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy_;
+
+ scoped_ptr<base::DictionaryValue> prefs_;
+
+ bool read_only_;
+
+ // Helper for safely writing pref data.
+ ImportantFileWriter writer_;
+
+ ObserverList<PrefStore::Observer, true> observers_;
+
+ scoped_ptr<ReadErrorDelegate> error_delegate_;
+
+ bool initialized_;
+ PrefReadError read_error_;
+
+ std::set<std::string> keys_need_empty_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
+};
+
+#endif // BASE_PREFS_JSON_PREF_STORE_H_
diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
new file mode 100644
index 0000000..14723ab
--- /dev/null
+++ b/base/prefs/json_pref_store_unittest.cc
@@ -0,0 +1,293 @@
+// Copyright (c) 2012 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 "base/file_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/path_service.h"
+#include "base/prefs/json_pref_store.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/threading/thread.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/pref_names.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MockPrefStoreObserver : public PrefStore::Observer {
+ public:
+ MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
+ MOCK_METHOD1(OnInitializationCompleted, void (bool));
+};
+
+class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
+ public:
+ MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
+};
+
+} // namespace
+
+class JsonPrefStoreTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ message_loop_proxy_ = base::MessageLoopProxy::current();
+
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_dir_));
+ data_dir_ = data_dir_.AppendASCII("pref_service");
+ ASSERT_TRUE(file_util::PathExists(data_dir_));
+ }
+
+ // The path to temporary directory used to contain the test operations.
+ ScopedTempDir temp_dir_;
+ // The path to the directory where the test data is stored.
+ FilePath data_dir_;
+ // A message loop that we can use as the file thread message loop.
+ MessageLoop message_loop_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+};
+
+// Test fallback behavior for a nonexistent file.
+TEST_F(JsonPrefStoreTest, NonExistentFile) {
+ FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+ ASSERT_FALSE(file_util::PathExists(bogus_input_file));
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(bogus_input_file, message_loop_proxy_.get());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+ pref_store->ReadPrefs());
+ EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+// Test fallback behavior for an invalid file.
+TEST_F(JsonPrefStoreTest, InvalidFile) {
+ FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
+ FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
+ ASSERT_TRUE(file_util::CopyFile(invalid_file_original, invalid_file));
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(invalid_file, message_loop_proxy_.get());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
+ pref_store->ReadPrefs());
+ EXPECT_FALSE(pref_store->ReadOnly());
+
+ // The file should have been moved aside.
+ EXPECT_FALSE(file_util::PathExists(invalid_file));
+ FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad");
+ EXPECT_TRUE(file_util::PathExists(moved_aside));
+ EXPECT_TRUE(file_util::TextContentsEqual(invalid_file_original,
+ moved_aside));
+}
+
+// This function is used to avoid code duplication while testing synchronous and
+// asynchronous version of the JsonPrefStore loading.
+void RunBasicJsonPrefStoreTest(JsonPrefStore *pref_store,
+ const FilePath& output_file,
+ const FilePath& golden_output_file) {
+ const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
+ const char kMaxTabs[] = "tabs.max_tabs";
+ const char kLongIntPref[] = "long_int.pref";
+
+ std::string cnn("http://www.cnn.com");
+
+ const Value* actual;
+ EXPECT_EQ(PrefStore::READ_OK,
+ pref_store->GetValue(prefs::kHomePage, &actual));
+ std::string string_value;
+ EXPECT_TRUE(actual->GetAsString(&string_value));
+ EXPECT_EQ(cnn, string_value);
+
+ const char kSomeDirectory[] = "some_directory";
+
+ EXPECT_EQ(PrefStore::READ_OK, pref_store->GetValue(kSomeDirectory, &actual));
+ FilePath::StringType path;
+ EXPECT_TRUE(actual->GetAsString(&path));
+ EXPECT_EQ(FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
+ FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
+
+ pref_store->SetValue(kSomeDirectory,
+ Value::CreateStringValue(some_path.value()));
+ EXPECT_EQ(PrefStore::READ_OK, pref_store->GetValue(kSomeDirectory, &actual));
+ EXPECT_TRUE(actual->GetAsString(&path));
+ EXPECT_EQ(some_path.value(), path);
+
+ // Test reading some other data types from sub-dictionaries.
+ EXPECT_EQ(PrefStore::READ_OK,
+ pref_store->GetValue(kNewWindowsInTabs, &actual));
+ bool boolean = false;
+ EXPECT_TRUE(actual->GetAsBoolean(&boolean));
+ EXPECT_TRUE(boolean);
+
+ pref_store->SetValue(kNewWindowsInTabs,
+ Value::CreateBooleanValue(false));
+ EXPECT_EQ(PrefStore::READ_OK,
+ pref_store->GetValue(kNewWindowsInTabs, &actual));
+ EXPECT_TRUE(actual->GetAsBoolean(&boolean));
+ EXPECT_FALSE(boolean);
+
+ EXPECT_EQ(PrefStore::READ_OK, pref_store->GetValue(kMaxTabs, &actual));
+ int integer = 0;
+ EXPECT_TRUE(actual->GetAsInteger(&integer));
+ EXPECT_EQ(20, integer);
+ pref_store->SetValue(kMaxTabs, Value::CreateIntegerValue(10));
+ EXPECT_EQ(PrefStore::READ_OK, pref_store->GetValue(kMaxTabs, &actual));
+ EXPECT_TRUE(actual->GetAsInteger(&integer));
+ EXPECT_EQ(10, integer);
+
+ pref_store->SetValue(kLongIntPref,
+ Value::CreateStringValue(
+ base::Int64ToString(214748364842LL)));
+ EXPECT_EQ(PrefStore::READ_OK, pref_store->GetValue(kLongIntPref, &actual));
+ EXPECT_TRUE(actual->GetAsString(&string_value));
+ int64 value;
+ base::StringToInt64(string_value, &value);
+ EXPECT_EQ(214748364842LL, value);
+
+ // Serialize and compare to expected output.
+ ASSERT_TRUE(file_util::PathExists(golden_output_file));
+ pref_store->CommitPendingWrite();
+ MessageLoop::current()->RunAllPending();
+ EXPECT_TRUE(file_util::TextContentsEqual(golden_output_file, output_file));
+ ASSERT_TRUE(file_util::Delete(output_file, false));
+}
+
+TEST_F(JsonPrefStoreTest, Basic) {
+ ASSERT_TRUE(file_util::CopyFile(data_dir_.AppendASCII("read.json"),
+ temp_dir_.path().AppendASCII("write.json")));
+
+ // Test that the persistent value can be loaded.
+ FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ ASSERT_TRUE(file_util::PathExists(input_file));
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, message_loop_proxy_.get());
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+ ASSERT_FALSE(pref_store->ReadOnly());
+
+ // The JSON file looks like this:
+ // {
+ // "homepage": "http://www.cnn.com",
+ // "some_directory": "/usr/local/",
+ // "tabs": {
+ // "new_windows_in_tabs": true,
+ // "max_tabs": 20
+ // }
+ // }
+
+ RunBasicJsonPrefStoreTest(pref_store,
+ input_file,
+ data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, BasicAsync) {
+ ASSERT_TRUE(file_util::CopyFile(data_dir_.AppendASCII("read.json"),
+ temp_dir_.path().AppendASCII("write.json")));
+
+ // Test that the persistent value can be loaded.
+ FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ ASSERT_TRUE(file_util::PathExists(input_file));
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, message_loop_proxy_.get());
+
+ MockPrefStoreObserver mock_observer;
+ pref_store->AddObserver(&mock_observer);
+
+ MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
+ pref_store->ReadPrefsAsync(mock_error_delegate);
+
+ EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+ EXPECT_CALL(*mock_error_delegate,
+ OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+ message_loop_.RunAllPending();
+ pref_store->RemoveObserver(&mock_observer);
+
+ ASSERT_FALSE(pref_store->ReadOnly());
+
+ // The JSON file looks like this:
+ // {
+ // "homepage": "http://www.cnn.com",
+ // "some_directory": "/usr/local/",
+ // "tabs": {
+ // "new_windows_in_tabs": true,
+ // "max_tabs": 20
+ // }
+ // }
+
+ RunBasicJsonPrefStoreTest(pref_store,
+ input_file,
+ data_dir_.AppendASCII("write.golden.json"));
+}
+
+// Tests asynchronous reading of the file when there is no file.
+TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
+ FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+ ASSERT_FALSE(file_util::PathExists(bogus_input_file));
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(bogus_input_file, message_loop_proxy_.get());
+ MockPrefStoreObserver mock_observer;
+ pref_store->AddObserver(&mock_observer);
+
+ MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
+ pref_store->ReadPrefsAsync(mock_error_delegate);
+
+ EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+ EXPECT_CALL(*mock_error_delegate,
+ OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
+ message_loop_.RunAllPending();
+ pref_store->RemoveObserver(&mock_observer);
+
+ EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+TEST_F(JsonPrefStoreTest, NeedsEmptyValue) {
+ FilePath pref_file = temp_dir_.path().AppendASCII("write.json");
+
+ ASSERT_TRUE(file_util::CopyFile(
+ data_dir_.AppendASCII("read.need_empty_value.json"),
+ pref_file));
+
+ // Test that the persistent value can be loaded.
+ ASSERT_TRUE(file_util::PathExists(pref_file));
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(pref_file, message_loop_proxy_.get());
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+ ASSERT_FALSE(pref_store->ReadOnly());
+
+ // The JSON file looks like this:
+ // {
+ // "list": [ 1 ],
+ // "list_needs_empty_value": [ 2 ],
+ // "dict": {
+ // "dummy": true,
+ // },
+ // "dict_needs_empty_value": {
+ // "dummy": true,
+ // },
+ // }
+
+ // Set flag to preserve empty values for the following keys.
+ pref_store->MarkNeedsEmptyValue("list_needs_empty_value");
+ pref_store->MarkNeedsEmptyValue("dict_needs_empty_value");
+
+ // Set all keys to empty values.
+ pref_store->SetValue("list", new base::ListValue);
+ pref_store->SetValue("list_needs_empty_value", new base::ListValue);
+ pref_store->SetValue("dict", new base::DictionaryValue);
+ pref_store->SetValue("dict_needs_empty_value", new base::DictionaryValue);
+
+ // Write to file.
+ pref_store->CommitPendingWrite();
+ MessageLoop::current()->RunAllPending();
+
+ // Compare to expected output.
+ FilePath golden_output_file =
+ data_dir_.AppendASCII("write.golden.need_empty_value.json");
+ ASSERT_TRUE(file_util::PathExists(golden_output_file));
+ EXPECT_TRUE(file_util::TextContentsEqual(golden_output_file, pref_file));
+}
diff --git a/base/prefs/overlay_user_pref_store.cc b/base/prefs/overlay_user_pref_store.cc
new file mode 100644
index 0000000..26ee45e
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2012 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 "base/prefs/overlay_user_pref_store.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+OverlayUserPrefStore::OverlayUserPrefStore(
+ PersistentPrefStore* underlay)
+ : underlay_(underlay) {
+ underlay_->AddObserver(this);
+}
+
+bool OverlayUserPrefStore::IsSetInOverlay(const std::string& key) const {
+ return overlay_.GetValue(key, NULL);
+}
+
+void OverlayUserPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void OverlayUserPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+size_t OverlayUserPrefStore::NumberOfObservers() const {
+ return observers_.size();
+}
+
+bool OverlayUserPrefStore::IsInitializationComplete() const {
+ return underlay_->IsInitializationComplete();
+}
+
+PrefStore::ReadResult OverlayUserPrefStore::GetValue(
+ const std::string& key,
+ const Value** result) const {
+ // If the |key| shall NOT be stored in the overlay store, there must not
+ // be an entry.
+ DCHECK(ShallBeStoredInOverlay(key) || !overlay_.GetValue(key, NULL));
+
+ if (overlay_.GetValue(key, result))
+ return READ_OK;
+ return underlay_->GetValue(GetUnderlayKey(key), result);
+}
+
+PrefStore::ReadResult OverlayUserPrefStore::GetMutableValue(
+ const std::string& key,
+ Value** result) {
+ if (!ShallBeStoredInOverlay(key))
+ return underlay_->GetMutableValue(GetUnderlayKey(key), result);
+
+ if (overlay_.GetValue(key, result))
+ return READ_OK;
+
+ // Try to create copy of underlay if the overlay does not contain a value.
+ Value* underlay_value = NULL;
+ PrefStore::ReadResult read_result =
+ underlay_->GetMutableValue(GetUnderlayKey(key), &underlay_value);
+ if (read_result != READ_OK)
+ return read_result;
+
+ *result = underlay_value->DeepCopy();
+ overlay_.SetValue(key, *result);
+ return READ_OK;
+}
+
+void OverlayUserPrefStore::SetValue(const std::string& key,
+ Value* value) {
+ if (!ShallBeStoredInOverlay(key)) {
+ underlay_->SetValue(GetUnderlayKey(key), value);
+ return;
+ }
+
+ if (overlay_.SetValue(key, value))
+ ReportValueChanged(key);
+}
+
+void OverlayUserPrefStore::SetValueSilently(const std::string& key,
+ Value* value) {
+ if (!ShallBeStoredInOverlay(key)) {
+ underlay_->SetValueSilently(GetUnderlayKey(key), value);
+ return;
+ }
+
+ overlay_.SetValue(key, value);
+}
+
+void OverlayUserPrefStore::RemoveValue(const std::string& key) {
+ if (!ShallBeStoredInOverlay(key)) {
+ underlay_->RemoveValue(GetUnderlayKey(key));
+ return;
+ }
+
+ if (overlay_.RemoveValue(key))
+ ReportValueChanged(key);
+}
+
+void OverlayUserPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+ if (!ShallBeStoredInOverlay(key))
+ underlay_->MarkNeedsEmptyValue(key);
+}
+
+bool OverlayUserPrefStore::ReadOnly() const {
+ return false;
+}
+
+PersistentPrefStore::PrefReadError OverlayUserPrefStore::GetReadError() const {
+ return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+PersistentPrefStore::PrefReadError OverlayUserPrefStore::ReadPrefs() {
+ // We do not read intentionally.
+ OnInitializationCompleted(true);
+ return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+void OverlayUserPrefStore::ReadPrefsAsync(
+ ReadErrorDelegate* error_delegate_raw) {
+ scoped_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
+ // We do not read intentionally.
+ OnInitializationCompleted(true);
+}
+
+void OverlayUserPrefStore::CommitPendingWrite() {
+ underlay_->CommitPendingWrite();
+ // We do not write our content intentionally.
+}
+
+void OverlayUserPrefStore::ReportValueChanged(const std::string& key) {
+ FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+}
+
+void OverlayUserPrefStore::OnPrefValueChanged(const std::string& key) {
+ if (!overlay_.GetValue(GetOverlayKey(key), NULL))
+ ReportValueChanged(GetOverlayKey(key));
+}
+
+void OverlayUserPrefStore::OnInitializationCompleted(bool succeeded) {
+ FOR_EACH_OBSERVER(PrefStore::Observer, observers_,
+ OnInitializationCompleted(succeeded));
+}
+
+void OverlayUserPrefStore::RegisterOverlayPref(const std::string& key) {
+ RegisterOverlayPref(key, key);
+}
+
+void OverlayUserPrefStore::RegisterOverlayPref(
+ const std::string& overlay_key,
+ const std::string& underlay_key) {
+ DCHECK(!overlay_key.empty()) << "Overlay key is empty";
+ DCHECK(overlay_to_underlay_names_map_.find(overlay_key) ==
+ overlay_to_underlay_names_map_.end()) <<
+ "Overlay key already registered";
+ DCHECK(!underlay_key.empty()) << "Underlay key is empty";
+ DCHECK(underlay_to_overlay_names_map_.find(underlay_key) ==
+ underlay_to_overlay_names_map_.end()) <<
+ "Underlay key already registered";
+ overlay_to_underlay_names_map_[overlay_key] = underlay_key;
+ underlay_to_overlay_names_map_[underlay_key] = overlay_key;
+}
+
+OverlayUserPrefStore::~OverlayUserPrefStore() {
+ underlay_->RemoveObserver(this);
+}
+
+const std::string& OverlayUserPrefStore::GetOverlayKey(
+ const std::string& underlay_key) const {
+ NamesMap::const_iterator i =
+ underlay_to_overlay_names_map_.find(underlay_key);
+ return i != underlay_to_overlay_names_map_.end() ? i->second : underlay_key;
+}
+
+const std::string& OverlayUserPrefStore::GetUnderlayKey(
+ const std::string& overlay_key) const {
+ NamesMap::const_iterator i =
+ overlay_to_underlay_names_map_.find(overlay_key);
+ return i != overlay_to_underlay_names_map_.end() ? i->second : overlay_key;
+}
+
+bool OverlayUserPrefStore::ShallBeStoredInOverlay(
+ const std::string& key) const {
+ return overlay_to_underlay_names_map_.find(key) !=
+ overlay_to_underlay_names_map_.end();
+}
diff --git a/base/prefs/overlay_user_pref_store.h b/base/prefs/overlay_user_pref_store.h
new file mode 100644
index 0000000..5c33c79
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 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 BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
+#define BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// PersistentPrefStore that directs all write operations into an in-memory
+// PrefValueMap. Read operations are first answered by the PrefValueMap.
+// If the PrefValueMap does not contain a value for the requested key,
+// the look-up is passed on to an underlying PersistentPrefStore |underlay_|.
+class OverlayUserPrefStore : public PersistentPrefStore,
+ public PrefStore::Observer {
+ public:
+ explicit OverlayUserPrefStore(PersistentPrefStore* underlay);
+
+ // Returns true if a value has been set for the |key| in this
+ // OverlayUserPrefStore, i.e. if it potentially overrides a value
+ // from the |underlay_|.
+ virtual bool IsSetInOverlay(const std::string& key) const;
+
+ // Methods of PrefStore.
+ virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE;
+ virtual size_t NumberOfObservers() const OVERRIDE;
+ virtual bool IsInitializationComplete() const OVERRIDE;
+ virtual ReadResult GetValue(const std::string& key,
+ const base::Value** result) const OVERRIDE;
+
+ // Methods of PersistentPrefStore.
+ virtual ReadResult GetMutableValue(const std::string& key,
+ base::Value** result) OVERRIDE;
+ virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE;
+ virtual void SetValueSilently(const std::string& key,
+ base::Value* value) OVERRIDE;
+ virtual void RemoveValue(const std::string& key) OVERRIDE;
+ virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
+ virtual bool ReadOnly() const OVERRIDE;
+ virtual PrefReadError GetReadError() const OVERRIDE;
+ virtual PrefReadError ReadPrefs() OVERRIDE;
+ virtual void ReadPrefsAsync(ReadErrorDelegate* delegate) OVERRIDE;
+ virtual void CommitPendingWrite() OVERRIDE;
+ virtual void ReportValueChanged(const std::string& key) OVERRIDE;
+
+ // Methods of PrefStore::Observer.
+ virtual void OnPrefValueChanged(const std::string& key) OVERRIDE;
+ virtual void OnInitializationCompleted(bool succeeded) OVERRIDE;
+
+ void RegisterOverlayPref(const std::string& key);
+ void RegisterOverlayPref(const std::string& overlay_key,
+ const std::string& underlay_key);
+
+ protected:
+ virtual ~OverlayUserPrefStore();
+
+ private:
+ typedef std::map<std::string, std::string> NamesMap;
+
+ const std::string& GetOverlayKey(const std::string& underlay_key) const;
+ const std::string& GetUnderlayKey(const std::string& overlay_key) const;
+
+ // Returns true if |key| corresponds to a preference that shall be stored in
+ // an in-memory PrefStore that is not persisted to disk.
+ bool ShallBeStoredInOverlay(const std::string& key) const;
+
+ ObserverList<PrefStore::Observer, true> observers_;
+ PrefValueMap overlay_;
+ scoped_refptr<PersistentPrefStore> underlay_;
+ NamesMap overlay_to_underlay_names_map_;
+ NamesMap underlay_to_overlay_names_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(OverlayUserPrefStore);
+};
+
+#endif // BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
diff --git a/base/prefs/overlay_user_pref_store_unittest.cc b/base/prefs/overlay_user_pref_store_unittest.cc
new file mode 100644
index 0000000..85b937f
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store_unittest.cc
@@ -0,0 +1,282 @@
+// Copyright (c) 2012 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 "base/prefs/overlay_user_pref_store.h"
+#include "base/prefs/pref_store_observer_mock.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/values.h"
+#include "chrome/common/pref_names.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::StrEq;
+
+namespace {
+
+const char* overlay_key = prefs::kBrowserWindowPlacement;
+const char* regular_key = prefs::kShowBookmarkBar;
+// With the removal of the kWebKitGlobalXXX prefs, we'll no longer have real
+// prefs using the overlay pref store, so make up keys here.
+const char* mapped_overlay_key = "test.per_tab.javascript_enabled";
+const char* mapped_underlay_key = "test.per_profile.javascript_enabled";
+
+} // namespace
+
+class OverlayUserPrefStoreTest : public testing::Test {
+ protected:
+ OverlayUserPrefStoreTest()
+ : underlay_(new TestingPrefStore()),
+ overlay_(new OverlayUserPrefStore(underlay_.get())) {
+ overlay_->RegisterOverlayPref(overlay_key);
+ overlay_->RegisterOverlayPref(mapped_overlay_key, mapped_underlay_key);
+ }
+
+ virtual ~OverlayUserPrefStoreTest() {}
+
+ scoped_refptr<TestingPrefStore> underlay_;
+ scoped_refptr<OverlayUserPrefStore> overlay_;
+};
+
+TEST_F(OverlayUserPrefStoreTest, Observer) {
+ PrefStoreObserverMock obs;
+ overlay_->AddObserver(&obs);
+
+ // Check that underlay first value is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+ underlay_->SetValue(overlay_key, Value::CreateIntegerValue(42));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that underlay overwriting is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+ underlay_->SetValue(overlay_key, Value::CreateIntegerValue(43));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that overwriting change in overlay is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+ overlay_->SetValue(overlay_key, Value::CreateIntegerValue(44));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that hidden underlay change is not reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0);
+ underlay_->SetValue(overlay_key, Value::CreateIntegerValue(45));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that overlay remove is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+ overlay_->RemoveValue(overlay_key);
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that underlay remove is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1);
+ underlay_->RemoveValue(overlay_key);
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check respecting of silence.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0);
+ overlay_->SetValueSilently(overlay_key, Value::CreateIntegerValue(46));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ overlay_->RemoveObserver(&obs);
+
+ // Check successful unsubscription.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0);
+ underlay_->SetValue(overlay_key, Value::CreateIntegerValue(47));
+ overlay_->SetValue(overlay_key, Value::CreateIntegerValue(48));
+ Mock::VerifyAndClearExpectations(&obs);
+}
+
+TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
+ const Value* value = NULL;
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ overlay_->GetValue(overlay_key, &value));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ underlay_->GetValue(overlay_key, &value));
+
+ underlay_->SetValue(overlay_key, Value::CreateIntegerValue(42));
+
+ // Value shines through:
+ EXPECT_EQ(PrefStore::READ_OK, overlay_->GetValue(overlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK, underlay_->GetValue(overlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+ overlay_->SetValue(overlay_key, Value::CreateIntegerValue(43));
+
+ EXPECT_EQ(PrefStore::READ_OK, overlay_->GetValue(overlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK, underlay_->GetValue(overlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+ overlay_->RemoveValue(overlay_key);
+
+ // Value shines through:
+ EXPECT_EQ(PrefStore::READ_OK, overlay_->GetValue(overlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK, underlay_->GetValue(overlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+}
+
+// Check that GetMutableValue does not return the dictionary of the underlay.
+TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) {
+ underlay_->SetValue(overlay_key, new DictionaryValue);
+
+ Value* modify = NULL;
+ EXPECT_EQ(PrefStore::READ_OK,
+ overlay_->GetMutableValue(overlay_key, &modify));
+ ASSERT_TRUE(modify);
+ ASSERT_TRUE(modify->IsType(Value::TYPE_DICTIONARY));
+ static_cast<DictionaryValue*>(modify)->SetInteger(overlay_key, 42);
+
+ Value* original_in_underlay = NULL;
+ EXPECT_EQ(PrefStore::READ_OK,
+ underlay_->GetMutableValue(overlay_key, &original_in_underlay));
+ ASSERT_TRUE(original_in_underlay);
+ ASSERT_TRUE(original_in_underlay->IsType(Value::TYPE_DICTIONARY));
+ EXPECT_TRUE(static_cast<DictionaryValue*>(original_in_underlay)->empty());
+
+ Value* modified = NULL;
+ EXPECT_EQ(PrefStore::READ_OK,
+ overlay_->GetMutableValue(overlay_key, &modified));
+ ASSERT_TRUE(modified);
+ ASSERT_TRUE(modified->IsType(Value::TYPE_DICTIONARY));
+ EXPECT_TRUE(Value::Equals(modify, static_cast<DictionaryValue*>(modified)));
+}
+
+// Here we consider a global preference that is not overlayed.
+TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
+ PrefStoreObserverMock obs;
+ overlay_->AddObserver(&obs);
+
+ const Value* value = NULL;
+
+ // Check that underlay first value is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1);
+ underlay_->SetValue(regular_key, Value::CreateIntegerValue(42));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that underlay overwriting is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1);
+ underlay_->SetValue(regular_key, Value::CreateIntegerValue(43));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that we get this value from the overlay
+ EXPECT_EQ(PrefStore::READ_OK, overlay_->GetValue(regular_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+ // Check that overwriting change in overlay is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1);
+ overlay_->SetValue(regular_key, Value::CreateIntegerValue(44));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that we get this value from the overlay and the underlay.
+ EXPECT_EQ(PrefStore::READ_OK, overlay_->GetValue(regular_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+ EXPECT_EQ(PrefStore::READ_OK, underlay_->GetValue(regular_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+
+ // Check that overlay remove is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1);
+ overlay_->RemoveValue(regular_key);
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that value was removed from overlay and underlay
+ EXPECT_EQ(PrefStore::READ_NO_VALUE, overlay_->GetValue(regular_key, &value));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE, underlay_->GetValue(regular_key, &value));
+
+ // Check respecting of silence.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(0);
+ overlay_->SetValueSilently(regular_key, Value::CreateIntegerValue(46));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ overlay_->RemoveObserver(&obs);
+
+ // Check successful unsubscription.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(0);
+ underlay_->SetValue(regular_key, Value::CreateIntegerValue(47));
+ overlay_->SetValue(regular_key, Value::CreateIntegerValue(48));
+ Mock::VerifyAndClearExpectations(&obs);
+}
+
+// Check that names mapping works correctly.
+TEST_F(OverlayUserPrefStoreTest, NamesMapping) {
+ PrefStoreObserverMock obs;
+ overlay_->AddObserver(&obs);
+
+ const Value* value = NULL;
+
+ // Check that if there is no override in the overlay, changing underlay value
+ // is reported as changing an overlay value.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+ underlay_->SetValue(mapped_underlay_key, Value::CreateIntegerValue(42));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that underlay overwriting is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+ underlay_->SetValue(mapped_underlay_key, Value::CreateIntegerValue(43));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that we get this value from the overlay with both keys
+ EXPECT_EQ(PrefStore::READ_OK, overlay_->GetValue(mapped_overlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+ // In this case, overlay reads directly from the underlay.
+ EXPECT_EQ(PrefStore::READ_OK,
+ overlay_->GetValue(mapped_underlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+ // Check that overwriting change in overlay is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+ overlay_->SetValue(mapped_overlay_key, Value::CreateIntegerValue(44));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that we get an overriden value from overlay, while reading the
+ // value from underlay still holds an old value.
+ EXPECT_EQ(PrefStore::READ_OK, overlay_->GetValue(mapped_overlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+ EXPECT_EQ(PrefStore::READ_OK,
+ overlay_->GetValue(mapped_underlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+ EXPECT_EQ(PrefStore::READ_OK,
+ underlay_->GetValue(mapped_underlay_key, &value));
+ EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+ // Check that hidden underlay change is not reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0);
+ underlay_->SetValue(mapped_underlay_key, Value::CreateIntegerValue(45));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that overlay remove is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+ overlay_->RemoveValue(mapped_overlay_key);
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that underlay remove is reported.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1);
+ underlay_->RemoveValue(mapped_underlay_key);
+ Mock::VerifyAndClearExpectations(&obs);
+
+ // Check that value was removed.
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ overlay_->GetValue(mapped_overlay_key, &value));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ overlay_->GetValue(mapped_underlay_key, &value));
+
+ // Check respecting of silence.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0);
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_underlay_key))).Times(0);
+ overlay_->SetValueSilently(mapped_overlay_key, Value::CreateIntegerValue(46));
+ Mock::VerifyAndClearExpectations(&obs);
+
+ overlay_->RemoveObserver(&obs);
+
+ // Check successful unsubscription.
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0);
+ EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_underlay_key))).Times(0);
+ underlay_->SetValue(mapped_underlay_key, Value::CreateIntegerValue(47));
+ overlay_->SetValue(mapped_overlay_key, Value::CreateIntegerValue(48));
+ Mock::VerifyAndClearExpectations(&obs);
+}
diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h
new file mode 100644
index 0000000..9dd0ff9
--- /dev/null
+++ b/base/prefs/persistent_pref_store.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 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 BASE_PREFS_PERSISTENT_PREF_STORE_H_
+#define BASE_PREFS_PERSISTENT_PREF_STORE_H_
+
+#include <string>
+
+#include "base/prefs/pref_store.h"
+
+// This interface is complementary to the PrefStore interface, declaring
+// additional functionality that adds support for setting values and persisting
+// the data to some backing store.
+class PersistentPrefStore : public PrefStore {
+ public:
+ // Unique integer code for each type of error so we can report them
+ // distinctly in a histogram.
+ // NOTE: Don't change the order here as it will change the server's meaning
+ // of the histogram.
+ enum PrefReadError {
+ PREF_READ_ERROR_NONE = 0,
+ PREF_READ_ERROR_JSON_PARSE,
+ PREF_READ_ERROR_JSON_TYPE,
+ PREF_READ_ERROR_ACCESS_DENIED,
+ PREF_READ_ERROR_FILE_OTHER,
+ PREF_READ_ERROR_FILE_LOCKED,
+ PREF_READ_ERROR_NO_FILE,
+ PREF_READ_ERROR_JSON_REPEAT,
+ PREF_READ_ERROR_OTHER,
+ PREF_READ_ERROR_FILE_NOT_SPECIFIED,
+ PREF_READ_ERROR_MAX_ENUM
+ };
+
+ class ReadErrorDelegate {
+ public:
+ virtual ~ReadErrorDelegate() {}
+
+ virtual void OnError(PrefReadError error) = 0;
+ };
+
+ // Equivalent to PrefStore::GetValue but returns a mutable value.
+ virtual ReadResult GetMutableValue(const std::string& key,
+ base::Value** result) = 0;
+
+ // Triggers a value changed notification. This function needs to be called
+ // if one retrieves a list or dictionary with GetMutableValue and change its
+ // value. SetValue takes care of notifications itself. Note that
+ // ReportValueChanged will trigger notifications even if nothing has changed.
+ virtual void ReportValueChanged(const std::string& key) = 0;
+
+ // Sets a |value| for |key| in the store. Assumes ownership of |value|, which
+ // must be non-NULL.
+ virtual void SetValue(const std::string& key, base::Value* value) = 0;
+
+ // Same as SetValue, but doesn't generate notifications. This is used by
+ // PrefService::GetMutableUserPref() in order to put empty entries
+ // into the user pref store. Using SetValue is not an option since existing
+ // tests rely on the number of notifications generated.
+ virtual void SetValueSilently(const std::string& key, base::Value* value) = 0;
+
+ // Removes the value for |key|.
+ virtual void RemoveValue(const std::string& key) = 0;
+
+ // Marks that the |key| with empty ListValue/DictionaryValue needs to be
+ // persisted.
+ virtual void MarkNeedsEmptyValue(const std::string& key) = 0;
+
+ // Whether the store is in a pseudo-read-only mode where changes are not
+ // actually persisted to disk. This happens in some cases when there are
+ // read errors during startup.
+ virtual bool ReadOnly() const = 0;
+
+ // Gets the read error. Only valid if IsInitializationComplete() returns true.
+ virtual PrefReadError GetReadError() const = 0;
+
+ // Reads the preferences from disk. Notifies observers via
+ // "PrefStore::OnInitializationCompleted" when done.
+ virtual PrefReadError ReadPrefs() = 0;
+
+ // Reads the preferences from disk asynchronously. Notifies observers via
+ // "PrefStore::OnInitializationCompleted" when done. Also it fires
+ // |error_delegate| if it is not NULL and reading error has occurred.
+ // Owns |error_delegate|.
+ virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) = 0;
+
+ // Lands any pending writes to disk.
+ virtual void CommitPendingWrite() = 0;
+
+ protected:
+ virtual ~PersistentPrefStore() {}
+};
+
+#endif // BASE_PREFS_PERSISTENT_PREF_STORE_H_
diff --git a/base/prefs/pref_notifier.h b/base/prefs/pref_notifier.h
new file mode 100644
index 0000000..e0df260
--- /dev/null
+++ b/base/prefs/pref_notifier.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 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 BASE_PREFS_PREF_NOTIFIER_H_
+#define BASE_PREFS_PREF_NOTIFIER_H_
+
+#include <string>
+
+// Delegate interface used by PrefValueStore to notify its owner about changes
+// to the preference values.
+// TODO(mnissler, danno): Move this declaration to pref_value_store.h once we've
+// cleaned up all public uses of this interface.
+class PrefNotifier {
+ public:
+ virtual ~PrefNotifier() {}
+
+ // Sends out a change notification for the preference identified by
+ // |pref_name|.
+ virtual void OnPreferenceChanged(const std::string& pref_name) = 0;
+
+ // Broadcasts the intialization completed notification.
+ virtual void OnInitializationCompleted(bool succeeded) = 0;
+};
+
+#endif // BASE_PREFS_PREF_NOTIFIER_H_
diff --git a/base/prefs/pref_store.cc b/base/prefs/pref_store.cc
new file mode 100644
index 0000000..0521654
--- /dev/null
+++ b/base/prefs/pref_store.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 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 "base/prefs/pref_store.h"
+
+size_t PrefStore::NumberOfObservers() const {
+ return 0;
+}
+
+bool PrefStore::IsInitializationComplete() const {
+ return true;
+}
diff --git a/base/prefs/pref_store.h b/base/prefs/pref_store.h
new file mode 100644
index 0000000..c54fb4e
--- /dev/null
+++ b/base/prefs/pref_store.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2012 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 BASE_PREFS_PREF_STORE_H_
+#define BASE_PREFS_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+class Value;
+}
+
+// This is an abstract interface for reading and writing from/to a persistent
+// preference store, used by PrefService. An implementation using a JSON file
+// can be found in JsonPrefStore, while an implementation without any backing
+// store for testing can be found in TestingPrefStore. Furthermore, there is
+// CommandLinePrefStore, which bridges command line options to preferences and
+// ConfigurationPolicyPrefStore, which is used for hooking up configuration
+// policy with the preference subsystem.
+class PrefStore : public base::RefCounted<PrefStore> {
+ public:
+ // Observer interface for monitoring PrefStore.
+ class Observer {
+ public:
+ // Called when the value for the given |key| in the store changes.
+ virtual void OnPrefValueChanged(const std::string& key) = 0;
+ // Notification about the PrefStore being fully initialized.
+ virtual void OnInitializationCompleted(bool succeeded) = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ // Return values for GetValue().
+ enum ReadResult {
+ // Value found and returned.
+ READ_OK,
+ // No value present, but skip other pref stores and use default.
+ READ_USE_DEFAULT,
+ // No value present.
+ READ_NO_VALUE,
+ };
+
+ PrefStore() {}
+
+ // Add and remove observers.
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
+ virtual size_t NumberOfObservers() const;
+
+ // Whether the store has completed all asynchronous initialization.
+ virtual bool IsInitializationComplete() const;
+
+ // Get the value for a given preference |key| and stores it in |*result|.
+ // |*result| is only modified if the return value is READ_OK and if |result|
+ // is not NULL. Ownership of the |*result| value remains with the PrefStore.
+ virtual ReadResult GetValue(const std::string& key,
+ const base::Value** result) const = 0;
+
+ protected:
+ friend class base::RefCounted<PrefStore>;
+ virtual ~PrefStore() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PrefStore);
+};
+
+#endif // BASE_PREFS_PREF_STORE_H_
diff --git a/base/prefs/pref_store_observer_mock.cc b/base/prefs/pref_store_observer_mock.cc
new file mode 100644
index 0000000..0970e63
--- /dev/null
+++ b/base/prefs/pref_store_observer_mock.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2011 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 "base/prefs/pref_store_observer_mock.h"
+
+PrefStoreObserverMock::PrefStoreObserverMock() {}
+
+PrefStoreObserverMock::~PrefStoreObserverMock() {}
diff --git a/base/prefs/pref_store_observer_mock.h b/base/prefs/pref_store_observer_mock.h
new file mode 100644
index 0000000..8252c3b
--- /dev/null
+++ b/base/prefs/pref_store_observer_mock.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 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 BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
+#define BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
+
+#include "base/basictypes.h"
+#include "base/prefs/pref_store.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+// A gmock-ified implementation of PrefStore::Observer.
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+ PrefStoreObserverMock();
+ virtual ~PrefStoreObserverMock();
+
+ MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
+ MOCK_METHOD1(OnInitializationCompleted, void(bool));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreObserverMock);
+};
+
+#endif // BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
diff --git a/base/prefs/pref_value_map.cc b/base/prefs/pref_value_map.cc
new file mode 100644
index 0000000..48e8fa3
--- /dev/null
+++ b/base/prefs/pref_value_map.cc
@@ -0,0 +1,151 @@
+// Copyright (c) 2011 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 "base/prefs/pref_value_map.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+
+PrefValueMap::PrefValueMap() {}
+
+PrefValueMap::~PrefValueMap() {
+ Clear();
+}
+
+bool PrefValueMap::GetValue(const std::string& key, const Value** value) const {
+ const Map::const_iterator entry = prefs_.find(key);
+ if (entry != prefs_.end()) {
+ if (value)
+ *value = entry->second;
+ return true;
+ }
+
+ return false;
+}
+
+bool PrefValueMap::GetValue(const std::string& key, Value** value) {
+ const Map::const_iterator entry = prefs_.find(key);
+ if (entry != prefs_.end()) {
+ if (value)
+ *value = entry->second;
+ return true;
+ }
+
+ return false;
+}
+
+bool PrefValueMap::SetValue(const std::string& key, Value* value) {
+ DCHECK(value);
+ scoped_ptr<Value> value_ptr(value);
+ const Map::iterator entry = prefs_.find(key);
+ if (entry != prefs_.end()) {
+ if (Value::Equals(entry->second, value))
+ return false;
+ delete entry->second;
+ entry->second = value_ptr.release();
+ } else {
+ prefs_[key] = value_ptr.release();
+ }
+
+ return true;
+}
+
+bool PrefValueMap::RemoveValue(const std::string& key) {
+ const Map::iterator entry = prefs_.find(key);
+ if (entry != prefs_.end()) {
+ delete entry->second;
+ prefs_.erase(entry);
+ return true;
+ }
+
+ return false;
+}
+
+void PrefValueMap::Clear() {
+ STLDeleteValues(&prefs_);
+ prefs_.clear();
+}
+
+void PrefValueMap::Swap(PrefValueMap* other) {
+ prefs_.swap(other->prefs_);
+}
+
+PrefValueMap::iterator PrefValueMap::begin() {
+ return prefs_.begin();
+}
+
+PrefValueMap::iterator PrefValueMap::end() {
+ return prefs_.end();
+}
+
+PrefValueMap::const_iterator PrefValueMap::begin() const {
+ return prefs_.begin();
+}
+
+PrefValueMap::const_iterator PrefValueMap::end() const {
+ return prefs_.end();
+}
+
+bool PrefValueMap::GetBoolean(const std::string& key,
+ bool* value) const {
+ const Value* stored_value = NULL;
+ return GetValue(key, &stored_value) && stored_value->GetAsBoolean(value);
+}
+
+void PrefValueMap::SetBoolean(const std::string& key, bool value) {
+ SetValue(key, Value::CreateBooleanValue(value));
+}
+
+bool PrefValueMap::GetString(const std::string& key,
+ std::string* value) const {
+ const Value* stored_value = NULL;
+ return GetValue(key, &stored_value) && stored_value->GetAsString(value);
+}
+
+void PrefValueMap::SetString(const std::string& key,
+ const std::string& value) {
+ SetValue(key, Value::CreateStringValue(value));
+}
+
+bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
+ const Value* stored_value = NULL;
+ return GetValue(key, &stored_value) && stored_value->GetAsInteger(value);
+}
+
+void PrefValueMap::SetInteger(const std::string& key, const int value) {
+ SetValue(key, Value::CreateIntegerValue(value));
+}
+
+void PrefValueMap::GetDifferingKeys(
+ const PrefValueMap* other,
+ std::vector<std::string>* differing_keys) const {
+ differing_keys->clear();
+
+ // Walk over the maps in lockstep, adding everything that is different.
+ Map::const_iterator this_pref(prefs_.begin());
+ Map::const_iterator other_pref(other->prefs_.begin());
+ while (this_pref != prefs_.end() && other_pref != other->prefs_.end()) {
+ const int diff = this_pref->first.compare(other_pref->first);
+ if (diff == 0) {
+ if (!this_pref->second->Equals(other_pref->second))
+ differing_keys->push_back(this_pref->first);
+ ++this_pref;
+ ++other_pref;
+ } else if (diff < 0) {
+ differing_keys->push_back(this_pref->first);
+ ++this_pref;
+ } else if (diff > 0) {
+ differing_keys->push_back(other_pref->first);
+ ++other_pref;
+ }
+ }
+
+ // Add the remaining entries.
+ for ( ; this_pref != prefs_.end(); ++this_pref)
+ differing_keys->push_back(this_pref->first);
+ for ( ; other_pref != other->prefs_.end(); ++other_pref)
+ differing_keys->push_back(other_pref->first);
+}
diff --git a/base/prefs/pref_value_map.h b/base/prefs/pref_value_map.h
new file mode 100644
index 0000000..9c846dc
--- /dev/null
+++ b/base/prefs/pref_value_map.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 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 BASE_PREFS_PREF_VALUE_MAP_H_
+#define BASE_PREFS_PREF_VALUE_MAP_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+
+namespace base {
+class Value;
+}
+
+// A generic string to value map used by the PrefStore implementations.
+class PrefValueMap {
+ public:
+ typedef std::map<std::string, base::Value*>::iterator iterator;
+ typedef std::map<std::string, base::Value*>::const_iterator const_iterator;
+
+ PrefValueMap();
+ virtual ~PrefValueMap();
+
+ // Gets the value for |key| and stores it in |value|. Ownership remains with
+ // the map. Returns true if a value is present. If not, |value| is not
+ // touched.
+ bool GetValue(const std::string& key, const base::Value** value) const;
+ bool GetValue(const std::string& key, base::Value** value);
+
+ // Sets a new |value| for |key|. Takes ownership of |value|, which must be
+ // non-NULL. Returns true if the value changed.
+ bool SetValue(const std::string& key, base::Value* value);
+
+ // Removes the value for |key| from the map. Returns true if a value was
+ // removed.
+ bool RemoveValue(const std::string& key);
+
+ // Clears the map.
+ void Clear();
+
+ // Swaps the contents of two maps.
+ void Swap(PrefValueMap* other);
+
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ // Gets a boolean value for |key| and stores it in |value|. Returns true if
+ // the value was found and of the proper type.
+ bool GetBoolean(const std::string& key, bool* value) const;
+
+ // Sets the value for |key| to the boolean |value|.
+ void SetBoolean(const std::string& key, bool value);
+
+ // Gets a string value for |key| and stores it in |value|. Returns true if
+ // the value was found and of the proper type.
+ bool GetString(const std::string& key, std::string* value) const;
+
+ // Sets the value for |key| to the string |value|.
+ void SetString(const std::string& key, const std::string& value);
+
+ // Gets an int value for |key| and stores it in |value|. Returns true if
+ // the value was found and of the proper type.
+ bool GetInteger(const std::string& key, int* value) const;
+
+ // Sets the value for |key| to the int |value|.
+ void SetInteger(const std::string& key, const int value);
+
+ // Compares this value map against |other| and stores all key names that have
+ // different values in |differing_keys|. This includes keys that are present
+ // only in one of the maps.
+ void GetDifferingKeys(const PrefValueMap* other,
+ std::vector<std::string>* differing_keys) const;
+
+ private:
+ typedef std::map<std::string, base::Value*> Map;
+
+ Map prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefValueMap);
+};
+
+#endif // BASE_PREFS_PREF_VALUE_MAP_H_
diff --git a/base/prefs/pref_value_map_unittest.cc b/base/prefs/pref_value_map_unittest.cc
new file mode 100644
index 0000000..b406db8
--- /dev/null
+++ b/base/prefs/pref_value_map_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2011 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 "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class PrefValueMapTest : public testing::Test {
+};
+
+TEST_F(PrefValueMapTest, SetValue) {
+ PrefValueMap map;
+ const Value* result = NULL;
+ EXPECT_FALSE(map.GetValue("key", &result));
+ EXPECT_FALSE(result);
+
+ EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+ EXPECT_FALSE(map.SetValue("key", Value::CreateStringValue("test")));
+ EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("hi mom!")));
+
+ EXPECT_TRUE(map.GetValue("key", &result));
+ EXPECT_TRUE(StringValue("hi mom!").Equals(result));
+}
+
+TEST_F(PrefValueMapTest, GetAndSetIntegerValue) {
+ PrefValueMap map;
+ ASSERT_TRUE(map.SetValue("key", Value::CreateIntegerValue(5)));
+
+ int int_value = 0;
+ EXPECT_TRUE(map.GetInteger("key", &int_value));
+ EXPECT_EQ(5, int_value);
+
+ map.SetInteger("key", -14);
+ EXPECT_TRUE(map.GetInteger("key", &int_value));
+ EXPECT_EQ(-14, int_value);
+}
+
+TEST_F(PrefValueMapTest, RemoveValue) {
+ PrefValueMap map;
+ EXPECT_FALSE(map.RemoveValue("key"));
+
+ EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+ EXPECT_TRUE(map.GetValue("key", NULL));
+
+ EXPECT_TRUE(map.RemoveValue("key"));
+ EXPECT_FALSE(map.GetValue("key", NULL));
+
+ EXPECT_FALSE(map.RemoveValue("key"));
+}
+
+TEST_F(PrefValueMapTest, Clear) {
+ PrefValueMap map;
+ EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+ EXPECT_TRUE(map.GetValue("key", NULL));
+
+ map.Clear();
+
+ EXPECT_FALSE(map.GetValue("key", NULL));
+}
+
+TEST_F(PrefValueMapTest, GetDifferingKeys) {
+ PrefValueMap reference;
+ EXPECT_TRUE(reference.SetValue("b", Value::CreateStringValue("test")));
+ EXPECT_TRUE(reference.SetValue("c", Value::CreateStringValue("test")));
+ EXPECT_TRUE(reference.SetValue("e", Value::CreateStringValue("test")));
+
+ PrefValueMap check;
+ std::vector<std::string> differing_paths;
+ std::vector<std::string> expected_differing_paths;
+
+ reference.GetDifferingKeys(&check, &differing_paths);
+ expected_differing_paths.push_back("b");
+ expected_differing_paths.push_back("c");
+ expected_differing_paths.push_back("e");
+ EXPECT_EQ(expected_differing_paths, differing_paths);
+
+ EXPECT_TRUE(check.SetValue("a", Value::CreateStringValue("test")));
+ EXPECT_TRUE(check.SetValue("c", Value::CreateStringValue("test")));
+ EXPECT_TRUE(check.SetValue("d", Value::CreateStringValue("test")));
+
+ reference.GetDifferingKeys(&check, &differing_paths);
+ expected_differing_paths.clear();
+ expected_differing_paths.push_back("a");
+ expected_differing_paths.push_back("b");
+ expected_differing_paths.push_back("d");
+ expected_differing_paths.push_back("e");
+ EXPECT_EQ(expected_differing_paths, differing_paths);
+}
+
+TEST_F(PrefValueMapTest, SwapTwoMaps) {
+ PrefValueMap first_map;
+ EXPECT_TRUE(first_map.SetValue("a", Value::CreateStringValue("test")));
+ EXPECT_TRUE(first_map.SetValue("b", Value::CreateStringValue("test")));
+ EXPECT_TRUE(first_map.SetValue("c", Value::CreateStringValue("test")));
+
+ PrefValueMap second_map;
+ EXPECT_TRUE(second_map.SetValue("d", Value::CreateStringValue("test")));
+ EXPECT_TRUE(second_map.SetValue("e", Value::CreateStringValue("test")));
+ EXPECT_TRUE(second_map.SetValue("f", Value::CreateStringValue("test")));
+
+ first_map.Swap(&second_map);
+
+ EXPECT_TRUE(first_map.GetValue("d", NULL));
+ EXPECT_TRUE(first_map.GetValue("e", NULL));
+ EXPECT_TRUE(first_map.GetValue("f", NULL));
+
+ EXPECT_TRUE(second_map.GetValue("a", NULL));
+ EXPECT_TRUE(second_map.GetValue("b", NULL));
+ EXPECT_TRUE(second_map.GetValue("c", NULL));
+}
diff --git a/base/prefs/public/pref_change_registrar.cc b/base/prefs/public/pref_change_registrar.cc
new file mode 100644
index 0000000..e7a9791
--- /dev/null
+++ b/base/prefs/public/pref_change_registrar.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2010 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 "base/prefs/public/pref_change_registrar.h"
+
+#include "base/logging.h"
+#include "base/prefs/public/pref_service_base.h"
+
+PrefChangeRegistrar::PrefChangeRegistrar() : service_(NULL) {}
+
+PrefChangeRegistrar::~PrefChangeRegistrar() {
+ // If you see an invalid memory access in this destructor, this
+ // PrefChangeRegistrar might be subscribed to an OffTheRecordProfileImpl that
+ // has been destroyed. This should not happen any more but be warned.
+ // Feel free to contact battre@chromium.org in case this happens.
+ RemoveAll();
+}
+
+void PrefChangeRegistrar::Init(PrefServiceBase* service) {
+ DCHECK(IsEmpty() || service_ == service);
+ service_ = service;
+}
+
+void PrefChangeRegistrar::Add(const char* path,
+ content::NotificationObserver* obs) {
+ if (!service_) {
+ NOTREACHED();
+ return;
+ }
+ ObserverRegistration registration(path, obs);
+ if (observers_.find(registration) != observers_.end()) {
+ NOTREACHED();
+ return;
+ }
+ observers_.insert(registration);
+ service_->AddPrefObserver(path, obs);
+}
+
+void PrefChangeRegistrar::Remove(const char* path,
+ content::NotificationObserver* obs) {
+ if (!service_) {
+ NOTREACHED();
+ return;
+ }
+ ObserverRegistration registration(path, obs);
+ std::set<ObserverRegistration>::iterator it =
+ observers_.find(registration);
+ if (it == observers_.end()) {
+ NOTREACHED();
+ return;
+ }
+ service_->RemovePrefObserver(it->first.c_str(), it->second);
+ observers_.erase(it);
+}
+
+void PrefChangeRegistrar::RemoveAll() {
+ if (service_) {
+ for (std::set<ObserverRegistration>::const_iterator it = observers_.begin();
+ it != observers_.end(); ++it) {
+ service_->RemovePrefObserver(it->first.c_str(), it->second);
+ }
+ observers_.clear();
+ }
+}
+
+bool PrefChangeRegistrar::IsEmpty() const {
+ return observers_.empty();
+}
+
+bool PrefChangeRegistrar::IsObserved(const std::string& pref) {
+ for (std::set<ObserverRegistration>::const_iterator it = observers_.begin();
+ it != observers_.end(); ++it) {
+ if (it->first == pref)
+ return true;
+ }
+ return false;
+}
+
+bool PrefChangeRegistrar::IsManaged() {
+ for (std::set<ObserverRegistration>::const_iterator it = observers_.begin();
+ it != observers_.end(); ++it) {
+ const PrefServiceBase::Preference* pref =
+ service_->FindPreference(it->first.c_str());
+ if (pref && pref->IsManaged())
+ return true;
+ }
+ return false;
+}
diff --git a/base/prefs/public/pref_change_registrar.h b/base/prefs/public/pref_change_registrar.h
new file mode 100644
index 0000000..97743e2
--- /dev/null
+++ b/base/prefs/public/pref_change_registrar.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2010 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 BASE_PREFS_PUBLIC_PREF_CHANGE_REGISTRAR_H_
+#define BASE_PREFS_PUBLIC_PREF_CHANGE_REGISTRAR_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+
+class PrefServiceBase;
+
+namespace content {
+class NotificationObserver;
+}
+
+// Automatically manages the registration of one or more pref change observers
+// with a PrefStore. Functions much like NotificationRegistrar, but specifically
+// manages observers of preference changes. When the Registrar is destroyed,
+// all registered observers are automatically unregistered with the PrefStore.
+class PrefChangeRegistrar {
+ public:
+ PrefChangeRegistrar();
+ virtual ~PrefChangeRegistrar();
+
+ // Must be called before adding or removing observers. Can be called more
+ // than once as long as the value of |service| doesn't change.
+ void Init(PrefServiceBase* service);
+
+ // Adds an pref observer for the specified pref |path| and |obs| observer
+ // object. All registered observers will be automatically unregistered
+ // when the registrar's destructor is called unless the observer has been
+ // explicitly removed by a call to Remove beforehand.
+ void Add(const char* path,
+ content::NotificationObserver* obs);
+
+ // Removes a preference observer that has previously been added with a call to
+ // Add.
+ void Remove(const char* path,
+ content::NotificationObserver* obs);
+
+ // Removes all observers that have been previously added with a call to Add.
+ void RemoveAll();
+
+ // Returns true if no pref observers are registered.
+ bool IsEmpty() const;
+
+ // Check whether |pref| is in the set of preferences being observed.
+ bool IsObserved(const std::string& pref);
+
+ // Check whether any of the observed preferences has the managed bit set.
+ bool IsManaged();
+
+ private:
+ typedef std::pair<std::string, content::NotificationObserver*>
+ ObserverRegistration;
+
+ std::set<ObserverRegistration> observers_;
+ PrefServiceBase* service_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefChangeRegistrar);
+};
+
+#endif // BASE_PREFS_PUBLIC_PREF_CHANGE_REGISTRAR_H_
diff --git a/base/prefs/public/pref_change_registrar_unittest.cc b/base/prefs/public/pref_change_registrar_unittest.cc
new file mode 100644
index 0000000..491d7db
--- /dev/null
+++ b/base/prefs/public/pref_change_registrar_unittest.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2010 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 "base/prefs/public/pref_change_registrar.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_pref_service.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/test/mock_notification_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Mock;
+using testing::Eq;
+
+namespace {
+
+// A mock provider that allows us to capture pref observer changes.
+class MockPrefService : public TestingPrefService {
+ public:
+ MockPrefService() {}
+ virtual ~MockPrefService() {}
+
+ MOCK_METHOD2(AddPrefObserver,
+ void(const char*, content::NotificationObserver*));
+ MOCK_METHOD2(RemovePrefObserver,
+ void(const char*, content::NotificationObserver*));
+};
+
+} // namespace
+
+class PrefChangeRegistrarTest : public testing::Test {
+ public:
+ PrefChangeRegistrarTest() {}
+ virtual ~PrefChangeRegistrarTest() {}
+
+ protected:
+ virtual void SetUp();
+
+ content::NotificationObserver* observer() const { return observer_.get(); }
+ MockPrefService* service() const { return service_.get(); }
+
+ private:
+ scoped_ptr<MockPrefService> service_;
+ scoped_ptr<content::MockNotificationObserver> observer_;
+};
+
+void PrefChangeRegistrarTest::SetUp() {
+ service_.reset(new MockPrefService());
+ observer_.reset(new content::MockNotificationObserver());
+}
+
+TEST_F(PrefChangeRegistrarTest, AddAndRemove) {
+ PrefChangeRegistrar registrar;
+ registrar.Init(service());
+
+ // Test adding.
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.2")), observer()));
+ registrar.Add("test.pref.1", observer());
+ registrar.Add("test.pref.2", observer());
+ EXPECT_FALSE(registrar.IsEmpty());
+
+ // Test removing.
+ Mock::VerifyAndClearExpectations(service());
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.2")), observer()));
+ registrar.Remove("test.pref.1", observer());
+ registrar.Remove("test.pref.2", observer());
+ EXPECT_TRUE(registrar.IsEmpty());
+
+ // Explicitly check the expectations now to make sure that the Removes
+ // worked (rather than the registrar destructor doing the work).
+ Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(PrefChangeRegistrarTest, AutoRemove) {
+ PrefChangeRegistrar registrar;
+ registrar.Init(service());
+
+ // Setup of auto-remove.
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+ registrar.Add("test.pref.1", observer());
+ Mock::VerifyAndClearExpectations(service());
+ EXPECT_FALSE(registrar.IsEmpty());
+
+ // Test auto-removing.
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+}
+
+TEST_F(PrefChangeRegistrarTest, RemoveAll) {
+ PrefChangeRegistrar registrar;
+ registrar.Init(service());
+
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.2")), observer()));
+ registrar.Add("test.pref.1", observer());
+ registrar.Add("test.pref.2", observer());
+ Mock::VerifyAndClearExpectations(service());
+
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.2")), observer()));
+ registrar.RemoveAll();
+ EXPECT_TRUE(registrar.IsEmpty());
+
+ // Explicitly check the expectations now to make sure that the RemoveAll
+ // worked (rather than the registrar destructor doing the work).
+ Mock::VerifyAndClearExpectations(service());
+}
+
+class ObserveSetOfPreferencesTest : public testing::Test {
+ public:
+ virtual void SetUp() {
+ pref_service_.reset(new TestingPrefService);
+ pref_service_->RegisterStringPref(prefs::kHomePage,
+ "http://google.com",
+ PrefService::UNSYNCABLE_PREF);
+ pref_service_->RegisterBooleanPref(prefs::kHomePageIsNewTabPage,
+ false,
+ PrefService::UNSYNCABLE_PREF);
+ pref_service_->RegisterStringPref(prefs::kApplicationLocale,
+ "",
+ PrefService::UNSYNCABLE_PREF);
+ }
+
+ PrefChangeRegistrar* CreatePrefChangeRegistrar(
+ content::NotificationObserver* observer) {
+ PrefChangeRegistrar* pref_set = new PrefChangeRegistrar();
+ pref_set->Init(pref_service_.get());
+ pref_set->Add(prefs::kHomePage, observer);
+ pref_set->Add(prefs::kHomePageIsNewTabPage, observer);
+ return pref_set;
+ }
+
+ scoped_ptr<TestingPrefService> pref_service_;
+};
+
+TEST_F(ObserveSetOfPreferencesTest, IsObserved) {
+ scoped_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar(NULL));
+ EXPECT_TRUE(pref_set->IsObserved(prefs::kHomePage));
+ EXPECT_TRUE(pref_set->IsObserved(prefs::kHomePageIsNewTabPage));
+ EXPECT_FALSE(pref_set->IsObserved(prefs::kApplicationLocale));
+}
+
+TEST_F(ObserveSetOfPreferencesTest, IsManaged) {
+ scoped_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar(NULL));
+ EXPECT_FALSE(pref_set->IsManaged());
+ pref_service_->SetManagedPref(prefs::kHomePage,
+ Value::CreateStringValue("http://crbug.com"));
+ EXPECT_TRUE(pref_set->IsManaged());
+ pref_service_->SetManagedPref(prefs::kHomePageIsNewTabPage,
+ Value::CreateBooleanValue(true));
+ EXPECT_TRUE(pref_set->IsManaged());
+ pref_service_->RemoveManagedPref(prefs::kHomePage);
+ EXPECT_TRUE(pref_set->IsManaged());
+ pref_service_->RemoveManagedPref(prefs::kHomePageIsNewTabPage);
+ EXPECT_FALSE(pref_set->IsManaged());
+}
+
+MATCHER_P(PrefNameDetails, name, "details references named preference") {
+ std::string* pstr =
+ reinterpret_cast<const content::Details<std::string>&>(arg).ptr();
+ return pstr && *pstr == name;
+}
+
+TEST_F(ObserveSetOfPreferencesTest, Observe) {
+ using testing::_;
+ using testing::Mock;
+
+ content::MockNotificationObserver observer;
+ scoped_ptr<PrefChangeRegistrar> pref_set(
+ CreatePrefChangeRegistrar(&observer));
+
+ EXPECT_CALL(observer,
+ Observe(int(chrome::NOTIFICATION_PREF_CHANGED),
+ content::Source<PrefService>(pref_service_.get()),
+ PrefNameDetails(prefs::kHomePage)));
+ pref_service_->SetUserPref(prefs::kHomePage,
+ Value::CreateStringValue("http://crbug.com"));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_CALL(observer,
+ Observe(int(chrome::NOTIFICATION_PREF_CHANGED),
+ content::Source<PrefService>(pref_service_.get()),
+ PrefNameDetails(prefs::kHomePageIsNewTabPage)));
+ pref_service_->SetUserPref(prefs::kHomePageIsNewTabPage,
+ Value::CreateBooleanValue(true));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_CALL(observer, Observe(_, _, _)).Times(0);
+ pref_service_->SetUserPref(prefs::kApplicationLocale,
+ Value::CreateStringValue("en_US.utf8"));
+ Mock::VerifyAndClearExpectations(&observer);
+}
diff --git a/base/prefs/public/pref_service_base.h b/base/prefs/public/pref_service_base.h
new file mode 100644
index 0000000..aa5b3fd
--- /dev/null
+++ b/base/prefs/public/pref_service_base.h
@@ -0,0 +1,272 @@
+// Copyright (c) 2012 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.
+
+// This is the base interface for a preference services that provides
+// a way to access the application's current preferences.
+//
+// This base interface assumes all preferences are local. See
+// SyncablePrefServiceBase for the interface to a preference service
+// that stores preferences that can be synced.
+//
+// Chromium settings and storage represent user-selected preferences and
+// information and MUST not be extracted, overwritten or modified except
+// through Chromium defined APIs.
+
+#ifndef BASE_PREFS_PUBLIC_PREF_SERVICE_BASE_H_
+#define BASE_PREFS_PUBLIC_PREF_SERVICE_BASE_H_
+
+#include "base/values.h"
+
+namespace content {
+class BrowserContext;
+class NotificationObserver;
+}
+
+namespace subtle {
+class PrefMemberBase;
+}
+
+class FilePath;
+class Profile;
+class TabContents;
+
+class PrefServiceBase {
+ public:
+ // Retrieves a PrefServiceBase for the given context.
+ static PrefServiceBase* FromBrowserContext(content::BrowserContext* context);
+
+ virtual ~PrefServiceBase() {}
+
+ // Enum used when registering preferences to determine if it should be synced
+ // or not. This is only used for profile prefs, not local state prefs.
+ // See the Register*Pref methods for profile prefs below.
+ enum PrefSyncStatus {
+ UNSYNCABLE_PREF,
+ SYNCABLE_PREF
+ };
+
+ // Interface to a single preference.
+ class Preference {
+ public:
+ virtual ~Preference() {}
+
+ // Returns the name of the Preference (i.e., the key, e.g.,
+ // browser.window_placement).
+ virtual const std::string name() const = 0;
+
+ // Returns the registered type of the preference.
+ virtual base::Value::Type GetType() const = 0;
+
+ // Returns the value of the Preference, falling back to the registered
+ // default value if no other has been set.
+ virtual const base::Value* GetValue() const = 0;
+
+ // Returns the value recommended by the admin, if any.
+ virtual const base::Value* GetRecommendedValue() const = 0;
+
+ // Returns true if the Preference is managed, i.e. set by an admin policy.
+ // Since managed prefs have the highest priority, this also indicates
+ // whether the pref is actually being controlled by the policy setting.
+ virtual bool IsManaged() const = 0;
+
+ // Returns true if the Preference is recommended, i.e. set by an admin
+ // policy but the user is allowed to change it.
+ virtual bool IsRecommended() const = 0;
+
+ // Returns true if the Preference has a value set by an extension, even if
+ // that value is being overridden by a higher-priority source.
+ virtual bool HasExtensionSetting() const = 0;
+
+ // Returns true if the Preference has a user setting, even if that value is
+ // being overridden by a higher-priority source.
+ virtual bool HasUserSetting() const = 0;
+
+ // Returns true if the Preference value is currently being controlled by an
+ // extension, and not by any higher-priority source.
+ virtual bool IsExtensionControlled() const = 0;
+
+ // Returns true if the Preference value is currently being controlled by a
+ // user setting, and not by any higher-priority source.
+ virtual bool IsUserControlled() const = 0;
+
+ // Returns true if the Preference is currently using its default value,
+ // and has not been set by any higher-priority source (even with the same
+ // value).
+ virtual bool IsDefaultValue() const = 0;
+
+ // Returns true if the user can change the Preference value, which is the
+ // case if no higher-priority source than the user store controls the
+ // Preference.
+ virtual bool IsUserModifiable() const = 0;
+
+ // Returns true if an extension can change the Preference value, which is
+ // the case if no higher-priority source than the extension store controls
+ // the Preference.
+ virtual bool IsExtensionModifiable() const = 0;
+ };
+
+ // Returns true if the preference for the given preference name is available
+ // and is managed.
+ virtual bool IsManagedPreference(const char* pref_name) const = 0;
+
+ // Returns |true| if a preference with the given name is available and its
+ // value can be changed by the user.
+ virtual bool IsUserModifiablePreference(const char* pref_name) const = 0;
+
+ // Make the PrefService aware of a pref.
+ // TODO(zea): split local state and profile prefs into their own subclasses.
+ // ---------- Local state prefs ----------
+ virtual void RegisterBooleanPref(const char* path,
+ bool default_value) = 0;
+ virtual void RegisterIntegerPref(const char* path,
+ int default_value) = 0;
+ virtual void RegisterDoublePref(const char* path,
+ double default_value) = 0;
+ virtual void RegisterStringPref(const char* path,
+ const std::string& default_value) = 0;
+ virtual void RegisterFilePathPref(const char* path,
+ const FilePath& default_value) = 0;
+ virtual void RegisterListPref(const char* path) = 0;
+ virtual void RegisterDictionaryPref(const char* path) = 0;
+ // These take ownership of the default_value:
+ virtual void RegisterListPref(const char* path,
+ base::ListValue* default_value) = 0;
+ virtual void RegisterDictionaryPref(
+ const char* path, base::DictionaryValue* default_value) = 0;
+ // These variants use a default value from the locale dll instead.
+ virtual void RegisterLocalizedBooleanPref(
+ const char* path, int locale_default_message_id) = 0;
+ virtual void RegisterLocalizedIntegerPref(
+ const char* path, int locale_default_message_id) = 0;
+ virtual void RegisterLocalizedDoublePref(
+ const char* path, int locale_default_message_id) = 0;
+ virtual void RegisterLocalizedStringPref(
+ const char* path, int locale_default_message_id) = 0;
+ virtual void RegisterInt64Pref(const char* path,
+ int64 default_value) = 0;
+
+ // ---------- Profile prefs ----------
+ // Profile prefs must specify whether the pref should be synchronized across
+ // machines or not (see PrefSyncStatus enum above).
+ virtual void RegisterBooleanPref(const char* path,
+ bool default_value,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterIntegerPref(const char* path,
+ int default_value,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterDoublePref(const char* path,
+ double default_value,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterStringPref(const char* path,
+ const std::string& default_value,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterFilePathPref(const char* path,
+ const FilePath& default_value,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterListPref(const char* path,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterDictionaryPref(const char* path,
+ PrefSyncStatus sync_status) = 0;
+ // These take ownership of the default_value:
+ virtual void RegisterListPref(const char* path,
+ base::ListValue* default_value,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterDictionaryPref(const char* path,
+ base::DictionaryValue* default_value,
+ PrefSyncStatus sync_status) = 0;
+ // These variants use a default value from the locale dll instead.
+ virtual void RegisterLocalizedBooleanPref(
+ const char* path,
+ int locale_default_message_id,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterLocalizedIntegerPref(
+ const char* path,
+ int locale_default_message_id,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterLocalizedDoublePref(
+ const char* path,
+ int locale_default_message_id,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterLocalizedStringPref(
+ const char* path,
+ int locale_default_message_id,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterInt64Pref(const char* path,
+ int64 default_value,
+ PrefSyncStatus sync_status) = 0;
+ virtual void RegisterUint64Pref(const char* path,
+ uint64 default_value,
+ PrefSyncStatus sync_status) = 0;
+ // Unregisters a preference.
+ virtual void UnregisterPreference(const char* path) = 0;
+
+ // Look up a preference. Returns NULL if the preference is not
+ // registered.
+ virtual const Preference* FindPreference(const char* pref_name) const = 0;
+
+ // If the path is valid and the value at the end of the path matches the type
+ // specified, it will return the specified value. Otherwise, the default
+ // value (set when the pref was registered) will be returned.
+ virtual bool GetBoolean(const char* path) const = 0;
+ virtual int GetInteger(const char* path) const = 0;
+ virtual double GetDouble(const char* path) const = 0;
+ virtual std::string GetString(const char* path) const = 0;
+ virtual FilePath GetFilePath(const char* path) const = 0;
+
+ // Returns the branch if it exists, or the registered default value otherwise.
+ // Note that |path| must point to a registered preference. In that case, these
+ // functions will never return NULL.
+ virtual const base::DictionaryValue* GetDictionary(
+ const char* path) const = 0;
+ virtual const base::ListValue* GetList(const char* path) const = 0;
+
+ // Removes a user pref and restores the pref to its default value.
+ virtual void ClearPref(const char* path) = 0;
+
+ // If the path is valid (i.e., registered), update the pref value in the user
+ // prefs.
+ // To set the value of dictionary or list values in the pref tree use
+ // Set(), but to modify the value of a dictionary or list use either
+ // ListPrefUpdate or DictionaryPrefUpdate from scoped_user_pref_update.h.
+ virtual void Set(const char* path, const base::Value& value) = 0;
+ virtual void SetBoolean(const char* path, bool value) = 0;
+ virtual void SetInteger(const char* path, int value) = 0;
+ virtual void SetDouble(const char* path, double value) = 0;
+ virtual void SetString(const char* path, const std::string& value) = 0;
+ virtual void SetFilePath(const char* path, const FilePath& value) = 0;
+
+ // Int64 helper methods that actually store the given value as a string.
+ // Note that if obtaining the named value via GetDictionary or GetList, the
+ // Value type will be TYPE_STRING.
+ virtual void SetInt64(const char* path, int64 value) = 0;
+ virtual int64 GetInt64(const char* path) const = 0;
+
+ // As above, but for unsigned values.
+ virtual void SetUint64(const char* path, uint64 value) = 0;
+ virtual uint64 GetUint64(const char* path) const = 0;
+
+ protected:
+ // Registration of pref change observers must be done using the
+ // PrefChangeRegistrar, which is declared as a friend here to grant it
+ // access to the otherwise protected members Add/RemovePrefObserver.
+ // PrefMember registers for preferences changes notification directly to
+ // avoid the storage overhead of the registrar, so its base class must be
+ // declared as a friend, too.
+ friend class PrefChangeRegistrar;
+ friend class subtle::PrefMemberBase;
+
+ // These are protected so they can only be accessed by the friend
+ // classes listed above.
+ //
+ // If the pref at the given path changes, we call the observer's Observe
+ // method with PREF_CHANGED. Note that observers should not call these methods
+ // directly but rather use a PrefChangeRegistrar to make sure the observer
+ // gets cleaned up properly.
+ virtual void AddPrefObserver(const char* path,
+ content::NotificationObserver* obs) = 0;
+ virtual void RemovePrefObserver(const char* path,
+ content::NotificationObserver* obs) = 0;
+};
+
+#endif // BASE_PREFS_PUBLIC_PREF_SERVICE_BASE_H_
diff --git a/base/prefs/testing_pref_store.cc b/base/prefs/testing_pref_store.cc
new file mode 100644
index 0000000..f7c7830
--- /dev/null
+++ b/base/prefs/testing_pref_store.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 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 "base/prefs/testing_pref_store.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+TestingPrefStore::TestingPrefStore()
+ : read_only_(true),
+ init_complete_(false) {
+}
+
+PrefStore::ReadResult TestingPrefStore::GetValue(const std::string& key,
+ const Value** value) const {
+ return prefs_.GetValue(key, value) ? READ_OK : READ_NO_VALUE;
+}
+
+PrefStore::ReadResult TestingPrefStore::GetMutableValue(const std::string& key,
+ Value** value) {
+ return prefs_.GetValue(key, value) ? READ_OK : READ_NO_VALUE;
+}
+
+void TestingPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void TestingPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+size_t TestingPrefStore::NumberOfObservers() const {
+ return observers_.size();
+}
+
+bool TestingPrefStore::IsInitializationComplete() const {
+ return init_complete_;
+}
+
+void TestingPrefStore::SetValue(const std::string& key, Value* value) {
+ if (prefs_.SetValue(key, value))
+ NotifyPrefValueChanged(key);
+}
+
+void TestingPrefStore::SetValueSilently(const std::string& key, Value* value) {
+ prefs_.SetValue(key, value);
+}
+
+void TestingPrefStore::RemoveValue(const std::string& key) {
+ if (prefs_.RemoveValue(key))
+ NotifyPrefValueChanged(key);
+}
+
+void TestingPrefStore::MarkNeedsEmptyValue(const std::string& key) {
+}
+
+bool TestingPrefStore::ReadOnly() const {
+ return read_only_;
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::GetReadError() const {
+ return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() {
+ NotifyInitializationCompleted();
+ return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+void TestingPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate_raw) {
+ scoped_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
+ NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::SetInitializationCompleted() {
+ init_complete_ = true;
+ NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::NotifyPrefValueChanged(const std::string& key) {
+ FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::NotifyInitializationCompleted() {
+ FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted(true));
+}
+
+void TestingPrefStore::ReportValueChanged(const std::string& key) {
+ FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::SetString(const std::string& key,
+ const std::string& value) {
+ SetValue(key, Value::CreateStringValue(value));
+}
+
+void TestingPrefStore::SetInteger(const std::string& key, int value) {
+ SetValue(key, Value::CreateIntegerValue(value));
+}
+
+void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
+ SetValue(key, Value::CreateBooleanValue(value));
+}
+
+bool TestingPrefStore::GetString(const std::string& key,
+ std::string* value) const {
+ const Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+ return false;
+
+ return stored_value->GetAsString(value);
+}
+
+bool TestingPrefStore::GetInteger(const std::string& key, int* value) const {
+ const Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+ return false;
+
+ return stored_value->GetAsInteger(value);
+}
+
+bool TestingPrefStore::GetBoolean(const std::string& key, bool* value) const {
+ const Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+ return false;
+
+ return stored_value->GetAsBoolean(value);
+}
+
+void TestingPrefStore::set_read_only(bool read_only) {
+ read_only_ = read_only;
+}
+
+TestingPrefStore::~TestingPrefStore() {}
diff --git a/base/prefs/testing_pref_store.h b/base/prefs/testing_pref_store.h
new file mode 100644
index 0000000..07e1401
--- /dev/null
+++ b/base/prefs/testing_pref_store.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 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 BASE_PREFS_TESTING_PREF_STORE_H_
+#define BASE_PREFS_TESTING_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// |TestingPrefStore| is a preference store implementation that allows tests to
+// explicitly manipulate the contents of the store, triggering notifications
+// where appropriate.
+class TestingPrefStore : public PersistentPrefStore {
+ public:
+ TestingPrefStore();
+
+ // Overriden from PrefStore.
+ virtual ReadResult GetValue(const std::string& key,
+ const base::Value** result) const OVERRIDE;
+ virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE;
+ virtual size_t NumberOfObservers() const OVERRIDE;
+ virtual bool IsInitializationComplete() const OVERRIDE;
+
+ // PersistentPrefStore overrides:
+ virtual ReadResult GetMutableValue(const std::string& key,
+ base::Value** result) OVERRIDE;
+ virtual void ReportValueChanged(const std::string& key) OVERRIDE;
+ virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE;
+ virtual void SetValueSilently(const std::string& key,
+ base::Value* value) OVERRIDE;
+ virtual void RemoveValue(const std::string& key) OVERRIDE;
+ virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE;
+ virtual bool ReadOnly() const OVERRIDE;
+ virtual PrefReadError GetReadError() const OVERRIDE;
+ virtual PersistentPrefStore::PrefReadError ReadPrefs() OVERRIDE;
+ virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE;
+ virtual void CommitPendingWrite() OVERRIDE {}
+
+ // Marks the store as having completed initialization.
+ void SetInitializationCompleted();
+
+ // Used for tests to trigger notifications explicitly.
+ void NotifyPrefValueChanged(const std::string& key);
+ void NotifyInitializationCompleted();
+
+ // Some convenience getters/setters.
+ void SetString(const std::string& key, const std::string& value);
+ void SetInteger(const std::string& key, int value);
+ void SetBoolean(const std::string& key, bool value);
+
+ bool GetString(const std::string& key, std::string* value) const;
+ bool GetInteger(const std::string& key, int* value) const;
+ bool GetBoolean(const std::string& key, bool* value) const;
+
+ // Getter and Setter methods for setting and getting the state of the
+ // |TestingPrefStore|.
+ virtual void set_read_only(bool read_only);
+
+ protected:
+ virtual ~TestingPrefStore();
+
+ private:
+ // Stores the preference values.
+ PrefValueMap prefs_;
+
+ // Flag that indicates if the PrefStore is read-only
+ bool read_only_;
+
+ // Whether initialization has been completed.
+ bool init_complete_;
+
+ ObserverList<PrefStore::Observer, true> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestingPrefStore);
+};
+
+#endif // BASE_PREFS_TESTING_PREF_STORE_H_
diff --git a/base/prefs/value_map_pref_store.cc b/base/prefs/value_map_pref_store.cc
new file mode 100644
index 0000000..dc33384
--- /dev/null
+++ b/base/prefs/value_map_pref_store.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 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 "base/prefs/value_map_pref_store.h"
+
+#include <algorithm>
+
+#include "base/stl_util.h"
+#include "base/values.h"
+
+ValueMapPrefStore::ValueMapPrefStore() {}
+
+PrefStore::ReadResult ValueMapPrefStore::GetValue(const std::string& key,
+ const Value** value) const {
+ return prefs_.GetValue(key, value) ? READ_OK : READ_NO_VALUE;
+}
+
+void ValueMapPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ValueMapPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+size_t ValueMapPrefStore::NumberOfObservers() const {
+ return observers_.size();
+}
+
+ValueMapPrefStore::iterator ValueMapPrefStore::begin() {
+ return prefs_.begin();
+}
+
+ValueMapPrefStore::iterator ValueMapPrefStore::end() {
+ return prefs_.end();
+}
+
+ValueMapPrefStore::const_iterator ValueMapPrefStore::begin() const {
+ return prefs_.begin();
+}
+
+ValueMapPrefStore::const_iterator ValueMapPrefStore::end() const {
+ return prefs_.end();
+}
+
+ValueMapPrefStore::~ValueMapPrefStore() {}
+
+void ValueMapPrefStore::SetValue(const std::string& key, Value* value) {
+ if (prefs_.SetValue(key, value))
+ FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::RemoveValue(const std::string& key) {
+ if (prefs_.RemoveValue(key))
+ FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::NotifyInitializationCompleted() {
+ FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted(true));
+}
diff --git a/base/prefs/value_map_pref_store.h b/base/prefs/value_map_pref_store.h
new file mode 100644
index 0000000..64ff265
--- /dev/null
+++ b/base/prefs/value_map_pref_store.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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 BASE_PREFS_VALUE_MAP_PREF_STORE_H_
+#define BASE_PREFS_VALUE_MAP_PREF_STORE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "base/prefs/pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// A basic PrefStore implementation that uses a simple name-value map for
+// storing the preference values.
+class ValueMapPrefStore : public PrefStore {
+ public:
+ typedef std::map<std::string, base::Value*>::iterator iterator;
+ typedef std::map<std::string, base::Value*>::const_iterator const_iterator;
+
+ ValueMapPrefStore();
+
+ // PrefStore overrides:
+ virtual ReadResult GetValue(const std::string& key,
+ const base::Value** value) const OVERRIDE;
+ virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE;
+ virtual size_t NumberOfObservers() const OVERRIDE;
+
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ protected:
+ virtual ~ValueMapPrefStore();
+
+ // Store a |value| for |key| in the store. Also generates an notification if
+ // the value changed. Assumes ownership of |value|, which must be non-NULL.
+ void SetValue(const std::string& key, base::Value* value);
+
+ // Remove the value for |key| from the store. Sends a notification if there
+ // was a value to be removed.
+ void RemoveValue(const std::string& key);
+
+ // Notify observers about the initialization completed event.
+ void NotifyInitializationCompleted();
+
+ private:
+ PrefValueMap prefs_;
+
+ ObserverList<PrefStore::Observer, true> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ValueMapPrefStore);
+};
+
+#endif // BASE_PREFS_VALUE_MAP_PREF_STORE_H_