|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <string> | 
|  |  | 
|  | #include "base/prefs/json_pref_store.h" | 
|  | #include "base/prefs/mock_pref_change_callback.h" | 
|  | #include "base/prefs/pref_change_registrar.h" | 
|  | #include "base/prefs/pref_registry_simple.h" | 
|  | #include "base/prefs/pref_service_factory.h" | 
|  | #include "base/prefs/pref_value_store.h" | 
|  | #include "base/prefs/testing_pref_service.h" | 
|  | #include "base/prefs/testing_pref_store.h" | 
|  | #include "base/values.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | using testing::_; | 
|  | using testing::Mock; | 
|  |  | 
|  | const char kPrefName[] = "pref.name"; | 
|  |  | 
|  | TEST(PrefServiceTest, NoObserverFire) { | 
|  | TestingPrefServiceSimple prefs; | 
|  |  | 
|  | const char pref_name[] = "homepage"; | 
|  | prefs.registry()->RegisterStringPref(pref_name, std::string()); | 
|  |  | 
|  | const char new_pref_value[] = "http://www.google.com/"; | 
|  | MockPrefChangeCallback obs(&prefs); | 
|  | PrefChangeRegistrar registrar; | 
|  | registrar.Init(&prefs); | 
|  | registrar.Add(pref_name, obs.GetCallback()); | 
|  |  | 
|  | // This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged. | 
|  | const base::StringValue expected_value(new_pref_value); | 
|  | obs.Expect(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. | 
|  | EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0); | 
|  | prefs.SetString(pref_name, new_pref_value); | 
|  | Mock::VerifyAndClearExpectations(&obs); | 
|  |  | 
|  | // Clearing the pref should cause the pref to fire. | 
|  | const base::StringValue expected_default_value((std::string())); | 
|  | obs.Expect(pref_name, &expected_default_value); | 
|  | prefs.ClearPref(pref_name); | 
|  | Mock::VerifyAndClearExpectations(&obs); | 
|  |  | 
|  | // Clearing the pref again should not cause the pref to fire. | 
|  | EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0); | 
|  | prefs.ClearPref(pref_name); | 
|  | Mock::VerifyAndClearExpectations(&obs); | 
|  | } | 
|  |  | 
|  | TEST(PrefServiceTest, HasPrefPath) { | 
|  | TestingPrefServiceSimple prefs; | 
|  |  | 
|  | const char path[] = "fake.path"; | 
|  |  | 
|  | // Shouldn't initially have a path. | 
|  | EXPECT_FALSE(prefs.HasPrefPath(path)); | 
|  |  | 
|  | // Register the path. This doesn't set a value, so the path still shouldn't | 
|  | // exist. | 
|  | prefs.registry()->RegisterStringPref(path, std::string()); | 
|  | EXPECT_FALSE(prefs.HasPrefPath(path)); | 
|  |  | 
|  | // Set a value and make sure we have a path. | 
|  | prefs.SetString(path, "blah"); | 
|  | EXPECT_TRUE(prefs.HasPrefPath(path)); | 
|  | } | 
|  |  | 
|  | TEST(PrefServiceTest, Observers) { | 
|  | const char pref_name[] = "homepage"; | 
|  |  | 
|  | TestingPrefServiceSimple prefs; | 
|  | prefs.SetUserPref(pref_name, | 
|  | new base::StringValue("http://www.cnn.com")); | 
|  | prefs.registry()->RegisterStringPref(pref_name, std::string()); | 
|  |  | 
|  | const char new_pref_value[] = "http://www.google.com/"; | 
|  | const base::StringValue expected_new_pref_value(new_pref_value); | 
|  | MockPrefChangeCallback obs(&prefs); | 
|  | PrefChangeRegistrar registrar; | 
|  | registrar.Init(&prefs); | 
|  | registrar.Add(pref_name, obs.GetCallback()); | 
|  |  | 
|  | PrefChangeRegistrar registrar_two; | 
|  | registrar_two.Init(&prefs); | 
|  |  | 
|  | // This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged. | 
|  | obs.Expect(pref_name, &expected_new_pref_value); | 
|  | prefs.SetString(pref_name, new_pref_value); | 
|  | Mock::VerifyAndClearExpectations(&obs); | 
|  |  | 
|  | // Now try adding a second pref observer. | 
|  | const char new_pref_value2[] = "http://www.youtube.com/"; | 
|  | const base::StringValue expected_new_pref_value2(new_pref_value2); | 
|  | MockPrefChangeCallback obs2(&prefs); | 
|  | obs.Expect(pref_name, &expected_new_pref_value2); | 
|  | obs2.Expect(pref_name, &expected_new_pref_value2); | 
|  | registrar_two.Add(pref_name, obs2.GetCallback()); | 
|  | // This should fire the checks in obs and obs2. | 
|  | prefs.SetString(pref_name, new_pref_value2); | 
|  | Mock::VerifyAndClearExpectations(&obs); | 
|  | Mock::VerifyAndClearExpectations(&obs2); | 
|  |  | 
|  | // Set a recommended value. | 
|  | const base::StringValue recommended_pref_value("http://www.gmail.com/"); | 
|  | obs.Expect(pref_name, &expected_new_pref_value2); | 
|  | obs2.Expect(pref_name, &expected_new_pref_value2); | 
|  | // This should fire the checks in obs and obs2 but with an unchanged value | 
|  | // as the recommended value is being overridden by the user-set value. | 
|  | prefs.SetRecommendedPref(pref_name, recommended_pref_value.DeepCopy()); | 
|  | Mock::VerifyAndClearExpectations(&obs); | 
|  | Mock::VerifyAndClearExpectations(&obs2); | 
|  |  | 
|  | // Make sure obs2 still works after removing obs. | 
|  | registrar.Remove(pref_name); | 
|  | EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0); | 
|  | obs2.Expect(pref_name, &expected_new_pref_value); | 
|  | // This should only fire the observer in obs2. | 
|  | prefs.SetString(pref_name, new_pref_value); | 
|  | Mock::VerifyAndClearExpectations(&obs); | 
|  | Mock::VerifyAndClearExpectations(&obs2); | 
|  | } | 
|  |  | 
|  | // 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(PrefServiceTest, GetValueChangedType) { | 
|  | const int kTestValue = 10; | 
|  | TestingPrefServiceSimple prefs; | 
|  | prefs.registry()->RegisterIntegerPref(kPrefName, kTestValue); | 
|  |  | 
|  | // Check falling back to a recommended value. | 
|  | prefs.SetUserPref(kPrefName, | 
|  | new base::StringValue("not an integer")); | 
|  | const PrefService::Preference* pref = prefs.FindPreference(kPrefName); | 
|  | ASSERT_TRUE(pref); | 
|  | const base::Value* value = pref->GetValue(); | 
|  | ASSERT_TRUE(value); | 
|  | EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); | 
|  | int actual_int_value = -1; | 
|  | EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); | 
|  | EXPECT_EQ(kTestValue, actual_int_value); | 
|  | } | 
|  |  | 
|  | TEST(PrefServiceTest, GetValueAndGetRecommendedValue) { | 
|  | const int kDefaultValue = 5; | 
|  | const int kUserValue = 10; | 
|  | const int kRecommendedValue = 15; | 
|  | TestingPrefServiceSimple prefs; | 
|  | prefs.registry()->RegisterIntegerPref(kPrefName, kDefaultValue); | 
|  |  | 
|  | // Create pref with a default value only. | 
|  | const PrefService::Preference* pref = prefs.FindPreference(kPrefName); | 
|  | ASSERT_TRUE(pref); | 
|  |  | 
|  | // Check that GetValue() returns the default value. | 
|  | const base::Value* value = pref->GetValue(); | 
|  | ASSERT_TRUE(value); | 
|  | EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); | 
|  | int actual_int_value = -1; | 
|  | EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); | 
|  | EXPECT_EQ(kDefaultValue, actual_int_value); | 
|  |  | 
|  | // Check that GetRecommendedValue() returns no value. | 
|  | value = pref->GetRecommendedValue(); | 
|  | ASSERT_FALSE(value); | 
|  |  | 
|  | // Set a user-set value. | 
|  | prefs.SetUserPref(kPrefName, new base::FundamentalValue(kUserValue)); | 
|  |  | 
|  | // Check that GetValue() returns the user-set value. | 
|  | value = pref->GetValue(); | 
|  | ASSERT_TRUE(value); | 
|  | EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); | 
|  | actual_int_value = -1; | 
|  | EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); | 
|  | EXPECT_EQ(kUserValue, actual_int_value); | 
|  |  | 
|  | // Check that GetRecommendedValue() returns no value. | 
|  | value = pref->GetRecommendedValue(); | 
|  | ASSERT_FALSE(value); | 
|  |  | 
|  | // Set a recommended value. | 
|  | prefs.SetRecommendedPref(kPrefName, | 
|  | new base::FundamentalValue(kRecommendedValue)); | 
|  |  | 
|  | // Check that GetValue() returns the user-set value. | 
|  | value = pref->GetValue(); | 
|  | ASSERT_TRUE(value); | 
|  | EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); | 
|  | actual_int_value = -1; | 
|  | EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); | 
|  | EXPECT_EQ(kUserValue, actual_int_value); | 
|  |  | 
|  | // Check that GetRecommendedValue() returns the recommended value. | 
|  | value = pref->GetRecommendedValue(); | 
|  | ASSERT_TRUE(value); | 
|  | EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); | 
|  | actual_int_value = -1; | 
|  | EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); | 
|  | EXPECT_EQ(kRecommendedValue, actual_int_value); | 
|  |  | 
|  | // Remove the user-set value. | 
|  | prefs.RemoveUserPref(kPrefName); | 
|  |  | 
|  | // Check that GetValue() returns the recommended value. | 
|  | value = pref->GetValue(); | 
|  | ASSERT_TRUE(value); | 
|  | EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); | 
|  | actual_int_value = -1; | 
|  | EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); | 
|  | EXPECT_EQ(kRecommendedValue, actual_int_value); | 
|  |  | 
|  | // Check that GetRecommendedValue() returns the recommended value. | 
|  | value = pref->GetRecommendedValue(); | 
|  | ASSERT_TRUE(value); | 
|  | EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); | 
|  | actual_int_value = -1; | 
|  | EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); | 
|  | EXPECT_EQ(kRecommendedValue, actual_int_value); | 
|  | } | 
|  |  | 
|  | // A PrefStore which just stores the last write flags that were used to write | 
|  | // values to it. | 
|  | class WriteFlagChecker : public TestingPrefStore { | 
|  | public: | 
|  | WriteFlagChecker() {} | 
|  |  | 
|  | void ReportValueChanged(const std::string& key, uint32 flags) override { | 
|  | SetLastWriteFlags(flags); | 
|  | } | 
|  |  | 
|  | void SetValue(const std::string& key, | 
|  | base::Value* value, | 
|  | uint32 flags) override { | 
|  | SetLastWriteFlags(flags); | 
|  | delete value; | 
|  | } | 
|  |  | 
|  | void SetValueSilently(const std::string& key, | 
|  | base::Value* value, | 
|  | uint32 flags) override { | 
|  | SetLastWriteFlags(flags); | 
|  | delete value; | 
|  | } | 
|  |  | 
|  | void RemoveValue(const std::string& key, uint32 flags) override { | 
|  | SetLastWriteFlags(flags); | 
|  | } | 
|  |  | 
|  | uint32 GetLastFlagsAndClear() { | 
|  | CHECK(last_write_flags_set_); | 
|  | uint32 result = last_write_flags_; | 
|  | last_write_flags_set_ = false; | 
|  | last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | bool last_write_flags_set() { return last_write_flags_set_; } | 
|  |  | 
|  | private: | 
|  | ~WriteFlagChecker() override {} | 
|  |  | 
|  | void SetLastWriteFlags(uint32 flags) { | 
|  | CHECK(!last_write_flags_set_); | 
|  | last_write_flags_set_ = true; | 
|  | last_write_flags_ = flags; | 
|  | } | 
|  |  | 
|  | bool last_write_flags_set_ = false; | 
|  | uint32 last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS; | 
|  | }; | 
|  |  | 
|  | TEST(PrefServiceTest, WriteablePrefStoreFlags) { | 
|  | scoped_refptr<WriteFlagChecker> flag_checker(new WriteFlagChecker); | 
|  | scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple); | 
|  | base::PrefServiceFactory factory; | 
|  | factory.set_user_prefs(flag_checker); | 
|  | scoped_ptr<PrefService> prefs(factory.Create(registry.get())); | 
|  |  | 
|  | // The first 8 bits of write flags are reserved for subclasses. Create a | 
|  | // custom flag in this range | 
|  | uint32 kCustomRegistrationFlag = 1 << 2; | 
|  |  | 
|  | // A map of the registration flags that will be tested and the write flags | 
|  | // they are expected to convert to. | 
|  | struct RegistrationToWriteFlags { | 
|  | const char* pref_name; | 
|  | uint32 registration_flags; | 
|  | uint32 write_flags; | 
|  | }; | 
|  | const RegistrationToWriteFlags kRegistrationToWriteFlags[] = { | 
|  | {"none", | 
|  | PrefRegistry::NO_REGISTRATION_FLAGS, | 
|  | WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS}, | 
|  | {"lossy", | 
|  | PrefRegistry::LOSSY_PREF, | 
|  | WriteablePrefStore::LOSSY_PREF_WRITE_FLAG}, | 
|  | {"custom", | 
|  | kCustomRegistrationFlag, | 
|  | WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS}, | 
|  | {"lossyandcustom", | 
|  | PrefRegistry::LOSSY_PREF | kCustomRegistrationFlag, | 
|  | WriteablePrefStore::LOSSY_PREF_WRITE_FLAG}}; | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(kRegistrationToWriteFlags); ++i) { | 
|  | RegistrationToWriteFlags entry = kRegistrationToWriteFlags[i]; | 
|  | registry->RegisterDictionaryPref( | 
|  | entry.pref_name, new base::DictionaryValue(), entry.registration_flags); | 
|  |  | 
|  | SCOPED_TRACE("Currently testing pref with name: " + | 
|  | std::string(entry.pref_name)); | 
|  |  | 
|  | prefs->GetMutableUserPref(entry.pref_name, base::Value::TYPE_DICTIONARY); | 
|  | EXPECT_TRUE(flag_checker->last_write_flags_set()); | 
|  | EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear()); | 
|  |  | 
|  | prefs->ReportUserPrefChanged(entry.pref_name); | 
|  | EXPECT_TRUE(flag_checker->last_write_flags_set()); | 
|  | EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear()); | 
|  |  | 
|  | prefs->ClearPref(entry.pref_name); | 
|  | EXPECT_TRUE(flag_checker->last_write_flags_set()); | 
|  | EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear()); | 
|  |  | 
|  | prefs->SetUserPrefValue(entry.pref_name, new base::DictionaryValue()); | 
|  | EXPECT_TRUE(flag_checker->last_write_flags_set()); | 
|  | EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear()); | 
|  | } | 
|  | } | 
|  |  | 
|  | class PrefServiceSetValueTest : public testing::Test { | 
|  | protected: | 
|  | static const char kName[]; | 
|  | static const char kValue[]; | 
|  |  | 
|  | PrefServiceSetValueTest() : observer_(&prefs_) {} | 
|  |  | 
|  | TestingPrefServiceSimple prefs_; | 
|  | MockPrefChangeCallback observer_; | 
|  | }; | 
|  |  | 
|  | const char PrefServiceSetValueTest::kName[] = "name"; | 
|  | const char PrefServiceSetValueTest::kValue[] = "value"; | 
|  |  | 
|  | TEST_F(PrefServiceSetValueTest, SetStringValue) { | 
|  | const char default_string[] = "default"; | 
|  | const base::StringValue default_value(default_string); | 
|  | prefs_.registry()->RegisterStringPref(kName, default_string); | 
|  |  | 
|  | PrefChangeRegistrar registrar; | 
|  | registrar.Init(&prefs_); | 
|  | registrar.Add(kName, observer_.GetCallback()); | 
|  |  | 
|  | // Changing the controlling store from default to user triggers notification. | 
|  | observer_.Expect(kName, &default_value); | 
|  | prefs_.Set(kName, default_value); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  |  | 
|  | EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); | 
|  | prefs_.Set(kName, default_value); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  |  | 
|  | base::StringValue new_value(kValue); | 
|  | observer_.Expect(kName, &new_value); | 
|  | prefs_.Set(kName, new_value); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  | } | 
|  |  | 
|  | TEST_F(PrefServiceSetValueTest, SetDictionaryValue) { | 
|  | prefs_.registry()->RegisterDictionaryPref(kName); | 
|  | PrefChangeRegistrar registrar; | 
|  | registrar.Init(&prefs_); | 
|  | registrar.Add(kName, observer_.GetCallback()); | 
|  |  | 
|  | EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); | 
|  | prefs_.RemoveUserPref(kName); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  |  | 
|  | base::DictionaryValue new_value; | 
|  | new_value.SetString(kName, kValue); | 
|  | observer_.Expect(kName, &new_value); | 
|  | prefs_.Set(kName, new_value); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  |  | 
|  | EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); | 
|  | prefs_.Set(kName, new_value); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  |  | 
|  | base::DictionaryValue empty; | 
|  | observer_.Expect(kName, &empty); | 
|  | prefs_.Set(kName, empty); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  | } | 
|  |  | 
|  | TEST_F(PrefServiceSetValueTest, SetListValue) { | 
|  | prefs_.registry()->RegisterListPref(kName); | 
|  | PrefChangeRegistrar registrar; | 
|  | registrar.Init(&prefs_); | 
|  | registrar.Add(kName, observer_.GetCallback()); | 
|  |  | 
|  | EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); | 
|  | prefs_.RemoveUserPref(kName); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  |  | 
|  | base::ListValue new_value; | 
|  | new_value.Append(new base::StringValue(kValue)); | 
|  | observer_.Expect(kName, &new_value); | 
|  | prefs_.Set(kName, new_value); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  |  | 
|  | EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); | 
|  | prefs_.Set(kName, new_value); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  |  | 
|  | base::ListValue empty; | 
|  | observer_.Expect(kName, &empty); | 
|  | prefs_.Set(kName, empty); | 
|  | Mock::VerifyAndClearExpectations(&observer_); | 
|  | } |