1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/prefs/pref_member.h"
6
7#include "base/message_loop.h"
8#include "chrome/browser/prefs/pref_value_store.h"
9#include "chrome/test/testing_pref_service.h"
10#include "content/browser/browser_thread.h"
11#include "content/common/notification_details.h"
12#include "content/common/notification_source.h"
13#include "content/common/notification_type.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace {
17
18const char kBoolPref[] = "bool";
19const char kIntPref[] = "int";
20const char kDoublePref[] = "double";
21const char kStringPref[] = "string";
22const char kListPref[] = "list";
23
24void RegisterTestPrefs(PrefService* prefs) {
25  prefs->RegisterBooleanPref(kBoolPref, false);
26  prefs->RegisterIntegerPref(kIntPref, 0);
27  prefs->RegisterDoublePref(kDoublePref, 0.0);
28  prefs->RegisterStringPref(kStringPref, "default");
29  prefs->RegisterListPref(kListPref);
30}
31
32class GetPrefValueCallback
33    : public base::RefCountedThreadSafe<GetPrefValueCallback> {
34 public:
35  GetPrefValueCallback() : value_(false) {}
36
37  void Init(const char* pref_name, PrefService* prefs) {
38    pref_.Init(pref_name, prefs, NULL);
39    pref_.MoveToThread(BrowserThread::IO);
40  }
41
42  bool FetchValue() {
43    if (!BrowserThread::PostTask(
44        BrowserThread::IO, FROM_HERE,
45        NewRunnableMethod(this,
46                          &GetPrefValueCallback::GetPrefValueOnIOThread))) {
47      return false;
48    }
49    MessageLoop::current()->Run();
50    return true;
51  }
52
53  bool value() { return value_; }
54
55 private:
56  friend class base::RefCountedThreadSafe<GetPrefValueCallback>;
57  ~GetPrefValueCallback() {}
58
59  void GetPrefValueOnIOThread() {
60    value_ = pref_.GetValue();
61    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
62                            new MessageLoop::QuitTask());
63  }
64
65  BooleanPrefMember pref_;
66  bool value_;
67};
68
69class PrefMemberTestClass : public NotificationObserver {
70 public:
71  explicit PrefMemberTestClass(PrefService* prefs)
72      : observe_cnt_(0), prefs_(prefs) {
73    str_.Init(kStringPref, prefs, this);
74  }
75
76  virtual void Observe(NotificationType type,
77                       const NotificationSource& source,
78                       const NotificationDetails& details) {
79    DCHECK(NotificationType::PREF_CHANGED == type);
80    PrefService* prefs_in = Source<PrefService>(source).ptr();
81    EXPECT_EQ(prefs_in, prefs_);
82    std::string* pref_name_in = Details<std::string>(details).ptr();
83    EXPECT_EQ(*pref_name_in, kStringPref);
84    EXPECT_EQ(str_.GetValue(), prefs_->GetString(kStringPref));
85    ++observe_cnt_;
86  }
87
88  StringPrefMember str_;
89  int observe_cnt_;
90
91 private:
92  PrefService* prefs_;
93};
94
95}  // anonymous namespace
96
97TEST(PrefMemberTest, BasicGetAndSet) {
98  TestingPrefService prefs;
99  RegisterTestPrefs(&prefs);
100
101  // Test bool
102  BooleanPrefMember boolean;
103  boolean.Init(kBoolPref, &prefs, NULL);
104
105  // Check the defaults
106  EXPECT_FALSE(prefs.GetBoolean(kBoolPref));
107  EXPECT_FALSE(boolean.GetValue());
108  EXPECT_FALSE(*boolean);
109
110  // Try changing through the member variable.
111  boolean.SetValue(true);
112  EXPECT_TRUE(boolean.GetValue());
113  EXPECT_TRUE(prefs.GetBoolean(kBoolPref));
114  EXPECT_TRUE(*boolean);
115
116  // Try changing back through the pref.
117  prefs.SetBoolean(kBoolPref, false);
118  EXPECT_FALSE(prefs.GetBoolean(kBoolPref));
119  EXPECT_FALSE(boolean.GetValue());
120  EXPECT_FALSE(*boolean);
121
122  // Test int
123  IntegerPrefMember integer;
124  integer.Init(kIntPref, &prefs, NULL);
125
126  // Check the defaults
127  EXPECT_EQ(0, prefs.GetInteger(kIntPref));
128  EXPECT_EQ(0, integer.GetValue());
129  EXPECT_EQ(0, *integer);
130
131  // Try changing through the member variable.
132  integer.SetValue(5);
133  EXPECT_EQ(5, integer.GetValue());
134  EXPECT_EQ(5, prefs.GetInteger(kIntPref));
135  EXPECT_EQ(5, *integer);
136
137  // Try changing back through the pref.
138  prefs.SetInteger(kIntPref, 2);
139  EXPECT_EQ(2, prefs.GetInteger(kIntPref));
140  EXPECT_EQ(2, integer.GetValue());
141  EXPECT_EQ(2, *integer);
142
143  // Test double
144  DoublePrefMember double_member;
145  double_member.Init(kDoublePref, &prefs, NULL);
146
147  // Check the defaults
148  EXPECT_EQ(0.0, prefs.GetDouble(kDoublePref));
149  EXPECT_EQ(0.0, double_member.GetValue());
150  EXPECT_EQ(0.0, *double_member);
151
152  // Try changing through the member variable.
153  double_member.SetValue(1.0);
154  EXPECT_EQ(1.0, double_member.GetValue());
155  EXPECT_EQ(1.0, prefs.GetDouble(kDoublePref));
156  EXPECT_EQ(1.0, *double_member);
157
158  // Try changing back through the pref.
159  prefs.SetDouble(kDoublePref, 3.0);
160  EXPECT_EQ(3.0, prefs.GetDouble(kDoublePref));
161  EXPECT_EQ(3.0, double_member.GetValue());
162  EXPECT_EQ(3.0, *double_member);
163
164  // Test string
165  StringPrefMember string;
166  string.Init(kStringPref, &prefs, NULL);
167
168  // Check the defaults
169  EXPECT_EQ("default", prefs.GetString(kStringPref));
170  EXPECT_EQ("default", string.GetValue());
171  EXPECT_EQ("default", *string);
172
173  // Try changing through the member variable.
174  string.SetValue("foo");
175  EXPECT_EQ("foo", string.GetValue());
176  EXPECT_EQ("foo", prefs.GetString(kStringPref));
177  EXPECT_EQ("foo", *string);
178
179  // Try changing back through the pref.
180  prefs.SetString(kStringPref, "bar");
181  EXPECT_EQ("bar", prefs.GetString(kStringPref));
182  EXPECT_EQ("bar", string.GetValue());
183  EXPECT_EQ("bar", *string);
184
185  // Test list
186  ListPrefMember list;
187  list.Init(kListPref, &prefs, NULL);
188
189  // Check the defaults
190  const ListValue* list_value = prefs.GetList(kListPref);
191  ASSERT_TRUE(list_value != NULL);
192  EXPECT_EQ(0u, list_value->GetSize());
193  EXPECT_TRUE(list_value->empty());
194  ASSERT_TRUE(list.GetValue() != NULL);
195  EXPECT_EQ(0u, list.GetValue()->GetSize());
196  EXPECT_TRUE(list.GetValue()->empty());
197  ASSERT_TRUE(*list != NULL);
198  EXPECT_EQ(0u, (*list)->GetSize());
199  EXPECT_TRUE((*list)->empty());
200
201  // Try changing through the member variable.
202  scoped_ptr<ListValue> list_value_numbers(new ListValue());
203  list_value_numbers->Append(new StringValue("one"));
204  list_value_numbers->Append(new StringValue("two"));
205  list_value_numbers->Append(new StringValue("three"));
206  list.SetValue(list_value_numbers.get());
207  EXPECT_TRUE(list_value_numbers->Equals(list.GetValue()));
208  EXPECT_TRUE(list_value_numbers->Equals(prefs.GetList(kListPref)));
209  EXPECT_TRUE(list_value_numbers->Equals(*list));
210
211  // Try changing back through the pref.
212  ListValue* list_value_ints = new ListValue();
213  list_value_ints->Append(new FundamentalValue(1));
214  list_value_ints->Append(new FundamentalValue(2));
215  list_value_ints->Append(new FundamentalValue(3));
216  prefs.SetList(kListPref, list_value_ints); // takes ownership
217  EXPECT_TRUE(list_value_ints->Equals(list.GetValue()));
218  EXPECT_TRUE(list_value_ints->Equals(prefs.GetList(kListPref)));
219  EXPECT_TRUE(list_value_ints->Equals(*list));
220}
221
222TEST(PrefMemberTest, TwoPrefs) {
223  // Make sure two DoublePrefMembers stay in sync.
224  TestingPrefService prefs;
225  RegisterTestPrefs(&prefs);
226
227  DoublePrefMember pref1;
228  pref1.Init(kDoublePref, &prefs, NULL);
229  DoublePrefMember pref2;
230  pref2.Init(kDoublePref, &prefs, NULL);
231
232  pref1.SetValue(2.3);
233  EXPECT_EQ(2.3, *pref2);
234
235  pref2.SetValue(3.5);
236  EXPECT_EQ(3.5, *pref1);
237
238  prefs.SetDouble(kDoublePref, 4.2);
239  EXPECT_EQ(4.2, *pref1);
240  EXPECT_EQ(4.2, *pref2);
241}
242
243TEST(PrefMemberTest, Observer) {
244  TestingPrefService prefs;
245  RegisterTestPrefs(&prefs);
246
247  PrefMemberTestClass test_obj(&prefs);
248  EXPECT_EQ("default", *test_obj.str_);
249
250  // Calling SetValue should not fire the observer.
251  test_obj.str_.SetValue("hello");
252  EXPECT_EQ(0, test_obj.observe_cnt_);
253  EXPECT_EQ("hello", prefs.GetString(kStringPref));
254
255  // Changing the pref does fire the observer.
256  prefs.SetString(kStringPref, "world");
257  EXPECT_EQ(1, test_obj.observe_cnt_);
258  EXPECT_EQ("world", *(test_obj.str_));
259
260  // Not changing the value should not fire the observer.
261  prefs.SetString(kStringPref, "world");
262  EXPECT_EQ(1, test_obj.observe_cnt_);
263  EXPECT_EQ("world", *(test_obj.str_));
264
265  prefs.SetString(kStringPref, "hello");
266  EXPECT_EQ(2, test_obj.observe_cnt_);
267  EXPECT_EQ("hello", prefs.GetString(kStringPref));
268}
269
270TEST(PrefMemberTest, NoInit) {
271  // Make sure not calling Init on a PrefMember doesn't cause problems.
272  IntegerPrefMember pref;
273}
274
275TEST(PrefMemberTest, MoveToThread) {
276  TestingPrefService prefs;
277  scoped_refptr<GetPrefValueCallback> callback =
278      make_scoped_refptr(new GetPrefValueCallback());
279  MessageLoop message_loop;
280  BrowserThread ui_thread(BrowserThread::UI, &message_loop);
281  BrowserThread io_thread(BrowserThread::IO);
282  ASSERT_TRUE(io_thread.Start());
283  RegisterTestPrefs(&prefs);
284  callback->Init(kBoolPref, &prefs);
285
286  ASSERT_TRUE(callback->FetchValue());
287  EXPECT_FALSE(callback->value());
288
289  prefs.SetBoolean(kBoolPref, true);
290
291  ASSERT_TRUE(callback->FetchValue());
292  EXPECT_TRUE(callback->value());
293}
294