diff options
author | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-30 20:21:17 +0000 |
---|---|---|
committer | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-30 20:21:17 +0000 |
commit | 9eec53fe1841f7ae4d5684074fc3118ef66bb943 (patch) | |
tree | bb2fe9582ddb8569bcb0b390cc2c45d4e61e30ca /base/prefs | |
parent | d39bf7539abbc238e8e5a73937b9531feeabb530 (diff) | |
download | chromium_src-9eec53fe1841f7ae4d5684074fc3118ef66bb943.zip chromium_src-9eec53fe1841f7ae4d5684074fc3118ef66bb943.tar.gz chromium_src-9eec53fe1841f7ae4d5684074fc3118ef66bb943.tar.bz2 |
Move ScopedUserPrefUpdate to base/prefs.
Move this outside of Chrome to enable moving ExtensionPrefs
to the top-level extensions/ directory.
BUG=313284
TBR=sky@chromium.org
Review URL: https://codereview.chromium.org/46073004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231905 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/prefs')
-rw-r--r-- | base/prefs/scoped_user_pref_update.cc | 36 | ||||
-rw-r--r-- | base/prefs/scoped_user_pref_update.h | 108 | ||||
-rw-r--r-- | base/prefs/scoped_user_pref_update_unittest.cc | 81 |
3 files changed, 225 insertions, 0 deletions
diff --git a/base/prefs/scoped_user_pref_update.cc b/base/prefs/scoped_user_pref_update.cc new file mode 100644 index 0000000..c86b163 --- /dev/null +++ b/base/prefs/scoped_user_pref_update.cc @@ -0,0 +1,36 @@ +// Copyright 2013 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/scoped_user_pref_update.h" + +#include "base/logging.h" +#include "base/prefs/pref_notifier.h" +#include "base/prefs/pref_service.h" + +namespace subtle { + +ScopedUserPrefUpdateBase::ScopedUserPrefUpdateBase(PrefService* service, + const char* path) + : service_(service), + path_(path), + value_(NULL) {} + +ScopedUserPrefUpdateBase::~ScopedUserPrefUpdateBase() { + Notify(); +} + +Value* ScopedUserPrefUpdateBase::GetValueOfType(base::Value::Type type) { + if (!value_) + value_ = service_->GetMutableUserPref(path_.c_str(), type); + return value_; +} + +void ScopedUserPrefUpdateBase::Notify() { + if (value_) { + service_->ReportUserPrefChanged(path_); + value_ = NULL; + } +} + +} // namespace subtle diff --git a/base/prefs/scoped_user_pref_update.h b/base/prefs/scoped_user_pref_update.h new file mode 100644 index 0000000..82d6739 --- /dev/null +++ b/base/prefs/scoped_user_pref_update.h @@ -0,0 +1,108 @@ +// Copyright 2013 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. +// +// A helper class that assists preferences in firing notifications when lists +// or dictionaries are changed. + +#ifndef BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_ +#define BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/prefs/base_prefs_export.h" +#include "base/prefs/pref_service.h" +#include "base/threading/non_thread_safe.h" +#include "base/values.h" + +class PrefService; + +namespace base { +class DictionaryValue; +class ListValue; +} + +namespace subtle { + +// Base class for ScopedUserPrefUpdateTemplate that contains the parts +// that do not depend on ScopedUserPrefUpdateTemplate's template parameter. +// +// We need this base class mostly for making it a friend of PrefService +// and getting access to PrefService::GetMutableUserPref and +// PrefService::ReportUserPrefChanged. +class BASE_PREFS_EXPORT ScopedUserPrefUpdateBase : public base::NonThreadSafe { + protected: + ScopedUserPrefUpdateBase(PrefService* service, const char* path); + + // Calls Notify(). + ~ScopedUserPrefUpdateBase(); + + // Sets |value_| to |service_|->GetMutableUserPref and returns it. + base::Value* GetValueOfType(base::Value::Type type); + + private: + // If |value_| is not null, triggers a notification of PrefObservers and + // resets |value_|. + void Notify(); + + // Weak pointer. + PrefService* service_; + // Path of the preference being updated. + std::string path_; + // Cache of value from user pref store (set between Get() and Notify() calls). + base::Value* value_; + + DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdateBase); +}; + +} // namespace subtle + +// Class to support modifications to DictionaryValues and ListValues while +// guaranteeing that PrefObservers are notified of changed values. +// +// This class may only be used on the UI thread as it requires access to the +// PrefService. +template <typename T, base::Value::Type type_enum_value> +class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase { + public: + ScopedUserPrefUpdate(PrefService* service, const char* path) + : ScopedUserPrefUpdateBase(service, path) {} + + // Triggers an update notification if Get() was called. + virtual ~ScopedUserPrefUpdate() {} + + // Returns a mutable |T| instance that + // - is already in the user pref store, or + // - is (silently) created and written to the user pref store if none existed + // before. + // + // Calling Get() implies that an update notification is necessary at + // destruction time. + // + // The ownership of the return value remains with the user pref store. + // Virtual so it can be overriden in subclasses that transform the value + // before returning it (for example to return a subelement of a dictionary). + virtual T* Get() { + return static_cast<T*>(GetValueOfType(type_enum_value)); + } + + T& operator*() { + return *Get(); + } + + T* operator->() { + return Get(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdate); +}; + +typedef ScopedUserPrefUpdate<base::DictionaryValue, + base::Value::TYPE_DICTIONARY> + DictionaryPrefUpdate; +typedef ScopedUserPrefUpdate<base::ListValue, base::Value::TYPE_LIST> + ListPrefUpdate; + +#endif // BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_ diff --git a/base/prefs/scoped_user_pref_update_unittest.cc b/base/prefs/scoped_user_pref_update_unittest.cc new file mode 100644 index 0000000..505526c --- /dev/null +++ b/base/prefs/scoped_user_pref_update_unittest.cc @@ -0,0 +1,81 @@ +// Copyright 2013 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/mock_pref_change_callback.h" +#include "base/prefs/pref_change_registrar.h" +#include "base/prefs/pref_registry_simple.h" +#include "base/prefs/scoped_user_pref_update.h" +#include "base/prefs/testing_pref_service.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::Mock; + +class ScopedUserPrefUpdateTest : public testing::Test { + public: + ScopedUserPrefUpdateTest() : observer_(&prefs_) {} + virtual ~ScopedUserPrefUpdateTest() {} + + protected: + virtual void SetUp() { + prefs_.registry()->RegisterDictionaryPref(kPref); + registrar_.Init(&prefs_); + registrar_.Add(kPref, observer_.GetCallback()); + } + + static const char kPref[]; + static const char kKey[]; + static const char kValue[]; + + TestingPrefServiceSimple prefs_; + MockPrefChangeCallback observer_; + PrefChangeRegistrar registrar_; +}; + +const char ScopedUserPrefUpdateTest::kPref[] = "name"; +const char ScopedUserPrefUpdateTest::kKey[] = "key"; +const char ScopedUserPrefUpdateTest::kValue[] = "value"; + +TEST_F(ScopedUserPrefUpdateTest, RegularUse) { + // Dictionary that will be expected to be set at the end. + DictionaryValue expected_dictionary; + expected_dictionary.SetString(kKey, kValue); + + { + EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); + DictionaryPrefUpdate update(&prefs_, kPref); + DictionaryValue* value = update.Get(); + ASSERT_TRUE(value); + value->SetString(kKey, kValue); + + // The dictionary was created for us but the creation should have happened + // silently without notifications. + Mock::VerifyAndClearExpectations(&observer_); + + // Modifications happen online and are instantly visible, though. + const DictionaryValue* current_value = prefs_.GetDictionary(kPref); + ASSERT_TRUE(current_value); + EXPECT_TRUE(expected_dictionary.Equals(current_value)); + + // Now we are leaving the scope of the update so we should be notified. + observer_.Expect(kPref, &expected_dictionary); + } + Mock::VerifyAndClearExpectations(&observer_); + + const DictionaryValue* current_value = prefs_.GetDictionary(kPref); + ASSERT_TRUE(current_value); + EXPECT_TRUE(expected_dictionary.Equals(current_value)); +} + +TEST_F(ScopedUserPrefUpdateTest, NeverTouchAnything) { + const DictionaryValue* old_value = prefs_.GetDictionary(kPref); + EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); + { + DictionaryPrefUpdate update(&prefs_, kPref); + } + const DictionaryValue* new_value = prefs_.GetDictionary(kPref); + EXPECT_EQ(old_value, new_value); + Mock::VerifyAndClearExpectations(&observer_); +} |