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