| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/prefs/pref_member.h" |
| |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/sequenced_task_runner.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/task/post_task.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/testing_pref_service.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| const char kBoolPref[] = "bool"; |
| const char kIntPref[] = "int"; |
| const char kDoublePref[] = "double"; |
| const char kStringPref[] = "string"; |
| const char kStringListPref[] = "string_list"; |
| |
| void RegisterTestPrefs(PrefRegistrySimple* registry) { |
| registry->RegisterBooleanPref(kBoolPref, false); |
| registry->RegisterIntegerPref(kIntPref, 0); |
| registry->RegisterDoublePref(kDoublePref, 0.0); |
| registry->RegisterStringPref(kStringPref, "default"); |
| registry->RegisterListPref(kStringListPref); |
| } |
| |
| class GetPrefValueHelper |
| : public base::RefCountedThreadSafe<GetPrefValueHelper> { |
| public: |
| GetPrefValueHelper() |
| : value_(false), task_runner_(base::CreateSequencedTaskRunner({})) {} |
| |
| void Init(const std::string& pref_name, PrefService* prefs) { |
| pref_.Init(pref_name, prefs); |
| pref_.MoveToSequence(task_runner_); |
| } |
| |
| void Destroy() { |
| pref_.Destroy(); |
| } |
| |
| void FetchValue() { |
| base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| ASSERT_TRUE(task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GetPrefValueHelper::GetPrefValue, this, &event))); |
| event.Wait(); |
| } |
| |
| bool value() { return value_; } |
| |
| private: |
| friend class base::RefCountedThreadSafe<GetPrefValueHelper>; |
| ~GetPrefValueHelper() {} |
| |
| void GetPrefValue(base::WaitableEvent* event) { |
| value_ = pref_.GetValue(); |
| event->Signal(); |
| } |
| |
| BooleanPrefMember pref_; |
| bool value_; |
| |
| // The sequence |pref_| runs on. |
| scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| }; |
| |
| class PrefMemberTestClass { |
| public: |
| explicit PrefMemberTestClass(PrefService* prefs) |
| : observe_cnt_(0), prefs_(prefs) { |
| str_.Init(kStringPref, prefs, |
| base::Bind(&PrefMemberTestClass::OnPreferenceChanged, |
| base::Unretained(this))); |
| } |
| |
| void OnPreferenceChanged(const std::string& pref_name) { |
| EXPECT_EQ(pref_name, kStringPref); |
| EXPECT_EQ(str_.GetValue(), prefs_->GetString(kStringPref)); |
| ++observe_cnt_; |
| } |
| |
| StringPrefMember str_; |
| int observe_cnt_; |
| |
| private: |
| PrefService* prefs_; |
| }; |
| |
| } // anonymous namespace |
| |
| class PrefMemberTest : public testing::Test { |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| }; |
| |
| TEST_F(PrefMemberTest, BasicGetAndSet) { |
| TestingPrefServiceSimple prefs; |
| RegisterTestPrefs(prefs.registry()); |
| |
| // Test bool |
| BooleanPrefMember boolean; |
| boolean.Init(kBoolPref, &prefs); |
| |
| // Check the defaults |
| EXPECT_FALSE(prefs.GetBoolean(kBoolPref)); |
| EXPECT_FALSE(boolean.GetValue()); |
| EXPECT_FALSE(*boolean); |
| |
| // Try changing through the member variable. |
| boolean.SetValue(true); |
| EXPECT_TRUE(boolean.GetValue()); |
| EXPECT_TRUE(prefs.GetBoolean(kBoolPref)); |
| EXPECT_TRUE(*boolean); |
| |
| // Try changing back through the pref. |
| prefs.SetBoolean(kBoolPref, false); |
| EXPECT_FALSE(prefs.GetBoolean(kBoolPref)); |
| EXPECT_FALSE(boolean.GetValue()); |
| EXPECT_FALSE(*boolean); |
| |
| // Test int |
| IntegerPrefMember integer; |
| integer.Init(kIntPref, &prefs); |
| |
| // Check the defaults |
| EXPECT_EQ(0, prefs.GetInteger(kIntPref)); |
| EXPECT_EQ(0, integer.GetValue()); |
| EXPECT_EQ(0, *integer); |
| |
| // Try changing through the member variable. |
| integer.SetValue(5); |
| EXPECT_EQ(5, integer.GetValue()); |
| EXPECT_EQ(5, prefs.GetInteger(kIntPref)); |
| EXPECT_EQ(5, *integer); |
| |
| // Try changing back through the pref. |
| prefs.SetInteger(kIntPref, 2); |
| EXPECT_EQ(2, prefs.GetInteger(kIntPref)); |
| EXPECT_EQ(2, integer.GetValue()); |
| EXPECT_EQ(2, *integer); |
| |
| // Test double |
| DoublePrefMember double_member; |
| double_member.Init(kDoublePref, &prefs); |
| |
| // Check the defaults |
| EXPECT_EQ(0.0, prefs.GetDouble(kDoublePref)); |
| EXPECT_EQ(0.0, double_member.GetValue()); |
| EXPECT_EQ(0.0, *double_member); |
| |
| // Try changing through the member variable. |
| double_member.SetValue(1.0); |
| EXPECT_EQ(1.0, double_member.GetValue()); |
| EXPECT_EQ(1.0, prefs.GetDouble(kDoublePref)); |
| EXPECT_EQ(1.0, *double_member); |
| |
| // Try changing back through the pref. |
| prefs.SetDouble(kDoublePref, 3.0); |
| EXPECT_EQ(3.0, prefs.GetDouble(kDoublePref)); |
| EXPECT_EQ(3.0, double_member.GetValue()); |
| EXPECT_EQ(3.0, *double_member); |
| |
| // Test string |
| StringPrefMember string; |
| string.Init(kStringPref, &prefs); |
| |
| // Check the defaults |
| EXPECT_EQ("default", prefs.GetString(kStringPref)); |
| EXPECT_EQ("default", string.GetValue()); |
| EXPECT_EQ("default", *string); |
| |
| // Try changing through the member variable. |
| string.SetValue("foo"); |
| EXPECT_EQ("foo", string.GetValue()); |
| EXPECT_EQ("foo", prefs.GetString(kStringPref)); |
| EXPECT_EQ("foo", *string); |
| |
| // Try changing back through the pref. |
| prefs.SetString(kStringPref, "bar"); |
| EXPECT_EQ("bar", prefs.GetString(kStringPref)); |
| EXPECT_EQ("bar", string.GetValue()); |
| EXPECT_EQ("bar", *string); |
| |
| // Test string list |
| base::ListValue expected_list; |
| std::vector<std::string> expected_vector; |
| StringListPrefMember string_list; |
| string_list.Init(kStringListPref, &prefs); |
| |
| // Check the defaults |
| EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref))); |
| EXPECT_EQ(expected_vector, string_list.GetValue()); |
| EXPECT_EQ(expected_vector, *string_list); |
| |
| // Try changing through the pref member. |
| expected_list.AppendString("foo"); |
| expected_vector.push_back("foo"); |
| string_list.SetValue(expected_vector); |
| |
| EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref))); |
| EXPECT_EQ(expected_vector, string_list.GetValue()); |
| EXPECT_EQ(expected_vector, *string_list); |
| |
| // Try adding through the pref. |
| expected_list.AppendString("bar"); |
| expected_vector.push_back("bar"); |
| prefs.Set(kStringListPref, expected_list); |
| |
| EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref))); |
| EXPECT_EQ(expected_vector, string_list.GetValue()); |
| EXPECT_EQ(expected_vector, *string_list); |
| |
| // Try removing through the pref. |
| expected_list.Remove(0, nullptr); |
| expected_vector.erase(expected_vector.begin()); |
| prefs.Set(kStringListPref, expected_list); |
| |
| EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref))); |
| EXPECT_EQ(expected_vector, string_list.GetValue()); |
| EXPECT_EQ(expected_vector, *string_list); |
| } |
| |
| TEST_F(PrefMemberTest, InvalidList) { |
| // Set the vector to an initial good value. |
| std::vector<std::string> expected_vector; |
| expected_vector.push_back("foo"); |
| |
| // Try to add a valid list first. |
| base::ListValue list; |
| list.AppendString("foo"); |
| std::vector<std::string> vector; |
| EXPECT_TRUE(subtle::PrefMemberVectorStringUpdate(list, &vector)); |
| EXPECT_EQ(expected_vector, vector); |
| |
| // Now try to add an invalid list. |vector| should not be changed. |
| list.AppendInteger(0); |
| EXPECT_FALSE(subtle::PrefMemberVectorStringUpdate(list, &vector)); |
| EXPECT_EQ(expected_vector, vector); |
| } |
| |
| TEST_F(PrefMemberTest, TwoPrefs) { |
| // Make sure two DoublePrefMembers stay in sync. |
| TestingPrefServiceSimple prefs; |
| RegisterTestPrefs(prefs.registry()); |
| |
| DoublePrefMember pref1; |
| pref1.Init(kDoublePref, &prefs); |
| DoublePrefMember pref2; |
| pref2.Init(kDoublePref, &prefs); |
| |
| pref1.SetValue(2.3); |
| EXPECT_EQ(2.3, *pref2); |
| |
| pref2.SetValue(3.5); |
| EXPECT_EQ(3.5, *pref1); |
| |
| prefs.SetDouble(kDoublePref, 4.2); |
| EXPECT_EQ(4.2, *pref1); |
| EXPECT_EQ(4.2, *pref2); |
| } |
| |
| TEST_F(PrefMemberTest, Observer) { |
| TestingPrefServiceSimple prefs; |
| RegisterTestPrefs(prefs.registry()); |
| |
| PrefMemberTestClass test_obj(&prefs); |
| EXPECT_EQ("default", *test_obj.str_); |
| |
| // Calling SetValue should not fire the observer. |
| test_obj.str_.SetValue("hello"); |
| EXPECT_EQ(0, test_obj.observe_cnt_); |
| EXPECT_EQ("hello", prefs.GetString(kStringPref)); |
| |
| // Changing the pref does fire the observer. |
| prefs.SetString(kStringPref, "world"); |
| EXPECT_EQ(1, test_obj.observe_cnt_); |
| EXPECT_EQ("world", *(test_obj.str_)); |
| |
| // Not changing the value should not fire the observer. |
| prefs.SetString(kStringPref, "world"); |
| EXPECT_EQ(1, test_obj.observe_cnt_); |
| EXPECT_EQ("world", *(test_obj.str_)); |
| |
| prefs.SetString(kStringPref, "hello"); |
| EXPECT_EQ(2, test_obj.observe_cnt_); |
| EXPECT_EQ("hello", prefs.GetString(kStringPref)); |
| } |
| |
| TEST_F(PrefMemberTest, NoInit) { |
| // Make sure not calling Init on a PrefMember doesn't cause problems. |
| IntegerPrefMember pref; |
| } |
| |
| TEST_F(PrefMemberTest, MoveToSequence) { |
| TestingPrefServiceSimple prefs; |
| scoped_refptr<GetPrefValueHelper> helper(new GetPrefValueHelper()); |
| RegisterTestPrefs(prefs.registry()); |
| helper->Init(kBoolPref, &prefs); |
| |
| helper->FetchValue(); |
| EXPECT_FALSE(helper->value()); |
| |
| prefs.SetBoolean(kBoolPref, true); |
| |
| helper->FetchValue(); |
| EXPECT_TRUE(helper->value()); |
| |
| helper->Destroy(); |
| |
| helper->FetchValue(); |
| EXPECT_TRUE(helper->value()); |
| } |