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/bind.h"
6#include "base/callback.h"
7#include "base/prefs/mock_pref_change_callback.h"
8#include "base/prefs/pref_notifier_impl.h"
9#include "base/prefs/pref_observer.h"
10#include "base/prefs/pref_registry_simple.h"
11#include "base/prefs/pref_service.h"
12#include "base/prefs/pref_value_store.h"
13#include "base/prefs/testing_pref_service.h"
14#include "testing/gmock/include/gmock/gmock.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17using testing::_;
18using testing::Field;
19using testing::Invoke;
20using testing::Mock;
21using testing::Truly;
22
23namespace {
24
25const char kChangedPref[] = "changed_pref";
26const char kUnchangedPref[] = "unchanged_pref";
27
28class MockPrefInitObserver {
29 public:
30  MOCK_METHOD1(OnInitializationCompleted, void(bool));
31};
32
33// This is an unmodified PrefNotifierImpl, except we make
34// OnPreferenceChanged public for tests.
35class TestingPrefNotifierImpl : public PrefNotifierImpl {
36 public:
37  explicit TestingPrefNotifierImpl(PrefService* service)
38      : PrefNotifierImpl(service) {
39  }
40
41  // Make public for tests.
42  using PrefNotifierImpl::OnPreferenceChanged;
43};
44
45// Mock PrefNotifier that allows tracking of observers and notifications.
46class MockPrefNotifier : public PrefNotifierImpl {
47 public:
48  explicit MockPrefNotifier(PrefService* pref_service)
49      : PrefNotifierImpl(pref_service) {}
50  virtual ~MockPrefNotifier() {}
51
52  MOCK_METHOD1(FireObservers, void(const std::string& path));
53
54  size_t CountObserver(const char* path, PrefObserver* obs) {
55    PrefObserverMap::const_iterator observer_iterator =
56        pref_observers()->find(path);
57    if (observer_iterator == pref_observers()->end())
58      return false;
59
60    PrefObserverList* observer_list = observer_iterator->second;
61    PrefObserverList::Iterator it(*observer_list);
62    PrefObserver* existing_obs;
63    size_t count = 0;
64    while ((existing_obs = it.GetNext()) != NULL) {
65      if (existing_obs == obs)
66        count++;
67    }
68
69    return count;
70  }
71
72  // Make public for tests below.
73  using PrefNotifierImpl::OnPreferenceChanged;
74  using PrefNotifierImpl::OnInitializationCompleted;
75};
76
77class PrefObserverMock : public PrefObserver {
78 public:
79  PrefObserverMock() {}
80  virtual ~PrefObserverMock() {}
81
82  MOCK_METHOD2(OnPreferenceChanged, void(PrefService*, const std::string&));
83};
84
85// Test fixture class.
86class PrefNotifierTest : public testing::Test {
87 protected:
88  virtual void SetUp() {
89    pref_service_.registry()->RegisterBooleanPref(kChangedPref, true);
90    pref_service_.registry()->RegisterBooleanPref(kUnchangedPref, true);
91  }
92
93  TestingPrefServiceSimple pref_service_;
94
95  PrefObserverMock obs1_;
96  PrefObserverMock obs2_;
97};
98
99TEST_F(PrefNotifierTest, OnPreferenceChanged) {
100  MockPrefNotifier notifier(&pref_service_);
101  EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1);
102  notifier.OnPreferenceChanged(kChangedPref);
103}
104
105TEST_F(PrefNotifierTest, OnInitializationCompleted) {
106  MockPrefNotifier notifier(&pref_service_);
107  MockPrefInitObserver observer;
108  notifier.AddInitObserver(
109      base::Bind(&MockPrefInitObserver::OnInitializationCompleted,
110                 base::Unretained(&observer)));
111  EXPECT_CALL(observer, OnInitializationCompleted(true));
112  notifier.OnInitializationCompleted(true);
113}
114
115TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) {
116  const char pref_name[] = "homepage";
117  const char pref_name2[] = "proxy";
118
119  MockPrefNotifier notifier(&pref_service_);
120  notifier.AddPrefObserver(pref_name, &obs1_);
121  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
122  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
123  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
124  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
125
126  // Re-adding the same observer for the same pref doesn't change anything.
127  // Skip this in debug mode, since it hits a DCHECK and death tests aren't
128  // thread-safe.
129#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
130  notifier.AddPrefObserver(pref_name, &obs1_);
131  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
132  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
133  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
134  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
135#endif
136
137  // Ensure that we can add the same observer to a different pref.
138  notifier.AddPrefObserver(pref_name2, &obs1_);
139  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
140  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
141  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
142  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
143
144  // Ensure that we can add another observer to the same pref.
145  notifier.AddPrefObserver(pref_name, &obs2_);
146  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
147  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
148  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
149  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
150
151  // Ensure that we can remove all observers, and that removing a non-existent
152  // observer is harmless.
153  notifier.RemovePrefObserver(pref_name, &obs1_);
154  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
155  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
156  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
157  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
158
159  notifier.RemovePrefObserver(pref_name, &obs2_);
160  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
161  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
162  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
163  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
164
165  notifier.RemovePrefObserver(pref_name, &obs1_);
166  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
167  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
168  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
169  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
170
171  notifier.RemovePrefObserver(pref_name2, &obs1_);
172  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
173  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
174  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
175  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
176}
177
178TEST_F(PrefNotifierTest, FireObservers) {
179  TestingPrefNotifierImpl notifier(&pref_service_);
180  notifier.AddPrefObserver(kChangedPref, &obs1_);
181  notifier.AddPrefObserver(kUnchangedPref, &obs1_);
182
183  EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref));
184  EXPECT_CALL(obs2_, OnPreferenceChanged(_, _)).Times(0);
185  notifier.OnPreferenceChanged(kChangedPref);
186  Mock::VerifyAndClearExpectations(&obs1_);
187  Mock::VerifyAndClearExpectations(&obs2_);
188
189  notifier.AddPrefObserver(kChangedPref, &obs2_);
190  notifier.AddPrefObserver(kUnchangedPref, &obs2_);
191
192  EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref));
193  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
194  notifier.OnPreferenceChanged(kChangedPref);
195  Mock::VerifyAndClearExpectations(&obs1_);
196  Mock::VerifyAndClearExpectations(&obs2_);
197
198  // Make sure removing an observer from one pref doesn't affect anything else.
199  notifier.RemovePrefObserver(kChangedPref, &obs1_);
200
201  EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0);
202  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
203  notifier.OnPreferenceChanged(kChangedPref);
204  Mock::VerifyAndClearExpectations(&obs1_);
205  Mock::VerifyAndClearExpectations(&obs2_);
206
207  // Make sure removing an observer entirely doesn't affect anything else.
208  notifier.RemovePrefObserver(kUnchangedPref, &obs1_);
209
210  EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0);
211  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
212  notifier.OnPreferenceChanged(kChangedPref);
213  Mock::VerifyAndClearExpectations(&obs1_);
214  Mock::VerifyAndClearExpectations(&obs2_);
215
216  notifier.RemovePrefObserver(kChangedPref, &obs2_);
217  notifier.RemovePrefObserver(kUnchangedPref, &obs2_);
218}
219
220}  // namespace
221