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 17 using testing::_; 18 using testing::Field; 19 using testing::Invoke; 20 using testing::Mock; 21 using testing::Truly; 22 23 namespace { 24 25 const char kChangedPref[] = "changed_pref"; 26 const char kUnchangedPref[] = "unchanged_pref"; 27 28 class 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. 35 class 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. 46 class 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 77 class PrefObserverMock : public PrefObserver { 78 public: 79 PrefObserverMock() {} 80 virtual ~PrefObserverMock() {} 81 82 MOCK_METHOD2(OnPreferenceChanged, void(PrefService*, const std::string&)); 83 84 void Expect(PrefService* prefs, 85 const std::string& pref_name, 86 const base::Value* value) { 87 EXPECT_CALL(*this, OnPreferenceChanged(prefs, pref_name)) 88 .With(PrefValueMatches(prefs, pref_name, value)); 89 } 90 }; 91 92 // Test fixture class. 93 class PrefNotifierTest : public testing::Test { 94 protected: 95 virtual void SetUp() { 96 pref_service_.registry()->RegisterBooleanPref(kChangedPref, true); 97 pref_service_.registry()->RegisterBooleanPref(kUnchangedPref, true); 98 } 99 100 TestingPrefServiceSimple pref_service_; 101 102 PrefObserverMock obs1_; 103 PrefObserverMock obs2_; 104 }; 105 106 TEST_F(PrefNotifierTest, OnPreferenceChanged) { 107 MockPrefNotifier notifier(&pref_service_); 108 EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1); 109 notifier.OnPreferenceChanged(kChangedPref); 110 } 111 112 TEST_F(PrefNotifierTest, OnInitializationCompleted) { 113 MockPrefNotifier notifier(&pref_service_); 114 MockPrefInitObserver observer; 115 notifier.AddInitObserver( 116 base::Bind(&MockPrefInitObserver::OnInitializationCompleted, 117 base::Unretained(&observer))); 118 EXPECT_CALL(observer, OnInitializationCompleted(true)); 119 notifier.OnInitializationCompleted(true); 120 } 121 122 TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) { 123 const char pref_name[] = "homepage"; 124 const char pref_name2[] = "proxy"; 125 126 MockPrefNotifier notifier(&pref_service_); 127 notifier.AddPrefObserver(pref_name, &obs1_); 128 ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); 129 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); 130 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); 131 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); 132 133 // Re-adding the same observer for the same pref doesn't change anything. 134 // Skip this in debug mode, since it hits a DCHECK and death tests aren't 135 // thread-safe. 136 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) 137 notifier.AddPrefObserver(pref_name, &obs1_); 138 ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); 139 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); 140 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); 141 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); 142 #endif 143 144 // Ensure that we can add the same observer to a different pref. 145 notifier.AddPrefObserver(pref_name2, &obs1_); 146 ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); 147 ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); 148 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); 149 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); 150 151 // Ensure that we can add another observer to the same pref. 152 notifier.AddPrefObserver(pref_name, &obs2_); 153 ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); 154 ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); 155 ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_)); 156 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); 157 158 // Ensure that we can remove all observers, and that removing a non-existent 159 // observer is harmless. 160 notifier.RemovePrefObserver(pref_name, &obs1_); 161 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); 162 ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); 163 ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_)); 164 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); 165 166 notifier.RemovePrefObserver(pref_name, &obs2_); 167 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); 168 ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); 169 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); 170 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); 171 172 notifier.RemovePrefObserver(pref_name, &obs1_); 173 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); 174 ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); 175 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); 176 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); 177 178 notifier.RemovePrefObserver(pref_name2, &obs1_); 179 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); 180 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); 181 ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); 182 ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); 183 } 184 185 TEST_F(PrefNotifierTest, FireObservers) { 186 TestingPrefNotifierImpl notifier(&pref_service_); 187 notifier.AddPrefObserver(kChangedPref, &obs1_); 188 notifier.AddPrefObserver(kUnchangedPref, &obs1_); 189 190 EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref)); 191 EXPECT_CALL(obs2_, OnPreferenceChanged(_, _)).Times(0); 192 notifier.OnPreferenceChanged(kChangedPref); 193 Mock::VerifyAndClearExpectations(&obs1_); 194 Mock::VerifyAndClearExpectations(&obs2_); 195 196 notifier.AddPrefObserver(kChangedPref, &obs2_); 197 notifier.AddPrefObserver(kUnchangedPref, &obs2_); 198 199 EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref)); 200 EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref)); 201 notifier.OnPreferenceChanged(kChangedPref); 202 Mock::VerifyAndClearExpectations(&obs1_); 203 Mock::VerifyAndClearExpectations(&obs2_); 204 205 // Make sure removing an observer from one pref doesn't affect anything else. 206 notifier.RemovePrefObserver(kChangedPref, &obs1_); 207 208 EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0); 209 EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref)); 210 notifier.OnPreferenceChanged(kChangedPref); 211 Mock::VerifyAndClearExpectations(&obs1_); 212 Mock::VerifyAndClearExpectations(&obs2_); 213 214 // Make sure removing an observer entirely doesn't affect anything else. 215 notifier.RemovePrefObserver(kUnchangedPref, &obs1_); 216 217 EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0); 218 EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref)); 219 notifier.OnPreferenceChanged(kChangedPref); 220 Mock::VerifyAndClearExpectations(&obs1_); 221 Mock::VerifyAndClearExpectations(&obs2_); 222 223 notifier.RemovePrefObserver(kChangedPref, &obs2_); 224 notifier.RemovePrefObserver(kUnchangedPref, &obs2_); 225 } 226 227 } // namespace 228