Home | History | Annotate | Download | only in prefs
      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