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 85 // Test fixture class. 86 class 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 99 TEST_F(PrefNotifierTest, OnPreferenceChanged) { 100 MockPrefNotifier notifier(&pref_service_); 101 EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1); 102 notifier.OnPreferenceChanged(kChangedPref); 103 } 104 105 TEST_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 115 TEST_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 178 TEST_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