| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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/in_memory_pref_store.h" | |
| 6 #include "chrome/browser/prefs/pref_notifier.h" | |
| 7 #include "chrome/browser/prefs/pref_service.h" | |
| 8 #include "chrome/browser/prefs/pref_value_store.h" | |
| 9 #include "chrome/common/notification_observer.h" | |
| 10 #include "chrome/common/notification_type.h" | |
| 11 #include "chrome/common/notification_service.h" | |
| 12 #include "testing/gmock/include/gmock/gmock.h" | |
| 13 #include "testing/gtest/include/gtest/gtest.h" | |
| 14 | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 const char kChangedPref[] = "changed_pref"; | |
| 19 const char kUnchangedPref[] = "unchanged_pref"; | |
| 20 | |
| 21 bool DetailsAreChangedPref(const Details<std::string>& details) { | |
| 22 std::string* string_in = Details<std::string>(details).ptr(); | |
| 23 return strcmp(string_in->c_str(), kChangedPref) == 0; | |
| 24 } | |
| 25 | |
| 26 // Test PrefNotifier that allows tracking of observers and notifications. | |
| 27 class MockPrefNotifier : public PrefNotifier { | |
| 28 public: | |
| 29 MockPrefNotifier(PrefService* prefs, PrefValueStore* value_store) | |
| 30 : PrefNotifier(prefs, value_store) {} | |
| 31 | |
| 32 virtual ~MockPrefNotifier() {} | |
| 33 | |
| 34 MOCK_METHOD1(FireObservers, void(const char* path)); | |
| 35 | |
| 36 void RealFireObservers(const char* path) { | |
| 37 PrefNotifier::FireObservers(path); | |
| 38 } | |
| 39 | |
| 40 size_t CountObserver(const char* path, NotificationObserver* obs) { | |
| 41 PrefObserverMap::const_iterator observer_iterator = | |
| 42 pref_observers()->find(path); | |
| 43 if (observer_iterator == pref_observers()->end()) | |
| 44 return false; | |
| 45 | |
| 46 NotificationObserverList* observer_list = observer_iterator->second; | |
| 47 NotificationObserverList::Iterator it(*observer_list); | |
| 48 NotificationObserver* existing_obs; | |
| 49 size_t count = 0; | |
| 50 while ((existing_obs = it.GetNext()) != NULL) { | |
| 51 if (existing_obs == obs) | |
| 52 count++; | |
| 53 } | |
| 54 | |
| 55 return count; | |
| 56 } | |
| 57 }; | |
| 58 | |
| 59 // Mock PrefValueStore that has no unnecessary PrefStores and injects a simpler | |
| 60 // PrefHasChanged(). | |
| 61 class MockPrefValueStore : public PrefValueStore { | |
| 62 public: | |
| 63 MockPrefValueStore() | |
| 64 : PrefValueStore(NULL, NULL, NULL, NULL, NULL, NULL, | |
| 65 new InMemoryPrefStore(), NULL) {} | |
| 66 | |
| 67 virtual ~MockPrefValueStore() {} | |
| 68 | |
| 69 // This mock version returns true if the pref path starts with "changed". | |
| 70 virtual bool PrefHasChanged(const char* path, | |
| 71 PrefNotifier::PrefStoreType new_store) { | |
| 72 std::string path_str(path); | |
| 73 if (path_str.compare(0, 7, "changed") == 0) | |
| 74 return true; | |
| 75 return false; | |
| 76 } | |
| 77 }; | |
| 78 | |
| 79 // Mock PrefService that allows the PrefNotifier to be injected. | |
| 80 class MockPrefService : public PrefService { | |
| 81 public: | |
| 82 explicit MockPrefService(PrefValueStore* pref_value_store) | |
| 83 : PrefService(pref_value_store) {} | |
| 84 | |
| 85 void SetPrefNotifier(PrefNotifier* notifier) { | |
| 86 pref_notifier_.reset(notifier); | |
| 87 } | |
| 88 }; | |
| 89 | |
| 90 // Mock PrefObserver that verifies notifications. | |
| 91 class MockPrefObserver : public NotificationObserver { | |
| 92 public: | |
| 93 virtual ~MockPrefObserver() {} | |
| 94 | |
| 95 MOCK_METHOD3(Observe, void(NotificationType type, | |
| 96 const NotificationSource& source, | |
| 97 const NotificationDetails& details)); | |
| 98 }; | |
| 99 | |
| 100 // Test fixture class. | |
| 101 class PrefNotifierTest : public testing::Test { | |
| 102 protected: | |
| 103 virtual void SetUp() { | |
| 104 value_store_ = new MockPrefValueStore; | |
| 105 pref_service_.reset(new MockPrefService(value_store_)); | |
| 106 notifier_ = new MockPrefNotifier(pref_service_.get(), value_store_); | |
| 107 pref_service_->SetPrefNotifier(notifier_); | |
| 108 | |
| 109 pref_service_->RegisterBooleanPref(kChangedPref, true); | |
| 110 pref_service_->RegisterBooleanPref(kUnchangedPref, true); | |
| 111 } | |
| 112 | |
| 113 // The PrefService takes ownership of the PrefValueStore and PrefNotifier. | |
| 114 PrefValueStore* value_store_; | |
| 115 MockPrefNotifier* notifier_; | |
| 116 scoped_ptr<MockPrefService> pref_service_; | |
| 117 | |
| 118 MockPrefObserver obs1_; | |
| 119 MockPrefObserver obs2_; | |
| 120 }; | |
| 121 | |
| 122 TEST_F(PrefNotifierTest, OnPreferenceSet) { | |
| 123 EXPECT_CALL(*notifier_, FireObservers(kChangedPref)) | |
| 124 .Times(PrefNotifier::PREF_STORE_TYPE_MAX + 1); | |
| 125 EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0); | |
| 126 | |
| 127 for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) { | |
| 128 notifier_->OnPreferenceSet(kChangedPref, | |
| 129 static_cast<PrefNotifier::PrefStoreType>(i)); | |
| 130 notifier_->OnPreferenceSet(kUnchangedPref, | |
| 131 static_cast<PrefNotifier::PrefStoreType>(i)); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 TEST_F(PrefNotifierTest, OnUserPreferenceSet) { | |
| 136 EXPECT_CALL(*notifier_, FireObservers(kChangedPref)); | |
| 137 EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0); | |
| 138 notifier_->OnUserPreferenceSet(kChangedPref); | |
| 139 notifier_->OnUserPreferenceSet(kUnchangedPref); | |
| 140 } | |
| 141 | |
| 142 TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) { | |
| 143 const char pref_name[] = "homepage"; | |
| 144 const char pref_name2[] = "proxy"; | |
| 145 | |
| 146 notifier_->AddPrefObserver(pref_name, &obs1_); | |
| 147 ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_)); | |
| 148 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_)); | |
| 149 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); | |
| 150 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); | |
| 151 | |
| 152 // Re-adding the same observer for the same pref doesn't change anything. | |
| 153 // Skip this in debug mode, since it hits a DCHECK and death tests aren't | |
| 154 // thread-safe. | |
| 155 #if defined(NDEBUG) | |
| 156 notifier_->AddPrefObserver(pref_name, &obs1_); | |
| 157 ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_)); | |
| 158 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_)); | |
| 159 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); | |
| 160 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); | |
| 161 #endif // NDEBUG | |
| 162 | |
| 163 // Ensure that we can add the same observer to a different pref. | |
| 164 notifier_->AddPrefObserver(pref_name2, &obs1_); | |
| 165 ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_)); | |
| 166 ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); | |
| 167 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); | |
| 168 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); | |
| 169 | |
| 170 // Ensure that we can add another observer to the same pref. | |
| 171 notifier_->AddPrefObserver(pref_name, &obs2_); | |
| 172 ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_)); | |
| 173 ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); | |
| 174 ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs2_)); | |
| 175 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); | |
| 176 | |
| 177 // Ensure that we can remove all observers, and that removing a non-existent | |
| 178 // observer is harmless. | |
| 179 notifier_->RemovePrefObserver(pref_name, &obs1_); | |
| 180 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_)); | |
| 181 ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); | |
| 182 ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs2_)); | |
| 183 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); | |
| 184 | |
| 185 notifier_->RemovePrefObserver(pref_name, &obs2_); | |
| 186 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_)); | |
| 187 ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); | |
| 188 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); | |
| 189 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); | |
| 190 | |
| 191 notifier_->RemovePrefObserver(pref_name, &obs1_); | |
| 192 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_)); | |
| 193 ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_)); | |
| 194 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); | |
| 195 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); | |
| 196 | |
| 197 notifier_->RemovePrefObserver(pref_name2, &obs1_); | |
| 198 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_)); | |
| 199 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_)); | |
| 200 ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_)); | |
| 201 ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_)); | |
| 202 } | |
| 203 | |
| 204 TEST_F(PrefNotifierTest, FireObservers) { | |
| 205 using testing::_; | |
| 206 using testing::Field; | |
| 207 using testing::Invoke; | |
| 208 using testing::Mock; | |
| 209 using testing::Truly; | |
| 210 | |
| 211 // Tell googlemock to pass calls to the mock's "back door" too. | |
| 212 ON_CALL(*notifier_, FireObservers(_)) | |
| 213 .WillByDefault(Invoke(notifier_, &MockPrefNotifier::RealFireObservers)); | |
| 214 EXPECT_CALL(*notifier_, FireObservers(kChangedPref)).Times(4); | |
| 215 EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0); | |
| 216 | |
| 217 notifier_->AddPrefObserver(kChangedPref, &obs1_); | |
| 218 notifier_->AddPrefObserver(kUnchangedPref, &obs1_); | |
| 219 | |
| 220 EXPECT_CALL(obs1_, Observe( | |
| 221 Field(&NotificationType::value, NotificationType::PREF_CHANGED), | |
| 222 Source<PrefService>(pref_service_.get()), | |
| 223 Truly(DetailsAreChangedPref))); | |
| 224 EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); | |
| 225 notifier_->OnUserPreferenceSet(kChangedPref); | |
| 226 Mock::VerifyAndClearExpectations(&obs1_); | |
| 227 Mock::VerifyAndClearExpectations(&obs2_); | |
| 228 | |
| 229 EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); | |
| 230 EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); | |
| 231 notifier_->OnUserPreferenceSet(kUnchangedPref); | |
| 232 Mock::VerifyAndClearExpectations(&obs1_); | |
| 233 Mock::VerifyAndClearExpectations(&obs2_); | |
| 234 | |
| 235 notifier_->AddPrefObserver(kChangedPref, &obs2_); | |
| 236 notifier_->AddPrefObserver(kUnchangedPref, &obs2_); | |
| 237 | |
| 238 EXPECT_CALL(obs1_, Observe( | |
| 239 Field(&NotificationType::value, NotificationType::PREF_CHANGED), | |
| 240 Source<PrefService>(pref_service_.get()), | |
| 241 Truly(DetailsAreChangedPref))); | |
| 242 EXPECT_CALL(obs2_, Observe( | |
| 243 Field(&NotificationType::value, NotificationType::PREF_CHANGED), | |
| 244 Source<PrefService>(pref_service_.get()), | |
| 245 Truly(DetailsAreChangedPref))); | |
| 246 notifier_->OnUserPreferenceSet(kChangedPref); | |
| 247 Mock::VerifyAndClearExpectations(&obs1_); | |
| 248 Mock::VerifyAndClearExpectations(&obs2_); | |
| 249 | |
| 250 EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); | |
| 251 EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); | |
| 252 notifier_->OnUserPreferenceSet(kUnchangedPref); | |
| 253 Mock::VerifyAndClearExpectations(&obs1_); | |
| 254 Mock::VerifyAndClearExpectations(&obs2_); | |
| 255 | |
| 256 // Make sure removing an observer from one pref doesn't affect anything else. | |
| 257 notifier_->RemovePrefObserver(kChangedPref, &obs1_); | |
| 258 | |
| 259 EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); | |
| 260 EXPECT_CALL(obs2_, Observe( | |
| 261 Field(&NotificationType::value, NotificationType::PREF_CHANGED), | |
| 262 Source<PrefService>(pref_service_.get()), | |
| 263 Truly(DetailsAreChangedPref))); | |
| 264 notifier_->OnUserPreferenceSet(kChangedPref); | |
| 265 Mock::VerifyAndClearExpectations(&obs1_); | |
| 266 Mock::VerifyAndClearExpectations(&obs2_); | |
| 267 | |
| 268 EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); | |
| 269 EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); | |
| 270 notifier_->OnUserPreferenceSet(kUnchangedPref); | |
| 271 Mock::VerifyAndClearExpectations(&obs1_); | |
| 272 Mock::VerifyAndClearExpectations(&obs2_); | |
| 273 | |
| 274 // Make sure removing an observer entirely doesn't affect anything else. | |
| 275 notifier_->RemovePrefObserver(kUnchangedPref, &obs1_); | |
| 276 | |
| 277 EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); | |
| 278 EXPECT_CALL(obs2_, Observe( | |
| 279 Field(&NotificationType::value, NotificationType::PREF_CHANGED), | |
| 280 Source<PrefService>(pref_service_.get()), | |
| 281 Truly(DetailsAreChangedPref))); | |
| 282 notifier_->OnUserPreferenceSet(kChangedPref); | |
| 283 Mock::VerifyAndClearExpectations(&obs1_); | |
| 284 Mock::VerifyAndClearExpectations(&obs2_); | |
| 285 | |
| 286 EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0); | |
| 287 EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0); | |
| 288 notifier_->OnUserPreferenceSet(kUnchangedPref); | |
| 289 | |
| 290 notifier_->RemovePrefObserver(kChangedPref, &obs2_); | |
| 291 notifier_->RemovePrefObserver(kUnchangedPref, &obs2_); | |
| 292 } | |
| 293 | |
| 294 } // namespace | |
| OLD | NEW |