// 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 "chrome/browser/prefs/pref_member.h" #include "base/message_loop.h" #include "chrome/browser/prefs/pref_value_store.h" #include "chrome/test/testing_pref_service.h" #include "content/browser/browser_thread.h" #include "content/common/notification_details.h" #include "content/common/notification_source.h" #include "content/common/notification_type.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 kListPref[] = "list"; void RegisterTestPrefs(PrefService* prefs) { prefs->RegisterBooleanPref(kBoolPref, false); prefs->RegisterIntegerPref(kIntPref, 0); prefs->RegisterDoublePref(kDoublePref, 0.0); prefs->RegisterStringPref(kStringPref, "default"); prefs->RegisterListPref(kListPref); } class GetPrefValueCallback : public base::RefCountedThreadSafe<GetPrefValueCallback> { public: GetPrefValueCallback() : value_(false) {} void Init(const char* pref_name, PrefService* prefs) { pref_.Init(pref_name, prefs, NULL); pref_.MoveToThread(BrowserThread::IO); } bool FetchValue() { if (!BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(this, &GetPrefValueCallback::GetPrefValueOnIOThread))) { return false; } MessageLoop::current()->Run(); return true; } bool value() { return value_; } private: friend class base::RefCountedThreadSafe<GetPrefValueCallback>; ~GetPrefValueCallback() {} void GetPrefValueOnIOThread() { value_ = pref_.GetValue(); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask()); } BooleanPrefMember pref_; bool value_; }; class PrefMemberTestClass : public NotificationObserver { public: explicit PrefMemberTestClass(PrefService* prefs) : observe_cnt_(0), prefs_(prefs) { str_.Init(kStringPref, prefs, this); } virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { DCHECK(NotificationType::PREF_CHANGED == type); PrefService* prefs_in = Source<PrefService>(source).ptr(); EXPECT_EQ(prefs_in, prefs_); std::string* pref_name_in = Details<std::string>(details).ptr(); EXPECT_EQ(*pref_name_in, kStringPref); EXPECT_EQ(str_.GetValue(), prefs_->GetString(kStringPref)); ++observe_cnt_; } StringPrefMember str_; int observe_cnt_; private: PrefService* prefs_; }; } // anonymous namespace TEST(PrefMemberTest, BasicGetAndSet) { TestingPrefService prefs; RegisterTestPrefs(&prefs); // Test bool BooleanPrefMember boolean; boolean.Init(kBoolPref, &prefs, NULL); // 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, NULL); // 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, NULL); // 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, NULL); // 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 list ListPrefMember list; list.Init(kListPref, &prefs, NULL); // Check the defaults const ListValue* list_value = prefs.GetList(kListPref); ASSERT_TRUE(list_value != NULL); EXPECT_EQ(0u, list_value->GetSize()); EXPECT_TRUE(list_value->empty()); ASSERT_TRUE(list.GetValue() != NULL); EXPECT_EQ(0u, list.GetValue()->GetSize()); EXPECT_TRUE(list.GetValue()->empty()); ASSERT_TRUE(*list != NULL); EXPECT_EQ(0u, (*list)->GetSize()); EXPECT_TRUE((*list)->empty()); // Try changing through the member variable. scoped_ptr<ListValue> list_value_numbers(new ListValue()); list_value_numbers->Append(new StringValue("one")); list_value_numbers->Append(new StringValue("two")); list_value_numbers->Append(new StringValue("three")); list.SetValue(list_value_numbers.get()); EXPECT_TRUE(list_value_numbers->Equals(list.GetValue())); EXPECT_TRUE(list_value_numbers->Equals(prefs.GetList(kListPref))); EXPECT_TRUE(list_value_numbers->Equals(*list)); // Try changing back through the pref. ListValue* list_value_ints = new ListValue(); list_value_ints->Append(new FundamentalValue(1)); list_value_ints->Append(new FundamentalValue(2)); list_value_ints->Append(new FundamentalValue(3)); prefs.SetList(kListPref, list_value_ints); // takes ownership EXPECT_TRUE(list_value_ints->Equals(list.GetValue())); EXPECT_TRUE(list_value_ints->Equals(prefs.GetList(kListPref))); EXPECT_TRUE(list_value_ints->Equals(*list)); } TEST(PrefMemberTest, TwoPrefs) { // Make sure two DoublePrefMembers stay in sync. TestingPrefService prefs; RegisterTestPrefs(&prefs); DoublePrefMember pref1; pref1.Init(kDoublePref, &prefs, NULL); DoublePrefMember pref2; pref2.Init(kDoublePref, &prefs, NULL); 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(PrefMemberTest, Observer) { TestingPrefService prefs; RegisterTestPrefs(&prefs); 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(PrefMemberTest, NoInit) { // Make sure not calling Init on a PrefMember doesn't cause problems. IntegerPrefMember pref; } TEST(PrefMemberTest, MoveToThread) { TestingPrefService prefs; scoped_refptr<GetPrefValueCallback> callback = make_scoped_refptr(new GetPrefValueCallback()); MessageLoop message_loop; BrowserThread ui_thread(BrowserThread::UI, &message_loop); BrowserThread io_thread(BrowserThread::IO); ASSERT_TRUE(io_thread.Start()); RegisterTestPrefs(&prefs); callback->Init(kBoolPref, &prefs); ASSERT_TRUE(callback->FetchValue()); EXPECT_FALSE(callback->value()); prefs.SetBoolean(kBoolPref, true); ASSERT_TRUE(callback->FetchValue()); EXPECT_TRUE(callback->value()); }