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 "base/prefs/pref_member.h"
6
7#include "base/bind.h"
8#include "base/message_loop/message_loop.h"
9#include "base/prefs/pref_registry_simple.h"
10#include "base/prefs/testing_pref_service.h"
11#include "base/synchronization/waitable_event.h"
12#include "base/threading/thread.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace {
16
17const char kBoolPref[] = "bool";
18const char kIntPref[] = "int";
19const char kDoublePref[] = "double";
20const char kStringPref[] = "string";
21const char kStringListPref[] = "string_list";
22
23void RegisterTestPrefs(PrefRegistrySimple* registry) {
24  registry->RegisterBooleanPref(kBoolPref, false);
25  registry->RegisterIntegerPref(kIntPref, 0);
26  registry->RegisterDoublePref(kDoublePref, 0.0);
27  registry->RegisterStringPref(kStringPref, "default");
28  registry->RegisterListPref(kStringListPref, new base::ListValue());
29}
30
31class GetPrefValueHelper
32    : public base::RefCountedThreadSafe<GetPrefValueHelper> {
33 public:
34  GetPrefValueHelper() : value_(false), pref_thread_("pref thread") {
35    pref_thread_.Start();
36  }
37
38  void Init(const char* pref_name, PrefService* prefs) {
39    pref_.Init(pref_name, prefs);
40    pref_.MoveToThread(pref_thread_.message_loop_proxy());
41  }
42
43  void Destroy() {
44    pref_.Destroy();
45  }
46
47  void FetchValue() {
48    base::WaitableEvent event(true, false);
49    ASSERT_TRUE(
50        pref_thread_.message_loop_proxy()->PostTask(
51            FROM_HERE,
52            base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
53    event.Wait();
54  }
55
56  // The thread must be stopped on the main thread. GetPrefValueHelper being
57  // ref-counted, the destructor can be called from any thread.
58  void StopThread() {
59    pref_thread_.Stop();
60  }
61
62  bool value() { return value_; }
63
64 private:
65  friend class base::RefCountedThreadSafe<GetPrefValueHelper>;
66  ~GetPrefValueHelper() {}
67
68  void GetPrefValue(base::WaitableEvent* event) {
69    value_ = pref_.GetValue();
70    event->Signal();
71  }
72
73  BooleanPrefMember pref_;
74  bool value_;
75
76  base::Thread pref_thread_;  // The thread |pref_| runs on.
77};
78
79class PrefMemberTestClass {
80 public:
81  explicit PrefMemberTestClass(PrefService* prefs)
82      : observe_cnt_(0), prefs_(prefs) {
83    str_.Init(kStringPref, prefs,
84              base::Bind(&PrefMemberTestClass::OnPreferenceChanged,
85                         base::Unretained(this)));
86  }
87
88  void OnPreferenceChanged(const std::string& pref_name) {
89    EXPECT_EQ(pref_name, kStringPref);
90    EXPECT_EQ(str_.GetValue(), prefs_->GetString(kStringPref));
91    ++observe_cnt_;
92  }
93
94  StringPrefMember str_;
95  int observe_cnt_;
96
97 private:
98  PrefService* prefs_;
99};
100
101}  // anonymous namespace
102
103TEST(PrefMemberTest, BasicGetAndSet) {
104  TestingPrefServiceSimple prefs;
105  RegisterTestPrefs(prefs.registry());
106
107  // Test bool
108  BooleanPrefMember boolean;
109  boolean.Init(kBoolPref, &prefs);
110
111  // Check the defaults
112  EXPECT_FALSE(prefs.GetBoolean(kBoolPref));
113  EXPECT_FALSE(boolean.GetValue());
114  EXPECT_FALSE(*boolean);
115
116  // Try changing through the member variable.
117  boolean.SetValue(true);
118  EXPECT_TRUE(boolean.GetValue());
119  EXPECT_TRUE(prefs.GetBoolean(kBoolPref));
120  EXPECT_TRUE(*boolean);
121
122  // Try changing back through the pref.
123  prefs.SetBoolean(kBoolPref, false);
124  EXPECT_FALSE(prefs.GetBoolean(kBoolPref));
125  EXPECT_FALSE(boolean.GetValue());
126  EXPECT_FALSE(*boolean);
127
128  // Test int
129  IntegerPrefMember integer;
130  integer.Init(kIntPref, &prefs);
131
132  // Check the defaults
133  EXPECT_EQ(0, prefs.GetInteger(kIntPref));
134  EXPECT_EQ(0, integer.GetValue());
135  EXPECT_EQ(0, *integer);
136
137  // Try changing through the member variable.
138  integer.SetValue(5);
139  EXPECT_EQ(5, integer.GetValue());
140  EXPECT_EQ(5, prefs.GetInteger(kIntPref));
141  EXPECT_EQ(5, *integer);
142
143  // Try changing back through the pref.
144  prefs.SetInteger(kIntPref, 2);
145  EXPECT_EQ(2, prefs.GetInteger(kIntPref));
146  EXPECT_EQ(2, integer.GetValue());
147  EXPECT_EQ(2, *integer);
148
149  // Test double
150  DoublePrefMember double_member;
151  double_member.Init(kDoublePref, &prefs);
152
153  // Check the defaults
154  EXPECT_EQ(0.0, prefs.GetDouble(kDoublePref));
155  EXPECT_EQ(0.0, double_member.GetValue());
156  EXPECT_EQ(0.0, *double_member);
157
158  // Try changing through the member variable.
159  double_member.SetValue(1.0);
160  EXPECT_EQ(1.0, double_member.GetValue());
161  EXPECT_EQ(1.0, prefs.GetDouble(kDoublePref));
162  EXPECT_EQ(1.0, *double_member);
163
164  // Try changing back through the pref.
165  prefs.SetDouble(kDoublePref, 3.0);
166  EXPECT_EQ(3.0, prefs.GetDouble(kDoublePref));
167  EXPECT_EQ(3.0, double_member.GetValue());
168  EXPECT_EQ(3.0, *double_member);
169
170  // Test string
171  StringPrefMember string;
172  string.Init(kStringPref, &prefs);
173
174  // Check the defaults
175  EXPECT_EQ("default", prefs.GetString(kStringPref));
176  EXPECT_EQ("default", string.GetValue());
177  EXPECT_EQ("default", *string);
178
179  // Try changing through the member variable.
180  string.SetValue("foo");
181  EXPECT_EQ("foo", string.GetValue());
182  EXPECT_EQ("foo", prefs.GetString(kStringPref));
183  EXPECT_EQ("foo", *string);
184
185  // Try changing back through the pref.
186  prefs.SetString(kStringPref, "bar");
187  EXPECT_EQ("bar", prefs.GetString(kStringPref));
188  EXPECT_EQ("bar", string.GetValue());
189  EXPECT_EQ("bar", *string);
190
191  // Test string list
192  base::ListValue expected_list;
193  std::vector<std::string> expected_vector;
194  StringListPrefMember string_list;
195  string_list.Init(kStringListPref, &prefs);
196
197  // Check the defaults
198  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
199  EXPECT_EQ(expected_vector, string_list.GetValue());
200  EXPECT_EQ(expected_vector, *string_list);
201
202  // Try changing through the pref member.
203  expected_list.AppendString("foo");
204  expected_vector.push_back("foo");
205  string_list.SetValue(expected_vector);
206
207  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
208  EXPECT_EQ(expected_vector, string_list.GetValue());
209  EXPECT_EQ(expected_vector, *string_list);
210
211  // Try adding through the pref.
212  expected_list.AppendString("bar");
213  expected_vector.push_back("bar");
214  prefs.Set(kStringListPref, expected_list);
215
216  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
217  EXPECT_EQ(expected_vector, string_list.GetValue());
218  EXPECT_EQ(expected_vector, *string_list);
219
220  // Try removing through the pref.
221  expected_list.Remove(0, NULL);
222  expected_vector.erase(expected_vector.begin());
223  prefs.Set(kStringListPref, expected_list);
224
225  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
226  EXPECT_EQ(expected_vector, string_list.GetValue());
227  EXPECT_EQ(expected_vector, *string_list);
228}
229
230TEST(PrefMemberTest, InvalidList) {
231  // Set the vector to an initial good value.
232  std::vector<std::string> expected_vector;
233  expected_vector.push_back("foo");
234
235  // Try to add a valid list first.
236  base::ListValue list;
237  list.AppendString("foo");
238  std::vector<std::string> vector;
239  EXPECT_TRUE(subtle::PrefMemberVectorStringUpdate(list, &vector));
240  EXPECT_EQ(expected_vector, vector);
241
242  // Now try to add an invalid list.  |vector| should not be changed.
243  list.AppendInteger(0);
244  EXPECT_FALSE(subtle::PrefMemberVectorStringUpdate(list, &vector));
245  EXPECT_EQ(expected_vector, vector);
246}
247
248TEST(PrefMemberTest, TwoPrefs) {
249  // Make sure two DoublePrefMembers stay in sync.
250  TestingPrefServiceSimple prefs;
251  RegisterTestPrefs(prefs.registry());
252
253  DoublePrefMember pref1;
254  pref1.Init(kDoublePref, &prefs);
255  DoublePrefMember pref2;
256  pref2.Init(kDoublePref, &prefs);
257
258  pref1.SetValue(2.3);
259  EXPECT_EQ(2.3, *pref2);
260
261  pref2.SetValue(3.5);
262  EXPECT_EQ(3.5, *pref1);
263
264  prefs.SetDouble(kDoublePref, 4.2);
265  EXPECT_EQ(4.2, *pref1);
266  EXPECT_EQ(4.2, *pref2);
267}
268
269TEST(PrefMemberTest, Observer) {
270  TestingPrefServiceSimple prefs;
271  RegisterTestPrefs(prefs.registry());
272
273  PrefMemberTestClass test_obj(&prefs);
274  EXPECT_EQ("default", *test_obj.str_);
275
276  // Calling SetValue should not fire the observer.
277  test_obj.str_.SetValue("hello");
278  EXPECT_EQ(0, test_obj.observe_cnt_);
279  EXPECT_EQ("hello", prefs.GetString(kStringPref));
280
281  // Changing the pref does fire the observer.
282  prefs.SetString(kStringPref, "world");
283  EXPECT_EQ(1, test_obj.observe_cnt_);
284  EXPECT_EQ("world", *(test_obj.str_));
285
286  // Not changing the value should not fire the observer.
287  prefs.SetString(kStringPref, "world");
288  EXPECT_EQ(1, test_obj.observe_cnt_);
289  EXPECT_EQ("world", *(test_obj.str_));
290
291  prefs.SetString(kStringPref, "hello");
292  EXPECT_EQ(2, test_obj.observe_cnt_);
293  EXPECT_EQ("hello", prefs.GetString(kStringPref));
294}
295
296TEST(PrefMemberTest, NoInit) {
297  // Make sure not calling Init on a PrefMember doesn't cause problems.
298  IntegerPrefMember pref;
299}
300
301TEST(PrefMemberTest, MoveToThread) {
302  TestingPrefServiceSimple prefs;
303  scoped_refptr<GetPrefValueHelper> helper(new GetPrefValueHelper());
304  RegisterTestPrefs(prefs.registry());
305  helper->Init(kBoolPref, &prefs);
306
307  helper->FetchValue();
308  EXPECT_FALSE(helper->value());
309
310  prefs.SetBoolean(kBoolPref, true);
311
312  helper->FetchValue();
313  EXPECT_TRUE(helper->value());
314
315  helper->Destroy();
316
317  helper->FetchValue();
318  EXPECT_TRUE(helper->value());
319
320  helper->StopThread();
321}
322