| // 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 <stddef.h> | 
 | #include <stdint.h> | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "base/macros.h" | 
 | #include "base/time/time.h" | 
 | #include "base/values.h" | 
 | #include "components/prefs/json_pref_store.h" | 
 | #include "components/prefs/mock_pref_change_callback.h" | 
 | #include "components/prefs/pref_change_registrar.h" | 
 | #include "components/prefs/pref_registry_simple.h" | 
 | #include "components/prefs/pref_service_factory.h" | 
 | #include "components/prefs/pref_value_store.h" | 
 | #include "components/prefs/testing_pref_service.h" | 
 | #include "components/prefs/testing_pref_store.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::Value 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::Value 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, | 
 |                     std::make_unique<base::Value>("http://www.cnn.com")); | 
 |   prefs.registry()->RegisterStringPref(pref_name, std::string()); | 
 |  | 
 |   const char new_pref_value[] = "http://www.google.com/"; | 
 |   const base::Value 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::Value 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::Value 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.CreateDeepCopy()); | 
 |   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, std::make_unique<base::Value>("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->type()); | 
 |   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->type()); | 
 |   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, std::make_unique<base::Value>(kUserValue)); | 
 |  | 
 |   // Check that GetValue() returns the user-set value. | 
 |   value = pref->GetValue(); | 
 |   ASSERT_TRUE(value); | 
 |   EXPECT_EQ(base::Value::Type::INTEGER, value->type()); | 
 |   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, | 
 |                            std::make_unique<base::Value>(kRecommendedValue)); | 
 |  | 
 |   // Check that GetValue() returns the user-set value. | 
 |   value = pref->GetValue(); | 
 |   ASSERT_TRUE(value); | 
 |   EXPECT_EQ(base::Value::Type::INTEGER, value->type()); | 
 |   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->type()); | 
 |   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->type()); | 
 |   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->type()); | 
 |   actual_int_value = -1; | 
 |   EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); | 
 |   EXPECT_EQ(kRecommendedValue, actual_int_value); | 
 | } | 
 |  | 
 | TEST(PrefServiceTest, SetTimeValue_RegularTime) { | 
 |   TestingPrefServiceSimple prefs; | 
 |  | 
 |   // Register a null time as the default. | 
 |   prefs.registry()->RegisterTimePref(kPrefName, base::Time()); | 
 |   EXPECT_TRUE(prefs.GetTime(kPrefName).is_null()); | 
 |  | 
 |   // Set a time and make sure that we can read it without any loss of precision. | 
 |   const base::Time time = base::Time::Now(); | 
 |   prefs.SetTime(kPrefName, time); | 
 |   EXPECT_EQ(time, prefs.GetTime(kPrefName)); | 
 | } | 
 |  | 
 | TEST(PrefServiceTest, SetTimeValue_NullTime) { | 
 |   TestingPrefServiceSimple prefs; | 
 |  | 
 |   // Register a non-null time as the default. | 
 |   const base::Time default_time = base::Time::FromDeltaSinceWindowsEpoch( | 
 |       base::TimeDelta::FromMicroseconds(12345)); | 
 |   prefs.registry()->RegisterTimePref(kPrefName, default_time); | 
 |   EXPECT_FALSE(prefs.GetTime(kPrefName).is_null()); | 
 |  | 
 |   // Set a null time and make sure that it remains null upon deserialization. | 
 |   prefs.SetTime(kPrefName, base::Time()); | 
 |   EXPECT_TRUE(prefs.GetTime(kPrefName).is_null()); | 
 | } | 
 |  | 
 | // 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_t flags) override { | 
 |     SetLastWriteFlags(flags); | 
 |   } | 
 |  | 
 |   void SetValue(const std::string& key, | 
 |                 std::unique_ptr<base::Value> value, | 
 |                 uint32_t flags) override { | 
 |     SetLastWriteFlags(flags); | 
 |   } | 
 |  | 
 |   void SetValueSilently(const std::string& key, | 
 |                         std::unique_ptr<base::Value> value, | 
 |                         uint32_t flags) override { | 
 |     SetLastWriteFlags(flags); | 
 |   } | 
 |  | 
 |   void RemoveValue(const std::string& key, uint32_t flags) override { | 
 |     SetLastWriteFlags(flags); | 
 |   } | 
 |  | 
 |   uint32_t GetLastFlagsAndClear() { | 
 |     CHECK(last_write_flags_set_); | 
 |     uint32_t 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_t flags) { | 
 |     CHECK(!last_write_flags_set_); | 
 |     last_write_flags_set_ = true; | 
 |     last_write_flags_ = flags; | 
 |   } | 
 |  | 
 |   bool last_write_flags_set_ = false; | 
 |   uint32_t last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS; | 
 | }; | 
 |  | 
 | TEST(PrefServiceTest, WriteablePrefStoreFlags) { | 
 |   scoped_refptr<WriteFlagChecker> flag_checker(new WriteFlagChecker); | 
 |   scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple); | 
 |   PrefServiceFactory factory; | 
 |   factory.set_user_prefs(flag_checker); | 
 |   std::unique_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_t 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_t registration_flags; | 
 |     uint32_t 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, | 
 |                                      std::make_unique<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, | 
 |                             std::make_unique<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::Value 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::Value 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.AppendString(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_); | 
 | } |