diff options
Diffstat (limited to 'chrome/browser/prefs')
39 files changed, 2105 insertions, 1742 deletions
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index ddc149b..1d21c1f 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc @@ -11,6 +11,9 @@ #include "chrome/browser/background_page_tracker.h" #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/browser_shutdown.h" +#include "chrome/browser/content_settings/host_content_settings_map.h" +#include "chrome/browser/content_settings/policy_content_settings_provider.h" +#include "chrome/browser/content_settings/pref_content_settings_provider.h" #include "chrome/browser/debugger/devtools_manager.h" #include "chrome/browser/dom_ui/flags_ui.h" #include "chrome/browser/dom_ui/new_tab_ui.h" @@ -23,7 +26,6 @@ #include "chrome/browser/geolocation/geolocation_content_settings_map.h" #include "chrome/browser/geolocation/geolocation_prefs.h" #include "chrome/browser/google/google_url_tracker.h" -#include "chrome/browser/host_content_settings_map.h" #include "chrome/browser/host_zoom_map.h" #include "chrome/browser/intranet_redirect_detector.h" #include "chrome/browser/instant/instant_controller.h" @@ -36,7 +38,7 @@ #include "chrome/browser/page_info_model.h" #include "chrome/browser/password_manager/password_manager.h" #include "chrome/browser/prefs/session_startup_pref.h" -#include "chrome/browser/profile_impl.h" +#include "chrome/browser/profiles/profile_impl.h" #include "chrome/browser/renderer_host/browser_render_process_host.h" #include "chrome/browser/renderer_host/web_cache_manager.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" @@ -90,7 +92,6 @@ void RegisterLocalState(PrefService* local_state) { MetricsService::RegisterPrefs(local_state); SafeBrowsingService::RegisterPrefs(local_state); browser_shutdown::RegisterPrefs(local_state); - chrome_browser_net::RegisterPrefs(local_state); #if defined(TOOLKIT_VIEWS) BrowserView::RegisterBrowserViewPrefs(local_state); #endif @@ -112,7 +113,6 @@ void RegisterLocalState(PrefService* local_state) { void RegisterUserPrefs(PrefService* user_prefs) { // User prefs AutoFillManager::RegisterUserPrefs(user_prefs); - BackgroundModeManager::RegisterUserPrefs(user_prefs); SessionStartupPref::RegisterUserPrefs(user_prefs); Browser::RegisterUserPrefs(user_prefs); PasswordManager::RegisterUserPrefs(user_prefs); @@ -128,6 +128,8 @@ void RegisterUserPrefs(PrefService* user_prefs) { PluginsUI::RegisterUserPrefs(user_prefs); ProfileImpl::RegisterUserPrefs(user_prefs); HostContentSettingsMap::RegisterUserPrefs(user_prefs); + PolicyContentSettingsProvider::RegisterUserPrefs(user_prefs); + PrefContentSettingsProvider::RegisterUserPrefs(user_prefs); HostZoomMap::RegisterUserPrefs(user_prefs); DevToolsManager::RegisterUserPrefs(user_prefs); PinnedTabCodec::RegisterUserPrefs(user_prefs); diff --git a/chrome/browser/prefs/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc index cbb7ef7..4a386d6 100644 --- a/chrome/browser/prefs/command_line_pref_store.cc +++ b/chrome/browser/prefs/command_line_pref_store.cc @@ -7,6 +7,7 @@ #include "app/app_switches.h" #include "base/logging.h" #include "base/values.h" +#include "chrome/browser/prefs/proxy_prefs.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" @@ -25,8 +26,6 @@ const CommandLinePrefStore::StringSwitchToPreferenceMapEntry const CommandLinePrefStore::BooleanSwitchToPreferenceMapEntry CommandLinePrefStore::boolean_switch_map_[] = { - { switches::kNoProxyServer, prefs::kNoProxyServer, true }, - { switches::kProxyAutoDetect, prefs::kProxyAutoDetect, true }, { switches::kDisableAuthNegotiateCnameLookup, prefs::kDisableAuthNegotiateCnameLookup, true }, { switches::kEnableAuthNegotiatePort, prefs::kEnableAuthNegotiatePort, @@ -35,24 +34,21 @@ const CommandLinePrefStore::BooleanSwitchToPreferenceMapEntry }; CommandLinePrefStore::CommandLinePrefStore(const CommandLine* command_line) - : command_line_(command_line), - prefs_(new DictionaryValue()) {} - -CommandLinePrefStore::~CommandLinePrefStore() {} - -PrefStore::PrefReadError CommandLinePrefStore::ReadPrefs() { + : command_line_(command_line) { ApplySimpleSwitches(); + ApplyProxyMode(); ValidateProxySwitches(); - return PrefStore::PREF_READ_ERROR_NONE; } +CommandLinePrefStore::~CommandLinePrefStore() {} + void CommandLinePrefStore::ApplySimpleSwitches() { // Look for each switch we know about and set its preference accordingly. for (size_t i = 0; i < arraysize(string_switch_map_); ++i) { if (command_line_->HasSwitch(string_switch_map_[i].switch_name)) { Value* value = Value::CreateStringValue(command_line_-> GetSwitchValueASCII(string_switch_map_[i].switch_name)); - prefs_->Set(string_switch_map_[i].preference_path, value); + SetValue(string_switch_map_[i].preference_path, value); } } @@ -60,7 +56,7 @@ void CommandLinePrefStore::ApplySimpleSwitches() { if (command_line_->HasSwitch(boolean_switch_map_[i].switch_name)) { Value* value = Value::CreateBooleanValue( boolean_switch_map_[i].set_value); - prefs_->Set(boolean_switch_map_[i].preference_path, value); + SetValue(boolean_switch_map_[i].preference_path, value); } } } @@ -77,3 +73,19 @@ bool CommandLinePrefStore::ValidateProxySwitches() { } return true; } + +void CommandLinePrefStore::ApplyProxyMode() { + if (command_line_->HasSwitch(switches::kNoProxyServer)) { + SetValue(prefs::kProxyMode, + Value::CreateIntegerValue(ProxyPrefs::MODE_DIRECT)); + } else if (command_line_->HasSwitch(switches::kProxyPacUrl)) { + SetValue(prefs::kProxyMode, + Value::CreateIntegerValue(ProxyPrefs::MODE_PAC_SCRIPT)); + } else if (command_line_->HasSwitch(switches::kProxyAutoDetect)) { + SetValue(prefs::kProxyMode, + Value::CreateIntegerValue(ProxyPrefs::MODE_AUTO_DETECT)); + } else if (command_line_->HasSwitch(switches::kProxyServer)) { + SetValue(prefs::kProxyMode, + Value::CreateIntegerValue(ProxyPrefs::MODE_FIXED_SERVERS)); + } +} diff --git a/chrome/browser/prefs/command_line_pref_store.h b/chrome/browser/prefs/command_line_pref_store.h index 2ea29ae..75d8b10 100644 --- a/chrome/browser/prefs/command_line_pref_store.h +++ b/chrome/browser/prefs/command_line_pref_store.h @@ -9,21 +9,18 @@ #include "base/basictypes.h" #include "base/command_line.h" #include "base/scoped_ptr.h" -#include "chrome/common/pref_store.h" +#include "base/values.h" +#include "chrome/browser/prefs/value_map_pref_store.h" class DictionaryValue; // This PrefStore keeps track of preferences set by command-line switches, // such as proxy settings. -class CommandLinePrefStore : public PrefStore { +class CommandLinePrefStore : public ValueMapPrefStore { public: explicit CommandLinePrefStore(const CommandLine* command_line); virtual ~CommandLinePrefStore(); - // PrefStore methods: - virtual PrefReadError ReadPrefs(); - virtual DictionaryValue* prefs() const { return prefs_.get(); } - protected: // Logs a message and returns false if the proxy switches are // self-contradictory. Protected so it can be used in unit testing. @@ -48,11 +45,12 @@ class CommandLinePrefStore : public PrefStore { // corresponding preferences in this pref store. void ApplySimpleSwitches(); + // Determines the proxy mode preference from the given proxy switches. + void ApplyProxyMode(); + // Weak reference. const CommandLine* command_line_; - scoped_ptr<DictionaryValue> prefs_; - static const StringSwitchToPreferenceMapEntry string_switch_map_[]; DISALLOW_COPY_AND_ASSIGN(CommandLinePrefStore); diff --git a/chrome/browser/prefs/command_line_pref_store_unittest.cc b/chrome/browser/prefs/command_line_pref_store_unittest.cc index 064c7e6..1be9c0a 100644 --- a/chrome/browser/prefs/command_line_pref_store_unittest.cc +++ b/chrome/browser/prefs/command_line_pref_store_unittest.cc @@ -9,6 +9,7 @@ #include "base/string_util.h" #include "base/values.h" #include "chrome/browser/prefs/command_line_pref_store.h" +#include "chrome/browser/prefs/proxy_prefs.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" @@ -22,6 +23,12 @@ class TestCommandLinePrefStore : public CommandLinePrefStore { bool ProxySwitchesAreValid() { return ValidateProxySwitches(); } + + void VerifyIntPref(const std::string& path, int expected_value) { + Value* actual = NULL; + ASSERT_EQ(PrefStore::READ_OK, GetValue(path, &actual)); + EXPECT_TRUE(FundamentalValue(expected_value).Equals(actual)); + } }; const char unknown_bool[] = "unknown_switch"; @@ -34,10 +41,12 @@ TEST(CommandLinePrefStoreTest, SimpleStringPref) { CommandLine cl(CommandLine::NO_PROGRAM); cl.AppendSwitchASCII(switches::kLang, "hi-MOM"); CommandLinePrefStore store(&cl); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + Value* actual = NULL; + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kApplicationLocale, &actual)); std::string result; - EXPECT_TRUE(store.prefs()->GetString(prefs::kApplicationLocale, &result)); + EXPECT_TRUE(actual->GetAsString(&result)); EXPECT_EQ("hi-MOM", result); } @@ -45,12 +54,9 @@ TEST(CommandLinePrefStoreTest, SimpleStringPref) { TEST(CommandLinePrefStoreTest, SimpleBooleanPref) { CommandLine cl(CommandLine::NO_PROGRAM); cl.AppendSwitch(switches::kNoProxyServer); - CommandLinePrefStore store(&cl); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + TestCommandLinePrefStore store(&cl); - bool result; - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &result)); - EXPECT_TRUE(result); + store.VerifyIntPref(prefs::kProxyMode, ProxyPrefs::MODE_DIRECT); } // Tests a command line with no recognized prefs. @@ -59,15 +65,10 @@ TEST(CommandLinePrefStoreTest, NoPrefs) { cl.AppendSwitch(unknown_string); cl.AppendSwitchASCII(unknown_bool, "a value"); CommandLinePrefStore store(&cl); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - - bool bool_result = false; - EXPECT_FALSE(store.prefs()->GetBoolean(unknown_bool, &bool_result)); - EXPECT_FALSE(bool_result); - std::string string_result = ""; - EXPECT_FALSE(store.prefs()->GetString(unknown_string, &string_result)); - EXPECT_EQ("", string_result); + Value* actual = NULL; + EXPECT_EQ(PrefStore::READ_NO_VALUE, store.GetValue(unknown_bool, &actual)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, store.GetValue(unknown_string, &actual)); } // Tests a complex command line with multiple known and unknown switches. @@ -78,22 +79,20 @@ TEST(CommandLinePrefStoreTest, MultipleSwitches) { cl.AppendSwitchASCII(switches::kProxyServer, "proxy"); cl.AppendSwitchASCII(switches::kProxyBypassList, "list"); cl.AppendSwitchASCII(unknown_bool, "a value"); - CommandLinePrefStore store(&cl); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); + TestCommandLinePrefStore store(&cl); - bool bool_result = false; - EXPECT_FALSE(store.prefs()->GetBoolean(unknown_bool, &bool_result)); - EXPECT_FALSE(bool_result); - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result)); - EXPECT_TRUE(bool_result); + Value* actual = NULL; + EXPECT_EQ(PrefStore::READ_NO_VALUE, store.GetValue(unknown_bool, &actual)); + store.VerifyIntPref(prefs::kProxyMode, ProxyPrefs::MODE_AUTO_DETECT); + EXPECT_EQ(PrefStore::READ_NO_VALUE, store.GetValue(unknown_string, &actual)); std::string string_result = ""; - EXPECT_FALSE(store.prefs()->GetString(unknown_string, &string_result)); - EXPECT_EQ("", string_result); - EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); + ASSERT_EQ(PrefStore::READ_OK, store.GetValue(prefs::kProxyServer, &actual)); + EXPECT_TRUE(actual->GetAsString(&string_result)); EXPECT_EQ("proxy", string_result); - EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList, - &string_result)); + ASSERT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kProxyBypassList, &actual)); + EXPECT_TRUE(actual->GetAsString(&string_result)); EXPECT_EQ("list", string_result); } @@ -103,19 +102,16 @@ TEST(CommandLinePrefStoreTest, ProxySwitchValidation) { // No switches. TestCommandLinePrefStore store(&cl); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); EXPECT_TRUE(store.ProxySwitchesAreValid()); // Only no-proxy. cl.AppendSwitch(switches::kNoProxyServer); TestCommandLinePrefStore store2(&cl); - EXPECT_EQ(store2.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); EXPECT_TRUE(store2.ProxySwitchesAreValid()); // Another proxy switch too. cl.AppendSwitch(switches::kProxyAutoDetect); TestCommandLinePrefStore store3(&cl); - EXPECT_EQ(store3.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); EXPECT_FALSE(store3.ProxySwitchesAreValid()); // All proxy switches except no-proxy. @@ -125,6 +121,18 @@ TEST(CommandLinePrefStoreTest, ProxySwitchValidation) { cl2.AppendSwitchASCII(switches::kProxyPacUrl, "url"); cl2.AppendSwitchASCII(switches::kProxyBypassList, "list"); TestCommandLinePrefStore store4(&cl2); - EXPECT_EQ(store4.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); EXPECT_TRUE(store4.ProxySwitchesAreValid()); } + +TEST(CommandLinePrefStoreTest, ManualProxyModeInference) { + CommandLine cl1(CommandLine::NO_PROGRAM); + cl1.AppendSwitch(unknown_string); + cl1.AppendSwitchASCII(switches::kProxyServer, "proxy"); + TestCommandLinePrefStore store1(&cl1); + store1.VerifyIntPref(prefs::kProxyMode, ProxyPrefs::MODE_FIXED_SERVERS); + + CommandLine cl2(CommandLine::NO_PROGRAM); + cl2.AppendSwitchASCII(switches::kProxyPacUrl, "proxy"); + TestCommandLinePrefStore store2(&cl2); + store2.VerifyIntPref(prefs::kProxyMode, ProxyPrefs::MODE_PAC_SCRIPT); +} diff --git a/chrome/browser/prefs/default_pref_store.cc b/chrome/browser/prefs/default_pref_store.cc deleted file mode 100644 index a9e6861..0000000 --- a/chrome/browser/prefs/default_pref_store.cc +++ /dev/null @@ -1,21 +0,0 @@ -// 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 "chrome/browser/prefs/default_pref_store.h" - -#include "base/values.h" - -DefaultPrefStore::DefaultPrefStore() : prefs_(new DictionaryValue()) { -} - -DefaultPrefStore::~DefaultPrefStore() { -} - -DictionaryValue* DefaultPrefStore::prefs() const { - return prefs_.get(); -} - -PrefStore::PrefReadError DefaultPrefStore::ReadPrefs() { - return PrefStore::PREF_READ_ERROR_NONE; -} diff --git a/chrome/browser/prefs/default_pref_store.h b/chrome/browser/prefs/default_pref_store.h index 6378aca..9e2e715 100644 --- a/chrome/browser/prefs/default_pref_store.h +++ b/chrome/browser/prefs/default_pref_store.h @@ -6,25 +6,24 @@ #define CHROME_BROWSER_PREFS_DEFAULT_PREF_STORE_H_ #pragma once +#include <map> + #include "base/basictypes.h" -#include "base/scoped_ptr.h" -#include "chrome/common/pref_store.h" +#include "chrome/browser/prefs/value_map_pref_store.h" // This PrefStore keeps track of default preference values set when a // preference is registered with the PrefService. -class DefaultPrefStore : public PrefStore { +class DefaultPrefStore : public ValueMapPrefStore { public: - DefaultPrefStore(); - virtual ~DefaultPrefStore(); + DefaultPrefStore() {} + virtual ~DefaultPrefStore() {} - // PrefStore methods: - virtual DictionaryValue* prefs() const; - virtual PrefStore::PrefReadError ReadPrefs(); + // Stores a new |value| for |key|. Assumes ownership of |value|. + void SetDefaultValue(const std::string& key, Value* value) { + SetValue(key, value); + } private: - // The default preference values. - scoped_ptr<DictionaryValue> prefs_; - DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore); }; diff --git a/chrome/browser/prefs/dummy_pref_store.cc b/chrome/browser/prefs/dummy_pref_store.cc deleted file mode 100644 index 3a0a81a..0000000 --- a/chrome/browser/prefs/dummy_pref_store.cc +++ /dev/null @@ -1,22 +0,0 @@ -// 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 "chrome/browser/prefs/dummy_pref_store.h" - -#include "base/values.h" - -DummyPrefStore::DummyPrefStore() - : prefs_(new DictionaryValue()), - read_only_(true), - prefs_written_(false) { } - -PrefStore::PrefReadError DummyPrefStore::ReadPrefs() { - prefs_.reset(new DictionaryValue()); - return PrefStore::PREF_READ_ERROR_NONE; -} - -bool DummyPrefStore::WritePrefs() { - prefs_written_ = true; - return prefs_written_; -} diff --git a/chrome/browser/prefs/dummy_pref_store.h b/chrome/browser/prefs/dummy_pref_store.h deleted file mode 100644 index 4a4e6ba..0000000 --- a/chrome/browser/prefs/dummy_pref_store.h +++ /dev/null @@ -1,49 +0,0 @@ -// 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 CHROME_BROWSER_PREFS_DUMMY_PREF_STORE_H_ -#define CHROME_BROWSER_PREFS_DUMMY_PREF_STORE_H_ -#pragma once - -#include "base/basictypes.h" -#include "base/scoped_ptr.h" -#include "chrome/common/pref_store.h" - -class DictionaryValue; - -// |DummyPrefStore| is a stub implementation of the |PrefStore| interface. -// It allows to get and set the state of the |PrefStore|. -class DummyPrefStore : public PrefStore { - public: - DummyPrefStore(); - virtual ~DummyPrefStore() {} - - virtual DictionaryValue* prefs() const { return prefs_.get(); } - - virtual PrefStore::PrefReadError ReadPrefs(); - - virtual bool ReadOnly() { return read_only_; } - - virtual bool WritePrefs(); - - // Getter and Setter methods for setting and getting the state of the - // |DummyPrefStore|. - virtual void set_read_only(bool read_only) { read_only_ = read_only; } - virtual void set_prefs(DictionaryValue* prefs) { prefs_.reset(prefs); } - virtual void set_prefs_written(bool status) { prefs_written_ = status; } - virtual bool get_prefs_written() { return prefs_written_; } - - private: - scoped_ptr<DictionaryValue> prefs_; - - // Flag that indicates if the PrefStore is read-only - bool read_only_; - - // Flag that indicates if the method WritePrefs was called. - bool prefs_written_; - - DISALLOW_COPY_AND_ASSIGN(DummyPrefStore); -}; - -#endif // CHROME_BROWSER_PREFS_DUMMY_PREF_STORE_H_ diff --git a/chrome/browser/prefs/pref_change_registrar.cc b/chrome/browser/prefs/pref_change_registrar.cc index 05372b1..5655a8e 100644 --- a/chrome/browser/prefs/pref_change_registrar.cc +++ b/chrome/browser/prefs/pref_change_registrar.cc @@ -4,6 +4,7 @@ #include "chrome/browser/prefs/pref_change_registrar.h" +#include "base/logging.h" #include "chrome/browser/prefs/pref_service.h" PrefChangeRegistrar::PrefChangeRegistrar() : service_(NULL) {} diff --git a/chrome/browser/prefs/pref_change_registrar_unittest.cc b/chrome/browser/prefs/pref_change_registrar_unittest.cc index 8096ee6..2e4cd0e 100644 --- a/chrome/browser/prefs/pref_change_registrar_unittest.cc +++ b/chrome/browser/prefs/pref_change_registrar_unittest.cc @@ -4,8 +4,9 @@ #include "chrome/browser/prefs/pref_change_registrar.h" #include "chrome/common/notification_details.h" -#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_observer_mock.h" #include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" #include "chrome/common/pref_names.h" #include "chrome/test/testing_pref_service.h" #include "testing/gmock/include/gmock/gmock.h" @@ -14,6 +15,8 @@ using testing::Mock; using testing::Eq; +namespace { + // A mock provider that allows us to capture pref observer changes. class MockPrefService : public TestingPrefService { public: @@ -24,12 +27,7 @@ class MockPrefService : public TestingPrefService { MOCK_METHOD2(RemovePrefObserver, void(const char*, NotificationObserver*)); }; -// A mock observer used as a pref observer -class MockObserver : public NotificationObserver { - public: - MOCK_METHOD3(Observe, void(NotificationType, const NotificationSource& source, - const NotificationDetails& details)); -}; +} // namespace class PrefChangeRegistrarTest : public testing::Test { public: @@ -44,12 +42,12 @@ class PrefChangeRegistrarTest : public testing::Test { private: scoped_ptr<MockPrefService> service_; - scoped_ptr<MockObserver> observer_; + scoped_ptr<NotificationObserverMock> observer_; }; void PrefChangeRegistrarTest::SetUp() { service_.reset(new MockPrefService()); - observer_.reset(new MockObserver()); + observer_.reset(new NotificationObserverMock()); } TEST_F(PrefChangeRegistrarTest, AddAndRemove) { diff --git a/chrome/browser/prefs/pref_member_unittest.cc b/chrome/browser/prefs/pref_member_unittest.cc index f59f937..3f786afb 100644 --- a/chrome/browser/prefs/pref_member_unittest.cc +++ b/chrome/browser/prefs/pref_member_unittest.cc @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/prefs/dummy_pref_store.h" #include "chrome/browser/prefs/pref_member.h" #include "chrome/browser/prefs/pref_value_store.h" -#include "chrome/common/notification_service.h" +#include "chrome/common/notification_details.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" #include "chrome/test/testing_pref_service.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/prefs/pref_notifier.cc b/chrome/browser/prefs/pref_notifier.cc deleted file mode 100644 index 151b128..0000000 --- a/chrome/browser/prefs/pref_notifier.cc +++ /dev/null @@ -1,137 +0,0 @@ -// 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 "chrome/browser/prefs/pref_notifier.h" - -#include "base/stl_util-inl.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/policy/configuration_policy_pref_store.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/prefs/pref_value_store.h" -#include "chrome/common/notification_service.h" - - -PrefNotifier::PrefNotifier(PrefService* service, PrefValueStore* value_store) - : pref_service_(service), - pref_value_store_(value_store) { - registrar_.Add(this, - NotificationType(NotificationType::POLICY_CHANGED), - NotificationService::AllSources()); -} - -PrefNotifier::~PrefNotifier() { - DCHECK(CalledOnValidThread()); - - // Verify that there are no pref observers when we shut down. - for (PrefObserverMap::iterator it = pref_observers_.begin(); - it != pref_observers_.end(); ++it) { - NotificationObserverList::Iterator obs_iterator(*(it->second)); - if (obs_iterator.GetNext()) { - LOG(WARNING) << "pref observer found at shutdown " << it->first; - } - } - - STLDeleteContainerPairSecondPointers(pref_observers_.begin(), - pref_observers_.end()); - pref_observers_.clear(); -} - -void PrefNotifier::OnPreferenceSet(const char* pref_name, - PrefNotifier::PrefStoreType new_store) { - if (pref_value_store_->PrefHasChanged(pref_name, new_store)) - FireObservers(pref_name); -} - -void PrefNotifier::OnUserPreferenceSet(const char* pref_name) { - OnPreferenceSet(pref_name, PrefNotifier::USER_STORE); -} - -void PrefNotifier::FireObservers(const char* path) { - DCHECK(CalledOnValidThread()); - - // Convert path to a std::string because the Details constructor requires a - // class. - std::string path_str(path); - PrefObserverMap::iterator observer_iterator = pref_observers_.find(path_str); - if (observer_iterator == pref_observers_.end()) - return; - - NotificationObserverList::Iterator it(*(observer_iterator->second)); - NotificationObserver* observer; - while ((observer = it.GetNext()) != NULL) { - observer->Observe(NotificationType::PREF_CHANGED, - Source<PrefService>(pref_service_), - Details<std::string>(&path_str)); - } -} - -void PrefNotifier::AddPrefObserver(const char* path, - NotificationObserver* obs) { - // Get the pref observer list associated with the path. - NotificationObserverList* observer_list = NULL; - PrefObserverMap::iterator observer_iterator = pref_observers_.find(path); - if (observer_iterator == pref_observers_.end()) { - observer_list = new NotificationObserverList; - pref_observers_[path] = observer_list; - } else { - observer_list = observer_iterator->second; - } - - // Verify that this observer doesn't already exist. - NotificationObserverList::Iterator it(*observer_list); - NotificationObserver* existing_obs; - while ((existing_obs = it.GetNext()) != NULL) { - DCHECK(existing_obs != obs) << path << " observer already registered"; - if (existing_obs == obs) - return; - } - - // Ok, safe to add the pref observer. - observer_list->AddObserver(obs); -} - -void PrefNotifier::RemovePrefObserver(const char* path, - NotificationObserver* obs) { - DCHECK(CalledOnValidThread()); - - PrefObserverMap::iterator observer_iterator = pref_observers_.find(path); - if (observer_iterator == pref_observers_.end()) { - return; - } - - NotificationObserverList* observer_list = observer_iterator->second; - observer_list->RemoveObserver(obs); -} - -void PrefNotifier::FireObserversForRefreshedManagedPrefs( - std::vector<std::string> changed_prefs_paths) { - DCHECK(CalledOnValidThread()); - std::vector<std::string>::const_iterator current; - for (current = changed_prefs_paths.begin(); - current != changed_prefs_paths.end(); - ++current) { - FireObservers(current->c_str()); - } -} - -void PrefNotifier::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - using policy::ConfigurationPolicyPrefStore; - - if (type == NotificationType::POLICY_CHANGED) { - PrefValueStore::AfterRefreshCallback* callback = - NewCallback(this, - &PrefNotifier::FireObserversForRefreshedManagedPrefs); - // The notification of the policy refresh can come from any thread, - // but the manipulation of the PrefValueStore must happen on the UI - // thread, thus the policy refresh must be explicitly started on it. - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - pref_value_store_, - &PrefValueStore::RefreshPolicyPrefs, - callback)); - } -} diff --git a/chrome/browser/prefs/pref_notifier.h b/chrome/browser/prefs/pref_notifier.h index 7334a51..f2d9c52 100644 --- a/chrome/browser/prefs/pref_notifier.h +++ b/chrome/browser/prefs/pref_notifier.h @@ -7,112 +7,21 @@ #pragma once #include <string> -#include <vector> -#include "base/hash_tables.h" -#include "base/non_thread_safe.h" -#include "base/observer_list.h" -#include "chrome/common/notification_observer.h" -#include "chrome/common/notification_registrar.h" - -class NotificationObserver; -class PrefService; -class PrefValueStore; -class Value; - -// Registers observers for particular preferences and sends notifications when -// preference values or sources (i.e., which preference layer controls the -// preference) change. -class PrefNotifier : public NonThreadSafe, - public NotificationObserver { +// 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: - // PrefStores must be listed here in order from highest to lowest priority. - // MANAGED_PLATFORM contains all managed preference values that are - // provided by a platform-specific policy mechanism (e.g. Windows - // Group Policy). - // DEVICE_MANAGEMENT contains all managed preference values supplied - // by the device management server (cloud policy). - // EXTENSION contains preference values set by extensions. - // COMMAND_LINE contains preference values set by command-line switches. - // USER contains all user-set preference values. - // RECOMMENDED contains all recommended (policy) preference values. - // DEFAULT contains all application default preference values. - // This enum is kept in pref_notifier.h rather than pref_value_store.h in - // order to minimize additional headers needed by the *PrefStore files. - enum PrefStoreType { - // INVALID_STORE is not associated with an actual PrefStore but used as - // an invalid marker, e.g. as a return value. - INVALID_STORE = -1, - MANAGED_PLATFORM_STORE = 0, - DEVICE_MANAGEMENT_STORE, - EXTENSION_STORE, - COMMAND_LINE_STORE, - USER_STORE, - RECOMMENDED_STORE, - DEFAULT_STORE, - PREF_STORE_TYPE_MAX = DEFAULT_STORE - }; - - // The |service| with which this notifier is associated will be sent as the - // source of any notifications. - PrefNotifier(PrefService* service, PrefValueStore* value_store); - - virtual ~PrefNotifier(); - - // For the given pref_name, fire any observer of the pref if the effective - // value of the pref or the store controlling its value has changed, been - // added, or been removed (but not if it's re-setting the same value it had - // already). |new_store| should be the PrefStoreType of the store reporting - // the change. - void OnPreferenceSet(const char* pref_name, - PrefNotifier::PrefStoreType new_store); - - // Convenience method to be called when a preference is set in the - // USER_STORE. See OnPreferenceSet(). - void OnUserPreferenceSet(const char* pref_name); - - // For the given pref_name, fire any observer of the pref. Virtual so it can - // be mocked for unit testing. - virtual void FireObservers(const char* path); - - // If the pref at the given path changes, we call the observer's Observe - // method with PREF_CHANGED. - void AddPrefObserver(const char* path, NotificationObserver* obs); - void RemovePrefObserver(const char* path, NotificationObserver* obs); - - protected: - // A map from pref names to a list of observers. Observers get fired in the - // order they are added. These should only be accessed externally for unit - // testing. - typedef ObserverList<NotificationObserver> NotificationObserverList; - typedef base::hash_map<std::string, NotificationObserverList*> - PrefObserverMap; - const PrefObserverMap* pref_observers() { return &pref_observers_; } - - private: - // Weak references. - PrefService* pref_service_; - PrefValueStore* pref_value_store_; - - NotificationRegistrar registrar_; - - PrefObserverMap pref_observers_; - - // Called after a policy refresh to notify relevant preference observers. - // |changed_prefs_paths| is the vector of preference paths changed by the - // policy update. It is passed by value and not reference because - // this method is called asynchronously as a callback from another thread. - // Copying the vector guarantees that the vector's lifecycle spans the - // method's invocation. - void FireObserversForRefreshedManagedPrefs( - std::vector<std::string> changed_prefs_paths); + virtual ~PrefNotifier() {} - // NotificationObserver methods: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); + // Sends out a change notification for the preference identified by + // |pref_name|. + virtual void OnPreferenceChanged(const std::string& pref_name) = 0; - DISALLOW_COPY_AND_ASSIGN(PrefNotifier); + // Broadcasts the intialization completed notification. + virtual void OnInitializationCompleted() = 0; }; #endif // CHROME_BROWSER_PREFS_PREF_NOTIFIER_H_ diff --git a/chrome/browser/prefs/pref_notifier_impl.cc b/chrome/browser/prefs/pref_notifier_impl.cc new file mode 100644 index 0000000..d15f425 --- /dev/null +++ b/chrome/browser/prefs/pref_notifier_impl.cc @@ -0,0 +1,105 @@ +// 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 "chrome/browser/prefs/pref_notifier_impl.h" + +#include "base/stl_util-inl.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_service.h" + +PrefNotifierImpl::PrefNotifierImpl(PrefService* service) + : pref_service_(service) { +} + +PrefNotifierImpl::~PrefNotifierImpl() { + DCHECK(CalledOnValidThread()); + + // Verify that there are no pref observers when we shut down. + for (PrefObserverMap::iterator it = pref_observers_.begin(); + it != pref_observers_.end(); ++it) { + NotificationObserverList::Iterator obs_iterator(*(it->second)); + if (obs_iterator.GetNext()) { + LOG(WARNING) << "pref observer found at shutdown " << it->first; + } + } + + STLDeleteContainerPairSecondPointers(pref_observers_.begin(), + pref_observers_.end()); + pref_observers_.clear(); +} + +void PrefNotifierImpl::AddPrefObserver(const char* path, + NotificationObserver* obs) { + // Get the pref observer list associated with the path. + NotificationObserverList* observer_list = NULL; + const PrefObserverMap::iterator observer_iterator = + pref_observers_.find(path); + if (observer_iterator == pref_observers_.end()) { + observer_list = new NotificationObserverList; + pref_observers_[path] = observer_list; + } else { + observer_list = observer_iterator->second; + } + + // Verify that this observer doesn't already exist. + NotificationObserverList::Iterator it(*observer_list); + NotificationObserver* existing_obs; + while ((existing_obs = it.GetNext()) != NULL) { + DCHECK(existing_obs != obs) << path << " observer already registered"; + if (existing_obs == obs) + return; + } + + // Ok, safe to add the pref observer. + observer_list->AddObserver(obs); +} + +void PrefNotifierImpl::RemovePrefObserver(const char* path, + NotificationObserver* obs) { + DCHECK(CalledOnValidThread()); + + const PrefObserverMap::iterator observer_iterator = + pref_observers_.find(path); + if (observer_iterator == pref_observers_.end()) { + return; + } + + NotificationObserverList* observer_list = observer_iterator->second; + observer_list->RemoveObserver(obs); +} + +void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) { + FireObservers(path); +} + +void PrefNotifierImpl::OnInitializationCompleted() { + DCHECK(CalledOnValidThread()); + + NotificationService::current()->Notify( + NotificationType::PREF_INITIALIZATION_COMPLETED, + Source<PrefService>(pref_service_), + NotificationService::NoDetails()); +} + +void PrefNotifierImpl::FireObservers(const std::string& path) { + DCHECK(CalledOnValidThread()); + + // Only send notifications for registered preferences. + if (!pref_service_->FindPreference(path.c_str())) + return; + + const PrefObserverMap::iterator observer_iterator = + pref_observers_.find(path); + if (observer_iterator == pref_observers_.end()) + return; + + NotificationObserverList::Iterator it(*(observer_iterator->second)); + NotificationObserver* observer; + while ((observer = it.GetNext()) != NULL) { + observer->Observe(NotificationType::PREF_CHANGED, + Source<PrefService>(pref_service_), + Details<const std::string>(&path)); + } +} diff --git a/chrome/browser/prefs/pref_notifier_impl.h b/chrome/browser/prefs/pref_notifier_impl.h new file mode 100644 index 0000000..1d61830 --- /dev/null +++ b/chrome/browser/prefs/pref_notifier_impl.h @@ -0,0 +1,58 @@ +// 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 CHROME_BROWSER_PREFS_PREF_NOTIFIER_IMPL_H_ +#define CHROME_BROWSER_PREFS_PREF_NOTIFIER_IMPL_H_ +#pragma once + +#include <string> + +#include "base/hash_tables.h" +#include "base/non_thread_safe.h" +#include "base/observer_list.h" +#include "chrome/browser/prefs/pref_notifier.h" + +class PrefService; +class NotificationObserver; + +// The PrefNotifier implementation used by the PrefService. +class PrefNotifierImpl : public PrefNotifier, + public NonThreadSafe { + public: + explicit PrefNotifierImpl(PrefService* pref_service); + virtual ~PrefNotifierImpl(); + + // If the pref at the given path changes, we call the observer's Observe + // method with PREF_CHANGED. + void AddPrefObserver(const char* path, NotificationObserver* obs); + void RemovePrefObserver(const char* path, NotificationObserver* obs); + + // PrefNotifier overrides. + virtual void OnPreferenceChanged(const std::string& pref_name); + virtual void OnInitializationCompleted(); + + protected: + // A map from pref names to a list of observers. Observers get fired in the + // order they are added. These should only be accessed externally for unit + // testing. + typedef ObserverList<NotificationObserver> NotificationObserverList; + typedef base::hash_map<std::string, NotificationObserverList*> + PrefObserverMap; + + const PrefObserverMap* pref_observers() const { return &pref_observers_; } + + private: + // For the given pref_name, fire any observer of the pref. Virtual so it can + // be mocked for unit testing. + virtual void FireObservers(const std::string& path); + + // Weak reference; the notifier is owned by the PrefService. + PrefService* pref_service_; + + PrefObserverMap pref_observers_; + + DISALLOW_COPY_AND_ASSIGN(PrefNotifierImpl); +}; + +#endif // CHROME_BROWSER_PREFS_PREF_NOTIFIER_IMPL_H_ diff --git a/chrome/browser/prefs/pref_notifier_impl_unittest.cc b/chrome/browser/prefs/pref_notifier_impl_unittest.cc new file mode 100644 index 0000000..a410884 --- /dev/null +++ b/chrome/browser/prefs/pref_notifier_impl_unittest.cc @@ -0,0 +1,200 @@ +// 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 "chrome/browser/prefs/pref_notifier_impl.h" +#include "chrome/browser/prefs/pref_observer_mock.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/prefs/pref_value_store.h" +#include "chrome/common/notification_observer_mock.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" +#include "chrome/test/testing_pref_service.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::Field; +using testing::Invoke; +using testing::Mock; +using testing::Truly; + +namespace { + +const char kChangedPref[] = "changed_pref"; +const char kUnchangedPref[] = "unchanged_pref"; + +bool DetailsAreChangedPref(const Details<std::string>& details) { + std::string* string_in = Details<std::string>(details).ptr(); + return strcmp(string_in->c_str(), kChangedPref) == 0; +} + +// Test PrefNotifier that allows tracking of observers and notifications. +class MockPrefNotifier : public PrefNotifierImpl { + public: + explicit MockPrefNotifier(PrefService* pref_service) + : PrefNotifierImpl(pref_service) {} + virtual ~MockPrefNotifier() {} + + MOCK_METHOD1(FireObservers, void(const std::string& path)); + + size_t CountObserver(const char* path, NotificationObserver* obs) { + PrefObserverMap::const_iterator observer_iterator = + pref_observers()->find(path); + if (observer_iterator == pref_observers()->end()) + return false; + + NotificationObserverList* observer_list = observer_iterator->second; + NotificationObserverList::Iterator it(*observer_list); + NotificationObserver* existing_obs; + size_t count = 0; + while ((existing_obs = it.GetNext()) != NULL) { + if (existing_obs == obs) + count++; + } + + return count; + } +}; + +// Test fixture class. +class PrefNotifierTest : public testing::Test { + protected: + virtual void SetUp() { + pref_service_.RegisterBooleanPref(kChangedPref, true); + pref_service_.RegisterBooleanPref(kUnchangedPref, true); + } + + TestingPrefService pref_service_; + + PrefObserverMock obs1_; + PrefObserverMock obs2_; +}; + +TEST_F(PrefNotifierTest, OnPreferenceChanged) { + MockPrefNotifier notifier(&pref_service_); + EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1); + notifier.OnPreferenceChanged(kChangedPref); +} + +TEST_F(PrefNotifierTest, OnInitializationCompleted) { + MockPrefNotifier notifier(&pref_service_); + NotificationObserverMock observer; + NotificationRegistrar registrar; + registrar.Add(&observer, NotificationType::PREF_INITIALIZATION_COMPLETED, + Source<PrefService>(&pref_service_)); + EXPECT_CALL(observer, Observe( + Field(&NotificationType::value, + NotificationType::PREF_INITIALIZATION_COMPLETED), + Source<PrefService>(&pref_service_), + NotificationService::NoDetails())); + notifier.OnInitializationCompleted(); +} + +TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) { + const char pref_name[] = "homepage"; + const char pref_name2[] = "proxy"; + + MockPrefNotifier notifier(&pref_service_); + notifier.AddPrefObserver(pref_name, &obs1_); + ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); + + // Re-adding the same observer for the same pref doesn't change anything. + // Skip this in debug mode, since it hits a DCHECK and death tests aren't + // thread-safe. +#if defined(NDEBUG) + notifier.AddPrefObserver(pref_name, &obs1_); + ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); +#endif // NDEBUG + + // Ensure that we can add the same observer to a different pref. + notifier.AddPrefObserver(pref_name2, &obs1_); + ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); + ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); + + // Ensure that we can add another observer to the same pref. + notifier.AddPrefObserver(pref_name, &obs2_); + ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); + ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); + ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); + + // Ensure that we can remove all observers, and that removing a non-existent + // observer is harmless. + notifier.RemovePrefObserver(pref_name, &obs1_); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); + ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); + ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); + + notifier.RemovePrefObserver(pref_name, &obs2_); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); + ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); + + notifier.RemovePrefObserver(pref_name, &obs1_); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); + ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); + + notifier.RemovePrefObserver(pref_name2, &obs1_); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); + ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); +} + +TEST_F(PrefNotifierTest, FireObservers) { + FundamentalValue value_true(true); + PrefNotifierImpl notifier(&pref_service_); + notifier.AddPrefObserver(kChangedPref, &obs1_); + notifier.AddPrefObserver(kUnchangedPref, &obs1_); + + obs1_.Expect(&pref_service_, kChangedPref, &value_true); + EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); + notifier.OnPreferenceChanged(kChangedPref); + Mock::VerifyAndClearExpectations(&obs1_); + Mock::VerifyAndClearExpectations(&obs2_); + + notifier.AddPrefObserver(kChangedPref, &obs2_); + notifier.AddPrefObserver(kUnchangedPref, &obs2_); + + obs1_.Expect(&pref_service_, kChangedPref, &value_true); + obs2_.Expect(&pref_service_, kChangedPref, &value_true); + notifier.OnPreferenceChanged(kChangedPref); + Mock::VerifyAndClearExpectations(&obs1_); + Mock::VerifyAndClearExpectations(&obs2_); + + // Make sure removing an observer from one pref doesn't affect anything else. + notifier.RemovePrefObserver(kChangedPref, &obs1_); + + EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); + obs2_.Expect(&pref_service_, kChangedPref, &value_true); + notifier.OnPreferenceChanged(kChangedPref); + Mock::VerifyAndClearExpectations(&obs1_); + Mock::VerifyAndClearExpectations(&obs2_); + + // Make sure removing an observer entirely doesn't affect anything else. + notifier.RemovePrefObserver(kUnchangedPref, &obs1_); + + EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); + obs2_.Expect(&pref_service_, kChangedPref, &value_true); + notifier.OnPreferenceChanged(kChangedPref); + Mock::VerifyAndClearExpectations(&obs1_); + Mock::VerifyAndClearExpectations(&obs2_); + + notifier.RemovePrefObserver(kChangedPref, &obs2_); + notifier.RemovePrefObserver(kUnchangedPref, &obs2_); +} + +} // namespace diff --git a/chrome/browser/prefs/pref_notifier_unittest.cc b/chrome/browser/prefs/pref_notifier_unittest.cc deleted file mode 100644 index 6792ada..0000000 --- a/chrome/browser/prefs/pref_notifier_unittest.cc +++ /dev/null @@ -1,294 +0,0 @@ -// 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 "chrome/browser/prefs/default_pref_store.h" -#include "chrome/browser/prefs/pref_notifier.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/prefs/pref_value_store.h" -#include "chrome/common/notification_observer.h" -#include "chrome/common/notification_type.h" -#include "chrome/common/notification_service.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - - -namespace { - -const char kChangedPref[] = "changed_pref"; -const char kUnchangedPref[] = "unchanged_pref"; - -bool DetailsAreChangedPref(const Details<std::string>& details) { - std::string* string_in = Details<std::string>(details).ptr(); - return strcmp(string_in->c_str(), kChangedPref) == 0; -} - -// Test PrefNotifier that allows tracking of observers and notifications. -class MockPrefNotifier : public PrefNotifier { - public: - MockPrefNotifier(PrefService* prefs, PrefValueStore* value_store) - : PrefNotifier(prefs, value_store) {} - - virtual ~MockPrefNotifier() {} - - MOCK_METHOD1(FireObservers, void(const char* path)); - - void RealFireObservers(const char* path) { - PrefNotifier::FireObservers(path); - } - - size_t CountObserver(const char* path, NotificationObserver* obs) { - PrefObserverMap::const_iterator observer_iterator = - pref_observers()->find(path); - if (observer_iterator == pref_observers()->end()) - return false; - - NotificationObserverList* observer_list = observer_iterator->second; - NotificationObserverList::Iterator it(*observer_list); - NotificationObserver* existing_obs; - size_t count = 0; - while ((existing_obs = it.GetNext()) != NULL) { - if (existing_obs == obs) - count++; - } - - return count; - } -}; - -// Mock PrefValueStore that has no unnecessary PrefStores and injects a simpler -// PrefHasChanged(). -class MockPrefValueStore : public PrefValueStore { - public: - MockPrefValueStore() - : PrefValueStore(NULL, NULL, NULL, NULL, NULL, NULL, - new DefaultPrefStore(), NULL) {} - - virtual ~MockPrefValueStore() {} - - // This mock version returns true if the pref path starts with "changed". - virtual bool PrefHasChanged(const char* path, - PrefNotifier::PrefStoreType new_store) { - std::string path_str(path); - if (path_str.compare(0, 7, "changed") == 0) - return true; - return false; - } -}; - -// Mock PrefService that allows the PrefNotifier to be injected. -class MockPrefService : public PrefService { - public: - explicit MockPrefService(PrefValueStore* pref_value_store) - : PrefService(pref_value_store) {} - - void SetPrefNotifier(PrefNotifier* notifier) { - pref_notifier_.reset(notifier); - } -}; - -// Mock PrefObserver that verifies notifications. -class MockPrefObserver : public NotificationObserver { - public: - virtual ~MockPrefObserver() {} - - MOCK_METHOD3(Observe, void(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details)); -}; - -// Test fixture class. -class PrefNotifierTest : public testing::Test { - protected: - virtual void SetUp() { - value_store_ = new MockPrefValueStore; - pref_service_.reset(new MockPrefService(value_store_)); - notifier_ = new MockPrefNotifier(pref_service_.get(), value_store_); - pref_service_->SetPrefNotifier(notifier_); - - pref_service_->RegisterBooleanPref(kChangedPref, true); - pref_service_->RegisterBooleanPref(kUnchangedPref, true); - } - - // The PrefService takes ownership of the PrefValueStore and PrefNotifier. - PrefValueStore* value_store_; - MockPrefNotifier* notifier_; - scoped_ptr<MockPrefService> pref_service_; - - MockPrefObserver obs1_; - MockPrefObserver obs2_; -}; - -TEST_F(PrefNotifierTest, OnPreferenceSet) { - EXPECT_CALL(*notifier_, FireObservers(kChangedPref)) - .Times(PrefNotifier::PREF_STORE_TYPE_MAX + 1); - EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0); - - for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) { - notifier_->OnPreferenceSet(kChangedPref, - static_cast<PrefNotifier::PrefStoreType>(i)); - notifier_->OnPreferenceSet(kUnchangedPref, - static_cast<PrefNotifier::PrefStoreType>(i)); - } -} - -TEST_F(PrefNotifierTest, OnUserPreferenceSet) { - EXPECT_CALL(*notifier_, FireObservers(kChangedPref)); - EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0); - notifier_->OnUserPreferenceSet(kChangedPref); - notifier_->OnUserPreferenceSet(kUnchangedPref); -} - -TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) { - const char pref_name[] = "homepage"; - const char pref_name2[] = "proxy"; - - notifier_->AddPrefObserver(pref_name, &obs1_); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); - - // Re-adding the same observer for the same pref doesn't change anything. - // Skip this in debug mode, since it hits a DCHECK and death tests aren't - // thread-safe. -#if defined(NDEBUG) - notifier_->AddPrefObserver(pref_name, &obs1_); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); -#endif // NDEBUG - - // Ensure that we can add the same observer to a different pref. - notifier_->AddPrefObserver(pref_name2, &obs1_); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); - - // Ensure that we can add another observer to the same pref. - notifier_->AddPrefObserver(pref_name, &obs2_); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); - - // Ensure that we can remove all observers, and that removing a non-existent - // observer is harmless. - notifier_->RemovePrefObserver(pref_name, &obs1_); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); - - notifier_->RemovePrefObserver(pref_name, &obs2_); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); - - notifier_->RemovePrefObserver(pref_name, &obs1_); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); - - notifier_->RemovePrefObserver(pref_name2, &obs1_); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); -} - -TEST_F(PrefNotifierTest, FireObservers) { - using testing::_; - using testing::Field; - using testing::Invoke; - using testing::Mock; - using testing::Truly; - - // Tell googlemock to pass calls to the mock's "back door" too. - ON_CALL(*notifier_, FireObservers(_)) - .WillByDefault(Invoke(notifier_, &MockPrefNotifier::RealFireObservers)); - EXPECT_CALL(*notifier_, FireObservers(kChangedPref)).Times(4); - EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0); - - notifier_->AddPrefObserver(kChangedPref, &obs1_); - notifier_->AddPrefObserver(kUnchangedPref, &obs1_); - - EXPECT_CALL(obs1_, Observe( - Field(&NotificationType::value, NotificationType::PREF_CHANGED), - Source<PrefService>(pref_service_.get()), - Truly(DetailsAreChangedPref))); - EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); - notifier_->OnUserPreferenceSet(kChangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); - EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); - notifier_->OnUserPreferenceSet(kUnchangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - notifier_->AddPrefObserver(kChangedPref, &obs2_); - notifier_->AddPrefObserver(kUnchangedPref, &obs2_); - - EXPECT_CALL(obs1_, Observe( - Field(&NotificationType::value, NotificationType::PREF_CHANGED), - Source<PrefService>(pref_service_.get()), - Truly(DetailsAreChangedPref))); - EXPECT_CALL(obs2_, Observe( - Field(&NotificationType::value, NotificationType::PREF_CHANGED), - Source<PrefService>(pref_service_.get()), - Truly(DetailsAreChangedPref))); - notifier_->OnUserPreferenceSet(kChangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); - EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); - notifier_->OnUserPreferenceSet(kUnchangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - // Make sure removing an observer from one pref doesn't affect anything else. - notifier_->RemovePrefObserver(kChangedPref, &obs1_); - - EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); - EXPECT_CALL(obs2_, Observe( - Field(&NotificationType::value, NotificationType::PREF_CHANGED), - Source<PrefService>(pref_service_.get()), - Truly(DetailsAreChangedPref))); - notifier_->OnUserPreferenceSet(kChangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); - EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); - notifier_->OnUserPreferenceSet(kUnchangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - // Make sure removing an observer entirely doesn't affect anything else. - notifier_->RemovePrefObserver(kUnchangedPref, &obs1_); - - EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); - EXPECT_CALL(obs2_, Observe( - Field(&NotificationType::value, NotificationType::PREF_CHANGED), - Source<PrefService>(pref_service_.get()), - Truly(DetailsAreChangedPref))); - notifier_->OnUserPreferenceSet(kChangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); - EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); - notifier_->OnUserPreferenceSet(kUnchangedPref); - - notifier_->RemovePrefObserver(kChangedPref, &obs2_); - notifier_->RemovePrefObserver(kUnchangedPref, &obs2_); -} - -} // namespace diff --git a/chrome/browser/prefs/pref_observer_mock.h b/chrome/browser/prefs/pref_observer_mock.h new file mode 100644 index 0000000..f339841 --- /dev/null +++ b/chrome/browser/prefs/pref_observer_mock.h @@ -0,0 +1,60 @@ +// 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 CHROME_BROWSER_PREFS_PREF_OBSERVER_MOCK_H_ +#define CHROME_BROWSER_PREFS_PREF_OBSERVER_MOCK_H_ +#pragma once + +#include <string> + +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/common/notification_details.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::Pointee; +using testing::Property; +using testing::Truly; + +// Matcher that checks whether the current value of the preference named +// |pref_name| in |prefs| matches |value|. If |value| is NULL, the matcher +// checks that the value is not set. +MATCHER_P3(PrefValueMatches, prefs, pref_name, value, "") { + const PrefService::Preference* pref = + prefs->FindPreference(pref_name.c_str()); + if (!pref) + return false; + + const Value* actual_value = pref->GetValue(); + if (!actual_value) + return value == NULL; + if (!value) + return actual_value == NULL; + return value->Equals(actual_value); +} + +// A mock for testing preference notifications and easy setup of expectations. +class PrefObserverMock : public NotificationObserver { + public: + PrefObserverMock() {} + virtual ~PrefObserverMock() {} + + MOCK_METHOD3(Observe, void(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details)); + + void Expect(const PrefService* prefs, + const std::string& pref_name, + const Value* value) { + EXPECT_CALL(*this, Observe(NotificationType(NotificationType::PREF_CHANGED), + Source<PrefService>(prefs), + Property(&Details<std::string>::ptr, + Pointee(pref_name)))) + .With(PrefValueMatches(prefs, pref_name, value)); + } +}; + +#endif // CHROME_BROWSER_PREFS_PREF_OBSERVER_MOCK_H_ diff --git a/chrome/browser/prefs/pref_service.cc b/chrome/browser/prefs/pref_service.cc index 8662f88..86149c5 100644 --- a/chrome/browser/prefs/pref_service.cc +++ b/chrome/browser/prefs/pref_service.cc @@ -23,10 +23,19 @@ #include "base/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/browser_thread.h" +<<<<<<< HEAD #include "chrome/browser/profile.h" #ifndef ANDROID // Notifications do not compile on Android and are the cause // of most of the ANDROID guards in this file. +======= +#include "chrome/browser/policy/configuration_policy_pref_store.h" +#include "chrome/browser/prefs/command_line_pref_store.h" +#include "chrome/browser/prefs/default_pref_store.h" +#include "chrome/browser/prefs/pref_notifier_impl.h" +#include "chrome/browser/prefs/pref_value_store.h" +#include "chrome/common/json_pref_store.h" +>>>>>>> chromium.org at r10.0.621.0 #include "chrome/common/notification_service.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -90,8 +99,15 @@ void NotifyReadError(PrefService* pref, int message_id) { // static PrefService* PrefService::CreatePrefService(const FilePath& pref_filename, + PrefStore* extension_prefs, Profile* profile) { +<<<<<<< HEAD #if defined(OS_LINUX) && !defined(ANDROID) +======= + using policy::ConfigurationPolicyPrefStore; + +#if defined(OS_LINUX) +>>>>>>> chromium.org at r10.0.621.0 // We'd like to see what fraction of our users have the preferences // stored on a network file system, as we've had no end of troubles // with NFS/AFS. @@ -104,6 +120,7 @@ PrefService* PrefService::CreatePrefService(const FilePath& pref_filename, } #endif +<<<<<<< HEAD return new PrefService( PrefValueStore::CreatePrefValueStore(pref_filename, profile, false)); } @@ -119,6 +136,43 @@ PrefService::PrefService(PrefValueStore* pref_value_store) #ifndef ANDROID pref_notifier_.reset(new PrefNotifier(this, pref_value_store)); #endif +======= + ConfigurationPolicyPrefStore* managed = + ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore(); + ConfigurationPolicyPrefStore* device_management = + ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore( + profile); + CommandLinePrefStore* command_line = + new CommandLinePrefStore(CommandLine::ForCurrentProcess()); + JsonPrefStore* user = new JsonPrefStore( + pref_filename, + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); + ConfigurationPolicyPrefStore* recommended = + ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore(); + + return new PrefService(managed, device_management, extension_prefs, + command_line, user, recommended); +} + +PrefService::PrefService(PrefStore* managed_platform_prefs, + PrefStore* device_management_prefs, + PrefStore* extension_prefs, + PrefStore* command_line_prefs, + PersistentPrefStore* user_prefs, + PrefStore* recommended_prefs) + : user_pref_store_(user_prefs) { + pref_notifier_.reset(new PrefNotifierImpl(this)); + default_store_ = new DefaultPrefStore(); + pref_value_store_ = + new PrefValueStore(managed_platform_prefs, + device_management_prefs, + extension_prefs, + command_line_prefs, + user_pref_store_, + recommended_prefs, + default_store_, + pref_notifier_.get()); +>>>>>>> chromium.org at r10.0.621.0 InitFromStorage(); } @@ -129,18 +183,24 @@ PrefService::~PrefService() { } void PrefService::InitFromStorage() { +<<<<<<< HEAD #ifndef ANDROID PrefStore::PrefReadError error = LoadPersistentPrefs(); if (error == PrefStore::PREF_READ_ERROR_NONE) +======= + const PersistentPrefStore::PrefReadError error = + user_pref_store_->ReadPrefs(); + if (error == PersistentPrefStore::PREF_READ_ERROR_NONE) +>>>>>>> chromium.org at r10.0.621.0 return; // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for // an example problem that this can cause. // Do some diagnosis and try to avoid losing data. int message_id = 0; - if (error <= PrefStore::PREF_READ_ERROR_JSON_TYPE) { + if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) { message_id = IDS_PREFERENCES_CORRUPT_ERROR; - } else if (error != PrefStore::PREF_READ_ERROR_NO_FILE) { + } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) { message_id = IDS_PREFERENCES_UNREADABLE_ERROR; } @@ -153,32 +213,20 @@ void PrefService::InitFromStorage() { } bool PrefService::ReloadPersistentPrefs() { - return (LoadPersistentPrefs() == PrefStore::PREF_READ_ERROR_NONE); -} - -PrefStore::PrefReadError PrefService::LoadPersistentPrefs() { - DCHECK(CalledOnValidThread()); - - PrefStore::PrefReadError pref_error = pref_value_store_->ReadPrefs(); - - for (PreferenceSet::iterator it = prefs_.begin(); - it != prefs_.end(); ++it) { - (*it)->pref_service_ = this; - } - - return pref_error; + return user_pref_store_->ReadPrefs() == + PersistentPrefStore::PREF_READ_ERROR_NONE; } bool PrefService::SavePersistentPrefs() { DCHECK(CalledOnValidThread()); - return pref_value_store_->WritePrefs(); + return user_pref_store_->WritePrefs(); } void PrefService::ScheduleSavePersistentPrefs() { DCHECK(CalledOnValidThread()); - pref_value_store_->ScheduleWritePrefs(); + user_pref_store_->ScheduleWritePrefs(); } void PrefService::RegisterBooleanPref(const char* path, @@ -331,6 +379,14 @@ const PrefService::Preference* PrefService::FindPreference( return it == prefs_.end() ? NULL : *it; } +bool PrefService::ReadOnly() const { + return user_pref_store_->ReadOnly(); +} + +PrefNotifier* PrefService::pref_notifier() const { + return pref_notifier_.get(); +} + bool PrefService::IsManagedPreference(const char* pref_name) const { const Preference* pref = FindPreference(pref_name); if (pref && pref->IsManaged()) { @@ -398,11 +454,10 @@ void PrefService::RegisterPreference(const char* path, Value* default_value) { // easier for callers to check for empty dict/list prefs. The PrefValueStore // accepts ownership of the value (null or default_value). if (Value::TYPE_LIST == orig_type || Value::TYPE_DICTIONARY == orig_type) { - pref_value_store_->SetDefaultPrefValue(path, Value::CreateNullValue()); + default_store_->SetDefaultValue(path, Value::CreateNullValue()); } else { // Hand off ownership. - DCHECK(!PrefStore::IsUseDefaultSentinelValue(default_value)); - pref_value_store_->SetDefaultPrefValue(path, scoped_value.release()); + default_store_->SetDefaultValue(path, scoped_value.release()); } pref_value_store_->RegisterPreferenceType(path, orig_type); @@ -417,10 +472,14 @@ void PrefService::ClearPref(const char* path) { NOTREACHED() << "Trying to clear an unregistered pref: " << path; return; } +<<<<<<< HEAD #ifndef ANDROID if (pref_value_store_->RemoveUserPrefValue(path)) pref_notifier_->OnUserPreferenceSet(path); #endif +======= + user_pref_store_->RemoveValue(path); +>>>>>>> chromium.org at r10.0.621.0 } void PrefService::Set(const char* path, const Value& value) { @@ -434,22 +493,24 @@ void PrefService::Set(const char* path, const Value& value) { // Allow dictionary and list types to be set to null, which removes their // user values. - bool value_changed = false; if (value.GetType() == Value::TYPE_NULL && (pref->GetType() == Value::TYPE_DICTIONARY || pref->GetType() == Value::TYPE_LIST)) { - value_changed = pref_value_store_->RemoveUserPrefValue(path); + user_pref_store_->RemoveValue(path); } else if (pref->GetType() != value.GetType()) { NOTREACHED() << "Trying to set pref " << path << " of type " << pref->GetType() << " to value of type " << value.GetType(); } else { - value_changed = pref_value_store_->SetUserPrefValue(path, value.DeepCopy()); + user_pref_store_->SetValue(path, value.DeepCopy()); } +<<<<<<< HEAD #ifndef ANDROID if (value_changed) pref_notifier_->OnUserPreferenceSet(path); #endif +======= +>>>>>>> chromium.org at r10.0.621.0 } void PrefService::SetBoolean(const char* path, bool value) { @@ -524,10 +585,11 @@ DictionaryValue* PrefService::GetMutableDictionary(const char* path) { Value* tmp_value = NULL; // Look for an existing preference in the user store. If it doesn't // exist or isn't the correct type, create a new user preference. - if (!pref_value_store_->GetUserValue(path, &tmp_value) || + if (user_pref_store_->GetValue(path, &tmp_value) + != PersistentPrefStore::READ_OK || !tmp_value->IsType(Value::TYPE_DICTIONARY)) { dict = new DictionaryValue; - pref_value_store_->SetUserPrefValue(path, dict); + user_pref_store_->SetValueSilently(path, dict); } else { dict = static_cast<DictionaryValue*>(tmp_value); } @@ -551,24 +613,17 @@ ListValue* PrefService::GetMutableList(const char* path) { Value* tmp_value = NULL; // Look for an existing preference in the user store. If it doesn't // exist or isn't the correct type, create a new user preference. - if (!pref_value_store_->GetUserValue(path, &tmp_value) || + if (user_pref_store_->GetValue(path, &tmp_value) + != PersistentPrefStore::READ_OK || !tmp_value->IsType(Value::TYPE_LIST)) { list = new ListValue; - pref_value_store_->SetUserPrefValue(path, list); + user_pref_store_->SetValueSilently(path, list); } else { list = static_cast<ListValue*>(tmp_value); } return list; } -Value* PrefService::GetPrefCopy(const char* path) { - DCHECK(CalledOnValidThread()); - - const Preference* pref = FindPreference(path); - DCHECK(pref); - return pref->GetValue()->DeepCopy(); -} - void PrefService::SetUserPrefValue(const char* path, Value* new_value) { DCHECK(CalledOnValidThread()); @@ -577,10 +632,6 @@ void PrefService::SetUserPrefValue(const char* path, Value* new_value) { NOTREACHED() << "Trying to write an unregistered pref: " << path; return; } - if (pref->IsManaged()) { - NOTREACHED() << "Preference is managed: " << path; - return; - } if (pref->GetType() != new_value->GetType()) { NOTREACHED() << "Trying to set pref " << path << " of type " << pref->GetType() @@ -588,10 +639,14 @@ void PrefService::SetUserPrefValue(const char* path, Value* new_value) { return; } +<<<<<<< HEAD #ifndef ANDROID if (pref_value_store_->SetUserPrefValue(path, new_value)) pref_notifier_->OnUserPreferenceSet(path); #endif +======= + user_pref_store_->SetValue(path, new_value); +>>>>>>> chromium.org at r10.0.621.0 } /////////////////////////////////////////////////////////////////////////////// @@ -623,8 +678,7 @@ const Value* PrefService::Preference::GetValue() const { } bool PrefService::Preference::IsManaged() const { - PrefValueStore* pref_value_store = - pref_service_->pref_value_store_; + PrefValueStore* pref_value_store = pref_service_->pref_value_store_; return pref_value_store->PrefValueInManagedPlatformStore(name_.c_str()) || pref_value_store->PrefValueInDeviceManagementStore(name_.c_str()); } diff --git a/chrome/browser/prefs/pref_service.h b/chrome/browser/prefs/pref_service.h index 44ae00b..40500b5 100644 --- a/chrome/browser/prefs/pref_service.h +++ b/chrome/browser/prefs/pref_service.h @@ -12,19 +12,23 @@ #include <string> #include "base/non_thread_safe.h" +#include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/values.h" -#include "chrome/browser/prefs/pref_value_store.h" -#include "chrome/common/pref_store.h" +class DefaultPrefStore; class FilePath; class NotificationObserver; +class PersistentPrefStore; class PrefChangeObserver; class PrefNotifier; +class PrefNotifierImpl; +class PrefStore; +class PrefValueStore; class Profile; namespace subtle { - class PrefMemberBase; +class PrefMemberBase; }; class PrefService : public NonThreadSafe { @@ -94,24 +98,17 @@ class PrefService : public NonThreadSafe { DISALLOW_COPY_AND_ASSIGN(Preference); }; - // Factory method that creates a new instance of a PrefService with - // a PrefValueStore containing all platform-applicable PrefStores. - // The |pref_filename| points to the user preference file. The |profile| is - // the one to which these preferences apply; it may be NULL if we're dealing - // with the local state. This is the usual way to create a new PrefService. + // Factory method that creates a new instance of a PrefService with the + // applicable PrefStores. The |pref_filename| points to the user preference + // file. The |profile| is the one to which these preferences apply; it may be + // NULL if we're dealing with the local state. This is the usual way to create + // a new PrefService. |extension_pref_store| is used as the source for + // extension-controlled preferences and may be NULL. The PrefService takes + // ownership of |extension_pref_store|. static PrefService* CreatePrefService(const FilePath& pref_filename, + PrefStore* extension_pref_store, Profile* profile); - // Convenience factory method for use in unit tests. Creates a new - // PrefService that uses a PrefValueStore with user preferences at the given - // |pref_filename|, a default PrefStore, and no other PrefStores (i.e., no - // other types of preferences). - static PrefService* CreateUserPrefService(const FilePath& pref_filename); - - // This constructor is primarily used by tests. The |pref_value_store| - // provides preference values. - explicit PrefService(PrefValueStore* pref_value_store); - virtual ~PrefService(); // Reloads the data from file. This should only be called when the importer @@ -142,7 +139,7 @@ class PrefService : public NonThreadSafe { void RegisterListPref(const char* path); void RegisterDictionaryPref(const char* path); - // These varients use a default value from the locale dll instead. + // These variants use a default value from the locale dll instead. void RegisterLocalizedBooleanPref(const char* path, int locale_default_message_id); void RegisterLocalizedIntegerPref(const char* path, @@ -218,23 +215,45 @@ class PrefService : public NonThreadSafe { // preference is not registered. const Preference* FindPreference(const char* pref_name) const; +<<<<<<< HEAD bool read_only() const { return pref_value_store_->ReadOnly(); } #ifndef ANDROID PrefNotifier* pref_notifier() const { return pref_notifier_.get(); } #endif +======= + bool ReadOnly() const; +>>>>>>> chromium.org at r10.0.621.0 - PrefValueStore* pref_value_store() const { return pref_value_store_.get(); } + // TODO(mnissler): This should not be public. Change client code to call a + // preference setter or use ScopedPrefUpdate. + PrefNotifier* pref_notifier() const; #ifndef ANDROID protected: + // Construct a new pref service, specifying the pref sources as explicit + // PrefStore pointers. This constructor is what CreatePrefService() ends up + // calling. It's also used for unit tests. + PrefService(PrefStore* managed_platform_prefs, + PrefStore* device_management_prefs, + PrefStore* extension_prefs, + PrefStore* command_line_prefs, + PersistentPrefStore* user_prefs, + PrefStore* recommended_prefs); + // The PrefNotifier handles registering and notifying preference observers. // It is created and owned by this PrefService. Subclasses may access it for // unit testing. +<<<<<<< HEAD scoped_ptr<PrefNotifier> pref_notifier_; #endif +======= + scoped_ptr<PrefNotifierImpl> pref_notifier_; +>>>>>>> chromium.org at r10.0.621.0 private: + friend class PrefServiceMockBuilder; + // 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. @@ -257,17 +276,10 @@ class PrefService : public NonThreadSafe { // false. This method takes ownership of |default_value|. void RegisterPreference(const char* path, Value* default_value); - // Returns a copy of the current pref value. The caller is responsible for - // deleting the returned object. - Value* GetPrefCopy(const char* pref_name); - // Sets the value for this pref path in the user pref store and informs the // PrefNotifier of the change. void SetUserPrefValue(const char* path, Value* new_value); - // Load from disk. Returns a non-zero error code on failure. - PrefStore::PrefReadError LoadPersistentPrefs(); - // Load preferences from storage, attempting to diagnose and handle errors. // This should only be called from the constructor. void InitFromStorage(); @@ -276,6 +288,12 @@ class PrefService : public NonThreadSafe { // and owned by this PrefService. Subclasses may access it for unit testing. scoped_refptr<PrefValueStore> pref_value_store_; + // The persistent pref store used for actual user data. + PersistentPrefStore* user_pref_store_; + + // Points to the default pref store we passed to the PrefValueStore. + DefaultPrefStore* default_store_; + // A set of all the registered Preference objects. PreferenceSet prefs_; diff --git a/chrome/browser/prefs/pref_service_mock_builder.cc b/chrome/browser/prefs/pref_service_mock_builder.cc new file mode 100644 index 0000000..005b700 --- /dev/null +++ b/chrome/browser/prefs/pref_service_mock_builder.cc @@ -0,0 +1,103 @@ +// 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 "chrome/browser/prefs/pref_service_mock_builder.h" + +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/configuration_policy_pref_store.h" +#include "chrome/browser/prefs/command_line_pref_store.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/prefs/testing_pref_store.h" +#include "chrome/common/json_pref_store.h" + +PrefServiceMockBuilder::PrefServiceMockBuilder() + : user_prefs_(new TestingPrefStore) { +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithManagedPlatformPrefs(PrefStore* store) { + managed_platform_prefs_.reset(store); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithDeviceManagementPrefs(PrefStore* store) { + device_management_prefs_.reset(store); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithExtensionPrefs(PrefStore* store) { + extension_prefs_.reset(store); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithCommandLinePrefs(PrefStore* store) { + command_line_prefs_.reset(store); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithUserPrefs(PersistentPrefStore* store) { + user_prefs_.reset(store); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithRecommendedPrefs(PrefStore* store) { + recommended_prefs_.reset(store); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithManagedPlatformProvider( + policy::ConfigurationPolicyProvider* provider) { + managed_platform_prefs_.reset( + new policy::ConfigurationPolicyPrefStore(provider)); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithDeviceManagementProvider( + policy::ConfigurationPolicyProvider* provider) { + device_management_prefs_.reset( + new policy::ConfigurationPolicyPrefStore(provider)); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithRecommendedProvider( + policy::ConfigurationPolicyProvider* provider) { + recommended_prefs_.reset( + new policy::ConfigurationPolicyPrefStore(provider)); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithCommandLine(CommandLine* command_line) { + command_line_prefs_.reset(new CommandLinePrefStore(command_line)); + return *this; +} + +PrefServiceMockBuilder& +PrefServiceMockBuilder::WithUserFilePrefs(const FilePath& prefs_file) { + user_prefs_.reset( + new JsonPrefStore(prefs_file, + BrowserThread::GetMessageLoopProxyForThread( + BrowserThread::FILE))); + return *this; +} + +PrefService* PrefServiceMockBuilder::Create() { + PrefService* pref_service = + new PrefService(managed_platform_prefs_.release(), + device_management_prefs_.release(), + extension_prefs_.release(), + command_line_prefs_.release(), + user_prefs_.release(), + recommended_prefs_.release()); + user_prefs_.reset(new TestingPrefStore); + return pref_service; +} diff --git a/chrome/browser/prefs/pref_service_mock_builder.h b/chrome/browser/prefs/pref_service_mock_builder.h new file mode 100644 index 0000000..b8e3275 --- /dev/null +++ b/chrome/browser/prefs/pref_service_mock_builder.h @@ -0,0 +1,68 @@ +// 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 CHROME_BROWSER_PREFS_PREF_SERVICE_MOCK_BUILDER_H_ +#define CHROME_BROWSER_PREFS_PREF_SERVICE_MOCK_BUILDER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "chrome/common/persistent_pref_store.h" +#include "chrome/common/pref_store.h" + +class CommandLine; +class FilePath; +class PrefService; +class Profile; + +namespace policy { +class ConfigurationPolicyProvider; +} + +// A helper that allows convenient building of custom PrefServices in tests. +class PrefServiceMockBuilder { + public: + PrefServiceMockBuilder(); + + // Functions for setting the various parameters of the PrefService to build. + // These take ownership of the |store| parameter. + PrefServiceMockBuilder& WithManagedPlatformPrefs(PrefStore* store); + PrefServiceMockBuilder& WithDeviceManagementPrefs(PrefStore* store); + PrefServiceMockBuilder& WithExtensionPrefs(PrefStore* store); + PrefServiceMockBuilder& WithCommandLinePrefs(PrefStore* store); + PrefServiceMockBuilder& WithUserPrefs(PersistentPrefStore* store); + PrefServiceMockBuilder& WithRecommendedPrefs(PrefStore* store); + + // Set up policy pref stores using the given policy provider. + PrefServiceMockBuilder& WithManagedPlatformProvider( + policy::ConfigurationPolicyProvider* provider); + PrefServiceMockBuilder& WithDeviceManagementProvider( + policy::ConfigurationPolicyProvider* provider); + PrefServiceMockBuilder& WithRecommendedProvider( + policy::ConfigurationPolicyProvider* provider); + + // Specifies to use an actual command-line backed command-line pref store. + PrefServiceMockBuilder& WithCommandLine(CommandLine* command_line); + + // Specifies to use an actual file-backed user pref store. + PrefServiceMockBuilder& WithUserFilePrefs(const FilePath& prefs_file); + + // Sets the profile to pass to the PrefService. + PrefServiceMockBuilder& WithRecommendedPrefs(Profile* profile); + + // Creates the PrefService, invalidating the entire builder configuration. + PrefService* Create(); + + private: + scoped_ptr<PrefStore> managed_platform_prefs_; + scoped_ptr<PrefStore> device_management_prefs_; + scoped_ptr<PrefStore> extension_prefs_; + scoped_ptr<PrefStore> command_line_prefs_; + scoped_ptr<PersistentPrefStore> user_prefs_; + scoped_ptr<PrefStore> recommended_prefs_; + + DISALLOW_COPY_AND_ASSIGN(PrefServiceMockBuilder); +}; + +#endif // CHROME_BROWSER_PREFS_PREF_SERVICE_MOCK_BUILDER_H_ diff --git a/chrome/browser/prefs/pref_service_unittest.cc b/chrome/browser/prefs/pref_service_unittest.cc index e7c737c..1a79708 100644 --- a/chrome/browser/prefs/pref_service_unittest.cc +++ b/chrome/browser/prefs/pref_service_unittest.cc @@ -12,15 +12,14 @@ #include "chrome/browser/policy/mock_configuration_policy_provider.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/prefs/command_line_pref_store.h" -#include "chrome/browser/prefs/default_pref_store.h" -#include "chrome/browser/prefs/dummy_pref_store.h" #include "chrome/browser/prefs/pref_change_registrar.h" +#include "chrome/browser/prefs/pref_observer_mock.h" +#include "chrome/browser/prefs/pref_service_mock_builder.h" #include "chrome/browser/prefs/pref_value_store.h" +#include "chrome/browser/prefs/proxy_prefs.h" +#include "chrome/browser/prefs/testing_pref_store.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/notification_observer_mock.h" -#include "chrome/common/notification_service.h" -#include "chrome/common/notification_type.h" #include "chrome/common/pref_names.h" #include "chrome/test/testing_pref_service.h" #include "testing/gmock/include/gmock/gmock.h" @@ -28,49 +27,6 @@ using testing::_; using testing::Mock; -using testing::Pointee; -using testing::Property; - -namespace { - -class TestPrefObserver : public NotificationObserver { - public: - TestPrefObserver(const PrefService* prefs, - const std::string& pref_name, - const std::string& new_pref_value) - : observer_fired_(false), - prefs_(prefs), - pref_name_(pref_name), - new_pref_value_(new_pref_value) {} - virtual ~TestPrefObserver() {} - - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - EXPECT_EQ(type.value, NotificationType::PREF_CHANGED); - const PrefService* prefs_in = Source<PrefService>(source).ptr(); - EXPECT_EQ(prefs_in, prefs_); - const std::string* pref_name_in = Details<std::string>(details).ptr(); - EXPECT_EQ(*pref_name_in, pref_name_); - EXPECT_EQ(new_pref_value_, prefs_in->GetString("homepage")); - observer_fired_ = true; - } - - bool observer_fired() { return observer_fired_; } - - void Reset(const std::string& new_pref_value) { - observer_fired_ = false; - new_pref_value_ = new_pref_value; - } - - private: - bool observer_fired_; - const PrefService* prefs_; - const std::string pref_name_; - std::string new_pref_value_; -}; - -} // namespace // TODO(port): port this test to POSIX. #if defined(OS_WIN) @@ -103,33 +59,34 @@ TEST(PrefServiceTest, NoObserverFire) { const char pref_name[] = "homepage"; prefs.RegisterStringPref(pref_name, std::string()); - const std::string new_pref_value("http://www.google.com/"); - TestPrefObserver obs(&prefs, pref_name, new_pref_value); - + const char new_pref_value[] = "http://www.google.com/"; + PrefObserverMock obs; PrefChangeRegistrar registrar; registrar.Init(&prefs); registrar.Add(pref_name, &obs); - // This should fire the checks in TestPrefObserver::Observe. - prefs.SetString(pref_name, new_pref_value); - // Make sure the observer was actually fired. - EXPECT_TRUE(obs.observer_fired()); + // This should fire the checks in PrefObserverMock::Observe. + const StringValue expected_value(new_pref_value); + obs.Expect(&prefs, pref_name, &expected_value); + prefs.SetString(pref_name, new_pref_value); + Mock::VerifyAndClearExpectations(&obs); // Setting the pref to the same value should not set the pref value a second // time. - obs.Reset(new_pref_value); + EXPECT_CALL(obs, Observe(_, _, _)).Times(0); prefs.SetString(pref_name, new_pref_value); - EXPECT_FALSE(obs.observer_fired()); + Mock::VerifyAndClearExpectations(&obs); // Clearing the pref should cause the pref to fire. - obs.Reset(std::string()); + const StringValue expected_default_value(""); + obs.Expect(&prefs, pref_name, &expected_default_value); prefs.ClearPref(pref_name); - EXPECT_TRUE(obs.observer_fired()); + Mock::VerifyAndClearExpectations(&obs); // Clearing the pref again should not cause the pref to fire. - obs.Reset(std::string()); + EXPECT_CALL(obs, Observe(_, _, _)).Times(0); prefs.ClearPref(pref_name); - EXPECT_FALSE(obs.observer_fired()); + Mock::VerifyAndClearExpectations(&obs); } TEST(PrefServiceTest, HasPrefPath) { @@ -157,120 +114,114 @@ TEST(PrefServiceTest, Observers) { prefs.SetUserPref(pref_name, Value::CreateStringValue("http://www.cnn.com")); prefs.RegisterStringPref(pref_name, std::string()); - const std::string new_pref_value("http://www.google.com/"); - TestPrefObserver obs(&prefs, pref_name, new_pref_value); + const char new_pref_value[] = "http://www.google.com/"; + const StringValue expected_new_pref_value(new_pref_value); + PrefObserverMock obs; PrefChangeRegistrar registrar; registrar.Init(&prefs); registrar.Add(pref_name, &obs); - // This should fire the checks in TestPrefObserver::Observe. - prefs.SetString(pref_name, new_pref_value); - // Make sure the tests were actually run. - EXPECT_TRUE(obs.observer_fired()); + // This should fire the checks in PrefObserverMock::Observe. + obs.Expect(&prefs, pref_name, &expected_new_pref_value); + prefs.SetString(pref_name, new_pref_value); + Mock::VerifyAndClearExpectations(&obs); // Now try adding a second pref observer. - const std::string new_pref_value2("http://www.youtube.com/"); - obs.Reset(new_pref_value2); - TestPrefObserver obs2(&prefs, pref_name, new_pref_value2); + const char new_pref_value2[] = "http://www.youtube.com/"; + const StringValue expected_new_pref_value2(new_pref_value2); + PrefObserverMock obs2; + obs.Expect(&prefs, pref_name, &expected_new_pref_value2); + obs2.Expect(&prefs, pref_name, &expected_new_pref_value2); registrar.Add(pref_name, &obs2); // This should fire the checks in obs and obs2. prefs.SetString(pref_name, new_pref_value2); - EXPECT_TRUE(obs.observer_fired()); - EXPECT_TRUE(obs2.observer_fired()); + Mock::VerifyAndClearExpectations(&obs); + Mock::VerifyAndClearExpectations(&obs2); // Make sure obs2 still works after removing obs. registrar.Remove(pref_name, &obs); - obs.Reset(std::string()); - obs2.Reset(new_pref_value); + EXPECT_CALL(obs, Observe(_, _, _)).Times(0); + obs2.Expect(&prefs, pref_name, &expected_new_pref_value); // This should only fire the observer in obs2. prefs.SetString(pref_name, new_pref_value); - EXPECT_FALSE(obs.observer_fired()); - EXPECT_TRUE(obs2.observer_fired()); -} - -TEST(PrefServiceTest, ProxyFromCommandLineNotPolicy) { - CommandLine command_line(CommandLine::NO_PROGRAM); - command_line.AppendSwitch(switches::kProxyAutoDetect); - TestingPrefService prefs(NULL, NULL, &command_line); - browser::RegisterUserPrefs(&prefs); - EXPECT_TRUE(prefs.GetBoolean(prefs::kProxyAutoDetect)); - const PrefService::Preference* pref = - prefs.FindPreference(prefs::kProxyAutoDetect); - ASSERT_TRUE(pref); - EXPECT_FALSE(pref->IsManaged()); + Mock::VerifyAndClearExpectations(&obs); + Mock::VerifyAndClearExpectations(&obs2); } TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineOptions) { CommandLine command_line(CommandLine::NO_PROGRAM); command_line.AppendSwitchASCII(switches::kProxyBypassList, "123"); - command_line.AppendSwitchASCII(switches::kProxyPacUrl, "456"); command_line.AppendSwitchASCII(switches::kProxyServer, "789"); scoped_ptr<policy::MockConfigurationPolicyProvider> provider( new policy::MockConfigurationPolicyProvider()); Value* mode_value = Value::CreateIntegerValue( policy::kPolicyManuallyConfiguredProxyMode); - provider->AddPolicy(policy::kPolicyProxyServerMode, mode_value); + provider->AddPolicy(policy::kPolicyProxyMode, mode_value); provider->AddPolicy(policy::kPolicyProxyBypassList, Value::CreateStringValue("abc")); - provider->AddPolicy(policy::kPolicyProxyPacUrl, - Value::CreateStringValue("def")); provider->AddPolicy(policy::kPolicyProxyServer, Value::CreateStringValue("ghi")); // First verify that command-line options are set correctly when // there is no policy in effect. - TestingPrefService prefs(NULL, NULL, &command_line); - browser::RegisterUserPrefs(&prefs); - EXPECT_FALSE(prefs.GetBoolean(prefs::kProxyAutoDetect)); - EXPECT_FALSE(prefs.GetBoolean(prefs::kNoProxyServer)); - EXPECT_EQ("789", prefs.GetString(prefs::kProxyServer)); - EXPECT_EQ("456", prefs.GetString(prefs::kProxyPacUrl)); - EXPECT_EQ("123", prefs.GetString(prefs::kProxyBypassList)); + PrefServiceMockBuilder builder; + builder.WithCommandLine(&command_line); + scoped_ptr<PrefService> prefs(builder.Create()); + browser::RegisterUserPrefs(prefs.get()); + EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, + prefs->GetInteger(prefs::kProxyMode)); + EXPECT_EQ("789", prefs->GetString(prefs::kProxyServer)); + EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyPacUrl)); + EXPECT_EQ("123", prefs->GetString(prefs::kProxyBypassList)); // Try a second time time with the managed PrefStore in place, the // manual proxy policy should have removed all traces of the command // line and replaced them with the policy versions. - TestingPrefService prefs2(provider.get(), NULL, &command_line); - browser::RegisterUserPrefs(&prefs2); - EXPECT_FALSE(prefs2.GetBoolean(prefs::kProxyAutoDetect)); - EXPECT_FALSE(prefs2.GetBoolean(prefs::kNoProxyServer)); - EXPECT_EQ("ghi", prefs2.GetString(prefs::kProxyServer)); - EXPECT_EQ("def", prefs2.GetString(prefs::kProxyPacUrl)); - EXPECT_EQ("abc", prefs2.GetString(prefs::kProxyBypassList)); + builder.WithCommandLine(&command_line); + builder.WithManagedPlatformProvider(provider.get()); + scoped_ptr<PrefService> prefs2(builder.Create()); + browser::RegisterUserPrefs(prefs2.get()); + EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, + prefs2->GetInteger(prefs::kProxyMode)); + EXPECT_EQ("ghi", prefs2->GetString(prefs::kProxyServer)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyPacUrl)); + EXPECT_EQ("abc", prefs2->GetString(prefs::kProxyBypassList)); } TEST(PrefServiceTest, ProxyPolicyOverridesUnrelatedCommandLineOptions) { CommandLine command_line(CommandLine::NO_PROGRAM); command_line.AppendSwitchASCII(switches::kProxyBypassList, "123"); - command_line.AppendSwitchASCII(switches::kProxyPacUrl, "456"); command_line.AppendSwitchASCII(switches::kProxyServer, "789"); scoped_ptr<policy::MockConfigurationPolicyProvider> provider( new policy::MockConfigurationPolicyProvider()); Value* mode_value = Value::CreateIntegerValue( - policy::kPolicyUseSystemProxyMode); - provider->AddPolicy(policy::kPolicyProxyServerMode, mode_value); + policy::kPolicyAutoDetectProxyMode); + provider->AddPolicy(policy::kPolicyProxyMode, mode_value); // First verify that command-line options are set correctly when // there is no policy in effect. - TestingPrefService prefs(NULL, NULL, &command_line); - browser::RegisterUserPrefs(&prefs); - EXPECT_FALSE(prefs.GetBoolean(prefs::kProxyAutoDetect)); - EXPECT_FALSE(prefs.GetBoolean(prefs::kNoProxyServer)); - EXPECT_EQ("789", prefs.GetString(prefs::kProxyServer)); - EXPECT_EQ("456", prefs.GetString(prefs::kProxyPacUrl)); - EXPECT_EQ("123", prefs.GetString(prefs::kProxyBypassList)); + PrefServiceMockBuilder builder; + builder.WithCommandLine(&command_line); + scoped_ptr<PrefService> prefs(builder.Create()); + browser::RegisterUserPrefs(prefs.get()); + EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, + prefs->GetInteger(prefs::kProxyMode)); + EXPECT_EQ("789", prefs->GetString(prefs::kProxyServer)); + EXPECT_EQ("123", prefs->GetString(prefs::kProxyBypassList)); // Try a second time time with the managed PrefStore in place, the // no proxy policy should have removed all traces of the command // line proxy settings, even though they were not the specific one // set in policy. - TestingPrefService prefs2(provider.get(), NULL, &command_line); - browser::RegisterUserPrefs(&prefs2); - EXPECT_FALSE(prefs2.GetBoolean(prefs::kProxyAutoDetect)); - EXPECT_FALSE(prefs2.GetBoolean(prefs::kNoProxyServer)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyServer)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyPacUrl)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyBypassList)); + builder.WithCommandLine(&command_line); + builder.WithManagedPlatformProvider(provider.get()); + scoped_ptr<PrefService> prefs2(builder.Create()); + browser::RegisterUserPrefs(prefs2.get()); + EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, + prefs2->GetInteger(prefs::kProxyMode)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyServer)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyPacUrl)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyBypassList)); } TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineNoProxy) { @@ -280,28 +231,31 @@ TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineNoProxy) { new policy::MockConfigurationPolicyProvider()); Value* mode_value = Value::CreateIntegerValue( policy::kPolicyAutoDetectProxyMode); - provider->AddPolicy(policy::kPolicyProxyServerMode, mode_value); + provider->AddPolicy(policy::kPolicyProxyMode, mode_value); // First verify that command-line options are set correctly when // there is no policy in effect. - TestingPrefService prefs(NULL, NULL, &command_line); - browser::RegisterUserPrefs(&prefs); - EXPECT_FALSE(prefs.GetBoolean(prefs::kProxyAutoDetect)); - EXPECT_TRUE(prefs.GetBoolean(prefs::kNoProxyServer)); - EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyServer)); - EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyPacUrl)); - EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyBypassList)); + PrefServiceMockBuilder builder; + builder.WithCommandLine(&command_line); + scoped_ptr<PrefService> prefs(builder.Create()); + browser::RegisterUserPrefs(prefs.get()); + EXPECT_EQ(ProxyPrefs::MODE_DIRECT, prefs->GetInteger(prefs::kProxyMode)); + EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyServer)); + EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyPacUrl)); + EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyBypassList)); // Try a second time time with the managed PrefStore in place, the // auto-detect should be overridden. The default pref store must be // in place with the appropriate default value for this to work. - TestingPrefService prefs2(provider.get(), NULL, &command_line); - browser::RegisterUserPrefs(&prefs2); - EXPECT_TRUE(prefs2.GetBoolean(prefs::kProxyAutoDetect)); - EXPECT_FALSE(prefs2.GetBoolean(prefs::kNoProxyServer)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyServer)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyPacUrl)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyBypassList)); + builder.WithCommandLine(&command_line); + builder.WithManagedPlatformProvider(provider.get()); + scoped_ptr<PrefService> prefs2(builder.Create()); + browser::RegisterUserPrefs(prefs2.get()); + EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, + prefs2->GetInteger(prefs::kProxyMode)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyServer)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyPacUrl)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyBypassList)); } TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineAutoDetect) { @@ -311,28 +265,30 @@ TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineAutoDetect) { new policy::MockConfigurationPolicyProvider()); Value* mode_value = Value::CreateIntegerValue( policy::kPolicyNoProxyServerMode); - provider->AddPolicy(policy::kPolicyProxyServerMode, mode_value); + provider->AddPolicy(policy::kPolicyProxyMode, mode_value); // First verify that the auto-detect is set if there is no managed // PrefStore. - TestingPrefService prefs(NULL, NULL, &command_line); - browser::RegisterUserPrefs(&prefs); - EXPECT_TRUE(prefs.GetBoolean(prefs::kProxyAutoDetect)); - EXPECT_FALSE(prefs.GetBoolean(prefs::kNoProxyServer)); - EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyServer)); - EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyPacUrl)); - EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyBypassList)); + PrefServiceMockBuilder builder; + builder.WithCommandLine(&command_line); + scoped_ptr<PrefService> prefs(builder.Create()); + browser::RegisterUserPrefs(prefs.get()); + EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, prefs->GetInteger(prefs::kProxyMode)); + EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyServer)); + EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyPacUrl)); + EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyBypassList)); // Try a second time time with the managed PrefStore in place, the // auto-detect should be overridden. The default pref store must be // in place with the appropriate default value for this to work. - TestingPrefService prefs2(provider.get(), NULL, &command_line); - browser::RegisterUserPrefs(&prefs2); - EXPECT_FALSE(prefs2.GetBoolean(prefs::kProxyAutoDetect)); - EXPECT_TRUE(prefs2.GetBoolean(prefs::kNoProxyServer)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyServer)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyPacUrl)); - EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyBypassList)); + builder.WithCommandLine(&command_line); + builder.WithManagedPlatformProvider(provider.get()); + scoped_ptr<PrefService> prefs2(builder.Create()); + browser::RegisterUserPrefs(prefs2.get()); + EXPECT_EQ(ProxyPrefs::MODE_DIRECT, prefs2->GetInteger(prefs::kProxyMode)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyServer)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyPacUrl)); + EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyBypassList)); } class PrefServiceSetValueTest : public testing::Test { @@ -341,24 +297,11 @@ class PrefServiceSetValueTest : public testing::Test { static const char kValue[]; PrefServiceSetValueTest() - : name_string_(kName), - null_value_(Value::CreateNullValue()) {} - - void SetExpectNoNotification() { - EXPECT_CALL(observer_, Observe(_, _, _)).Times(0); - } - - void SetExpectPrefChanged() { - EXPECT_CALL(observer_, - Observe(NotificationType(NotificationType::PREF_CHANGED), _, - Property(&Details<std::string>::ptr, - Pointee(name_string_)))); - } + : null_value_(Value::CreateNullValue()) {} TestingPrefService prefs_; - std::string name_string_; scoped_ptr<Value> null_value_; - NotificationObserverMock observer_; + PrefObserverMock observer_; }; const char PrefServiceSetValueTest::kName[] = "name"; @@ -366,8 +309,7 @@ const char PrefServiceSetValueTest::kValue[] = "value"; TEST_F(PrefServiceSetValueTest, SetStringValue) { const char default_string[] = "default"; - const scoped_ptr<Value> default_value( - Value::CreateStringValue(default_string)); + const StringValue default_value(default_string); prefs_.RegisterStringPref(kName, default_string); PrefChangeRegistrar registrar; @@ -375,18 +317,18 @@ TEST_F(PrefServiceSetValueTest, SetStringValue) { registrar.Add(kName, &observer_); // Changing the controlling store from default to user triggers notification. - SetExpectPrefChanged(); - prefs_.Set(kName, *default_value); + observer_.Expect(&prefs_, kName, &default_value); + prefs_.Set(kName, default_value); Mock::VerifyAndClearExpectations(&observer_); - SetExpectNoNotification(); - prefs_.Set(kName, *default_value); + EXPECT_CALL(observer_, Observe(_, _, _)).Times(0); + prefs_.Set(kName, default_value); Mock::VerifyAndClearExpectations(&observer_); - const scoped_ptr<Value> new_value(Value::CreateStringValue(kValue)); - SetExpectPrefChanged(); - prefs_.Set(kName, *new_value); - EXPECT_EQ(kValue, prefs_.GetString(kName)); + StringValue new_value(kValue); + observer_.Expect(&prefs_, kName, &new_value); + prefs_.Set(kName, new_value); + Mock::VerifyAndClearExpectations(&observer_); } TEST_F(PrefServiceSetValueTest, SetDictionaryValue) { @@ -397,30 +339,23 @@ TEST_F(PrefServiceSetValueTest, SetDictionaryValue) { // Dictionary values are special: setting one to NULL is the same as clearing // the user value, allowing the NULL default to take (or keep) control. - SetExpectNoNotification(); + EXPECT_CALL(observer_, Observe(_, _, _)).Times(0); prefs_.Set(kName, *null_value_); Mock::VerifyAndClearExpectations(&observer_); DictionaryValue new_value; new_value.SetString(kName, kValue); - SetExpectPrefChanged(); + observer_.Expect(&prefs_, kName, &new_value); prefs_.Set(kName, new_value); Mock::VerifyAndClearExpectations(&observer_); - DictionaryValue* dict = prefs_.GetMutableDictionary(kName); - EXPECT_EQ(1U, dict->size()); - std::string out_value; - dict->GetString(kName, &out_value); - EXPECT_EQ(kValue, out_value); - SetExpectNoNotification(); + EXPECT_CALL(observer_, Observe(_, _, _)).Times(0); prefs_.Set(kName, new_value); Mock::VerifyAndClearExpectations(&observer_); - SetExpectPrefChanged(); + observer_.Expect(&prefs_, kName, null_value_.get()); prefs_.Set(kName, *null_value_); Mock::VerifyAndClearExpectations(&observer_); - dict = prefs_.GetMutableDictionary(kName); - EXPECT_EQ(0U, dict->size()); } TEST_F(PrefServiceSetValueTest, SetListValue) { @@ -431,28 +366,21 @@ TEST_F(PrefServiceSetValueTest, SetListValue) { // List values are special: setting one to NULL is the same as clearing the // user value, allowing the NULL default to take (or keep) control. - SetExpectNoNotification(); + EXPECT_CALL(observer_, Observe(_, _, _)).Times(0); prefs_.Set(kName, *null_value_); Mock::VerifyAndClearExpectations(&observer_); ListValue new_value; new_value.Append(Value::CreateStringValue(kValue)); - SetExpectPrefChanged(); + observer_.Expect(&prefs_, kName, &new_value); prefs_.Set(kName, new_value); Mock::VerifyAndClearExpectations(&observer_); - const ListValue* list = prefs_.GetMutableList(kName); - ASSERT_EQ(1U, list->GetSize()); - std::string out_value; - list->GetString(0, &out_value); - EXPECT_EQ(kValue, out_value); - SetExpectNoNotification(); + EXPECT_CALL(observer_, Observe(_, _, _)).Times(0); prefs_.Set(kName, new_value); Mock::VerifyAndClearExpectations(&observer_); - SetExpectPrefChanged(); + observer_.Expect(&prefs_, kName, null_value_.get()); prefs_.Set(kName, *null_value_); Mock::VerifyAndClearExpectations(&observer_); - list = prefs_.GetMutableList(kName); - EXPECT_EQ(0U, list->GetSize()); } diff --git a/chrome/browser/prefs/pref_set_observer.cc b/chrome/browser/prefs/pref_set_observer.cc index a073eb2..133b219 100644 --- a/chrome/browser/prefs/pref_set_observer.cc +++ b/chrome/browser/prefs/pref_set_observer.cc @@ -47,8 +47,7 @@ PrefSetObserver* PrefSetObserver::CreateProxyPrefSetObserver( PrefService* pref_service, NotificationObserver* observer) { PrefSetObserver* pref_set = new PrefSetObserver(pref_service, observer); - pref_set->AddPref(prefs::kNoProxyServer); - pref_set->AddPref(prefs::kProxyAutoDetect); + pref_set->AddPref(prefs::kProxyMode); pref_set->AddPref(prefs::kProxyServer); pref_set->AddPref(prefs::kProxyPacUrl); pref_set->AddPref(prefs::kProxyBypassList); diff --git a/chrome/browser/prefs/pref_value_map.cc b/chrome/browser/prefs/pref_value_map.cc new file mode 100644 index 0000000..6e7bf79 --- /dev/null +++ b/chrome/browser/prefs/pref_value_map.cc @@ -0,0 +1,107 @@ +// 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 "chrome/browser/prefs/pref_value_map.h" + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/stl_util-inl.h" +#include "base/values.h" + +PrefValueMap::PrefValueMap() {} + +PrefValueMap::~PrefValueMap() { + Clear(); +} + +bool PrefValueMap::GetValue(const std::string& key, 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::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(); +} + +bool PrefValueMap::GetBoolean(const std::string& key, + bool* value) const { + Value* stored_value = NULL; + return GetValue(key, &stored_value) && stored_value->GetAsBoolean(value); +} + +bool PrefValueMap::GetString(const std::string& key, + std::string* value) 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)); +} + +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/chrome/browser/prefs/pref_value_map.h b/chrome/browser/prefs/pref_value_map.h new file mode 100644 index 0000000..0e99920 --- /dev/null +++ b/chrome/browser/prefs/pref_value_map.h @@ -0,0 +1,64 @@ +// 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 CHROME_BROWSER_PREFS_PREF_VALUE_MAP_H_ +#define CHROME_BROWSER_PREFS_PREF_VALUE_MAP_H_ +#pragma once + +#include <map> +#include <string> +#include <vector> + +#include "base/basictypes.h" + +class Value; + +// A generic string to value map used by the PrefStore implementations. +class PrefValueMap { + public: + 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, Value** value) const; + + // 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, 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(); + + // 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; + + // 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); + + // 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, Value*> Map; + + Map prefs_; + + DISALLOW_COPY_AND_ASSIGN(PrefValueMap); +}; + +#endif // CHROME_BROWSER_PREFS_PREF_VALUE_MAP_H_ diff --git a/chrome/browser/prefs/pref_value_map_unittest.cc b/chrome/browser/prefs/pref_value_map_unittest.cc new file mode 100644 index 0000000..5e248b0 --- /dev/null +++ b/chrome/browser/prefs/pref_value_map_unittest.cc @@ -0,0 +1,76 @@ +// 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/values.h" +#include "chrome/browser/prefs/pref_value_map.h" +#include "testing/gtest/include/gtest/gtest.h" + +class PrefValueMapTest : public testing::Test { +}; + +TEST_F(PrefValueMapTest, SetValue) { + PrefValueMap map; + 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, 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); +} diff --git a/chrome/browser/prefs/pref_value_store.cc b/chrome/browser/prefs/pref_value_store.cc index ee23b3b..431e55f 100644 --- a/chrome/browser/prefs/pref_value_store.cc +++ b/chrome/browser/prefs/pref_value_store.cc @@ -4,6 +4,7 @@ #include "chrome/browser/prefs/pref_value_store.h" +<<<<<<< HEAD #ifndef ANDROID #include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/extension_pref_store.h" @@ -15,26 +16,34 @@ #include "chrome/common/json_pref_store.h" #include "chrome/common/notification_service.h" #endif +======= +#include "chrome/browser/prefs/pref_notifier.h" +>>>>>>> chromium.org at r10.0.621.0 -namespace { +PrefValueStore::PrefStoreKeeper::PrefStoreKeeper() + : pref_value_store_(NULL), + type_(PrefValueStore::INVALID_STORE) { +} -// Returns true if the actual value is a valid type for the expected type when -// found in the given store. -bool IsValidType(Value::ValueType expected, Value::ValueType actual, - PrefNotifier::PrefStoreType store) { - if (expected == actual) - return true; +PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() { + if (pref_store_.get()) + pref_store_->RemoveObserver(this); +} - // Dictionaries and lists are allowed to hold TYPE_NULL values too, but only - // in the default pref store. - if (store == PrefNotifier::DEFAULT_STORE && - actual == Value::TYPE_NULL && - (expected == Value::TYPE_DICTIONARY || expected == Value::TYPE_LIST)) { - return true; - } - return false; +void PrefValueStore::PrefStoreKeeper::Initialize( + PrefValueStore* store, + PrefStore* pref_store, + PrefValueStore::PrefStoreType type) { + if (pref_store_.get()) + pref_store_->RemoveObserver(this); + type_ = type; + pref_value_store_ = store; + pref_store_.reset(pref_store); + if (pref_store_.get()) + pref_store_->AddObserver(this); } +<<<<<<< HEAD } // namespace // static @@ -73,6 +82,35 @@ PrefValueStore* PrefValueStore::CreatePrefValueStore( command_line, user, recommended, default_store, profile); #endif +======= +void PrefValueStore::PrefStoreKeeper::OnPrefValueChanged( + const std::string& key) { + pref_value_store_->OnPrefValueChanged(type_, key); +} + +void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted() { + pref_value_store_->OnInitializationCompleted(type_); +} + +PrefValueStore::PrefValueStore(PrefStore* managed_platform_prefs, + PrefStore* device_management_prefs, + PrefStore* extension_prefs, + PrefStore* command_line_prefs, + PrefStore* user_prefs, + PrefStore* recommended_prefs, + PrefStore* default_prefs, + PrefNotifier* pref_notifier) + : pref_notifier_(pref_notifier) { + InitPrefStore(MANAGED_PLATFORM_STORE, managed_platform_prefs); + InitPrefStore(DEVICE_MANAGEMENT_STORE, device_management_prefs); + InitPrefStore(EXTENSION_STORE, extension_prefs); + InitPrefStore(COMMAND_LINE_STORE, command_line_prefs); + InitPrefStore(USER_STORE, user_prefs); + InitPrefStore(RECOMMENDED_STORE, recommended_prefs); + InitPrefStore(DEFAULT_STORE, default_prefs); + + CheckInitializationCompleted(); +>>>>>>> chromium.org at r10.0.621.0 } PrefValueStore::~PrefValueStore() {} @@ -81,20 +119,14 @@ bool PrefValueStore::GetValue(const std::string& name, Value** out_value) const { // Check the |PrefStore|s in order of their priority from highest to lowest // to find the value of the preference described by the given preference name. - for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) { - if (GetValueFromStore(name.c_str(), - static_cast<PrefNotifier::PrefStoreType>(i), + for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { + if (GetValueFromStore(name.c_str(), static_cast<PrefStoreType>(i), out_value)) return true; } return false; } -bool PrefValueStore::GetUserValue(const std::string& name, - Value** out_value) const { - return GetValueFromStore(name.c_str(), PrefNotifier::USER_STORE, out_value); -} - void PrefValueStore::RegisterPreferenceType(const std::string& name, Value::ValueType type) { pref_types_[name] = type; @@ -108,43 +140,6 @@ Value::ValueType PrefValueStore::GetRegisteredType( return found->second; } -bool PrefValueStore::WritePrefs() { - bool success = true; - for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) { - if (pref_stores_[i].get()) - success = pref_stores_[i]->WritePrefs() && success; - } - return success; -} - -void PrefValueStore::ScheduleWritePrefs() { - for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) { - if (pref_stores_[i].get()) - pref_stores_[i]->ScheduleWritePrefs(); - } -} - -PrefStore::PrefReadError PrefValueStore::ReadPrefs() { - PrefStore::PrefReadError result = PrefStore::PREF_READ_ERROR_NONE; - for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) { - if (pref_stores_[i].get()) { - PrefStore::PrefReadError this_error = pref_stores_[i]->ReadPrefs(); - if (result == PrefStore::PREF_READ_ERROR_NONE) - result = this_error; - } - } - - if (HasPolicyConflictingUserProxySettings()) { - LOG(WARNING) << "user-requested proxy options have been overridden" - << " by a proxy configuration specified in a centrally" - << " administered policy."; - } - - // TODO(markusheintz): Return a better error status: maybe a struct with - // the error status of all PrefStores. - return result; -} - bool PrefValueStore::HasPrefPath(const char* path) const { Value* tmp_value = NULL; const std::string name(path); @@ -154,158 +149,112 @@ bool PrefValueStore::HasPrefPath(const char* path) const { return rv && !PrefValueFromDefaultStore(path); } -bool PrefValueStore::PrefHasChanged(const char* path, - PrefNotifier::PrefStoreType new_store) { - DCHECK(new_store != PrefNotifier::INVALID_STORE); - // Replying that the pref has changed may cause problems, but it's the safer - // choice. - if (new_store == PrefNotifier::INVALID_STORE) - return true; - - PrefNotifier::PrefStoreType controller = ControllingPrefStoreForPref(path); - DCHECK(controller != PrefNotifier::INVALID_STORE); - if (controller == PrefNotifier::INVALID_STORE) - return true; - - // If the pref is controlled by a higher-priority store, its effective value - // cannot have changed. - if (controller < new_store) - return false; - - // Otherwise, we take the pref store's word that something changed. - return true; -} - -// Note the |DictionaryValue| referenced by the |PrefStore| USER_STORE -// (returned by the method prefs()) takes the ownership of the Value referenced -// by in_value. -bool PrefValueStore::SetUserPrefValue(const char* name, Value* in_value) { - Value* old_value = NULL; - pref_stores_[PrefNotifier::USER_STORE]->prefs()->Get(name, &old_value); - bool value_changed = !(old_value && old_value->Equals(in_value)); +void PrefValueStore::NotifyPrefChanged( + const char* path, + PrefValueStore::PrefStoreType new_store) { + DCHECK(new_store != INVALID_STORE); - pref_stores_[PrefNotifier::USER_STORE]->prefs()->Set(name, in_value); - return value_changed; -} - -// Note the |DictionaryValue| referenced by the |PrefStore| DEFAULT_STORE -// (returned by the method prefs()) takes the ownership of the Value referenced -// by in_value. -void PrefValueStore::SetDefaultPrefValue(const char* name, Value* in_value) { - pref_stores_[PrefNotifier::DEFAULT_STORE]->prefs()->Set(name, in_value); -} - -bool PrefValueStore::ReadOnly() { - return pref_stores_[PrefNotifier::USER_STORE]->ReadOnly(); -} + // If this pref is not registered, just discard the notification. + if (!pref_types_.count(path)) + return; -bool PrefValueStore::RemoveUserPrefValue(const char* name) { - if (pref_stores_[PrefNotifier::USER_STORE].get()) { - return pref_stores_[PrefNotifier::USER_STORE]->prefs()->Remove(name, NULL); + bool changed = true; + // Replying that the pref has changed in case the new store is invalid may + // cause problems, but it's the safer choice. + if (new_store != INVALID_STORE) { + PrefStoreType controller = ControllingPrefStoreForPref(path); + DCHECK(controller != INVALID_STORE); + // If the pref is controlled by a higher-priority store, its effective value + // cannot have changed. + if (controller != INVALID_STORE && + controller < new_store) { + changed = false; + } } - return false; + + if (changed) + pref_notifier_->OnPreferenceChanged(path); } bool PrefValueStore::PrefValueInManagedPlatformStore(const char* name) const { - return PrefValueInStore(name, PrefNotifier::MANAGED_PLATFORM_STORE); + return PrefValueInStore(name, MANAGED_PLATFORM_STORE); } bool PrefValueStore::PrefValueInDeviceManagementStore(const char* name) const { - return PrefValueInStore(name, PrefNotifier::DEVICE_MANAGEMENT_STORE); + return PrefValueInStore(name, DEVICE_MANAGEMENT_STORE); } bool PrefValueStore::PrefValueInExtensionStore(const char* name) const { - return PrefValueInStore(name, PrefNotifier::EXTENSION_STORE); + return PrefValueInStore(name, EXTENSION_STORE); } bool PrefValueStore::PrefValueInUserStore(const char* name) const { - return PrefValueInStore(name, PrefNotifier::USER_STORE); -} - -bool PrefValueStore::PrefValueInStoreRange( - const char* name, - PrefNotifier::PrefStoreType first_checked_store, - PrefNotifier::PrefStoreType last_checked_store) { - if (first_checked_store > last_checked_store) { - NOTREACHED(); - return false; - } - - for (size_t i = first_checked_store; - i <= static_cast<size_t>(last_checked_store); ++i) { - if (PrefValueInStore(name, static_cast<PrefNotifier::PrefStoreType>(i))) - return true; - } - return false; + return PrefValueInStore(name, USER_STORE); } bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const { - return ControllingPrefStoreForPref(name) == PrefNotifier::EXTENSION_STORE; + return ControllingPrefStoreForPref(name) == EXTENSION_STORE; } bool PrefValueStore::PrefValueFromUserStore(const char* name) const { - return ControllingPrefStoreForPref(name) == PrefNotifier::USER_STORE; + return ControllingPrefStoreForPref(name) == USER_STORE; } bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const { - return ControllingPrefStoreForPref(name) == PrefNotifier::DEFAULT_STORE; + return ControllingPrefStoreForPref(name) == DEFAULT_STORE; } bool PrefValueStore::PrefValueUserModifiable(const char* name) const { - PrefNotifier::PrefStoreType effective_store = - ControllingPrefStoreForPref(name); - return effective_store >= PrefNotifier::USER_STORE || - effective_store == PrefNotifier::INVALID_STORE; + PrefStoreType effective_store = ControllingPrefStoreForPref(name); + return effective_store >= USER_STORE || + effective_store == INVALID_STORE; } -PrefNotifier::PrefStoreType PrefValueStore::ControllingPrefStoreForPref( - const char* name) const { - for (int i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) { - if (PrefValueInStore(name, static_cast<PrefNotifier::PrefStoreType>(i))) - return static_cast<PrefNotifier::PrefStoreType>(i); +// Returns true if the actual value is a valid type for the expected type when +// found in the given store. +bool PrefValueStore::IsValidType(Value::ValueType expected, + Value::ValueType actual, + PrefValueStore::PrefStoreType store) { + if (expected == actual) + return true; + + // Dictionaries and lists are allowed to hold TYPE_NULL values too, but only + // in the default pref store. + if (store == DEFAULT_STORE && + actual == Value::TYPE_NULL && + (expected == Value::TYPE_DICTIONARY || expected == Value::TYPE_LIST)) { + return true; } - return PrefNotifier::INVALID_STORE; + return false; } bool PrefValueStore::PrefValueInStore( const char* name, - PrefNotifier::PrefStoreType store) const { + PrefValueStore::PrefStoreType store) const { // Declare a temp Value* and call GetValueFromStore, // ignoring the output value. Value* tmp_value = NULL; return GetValueFromStore(name, store, &tmp_value); } -bool PrefValueStore::GetValueFromStore( +bool PrefValueStore::PrefValueInStoreRange( const char* name, - PrefNotifier::PrefStoreType store, - Value** out_value) const { - // Only return true if we find a value and it is the correct type, so stale - // values with the incorrect type will be ignored. - if (pref_stores_[store].get() && - pref_stores_[store]->prefs()->Get(name, out_value)) { - // If the value is the sentinel that redirects to the default - // store, re-fetch the value from the default store explicitly. - // Because the default values are not available when creating - // stores, the default value must be fetched dynamically for every - // redirect. - if (PrefStore::IsUseDefaultSentinelValue(*out_value)) { - DCHECK(pref_stores_[PrefNotifier::DEFAULT_STORE].get()); - if (!pref_stores_[PrefNotifier::DEFAULT_STORE]->prefs()->Get(name, - out_value)) { - *out_value = NULL; - return false; - } - store = PrefNotifier::DEFAULT_STORE; - } - if (IsValidType(GetRegisteredType(name), (*out_value)->GetType(), store)) + PrefValueStore::PrefStoreType first_checked_store, + PrefValueStore::PrefStoreType last_checked_store) const { + if (first_checked_store > last_checked_store) { + NOTREACHED(); + return false; + } + + for (size_t i = first_checked_store; + i <= static_cast<size_t>(last_checked_store); ++i) { + if (PrefValueInStore(name, static_cast<PrefStoreType>(i))) return true; } - // No valid value found for the given preference name: set the return false. - *out_value = NULL; return false; } +<<<<<<< HEAD #ifndef ANDROID void PrefValueStore::RefreshPolicyPrefsOnFileThread( BrowserThread::ID calling_thread_id, @@ -334,130 +283,61 @@ void PrefValueStore::RefreshPolicyPrefsOnFileThread( LOG(ERROR) << "refresh of device management policy failed: " << "PrefReadError = " << read_error; return; +======= +PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref( + const char* name) const { + for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { + if (PrefValueInStore(name, static_cast<PrefStoreType>(i))) + return static_cast<PrefStoreType>(i); +>>>>>>> chromium.org at r10.0.621.0 } + return INVALID_STORE; +} - read_error = new_recommended_pref_store->ReadPrefs(); - if (read_error != PrefStore::PREF_READ_ERROR_NONE) { - LOG(ERROR) << "refresh of recommended policy failed: PrefReadError = " - << read_error; - return; +bool PrefValueStore::GetValueFromStore(const char* name, + PrefValueStore::PrefStoreType store_type, + Value** out_value) const { + // Only return true if we find a value and it is the correct type, so stale + // values with the incorrect type will be ignored. + const PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(store_type)); + if (store) { + switch (store->GetValue(name, out_value)) { + case PrefStore::READ_USE_DEFAULT: + store = GetPrefStore(DEFAULT_STORE); + if (!store || store->GetValue(name, out_value) != PrefStore::READ_OK) { + *out_value = NULL; + return false; + } + // Fall through... + case PrefStore::READ_OK: + if (IsValidType(GetRegisteredType(name), + (*out_value)->GetType(), + store_type)) { + return true; + } + break; + case PrefStore::READ_NO_VALUE: + break; + } } - BrowserThread::PostTask( - calling_thread_id, FROM_HERE, - NewRunnableMethod(this, - &PrefValueStore::RefreshPolicyPrefsCompletion, - managed_platform_pref_store.release(), - device_management_pref_store.release(), - recommended_pref_store.release(), - callback.release())); + // No valid value found for the given preference name: set the return false. + *out_value = NULL; + return false; } -void PrefValueStore::RefreshPolicyPrefsCompletion( - PrefStore* new_managed_platform_pref_store, - PrefStore* new_device_management_pref_store, - PrefStore* new_recommended_pref_store, - AfterRefreshCallback* callback_pointer) { - scoped_ptr<AfterRefreshCallback> callback(callback_pointer); - - // Determine the paths of all the changed preferences values in the three - // policy-related stores (managed platform, device management and - // recommended). - DictionaryValue* managed_platform_prefs_before( - pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE]->prefs()); - DictionaryValue* managed_platform_prefs_after( - new_managed_platform_pref_store->prefs()); - DictionaryValue* device_management_prefs_before( - pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE]->prefs()); - DictionaryValue* device_management_prefs_after( - new_device_management_pref_store->prefs()); - DictionaryValue* recommended_prefs_before( - pref_stores_[PrefNotifier::RECOMMENDED_STORE]->prefs()); - DictionaryValue* recommended_prefs_after(new_recommended_pref_store->prefs()); - - std::vector<std::string> changed_managed_platform_paths; - managed_platform_prefs_before->GetDifferingPaths(managed_platform_prefs_after, - &changed_managed_platform_paths); - - std::vector<std::string> changed_device_management_paths; - device_management_prefs_before->GetDifferingPaths( - device_management_prefs_after, - &changed_device_management_paths); - - std::vector<std::string> changed_recommended_paths; - recommended_prefs_before->GetDifferingPaths(recommended_prefs_after, - &changed_recommended_paths); - - // Merge all three vectors of changed value paths together, filtering - // duplicates in a post-processing step. - std::vector<std::string> all_changed_managed_platform_paths( - changed_managed_platform_paths.size() + - changed_device_management_paths.size()); - - std::vector<std::string>::iterator last_insert = - std::merge(changed_managed_platform_paths.begin(), - changed_managed_platform_paths.end(), - changed_device_management_paths.begin(), - changed_device_management_paths.end(), - all_changed_managed_platform_paths.begin()); - all_changed_managed_platform_paths.resize( - last_insert - all_changed_managed_platform_paths.begin()); - - std::vector<std::string> changed_paths( - all_changed_managed_platform_paths.size() + - changed_recommended_paths.size()); - last_insert = std::merge(all_changed_managed_platform_paths.begin(), - all_changed_managed_platform_paths.end(), - changed_recommended_paths.begin(), - changed_recommended_paths.end(), - changed_paths.begin()); - changed_paths.resize(last_insert - changed_paths.begin()); - - last_insert = unique(changed_paths.begin(), changed_paths.end()); - changed_paths.resize(last_insert - changed_paths.begin()); - - // Replace the old stores with the new and send notification of the changed - // preferences. - pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE].reset( - new_managed_platform_pref_store); - pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE].reset( - new_device_management_pref_store); - pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset( - new_recommended_pref_store); - callback->Run(changed_paths); +void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type, + const std::string& key) { + NotifyPrefChanged(key.c_str(), type); } -void PrefValueStore::RefreshPolicyPrefs( - AfterRefreshCallback* callback) { - using policy::ConfigurationPolicyPrefStore; - // Because loading of policy information must happen on the FILE - // thread, it's not possible to just replace the contents of the - // managed and recommended stores in place due to possible - // concurrent access from the UI thread. Instead, new stores are - // created and the refreshed policy read into them. The new stores - // are swapped with the old from a Task on the UI thread after the - // load is complete. - PrefStore* new_managed_platform_pref_store( - ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore()); - PrefStore* new_device_management_pref_store( - ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore( - profile_)); - PrefStore* new_recommended_pref_store( - ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore()); - BrowserThread::ID current_thread_id; - CHECK(BrowserThread::GetCurrentThreadIdentifier(¤t_thread_id)); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(this, - &PrefValueStore::RefreshPolicyPrefsOnFileThread, - current_thread_id, - new_managed_platform_pref_store, - new_device_management_pref_store, - new_recommended_pref_store, - callback)); +void PrefValueStore::OnInitializationCompleted( + PrefValueStore::PrefStoreType type) { + CheckInitializationCompleted(); } #endif // ANDROID +<<<<<<< HEAD bool PrefValueStore::HasPolicyConflictingUserProxySettings() { #if !defined(ANDROID) using policy::ConfigurationPolicyPrefStore; @@ -474,27 +354,18 @@ bool PrefValueStore::HasPolicyConflictingUserProxySettings() { } #endif return false; -} - -PrefValueStore::PrefValueStore(PrefStore* managed_platform_prefs, - PrefStore* device_management_prefs, - PrefStore* extension_prefs, - PrefStore* command_line_prefs, - PrefStore* user_prefs, - PrefStore* recommended_prefs, - PrefStore* default_prefs, - Profile* profile) - : profile_(profile) { - // NULL default pref store is usually bad, but may be OK for some unit tests. - if (!default_prefs) - LOG(WARNING) << "default pref store is null"; - pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE].reset( - managed_platform_prefs); - pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE].reset( - device_management_prefs); - pref_stores_[PrefNotifier::EXTENSION_STORE].reset(extension_prefs); - pref_stores_[PrefNotifier::COMMAND_LINE_STORE].reset(command_line_prefs); - pref_stores_[PrefNotifier::USER_STORE].reset(user_prefs); - pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset(recommended_prefs); - pref_stores_[PrefNotifier::DEFAULT_STORE].reset(default_prefs); +======= +void PrefValueStore::InitPrefStore(PrefValueStore::PrefStoreType type, + PrefStore* pref_store) { + pref_stores_[type].Initialize(this, pref_store, type); +>>>>>>> chromium.org at r10.0.621.0 +} + +void PrefValueStore::CheckInitializationCompleted() { + for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { + PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(i)); + if (store && !store->IsInitializationComplete()) + return; + } + pref_notifier_->OnInitializationCompleted(); } diff --git a/chrome/browser/prefs/pref_value_store.h b/chrome/browser/prefs/pref_value_store.h index a82944d..2b8c539 100644 --- a/chrome/browser/prefs/pref_value_store.h +++ b/chrome/browser/prefs/pref_value_store.h @@ -11,18 +11,21 @@ #include <vector> #include "base/basictypes.h" -#include "base/callback.h" #include "base/gtest_prod_util.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/values.h" #ifndef ANDROID #include "chrome/browser/browser_thread.h" +<<<<<<< HEAD #endif #include "chrome/browser/prefs/pref_notifier.h" +======= +>>>>>>> chromium.org at r10.0.621.0 #include "chrome/common/pref_store.h" class FilePath; +class PrefNotifier; class PrefStore; class Profile; @@ -30,13 +33,12 @@ class Profile; // (e.g., configuration policies, extensions, and user settings). It returns // the value of a Preference from the source with the highest priority, and // allows setting user-defined values for preferences that are not managed. -// See PrefNotifier for a list of the available preference sources (PrefStores) -// and their descriptions. // // Unless otherwise explicitly noted, all of the methods of this class must // be called on the UI thread. class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { public: +<<<<<<< HEAD // Returns a new PrefValueStore with all applicable PrefStores. The // |pref_filename| points to the user preference file. The |profile| is the // one to which these preferences apply; it may be NULL if we're dealing @@ -53,6 +55,38 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { virtual #endif ~PrefValueStore(); +======= + // In decreasing order of precedence: + // |managed_platform_prefs| contains all managed platform (non-cloud policy) + // preference values. + // |device_management_prefs| contains all device management (cloud policy) + // preference values. + // |extension_prefs| contains preference values set by extensions. + // |command_line_prefs| contains preference values set by command-line + // switches. + // |user_prefs| contains all user-set preference values. + // |recommended_prefs| contains all recommended (policy) preference values. + // |default_prefs| contains application-default preference values. It must + // be non-null if any preferences are to be registered. + // + // |pref_notifier| facilitates broadcasting preference change notifications + // to the world. + // + // The |profile| parameter is used to construct a replacement device + // management pref store. This is done after policy refresh when we swap out + // the policy pref stores for new ones, so the |profile| pointer needs to be + // kept around for then. It is safe to pass a NULL pointer for local state + // preferences. + PrefValueStore(PrefStore* managed_platform_prefs, + PrefStore* device_management_prefs, + PrefStore* extension_prefs, + PrefStore* command_line_prefs, + PrefStore* user_prefs, + PrefStore* recommended_prefs, + PrefStore* default_prefs, + PrefNotifier* pref_notifier); + virtual ~PrefValueStore(); +>>>>>>> chromium.org at r10.0.621.0 // Gets the value for the given preference name that has a valid value type; // that is, the same type the preference was registered with, or NULL for @@ -61,9 +95,6 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { // Preference::GetValue() instead of calling this method directly. bool GetValue(const std::string& name, Value** out_value) const; - // Same as GetValue but only searches USER_STORE. - bool GetUserValue(const std::string& name, Value** out_value) const; - // Adds a preference to the mapping of names to types. void RegisterPreferenceType(const std::string& name, Value::ValueType type); @@ -71,20 +102,6 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { // Value::TYPE_NULL if the preference has never been registered. Value::ValueType GetRegisteredType(const std::string& name) const; - // Read preference values into the three PrefStores so that they are available - // through the GetValue method. Return the first error that occurs (but - // continue reading the remaining PrefStores). - PrefStore::PrefReadError ReadPrefs(); - - // Persists prefs (to disk or elsewhere). Returns true if writing values was - // successful. In practice, only the user prefs are expected to be written - // out. - bool WritePrefs(); - - // Calls the method ScheduleWritePrefs on the PrefStores. In practice, only - // the user prefs are expected to be written out. - void ScheduleWritePrefs(); - // Returns true if the PrefValueStore contains the given preference (i.e., // it's been registered), and a value with the correct type has been actively // set in some pref store. The application default specified when the pref was @@ -92,38 +109,6 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { // store setting a value that happens to be equal to the default does. bool HasPrefPath(const char* name) const; - // Called by the PrefNotifier when the value of the preference at |path| has - // changed, been added, or been removed in one of the PrefStores. The - // |new_store| is the PrefStoreType of the caller. Returns true if the - // effective value of the preference has changed, or if the store controlling - // the pref has changed. Virtual so it can be mocked for a unit test. - virtual bool PrefHasChanged(const char* path, - PrefNotifier::PrefStoreType new_store); - - // Returns true if the PrefValueStore is read-only. Because the managed - // platform, device management and recommended PrefStores are always - // read-only, the PrefValueStore as a whole is read-only if the PrefStore - // containing the user preferences is read-only. - bool ReadOnly(); - - // Alters the user-defined value of a preference. Even if the preference is - // managed this method allows the user-defined value of the preference to be - // set. But GetValue calls will not return this value as long as the - // preference is managed. Instead GetValue will return the managed value - // of the preference. Note that the PrefValueStore takes the ownership of - // the value referenced by |in_value|. It is an error to call this when no - // user PrefStore has been set. Returns true if the user-set value of the - // preference was newly added or changed. - bool SetUserPrefValue(const char* name, Value* in_value); - - // Removes a value from the user PrefStore. If a preference is managed - // this function should have no visible effect. Returns true if there was a - // user-set value to be removed. - bool RemoveUserPrefValue(const char* name); - - // Sets a value in the DefaultPrefStore, which takes ownership of the Value. - void SetDefaultPrefValue(const char* name, Value* in_value); - // These methods return true if a preference with the given name is in the // indicated pref store, even if that value is currently being overridden by // a higher-priority source. @@ -132,14 +117,6 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { bool PrefValueInExtensionStore(const char* name) const; bool PrefValueInUserStore(const char* name) const; - // Returns true if a preference has an explicit value in any of the - // stores in the range specified by |first_checked_store| and - // |last_checked_store|, even if that value is currently being - // overridden by a higher-priority store. - bool PrefValueInStoreRange(const char* name, - PrefNotifier::PrefStoreType first_checked_store, - PrefNotifier::PrefStoreType last_checked_store); - // These methods return true if a preference with the given name is actually // being controlled by the indicated pref store and not being overridden by // a higher-priority source. @@ -151,6 +128,7 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { // there is no higher-priority source controlling it. bool PrefValueUserModifiable(const char* name) const; +<<<<<<< HEAD // Returns the pref store type identifying the source that controls the // Preference identified by |name|. If none of the sources has a value, // PrefNotifier::INVALID_STORE is returned. In practice, the default PrefStore @@ -215,24 +193,109 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { PrefStore* default_prefs, Profile* profile); +======= +>>>>>>> chromium.org at r10.0.621.0 private: + // PrefStores must be listed here in order from highest to lowest priority. + // MANAGED_PLATFORM contains all managed preference values that are + // provided by a platform-specific policy mechanism (e.g. Windows + // Group Policy). + // DEVICE_MANAGEMENT contains all managed preference values supplied + // by the device management server (cloud policy). + // EXTENSION contains preference values set by extensions. + // COMMAND_LINE contains preference values set by command-line switches. + // USER contains all user-set preference values. + // RECOMMENDED contains all recommended (policy) preference values. + // DEFAULT contains all application default preference values. + enum PrefStoreType { + // INVALID_STORE is not associated with an actual PrefStore but used as + // an invalid marker, e.g. as a return value. + INVALID_STORE = -1, + MANAGED_PLATFORM_STORE = 0, + DEVICE_MANAGEMENT_STORE, + EXTENSION_STORE, + COMMAND_LINE_STORE, + USER_STORE, + RECOMMENDED_STORE, + DEFAULT_STORE, + PREF_STORE_TYPE_MAX = DEFAULT_STORE + }; + + // Keeps a PrefStore reference on behalf of the PrefValueStore and monitors + // the PrefStore for changes, forwarding notifications to PrefValueStore. This + // indirection is here for the sake of disambiguating notifications from the + // individual PrefStores. + class PrefStoreKeeper : public PrefStore::Observer { + public: + PrefStoreKeeper(); + virtual ~PrefStoreKeeper(); + + // Takes ownership of |pref_store|. + void Initialize(PrefValueStore* store, + PrefStore* pref_store, + PrefStoreType type); + + PrefStore* store() { return pref_store_.get(); } + const PrefStore* store() const { return pref_store_.get(); } + + private: + // PrefStore::Observer implementation. + virtual void OnPrefValueChanged(const std::string& key); + virtual void OnInitializationCompleted(); + + // PrefValueStore this keeper is part of. + PrefValueStore* pref_value_store_; + + // The PrefStore managed by this keeper. + scoped_ptr<PrefStore> pref_store_; + + // Type of the pref store. + PrefStoreType type_; + + DISALLOW_COPY_AND_ASSIGN(PrefStoreKeeper); + }; + typedef std::map<std::string, Value::ValueType> PrefTypeMap; - friend class PrefValueStoreTest; - FRIEND_TEST_ALL_PREFIXES(PrefValueStoreTest, + friend class PrefValueStorePolicyRefreshTest; + FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, TestPolicyRefresh); + FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, TestRefreshPolicyPrefsCompletion); + FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, + TestConcurrentPolicyRefresh); + + // Returns true if the actual type is a valid type for the expected type when + // found in the given store. + static bool IsValidType(Value::ValueType expected, + Value::ValueType actual, + PrefStoreType store); // Returns true if the preference with the given name has a value in the // given PrefStoreType, of the same value type as the preference was // registered with. - bool PrefValueInStore(const char* name, - PrefNotifier::PrefStoreType store) const; + bool PrefValueInStore(const char* name, PrefStoreType store) const; + + // Returns true if a preference has an explicit value in any of the + // stores in the range specified by |first_checked_store| and + // |last_checked_store|, even if that value is currently being + // overridden by a higher-priority store. + bool PrefValueInStoreRange(const char* name, + PrefStoreType first_checked_store, + PrefStoreType last_checked_store) const; + + // Returns the pref store type identifying the source that controls the + // Preference identified by |name|. If none of the sources has a value, + // INVALID_STORE is returned. In practice, the default PrefStore + // should always have a value for any registered preferencem, so INVALID_STORE + // indicates an error. + PrefStoreType ControllingPrefStoreForPref(const char* name) const; // Get a value from the specified store type. bool GetValueFromStore(const char* name, - PrefNotifier::PrefStoreType store, + PrefStoreType store, Value** out_value) const; +<<<<<<< HEAD #ifndef ANDROID // Called during policy refresh after ReadPrefs completes on the thread // that initiated the policy refresh. RefreshPolicyPrefsCompletion takes @@ -254,15 +317,49 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> { #endif scoped_ptr<PrefStore> pref_stores_[PrefNotifier::PREF_STORE_TYPE_MAX + 1]; +======= + // Called upon changes in individual pref stores in order to determine whether + // the user-visible pref value has changed. Triggers the change notification + // if the effective value of the preference has changed, or if the store + // controlling the pref has changed. + void NotifyPrefChanged(const char* path, PrefStoreType new_store); + + // Called from the PrefStoreKeeper implementation when a pref value for |key| + // changed in the pref store for |type|. + void OnPrefValueChanged(PrefStoreType type, const std::string& key); + + // Handle the event that the store for |type| has completed initialization. + void OnInitializationCompleted(PrefStoreType type); + + // Initializes a pref store keeper. Sets up a PrefStoreKeeper that will take + // ownership of the passed |pref_store|. + void InitPrefStore(PrefStoreType type, PrefStore* pref_store); + + // Checks whether initialization is completed and tells the notifier if that + // is the case. + void CheckInitializationCompleted(); + + // Get the PrefStore pointer for the given type. May return NULL if there is + // no PrefStore for that type. + PrefStore* GetPrefStore(PrefStoreType type) { + return pref_stores_[type].store(); + } + const PrefStore* GetPrefStore(PrefStoreType type) const { + return pref_stores_[type].store(); + } + + // Keeps the PrefStore references in order of precedence. + PrefStoreKeeper pref_stores_[PREF_STORE_TYPE_MAX + 1]; + + // Used for generating PREF_CHANGED and PREF_INITIALIZATION_COMPLETED + // notifications. This is a weak reference, since the notifier is owned by the + // corresponding PrefService. + PrefNotifier* pref_notifier_; +>>>>>>> chromium.org at r10.0.621.0 // A mapping of preference names to their registered types. PrefTypeMap pref_types_; - // The associated profile, in case this value store is associated with a - // profile pref service. Used for recreating the device management pref store - // upon policy refresh. - Profile* profile_; - DISALLOW_COPY_AND_ASSIGN(PrefValueStore); }; diff --git a/chrome/browser/prefs/pref_value_store_unittest.cc b/chrome/browser/prefs/pref_value_store_unittest.cc index cbf7ccc..5c0fa53 100644 --- a/chrome/browser/prefs/pref_value_store_unittest.cc +++ b/chrome/browser/prefs/pref_value_store_unittest.cc @@ -2,26 +2,33 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <set> +#include <string> + #include "base/scoped_ptr.h" #include "base/values.h" #include "chrome/browser/browser_thread.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" -#include "chrome/browser/prefs/dummy_pref_store.h" +#include "chrome/browser/policy/dummy_configuration_policy_provider.h" +#include "chrome/browser/prefs/pref_notifier.h" #include "chrome/browser/prefs/pref_value_store.h" +#include "chrome/browser/prefs/testing_pref_store.h" #include "chrome/common/pref_names.h" -#include "chrome/test/testing_pref_service.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using testing::_; +using testing::AnyNumber; using testing::Mock; +using testing::Invoke; namespace { -class MockPolicyRefreshCallback { +// Allows to capture pref notifications through gmock. +class MockPrefNotifier : public PrefNotifier { public: - MockPolicyRefreshCallback() {} - MOCK_METHOD1(DoCallback, void(const std::vector<std::string>)); + MOCK_METHOD1(OnPreferenceChanged, void(const std::string&)); + MOCK_METHOD0(OnInitializationCompleted, void()); }; } // namespace @@ -83,44 +90,25 @@ const std::string kSearchProviderNameValue = "AreYouFeelingExtraLucky"; class PrefValueStoreTest : public testing::Test { protected: virtual void SetUp() { - // Create dummy user preferences. - managed_platform_prefs_= CreateManagedPlatformPrefs(); - device_management_prefs_ = CreateDeviceManagementPrefs(); - extension_prefs_ = CreateExtensionPrefs(); - command_line_prefs_ = CreateCommandLinePrefs(); - user_prefs_ = CreateUserPrefs(); - recommended_prefs_ = CreateRecommendedPrefs(); - default_prefs_ = CreateDefaultPrefs(); - - std::sort(expected_differing_paths_.begin(), - expected_differing_paths_.end()); - - // Create |DummyPrefStore|s. - managed_platform_pref_store_ = new DummyPrefStore(); - managed_platform_pref_store_->set_prefs(managed_platform_prefs_); - device_management_pref_store_ = new DummyPrefStore(); - device_management_pref_store_->set_prefs(device_management_prefs_); - extension_pref_store_ = new DummyPrefStore(); - extension_pref_store_->set_prefs(extension_prefs_); - command_line_pref_store_ = new DummyPrefStore(); - command_line_pref_store_->set_prefs(command_line_prefs_); - user_pref_store_ = new DummyPrefStore(); - user_pref_store_->set_read_only(false); - user_pref_store_->set_prefs(user_prefs_); - recommended_pref_store_ = new DummyPrefStore(); - recommended_pref_store_->set_prefs(recommended_prefs_); - default_pref_store_ = new DummyPrefStore(); - default_pref_store_->set_prefs(default_prefs_); - - // Create a new pref-value-store. - pref_value_store_ = new TestingPrefService::TestingPrefValueStore( + // Create TestingPrefStores. + CreateManagedPlatformPrefs(); + CreateDeviceManagementPrefs(); + CreateExtensionPrefs(); + CreateCommandLinePrefs(); + CreateUserPrefs(); + CreateRecommendedPrefs(); + CreateDefaultPrefs(); + + // Create a fresh PrefValueStore. + pref_value_store_ = new PrefValueStore( managed_platform_pref_store_, device_management_pref_store_, extension_pref_store_, command_line_pref_store_, user_pref_store_, recommended_pref_store_, - default_pref_store_); + default_pref_store_, + &pref_notifier_); // Register prefs with the PrefValueStore. pref_value_store_->RegisterPreferenceType(prefs::kApplicationLocale, @@ -144,99 +132,76 @@ class PrefValueStoreTest : public testing::Test { Value::TYPE_LIST); pref_value_store_->RegisterPreferenceType(prefs::kDefaultPref, Value::TYPE_INTEGER); - pref_value_store_->RegisterPreferenceType(prefs::kProxyAutoDetect, - Value::TYPE_BOOLEAN); - - ui_thread_.reset(new BrowserThread(BrowserThread::UI, &loop_)); - file_thread_.reset(new BrowserThread(BrowserThread::FILE, &loop_)); + pref_value_store_->RegisterPreferenceType(prefs::kProxyMode, + Value::TYPE_INTEGER); } // Creates a new dictionary and stores some sample user preferences // in it. - DictionaryValue* CreateUserPrefs() { - DictionaryValue* user_prefs = new DictionaryValue(); - user_prefs->SetBoolean(prefs::kDeleteCache, user_pref::kDeleteCacheValue); - user_prefs->SetInteger(prefs::kStabilityLaunchCount, - user_pref::kStabilityLaunchCountValue); - user_prefs->SetString(prefs::kCurrentThemeID, + void CreateUserPrefs() { + user_pref_store_ = new TestingPrefStore; + user_pref_store_->SetBoolean(prefs::kDeleteCache, + user_pref::kDeleteCacheValue); + user_pref_store_->SetInteger(prefs::kStabilityLaunchCount, + user_pref::kStabilityLaunchCountValue); + user_pref_store_->SetString(prefs::kCurrentThemeID, user_pref::kCurrentThemeIDValue); - user_prefs->SetString(prefs::kApplicationLocale, + user_pref_store_->SetString(prefs::kApplicationLocale, user_pref::kApplicationLocaleValue); - user_prefs->SetString(prefs::kDefaultSearchProviderName, + user_pref_store_->SetString(prefs::kDefaultSearchProviderName, user_pref::kSearchProviderNameValue); - user_prefs->SetString(prefs::kHomePage, user_pref::kHomepageValue); - return user_prefs; + user_pref_store_->SetString(prefs::kHomePage, + user_pref::kHomepageValue); } - DictionaryValue* CreateManagedPlatformPrefs() { - DictionaryValue* managed_platform_prefs = new DictionaryValue(); - managed_platform_prefs->SetString( - prefs::kHomePage, + void CreateManagedPlatformPrefs() { + managed_platform_pref_store_ = new TestingPrefStore; + managed_platform_pref_store_->SetString(prefs::kHomePage, managed_platform_pref::kHomepageValue); - expected_differing_paths_.push_back(prefs::kHomePage); - return managed_platform_prefs; } - DictionaryValue* CreateDeviceManagementPrefs() { - DictionaryValue* device_management_prefs = new DictionaryValue(); - device_management_prefs->SetString( - prefs::kDefaultSearchProviderName, + void CreateDeviceManagementPrefs() { + device_management_pref_store_ = new TestingPrefStore; + device_management_pref_store_->SetString(prefs::kDefaultSearchProviderName, device_management_pref::kSearchProviderNameValue); - expected_differing_paths_.push_back("default_search_provider"); - expected_differing_paths_.push_back(prefs::kDefaultSearchProviderName); - device_management_prefs->SetString(prefs::kHomePage, - device_management_pref::kHomepageValue); - return device_management_prefs; + device_management_pref_store_->SetString(prefs::kHomePage, + device_management_pref::kHomepageValue); } - DictionaryValue* CreateExtensionPrefs() { - DictionaryValue* extension_prefs = new DictionaryValue(); - extension_prefs->SetString(prefs::kCurrentThemeID, + void CreateExtensionPrefs() { + extension_pref_store_ = new TestingPrefStore; + extension_pref_store_->SetString(prefs::kCurrentThemeID, extension_pref::kCurrentThemeIDValue); - extension_prefs->SetString(prefs::kHomePage, + extension_pref_store_->SetString(prefs::kHomePage, extension_pref::kHomepageValue); - extension_prefs->SetString(prefs::kDefaultSearchProviderName, - extension_pref::kSearchProviderNameValue); - return extension_prefs; + extension_pref_store_->SetString(prefs::kDefaultSearchProviderName, + extension_pref::kSearchProviderNameValue); } - DictionaryValue* CreateCommandLinePrefs() { - DictionaryValue* command_line_prefs = new DictionaryValue(); - command_line_prefs->SetString(prefs::kCurrentThemeID, + void CreateCommandLinePrefs() { + command_line_pref_store_ = new TestingPrefStore; + command_line_pref_store_->SetString(prefs::kCurrentThemeID, command_line_pref::kCurrentThemeIDValue); - command_line_prefs->SetString(prefs::kApplicationLocale, + command_line_pref_store_->SetString(prefs::kApplicationLocale, command_line_pref::kApplicationLocaleValue); - command_line_prefs->SetString(prefs::kHomePage, + command_line_pref_store_->SetString(prefs::kHomePage, command_line_pref::kHomepageValue); - command_line_prefs->SetString( - prefs::kDefaultSearchProviderName, + command_line_pref_store_->SetString(prefs::kDefaultSearchProviderName, command_line_pref::kSearchProviderNameValue); - return command_line_prefs; } - DictionaryValue* CreateRecommendedPrefs() { - DictionaryValue* recommended_prefs = new DictionaryValue(); - recommended_prefs->SetInteger(prefs::kStabilityLaunchCount, + void CreateRecommendedPrefs() { + recommended_pref_store_ = new TestingPrefStore; + recommended_pref_store_->SetInteger(prefs::kStabilityLaunchCount, recommended_pref::kStabilityLaunchCountValue); - recommended_prefs->SetBoolean( - prefs::kRecommendedPref, + recommended_pref_store_->SetBoolean(prefs::kRecommendedPref, recommended_pref::kRecommendedPrefValue); - - // Expected differing paths must be added in lexicographic order - // to work properly - expected_differing_paths_.push_back("this"); - expected_differing_paths_.push_back("this.pref"); - expected_differing_paths_.push_back(prefs::kRecommendedPref); - expected_differing_paths_.push_back("user_experience_metrics"); - expected_differing_paths_.push_back("user_experience_metrics.stability"); - expected_differing_paths_.push_back(prefs::kStabilityLaunchCount); - return recommended_prefs; } - DictionaryValue* CreateDefaultPrefs() { - DictionaryValue* default_prefs = new DictionaryValue(); - default_prefs->SetInteger(prefs::kDefaultPref, default_pref::kDefaultValue); - return default_prefs; + void CreateDefaultPrefs() { + default_pref_store_ = new TestingPrefStore; + default_pref_store_->SetInteger(prefs::kDefaultPref, + default_pref::kDefaultValue); } DictionaryValue* CreateSampleDictValue() { @@ -256,56 +221,19 @@ class PrefValueStoreTest : public testing::Test { return sample_list; } - virtual void TearDown() { - loop_.RunAllPending(); - } - - MessageLoop loop_; - - scoped_refptr<TestingPrefService::TestingPrefValueStore> pref_value_store_; + MockPrefNotifier pref_notifier_; + scoped_refptr<PrefValueStore> pref_value_store_; // |PrefStore|s are owned by the |PrefValueStore|. - DummyPrefStore* managed_platform_pref_store_; - DummyPrefStore* device_management_pref_store_; - DummyPrefStore* extension_pref_store_; - DummyPrefStore* command_line_pref_store_; - DummyPrefStore* user_pref_store_; - DummyPrefStore* recommended_pref_store_; - DummyPrefStore* default_pref_store_; - - // A vector of the preferences paths in the managed and recommended - // PrefStores that are set at the beginning of a test. Can be modified - // by the test to track changes that it makes to the preferences - // stored in the managed and recommended PrefStores. - std::vector<std::string> expected_differing_paths_; - - // Preferences are owned by the individual |DummyPrefStores|. - DictionaryValue* managed_platform_prefs_; - DictionaryValue* device_management_prefs_; - DictionaryValue* extension_prefs_; - DictionaryValue* command_line_prefs_; - DictionaryValue* user_prefs_; - DictionaryValue* recommended_prefs_; - DictionaryValue* default_prefs_; - - private: - scoped_ptr<BrowserThread> ui_thread_; - scoped_ptr<BrowserThread> file_thread_; + TestingPrefStore* managed_platform_pref_store_; + TestingPrefStore* device_management_pref_store_; + TestingPrefStore* extension_pref_store_; + TestingPrefStore* command_line_pref_store_; + TestingPrefStore* user_pref_store_; + TestingPrefStore* recommended_pref_store_; + TestingPrefStore* default_pref_store_; }; -TEST_F(PrefValueStoreTest, IsReadOnly) { - managed_platform_pref_store_->set_read_only(true); - extension_pref_store_->set_read_only(true); - command_line_pref_store_->set_read_only(true); - user_pref_store_->set_read_only(true); - recommended_pref_store_->set_read_only(true); - default_pref_store_->set_read_only(true); - EXPECT_TRUE(pref_value_store_->ReadOnly()); - - user_pref_store_->set_read_only(false); - EXPECT_FALSE(pref_value_store_->ReadOnly()); -} - TEST_F(PrefValueStoreTest, GetValue) { Value* value; @@ -378,8 +306,10 @@ TEST_F(PrefValueStoreTest, GetValue) { // Make sure that if a preference changes type, so the wrong type is stored in // the user pref file, it uses the correct fallback value instead. TEST_F(PrefValueStoreTest, GetValueChangedType) { + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(_)).Times(AnyNumber()); + // Check falling back to a recommended value. - user_pref_store_->prefs()->SetString(prefs::kStabilityLaunchCount, + user_pref_store_->SetString(prefs::kStabilityLaunchCount, "not an integer"); Value* value = NULL; ASSERT_TRUE(pref_value_store_->GetValue(prefs::kStabilityLaunchCount, @@ -391,14 +321,14 @@ TEST_F(PrefValueStoreTest, GetValueChangedType) { EXPECT_EQ(recommended_pref::kStabilityLaunchCountValue, actual_int_value); // Check falling back multiple times, to a default string. - managed_platform_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1); - device_management_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1); - extension_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1); - command_line_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1); - user_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1); - recommended_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1); - default_pref_store_->prefs()->SetString(prefs::kHomePage, - default_pref::kHomepageValue); + default_pref_store_->SetString(prefs::kHomePage, + default_pref::kHomepageValue); + managed_platform_pref_store_->SetInteger(prefs::kHomePage, 1); + device_management_pref_store_->SetInteger(prefs::kHomePage, 1); + extension_pref_store_->SetInteger(prefs::kHomePage, 1); + command_line_pref_store_->SetInteger(prefs::kHomePage, 1); + user_pref_store_->SetInteger(prefs::kHomePage, 1); + recommended_pref_store_->SetInteger(prefs::kHomePage, 1); value = NULL; ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomePage, &value)); @@ -427,109 +357,70 @@ TEST_F(PrefValueStoreTest, HasPrefPath) { EXPECT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref)); } -TEST_F(PrefValueStoreTest, PrefHasChanged) { +TEST_F(PrefValueStoreTest, PrefChanges) { // Setup. + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(_)).Times(AnyNumber()); const char managed_platform_pref_path[] = "managed_platform_pref"; pref_value_store_->RegisterPreferenceType(managed_platform_pref_path, Value::TYPE_STRING); - managed_platform_pref_store_->prefs()->SetString(managed_platform_pref_path, + managed_platform_pref_store_->SetString(managed_platform_pref_path, "managed value"); const char user_pref_path[] = "user_pref"; pref_value_store_->RegisterPreferenceType(user_pref_path, Value::TYPE_STRING); - user_pref_store_->prefs()->SetString(user_pref_path, "user value"); + user_pref_store_->SetString(user_pref_path, "user value"); const char default_pref_path[] = "default_pref"; pref_value_store_->RegisterPreferenceType(default_pref_path, Value::TYPE_STRING); - default_pref_store_->prefs()->SetString(default_pref_path, "default value"); + default_pref_store_->SetString(default_pref_path, "default value"); + Mock::VerifyAndClearExpectations(&pref_notifier_); // Check pref controlled by highest-priority store. - EXPECT_TRUE(pref_value_store_->PrefHasChanged(managed_platform_pref_path, - static_cast<PrefNotifier::PrefStoreType>(0))); - EXPECT_FALSE(pref_value_store_->PrefHasChanged(managed_platform_pref_path, - PrefNotifier::USER_STORE)); + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(managed_platform_pref_path)); + managed_platform_pref_store_->NotifyPrefValueChanged( + managed_platform_pref_path); + Mock::VerifyAndClearExpectations(&pref_notifier_); - // Check pref controlled by user store. - EXPECT_TRUE(pref_value_store_->PrefHasChanged(user_pref_path, - static_cast<PrefNotifier::PrefStoreType>(0))); - EXPECT_TRUE(pref_value_store_->PrefHasChanged(user_pref_path, - PrefNotifier::USER_STORE)); - EXPECT_FALSE(pref_value_store_->PrefHasChanged(user_pref_path, - PrefNotifier::PREF_STORE_TYPE_MAX)); - - // Check pref controlled by default-pref store. - EXPECT_TRUE(pref_value_store_->PrefHasChanged(default_pref_path, - PrefNotifier::USER_STORE)); - EXPECT_TRUE(pref_value_store_->PrefHasChanged(default_pref_path, - PrefNotifier::DEFAULT_STORE)); -} + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(_)).Times(0); + user_pref_store_->NotifyPrefValueChanged(managed_platform_pref_path); + Mock::VerifyAndClearExpectations(&pref_notifier_); -TEST_F(PrefValueStoreTest, ReadPrefs) { - pref_value_store_->ReadPrefs(); - // The ReadPrefs method of the |DummyPrefStore| deletes the |pref_store|s - // internal dictionary and creates a new empty dictionary. Hence this - // dictionary does not contain any of the preloaded preferences. - // This shows that the ReadPrefs method of the |DummyPrefStore| was called. - EXPECT_FALSE(pref_value_store_->HasPrefPath(prefs::kDeleteCache)); -} + // Check pref controlled by user store. + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(user_pref_path)); + managed_platform_pref_store_->NotifyPrefValueChanged(user_pref_path); + Mock::VerifyAndClearExpectations(&pref_notifier_); -TEST_F(PrefValueStoreTest, WritePrefs) { - user_pref_store_->set_prefs_written(false); - pref_value_store_->WritePrefs(); - ASSERT_TRUE(user_pref_store_->get_prefs_written()); -} + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(user_pref_path)); + user_pref_store_->NotifyPrefValueChanged(user_pref_path); + Mock::VerifyAndClearExpectations(&pref_notifier_); -TEST_F(PrefValueStoreTest, SetUserPrefValue) { - Value* new_value = NULL; - Value* actual_value = NULL; + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(_)).Times(0); + default_pref_store_->NotifyPrefValueChanged(user_pref_path); + Mock::VerifyAndClearExpectations(&pref_notifier_); - // Test that managed platform values can not be set. - ASSERT_TRUE(pref_value_store_->PrefValueInManagedPlatformStore( - prefs::kHomePage)); - // The Ownership is tranfered to |PrefValueStore|. - new_value = Value::CreateStringValue("http://www.youtube.com"); - pref_value_store_->SetUserPrefValue(prefs::kHomePage, new_value); + // Check pref controlled by default-pref store. + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(default_pref_path)); + user_pref_store_->NotifyPrefValueChanged(default_pref_path); + Mock::VerifyAndClearExpectations(&pref_notifier_); - ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomePage, &actual_value)); - std::string value_str; - actual_value->GetAsString(&value_str); - ASSERT_EQ(managed_platform_pref::kHomepageValue, value_str); + EXPECT_CALL(pref_notifier_, OnPreferenceChanged(default_pref_path)); + default_pref_store_->NotifyPrefValueChanged(default_pref_path); + Mock::VerifyAndClearExpectations(&pref_notifier_); +} - // User preferences values can be set - ASSERT_FALSE(pref_value_store_->PrefValueInManagedPlatformStore( - prefs::kStabilityLaunchCount)); - actual_value = NULL; - pref_value_store_->GetValue(prefs::kStabilityLaunchCount, &actual_value); - int int_value; - EXPECT_TRUE(actual_value->GetAsInteger(&int_value)); - EXPECT_EQ(user_pref::kStabilityLaunchCountValue, int_value); - - new_value = Value::CreateIntegerValue(1); - pref_value_store_->SetUserPrefValue(prefs::kStabilityLaunchCount, new_value); - actual_value = NULL; - pref_value_store_->GetValue(prefs::kStabilityLaunchCount, &actual_value); - EXPECT_TRUE(new_value->Equals(actual_value)); - - // Set and Get |DictionaryValue| - DictionaryValue* expected_dict_value = CreateSampleDictValue(); - pref_value_store_->SetUserPrefValue(prefs::kSampleDict, expected_dict_value); - - actual_value = NULL; - std::string key(prefs::kSampleDict); - pref_value_store_->GetValue(key, &actual_value); - - ASSERT_EQ(expected_dict_value, actual_value); - ASSERT_TRUE(expected_dict_value->Equals(actual_value)); - - // Set and Get a |ListValue| - ListValue* expected_list_value = CreateSampleListValue(); - pref_value_store_->SetUserPrefValue(prefs::kSampleList, expected_list_value); - - actual_value = NULL; - key = prefs::kSampleList; - pref_value_store_->GetValue(key, &actual_value); - - ASSERT_EQ(expected_list_value, actual_value); - ASSERT_TRUE(expected_list_value->Equals(actual_value)); +TEST_F(PrefValueStoreTest, OnInitializationCompleted) { + EXPECT_CALL(pref_notifier_, OnInitializationCompleted()).Times(0); + managed_platform_pref_store_->SetInitializationCompleted(); + device_management_pref_store_->SetInitializationCompleted(); + extension_pref_store_->SetInitializationCompleted(); + command_line_pref_store_->SetInitializationCompleted(); + recommended_pref_store_->SetInitializationCompleted(); + default_pref_store_->SetInitializationCompleted(); + Mock::VerifyAndClearExpectations(&pref_notifier_); + + // The notification should only be triggered after the last store is done. + EXPECT_CALL(pref_notifier_, OnInitializationCompleted()).Times(1); + user_pref_store_->SetInitializationCompleted(); + Mock::VerifyAndClearExpectations(&pref_notifier_); } TEST_F(PrefValueStoreTest, PrefValueInManagedPlatformStore) { @@ -633,18 +524,6 @@ TEST_F(PrefValueStoreTest, PrefValueInExtensionStore) { prefs::kMissingPref)); } -TEST_F(PrefValueStoreTest, DetectProxyConfigurationConflict) { - // There should be no conflicting proxy prefs in the default - // preference stores created for the test. - ASSERT_FALSE(pref_value_store_->HasPolicyConflictingUserProxySettings()); - - // Create conflicting proxy settings in the managed and command-line - // preference stores. - command_line_prefs_->SetBoolean(prefs::kProxyAutoDetect, false); - managed_platform_prefs_->SetBoolean(prefs::kProxyAutoDetect, true); - ASSERT_TRUE(pref_value_store_->HasPolicyConflictingUserProxySettings()); -} - TEST_F(PrefValueStoreTest, PrefValueInUserStore) { // Test a managed platform preference. ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomePage)); @@ -739,147 +618,3 @@ TEST_F(PrefValueStoreTest, PrefValueFromDefaultStore) { EXPECT_FALSE( pref_value_store_->PrefValueFromDefaultStore(prefs::kMissingPref)); } - -TEST_F(PrefValueStoreTest, TestPolicyRefresh) { - // pref_value_store_ is initialized by PrefValueStoreTest to have values in - // the managed platform, device management and recommended stores. By - // replacing them with dummy stores, all of the paths of the prefs originally - // in the managed platform, device management and recommended stores should - // change. - MockPolicyRefreshCallback callback; - EXPECT_CALL(callback, DoCallback(_)).Times(0); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - pref_value_store_.get(), - &PrefValueStore::RefreshPolicyPrefs, - NewCallback(&callback, - &MockPolicyRefreshCallback::DoCallback))); - Mock::VerifyAndClearExpectations(&callback); - EXPECT_CALL(callback, DoCallback(expected_differing_paths_)).Times(1); - loop_.RunAllPending(); -} - -TEST_F(PrefValueStoreTest, TestRefreshPolicyPrefsCompletion) { - // Test changed preferences in the managed platform store and removed - // preferences in the recommended store. In addition to "homepage", the other - // prefs that are set by default in the test class are removed by the - // DummyStore. - scoped_ptr<DummyPrefStore> new_managed_platform_store(new DummyPrefStore()); - DictionaryValue* dict = new DictionaryValue(); - dict->SetString("homepage", "some other changed homepage"); - new_managed_platform_store->set_prefs(dict); - MockPolicyRefreshCallback callback; - EXPECT_CALL(callback, DoCallback(expected_differing_paths_)).Times(1); - pref_value_store_->RefreshPolicyPrefsCompletion( - new_managed_platform_store.release(), - new DummyPrefStore(), - new DummyPrefStore(), - NewCallback(&callback, - &MockPolicyRefreshCallback::DoCallback)); - - // Test properties that have been removed from the managed platform store. - // Homepage is still set in managed prefs. - expected_differing_paths_.clear(); - expected_differing_paths_.push_back(std::string("homepage")); - MockPolicyRefreshCallback callback2; - EXPECT_CALL(callback2, DoCallback(expected_differing_paths_)).Times(1); - pref_value_store_->RefreshPolicyPrefsCompletion( - new DummyPrefStore(), - new DummyPrefStore(), - new DummyPrefStore(), - NewCallback(&callback2, - &MockPolicyRefreshCallback::DoCallback)); - - // Test properties that are added to the device management store. - expected_differing_paths_.clear(); - expected_differing_paths_.push_back(std::string("homepage")); - scoped_ptr<DummyPrefStore> new_device_management_store( - new DummyPrefStore()); - dict = new DictionaryValue(); - dict->SetString("homepage", "some other changed homepage"); - new_device_management_store->set_prefs(dict); - MockPolicyRefreshCallback callback3; - EXPECT_CALL(callback3, DoCallback(expected_differing_paths_)).Times(1); - pref_value_store_->RefreshPolicyPrefsCompletion( - new DummyPrefStore(), - new_device_management_store.release(), - new DummyPrefStore(), - NewCallback(&callback3, - &MockPolicyRefreshCallback::DoCallback)); - - // Test properties that are added to the recommended store. - scoped_ptr<DummyPrefStore> new_recommended_store(new DummyPrefStore()); - dict = new DictionaryValue(); - dict->SetString("homepage", "some other changed homepage 2"); - new_recommended_store->set_prefs(dict); - expected_differing_paths_.clear(); - expected_differing_paths_.push_back(std::string("homepage")); - MockPolicyRefreshCallback callback4; - EXPECT_CALL(callback4, DoCallback(expected_differing_paths_)).Times(1); - pref_value_store_->RefreshPolicyPrefsCompletion( - new DummyPrefStore(), - new DummyPrefStore(), - new_recommended_store.release(), - NewCallback(&callback4, - &MockPolicyRefreshCallback::DoCallback)); - - // Test adding a multi-key path. - new_managed_platform_store.reset(new DummyPrefStore()); - dict = new DictionaryValue(); - dict->SetString("segment1.segment2", "value"); - new_managed_platform_store->set_prefs(dict); - expected_differing_paths_.clear(); - expected_differing_paths_.push_back(std::string("homepage")); - expected_differing_paths_.push_back(std::string("segment1")); - expected_differing_paths_.push_back(std::string("segment1.segment2")); - MockPolicyRefreshCallback callback5; - EXPECT_CALL(callback5, DoCallback(expected_differing_paths_)).Times(1); - pref_value_store_->RefreshPolicyPrefsCompletion( - new_managed_platform_store.release(), - new DummyPrefStore(), - new DummyPrefStore(), - NewCallback(&callback5, - &MockPolicyRefreshCallback::DoCallback)); -} - -TEST_F(PrefValueStoreTest, TestConcurrentPolicyRefresh) { - MockPolicyRefreshCallback callback1; - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - pref_value_store_.get(), - &PrefValueStore::RefreshPolicyPrefs, - NewCallback(&callback1, - &MockPolicyRefreshCallback::DoCallback))); - EXPECT_CALL(callback1, DoCallback(_)).Times(0); - - MockPolicyRefreshCallback callback2; - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - pref_value_store_.get(), - &PrefValueStore::RefreshPolicyPrefs, - NewCallback(&callback2, - &MockPolicyRefreshCallback::DoCallback))); - EXPECT_CALL(callback2, DoCallback(_)).Times(0); - - MockPolicyRefreshCallback callback3; - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - pref_value_store_.get(), - &PrefValueStore::RefreshPolicyPrefs, - NewCallback(&callback3, - &MockPolicyRefreshCallback::DoCallback))); - EXPECT_CALL(callback3, DoCallback(_)).Times(0); - Mock::VerifyAndClearExpectations(&callback1); - Mock::VerifyAndClearExpectations(&callback2); - Mock::VerifyAndClearExpectations(&callback3); - - EXPECT_CALL(callback1, DoCallback(expected_differing_paths_)).Times(1); - std::vector<std::string> no_differing_paths; - EXPECT_CALL(callback2, DoCallback(no_differing_paths)).Times(1); - EXPECT_CALL(callback3, DoCallback(no_differing_paths)).Times(1); - loop_.RunAllPending(); -} diff --git a/chrome/browser/prefs/proxy_prefs.cc b/chrome/browser/prefs/proxy_prefs.cc new file mode 100644 index 0000000..7eb504c --- /dev/null +++ b/chrome/browser/prefs/proxy_prefs.cc @@ -0,0 +1,45 @@ +// 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 "chrome/browser/prefs/proxy_prefs.h" + +#include "base/basictypes.h" +#include "base/logging.h" + +namespace { + +// These names are exposed to the proxy extension API. They must be in sync +// with the constants of ProxyPrefs. +const char* kProxyModeNames[] = { "direct", + "auto_detect", + "pac_script", + "fixed_servers", + "system" }; + +} // namespace + +namespace ProxyPrefs { + +COMPILE_ASSERT(arraysize(kProxyModeNames) == kModeCount, + kProxyModeNames_must_have_size_of_NUM_MODES); + +bool IntToProxyMode(int in_value, ProxyMode* out_value) { + DCHECK(out_value); + if (in_value < 0 || in_value >= kModeCount) + return false; + *out_value = static_cast<ProxyMode>(in_value); + return true; +} + +// static +bool StringToProxyMode(const std::string& in_value, ProxyMode* out_value) { + DCHECK(out_value); + for (int i = 0; i < kModeCount; i++) { + if (in_value == kProxyModeNames[i]) + return IntToProxyMode(i, out_value); + } + return false; +} + +} // namespace diff --git a/chrome/browser/prefs/proxy_prefs.h b/chrome/browser/prefs/proxy_prefs.h new file mode 100644 index 0000000..bbeb44d --- /dev/null +++ b/chrome/browser/prefs/proxy_prefs.h @@ -0,0 +1,45 @@ +// 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 CHROME_BROWSER_PREFS_PROXY_PREFS_H_ +#define CHROME_BROWSER_PREFS_PROXY_PREFS_H_ +#pragma once + +#include <string> + +namespace ProxyPrefs { + +// Possible types of specifying proxy settings. Do not change the order of +// the constants, because numeric values are exposed to users. +// If you add an enum constant, you should also add a string to +// kProxyModeNames in the .cc file. +enum ProxyMode { + // Direct connection to the network, other proxy preferences are ignored. + MODE_DIRECT = 0, + + // Try to retrieve a PAC script from http://wpad/wpad.dat or fall back to + // direct connection. + MODE_AUTO_DETECT = 1, + + // Try to retrieve a PAC script from kProxyPacURL or fall back to direct + // connection. + MODE_PAC_SCRIPT = 2, + + // Use the settings specified in kProxyServer and kProxyBypassList. + MODE_FIXED_SERVERS = 3, + + // The system's proxy settings are used, other proxy preferences are + // ignored. + MODE_SYSTEM = 4, + + kModeCount +}; + +bool IntToProxyMode(int in_value, ProxyMode* out_value); +bool StringToProxyMode(const std::string& in_value, + ProxyMode* out_value); + +} // namespace ProxyPrefs + +#endif // CHROME_BROWSER_PREFS_PROXY_PREFS_H_ diff --git a/chrome/browser/prefs/proxy_prefs_unittest.cc b/chrome/browser/prefs/proxy_prefs_unittest.cc new file mode 100644 index 0000000..72aa0f1 --- /dev/null +++ b/chrome/browser/prefs/proxy_prefs_unittest.cc @@ -0,0 +1,52 @@ +// 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 <string> + +#include "base/logging.h" +#include "base/values.h" +#include "base/version.h" +#include "chrome/browser/prefs/proxy_prefs.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(ProxyPrefsTest, StringToProxyMode) { + ProxyPrefs::ProxyMode mode; + EXPECT_TRUE(ProxyPrefs::StringToProxyMode("direct", &mode)); + EXPECT_EQ(ProxyPrefs::MODE_DIRECT, mode); + EXPECT_TRUE(ProxyPrefs::StringToProxyMode("auto_detect", &mode)); + EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, mode); + EXPECT_TRUE(ProxyPrefs::StringToProxyMode("pac_script", &mode)); + EXPECT_EQ(ProxyPrefs::MODE_PAC_SCRIPT, mode); + EXPECT_TRUE(ProxyPrefs::StringToProxyMode("system", &mode)); + EXPECT_EQ(ProxyPrefs::MODE_SYSTEM, mode); + EXPECT_TRUE(ProxyPrefs::StringToProxyMode("fixed_servers", &mode)); + EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, mode); + + EXPECT_FALSE(ProxyPrefs::StringToProxyMode("monkey", &mode)); +} + +TEST(ProxyPrefsTest, IntToProxyMode) { + ASSERT_EQ(ProxyPrefs::MODE_DIRECT, 0); + ASSERT_EQ(ProxyPrefs::MODE_AUTO_DETECT, 1); + ASSERT_EQ(ProxyPrefs::MODE_PAC_SCRIPT, 2); + ASSERT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, 3); + ASSERT_EQ(ProxyPrefs::MODE_SYSTEM, 4); + // Update the following as necessary, don't change the previous ones. + ASSERT_EQ(ProxyPrefs::kModeCount, 5); + + ProxyPrefs::ProxyMode mode; + EXPECT_TRUE(ProxyPrefs::IntToProxyMode(0, &mode)); + EXPECT_EQ(ProxyPrefs::MODE_DIRECT, mode); + EXPECT_TRUE(ProxyPrefs::IntToProxyMode(1, &mode)); + EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, mode); + EXPECT_TRUE(ProxyPrefs::IntToProxyMode(2, &mode)); + EXPECT_EQ(ProxyPrefs::MODE_PAC_SCRIPT, mode); + EXPECT_TRUE(ProxyPrefs::IntToProxyMode(3, &mode)); + EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, mode); + EXPECT_TRUE(ProxyPrefs::IntToProxyMode(4, &mode)); + EXPECT_EQ(ProxyPrefs::MODE_SYSTEM, mode); + + EXPECT_FALSE(ProxyPrefs::IntToProxyMode(-1, &mode)); + EXPECT_FALSE(ProxyPrefs::IntToProxyMode(ProxyPrefs::kModeCount, &mode)); +} diff --git a/chrome/browser/prefs/scoped_pref_update.cc b/chrome/browser/prefs/scoped_pref_update.cc index bc77b28..024d71b 100644 --- a/chrome/browser/prefs/scoped_pref_update.cc +++ b/chrome/browser/prefs/scoped_pref_update.cc @@ -4,6 +4,7 @@ #include "chrome/browser/prefs/scoped_pref_update.h" +#include "chrome/browser/prefs/pref_notifier.h" #include "chrome/browser/prefs/pref_service.h" ScopedPrefUpdate::ScopedPrefUpdate(PrefService* service, const char* path) @@ -11,5 +12,8 @@ ScopedPrefUpdate::ScopedPrefUpdate(PrefService* service, const char* path) path_(path) {} ScopedPrefUpdate::~ScopedPrefUpdate() { - service_->pref_notifier()->FireObservers(path_.c_str()); + // TODO(mnissler, danno): This sends a notification unconditionally, which is + // wrong. We should rather tell the PrefService that the user pref got + // updated. + service_->pref_notifier()->OnPreferenceChanged(path_.c_str()); } diff --git a/chrome/browser/prefs/session_startup_pref.cc b/chrome/browser/prefs/session_startup_pref.cc index 188bb4c..b339e1d 100644 --- a/chrome/browser/prefs/session_startup_pref.cc +++ b/chrome/browser/prefs/session_startup_pref.cc @@ -12,7 +12,7 @@ #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/scoped_pref_update.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" namespace { diff --git a/chrome/browser/prefs/testing_pref_store.cc b/chrome/browser/prefs/testing_pref_store.cc new file mode 100644 index 0000000..39c20f2 --- /dev/null +++ b/chrome/browser/prefs/testing_pref_store.cc @@ -0,0 +1,100 @@ +// 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 "chrome/browser/prefs/testing_pref_store.h" + +#include "base/values.h" + +TestingPrefStore::TestingPrefStore() + : read_only_(true), + prefs_written_(false), + init_complete_(false) { } + +PrefStore::ReadResult TestingPrefStore::GetValue(const std::string& key, + Value** value) const { + 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); +} + +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); +} + +PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() { + prefs_.Clear(); + return PersistentPrefStore::PREF_READ_ERROR_NONE; +} + +bool TestingPrefStore::WritePrefs() { + prefs_written_ = true; + return prefs_written_; +} + +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()); +} + +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 { + 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 { + 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 { + Value* stored_value; + if (!prefs_.GetValue(key, &stored_value) || !stored_value) + return false; + + return stored_value->GetAsBoolean(value); +} diff --git a/chrome/browser/prefs/testing_pref_store.h b/chrome/browser/prefs/testing_pref_store.h new file mode 100644 index 0000000..555ee69 --- /dev/null +++ b/chrome/browser/prefs/testing_pref_store.h @@ -0,0 +1,80 @@ +// 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 CHROME_BROWSER_PREFS_TESTING_PREF_STORE_H_ +#define CHROME_BROWSER_PREFS_TESTING_PREF_STORE_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/observer_list.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/prefs/pref_value_map.h" +#include "chrome/common/persistent_pref_store.h" + +class DictionaryValue; + +// |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(); + virtual ~TestingPrefStore() {} + + // Overriden from PrefStore. + virtual ReadResult GetValue(const std::string& key, Value** result) const; + virtual void AddObserver(PrefStore::Observer* observer); + virtual void RemoveObserver(PrefStore::Observer* observer); + virtual bool IsInitializationComplete() const { return init_complete_; } + + // PersistentPrefStore overrides: + virtual void SetValue(const std::string& key, Value* value); + virtual void SetValueSilently(const std::string& key, Value* value); + virtual void RemoveValue(const std::string& key); + virtual bool ReadOnly() const { return read_only_; } + virtual PersistentPrefStore::PrefReadError ReadPrefs(); + virtual bool WritePrefs(); + virtual void ScheduleWritePrefs() {} + + // 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) { read_only_ = read_only; } + virtual void set_prefs_written(bool status) { prefs_written_ = status; } + virtual bool get_prefs_written() { return prefs_written_; } + + private: + // Stores the preference values. + PrefValueMap prefs_; + + // Flag that indicates if the PrefStore is read-only + bool read_only_; + + // Flag that indicates if the method WritePrefs was called. + bool prefs_written_; + + // Whether initialization has been completed. + bool init_complete_; + + ObserverList<PrefStore::Observer, true> observers_; + + DISALLOW_COPY_AND_ASSIGN(TestingPrefStore); +}; + +#endif // CHROME_BROWSER_PREFS_TESTING_PREF_STORE_H_ diff --git a/chrome/browser/prefs/value_map_pref_store.cc b/chrome/browser/prefs/value_map_pref_store.cc new file mode 100644 index 0000000..705c958 --- /dev/null +++ b/chrome/browser/prefs/value_map_pref_store.cc @@ -0,0 +1,41 @@ +// 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 "chrome/browser/prefs/value_map_pref_store.h" + +#include <algorithm> + +#include "base/stl_util-inl.h" +#include "base/values.h" + +ValueMapPrefStore::ValueMapPrefStore() {} + +ValueMapPrefStore::~ValueMapPrefStore() {} + +PrefStore::ReadResult ValueMapPrefStore::GetValue(const std::string& key, + 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); +} + +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()); +} diff --git a/chrome/browser/prefs/value_map_pref_store.h b/chrome/browser/prefs/value_map_pref_store.h new file mode 100644 index 0000000..20bf290 --- /dev/null +++ b/chrome/browser/prefs/value_map_pref_store.h @@ -0,0 +1,48 @@ +// 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 CHROME_BROWSER_PREFS_VALUE_MAP_PREF_STORE_H_ +#define CHROME_BROWSER_PREFS_VALUE_MAP_PREF_STORE_H_ +#pragma once + +#include <map> + +#include "base/basictypes.h" +#include "base/observer_list.h" +#include "chrome/browser/prefs/pref_value_map.h" +#include "chrome/common/pref_store.h" + +// A basic PrefStore implementation that uses a simple name-value map for +// storing the preference values. +class ValueMapPrefStore : public PrefStore { + public: + ValueMapPrefStore(); + virtual ~ValueMapPrefStore(); + + // PrefStore overrides: + virtual ReadResult GetValue(const std::string& key, Value** value) const; + virtual void AddObserver(PrefStore::Observer* observer); + virtual void RemoveObserver(PrefStore::Observer* observer); + + protected: + // 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, 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 // CHROME_BROWSER_PREFS_VALUE_MAP_PREF_STORE_H_ |