Home | History | Annotate | Download | only in prefs
      1 // Copyright 2013 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_hash_filter.h"
      6 
      7 #include <map>
      8 #include <set>
      9 #include <string>
     10 #include <utility>
     11 #include <vector>
     12 
     13 #include "base/basictypes.h"
     14 #include "base/bind.h"
     15 #include "base/callback_forward.h"
     16 #include "base/compiler_specific.h"
     17 #include "base/logging.h"
     18 #include "base/memory/ref_counted.h"
     19 #include "base/memory/scoped_ptr.h"
     20 #include "base/prefs/testing_pref_store.h"
     21 #include "base/values.h"
     22 #include "chrome/browser/prefs/mock_validation_delegate.h"
     23 #include "chrome/browser/prefs/pref_hash_store.h"
     24 #include "chrome/browser/prefs/pref_hash_store_transaction.h"
     25 #include "chrome/browser/prefs/tracked/hash_store_contents.h"
     26 #include "chrome/common/pref_names.h"
     27 #include "testing/gtest/include/gtest/gtest.h"
     28 
     29 namespace {
     30 
     31 const char kAtomicPref[] = "atomic_pref";
     32 const char kAtomicPref2[] = "atomic_pref2";
     33 const char kAtomicPref3[] = "pref3";
     34 const char kAtomicPref4[] = "pref4";
     35 const char kReportOnlyPref[] = "report_only";
     36 const char kReportOnlySplitPref[] = "report_only_split_pref";
     37 const char kSplitPref[] = "split_pref";
     38 
     39 const PrefHashFilter::TrackedPreferenceMetadata kTestTrackedPrefs[] = {
     40   {
     41     0, kAtomicPref, PrefHashFilter::ENFORCE_ON_LOAD,
     42     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
     43   },
     44   {
     45     1, kReportOnlyPref, PrefHashFilter::NO_ENFORCEMENT,
     46     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
     47   },
     48   {
     49     2, kSplitPref, PrefHashFilter::ENFORCE_ON_LOAD,
     50     PrefHashFilter::TRACKING_STRATEGY_SPLIT
     51   },
     52   {
     53     3, kReportOnlySplitPref, PrefHashFilter::NO_ENFORCEMENT,
     54     PrefHashFilter::TRACKING_STRATEGY_SPLIT
     55   },
     56   {
     57     4, kAtomicPref2, PrefHashFilter::ENFORCE_ON_LOAD,
     58     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
     59   },
     60   {
     61     5, kAtomicPref3, PrefHashFilter::ENFORCE_ON_LOAD,
     62     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
     63   },
     64   {
     65     6, kAtomicPref4, PrefHashFilter::ENFORCE_ON_LOAD,
     66     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
     67   },
     68 };
     69 
     70 }  // namespace
     71 
     72 // A PrefHashStore that allows simulation of CheckValue results and captures
     73 // checked and stored values.
     74 class MockPrefHashStore : public PrefHashStore {
     75  public:
     76   typedef std::pair<const void*, PrefHashFilter::PrefTrackingStrategy>
     77       ValuePtrStrategyPair;
     78 
     79   MockPrefHashStore()
     80       : transactions_performed_(0), transaction_active_(false) {}
     81 
     82   virtual ~MockPrefHashStore() {
     83     EXPECT_FALSE(transaction_active_);
     84   }
     85 
     86   // Set the result that will be returned when |path| is passed to
     87   // |CheckValue/CheckSplitValue|.
     88   void SetCheckResult(const std::string& path,
     89                       PrefHashStoreTransaction::ValueState result);
     90 
     91   // Set the invalid_keys that will be returned when |path| is passed to
     92   // |CheckSplitValue|. SetCheckResult should already have been called for
     93   // |path| with |result == CHANGED| for this to make any sense.
     94   void SetInvalidKeysResult(
     95       const std::string& path,
     96       const std::vector<std::string>& invalid_keys_result);
     97 
     98   // Returns the number of transactions that were performed.
     99   size_t transactions_performed() { return transactions_performed_; }
    100 
    101   // Returns the number of paths checked.
    102   size_t checked_paths_count() const {
    103     return checked_values_.size();
    104   }
    105 
    106   // Returns the number of paths stored.
    107   size_t stored_paths_count() const {
    108     return stored_values_.size();
    109   }
    110 
    111   // Returns the pointer value and strategy that was passed to
    112   // |CheckHash/CheckSplitHash| for |path|. The returned pointer could since
    113   // have been freed and is thus not safe to dereference.
    114   ValuePtrStrategyPair checked_value(const std::string& path) const {
    115     std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
    116         checked_values_.find(path);
    117     if (value != checked_values_.end())
    118       return value->second;
    119     return std::make_pair(
    120                reinterpret_cast<void*>(0xBAD),
    121                static_cast<PrefHashFilter::PrefTrackingStrategy>(-1));
    122   }
    123 
    124   // Returns the pointer value that was passed to |StoreHash/StoreSplitHash| for
    125   // |path|. The returned pointer could since have been freed and is thus not
    126   // safe to dereference.
    127   ValuePtrStrategyPair stored_value(const std::string& path) const {
    128     std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
    129         stored_values_.find(path);
    130     if (value != stored_values_.end())
    131       return value->second;
    132     return std::make_pair(
    133                reinterpret_cast<void*>(0xBAD),
    134                static_cast<PrefHashFilter::PrefTrackingStrategy>(-1));
    135   }
    136 
    137   // PrefHashStore implementation.
    138   virtual scoped_ptr<PrefHashStoreTransaction> BeginTransaction(
    139       scoped_ptr<HashStoreContents> storage) OVERRIDE;
    140 
    141  private:
    142   // A MockPrefHashStoreTransaction is handed to the caller on
    143   // MockPrefHashStore::BeginTransaction(). It then stores state in its
    144   // underlying MockPrefHashStore about calls it receives from that same caller
    145   // which can later be verified in tests.
    146   class MockPrefHashStoreTransaction : public PrefHashStoreTransaction {
    147    public:
    148     explicit MockPrefHashStoreTransaction(MockPrefHashStore* outer)
    149         : outer_(outer) {}
    150 
    151     virtual ~MockPrefHashStoreTransaction() {
    152       outer_->transaction_active_ = false;
    153       ++outer_->transactions_performed_;
    154     }
    155 
    156     // PrefHashStoreTransaction implementation.
    157     virtual PrefHashStoreTransaction::ValueState CheckValue(
    158         const std::string& path, const base::Value* value) const OVERRIDE;
    159     virtual void StoreHash(const std::string& path,
    160                            const base::Value* new_value) OVERRIDE;
    161     virtual PrefHashStoreTransaction::ValueState CheckSplitValue(
    162         const std::string& path,
    163         const base::DictionaryValue* initial_split_value,
    164         std::vector<std::string>* invalid_keys) const OVERRIDE;
    165     virtual void StoreSplitHash(
    166         const std::string& path,
    167         const base::DictionaryValue* split_value) OVERRIDE;
    168     virtual bool HasHash(const std::string& path) const OVERRIDE;
    169     virtual void ImportHash(const std::string& path,
    170                             const base::Value* hash) OVERRIDE;
    171     virtual void ClearHash(const std::string& path) OVERRIDE;
    172     virtual bool IsSuperMACValid() const OVERRIDE;
    173     virtual bool StampSuperMac() OVERRIDE;
    174 
    175    private:
    176     MockPrefHashStore* outer_;
    177 
    178     DISALLOW_COPY_AND_ASSIGN(MockPrefHashStoreTransaction);
    179   };
    180 
    181   // Records a call to this mock's CheckValue/CheckSplitValue methods.
    182   PrefHashStoreTransaction::ValueState RecordCheckValue(
    183       const std::string& path,
    184       const base::Value* value,
    185       PrefHashFilter::PrefTrackingStrategy strategy);
    186 
    187   // Records a call to this mock's StoreHash/StoreSplitHash methods.
    188   void RecordStoreHash(const std::string& path,
    189                        const base::Value* new_value,
    190                        PrefHashFilter::PrefTrackingStrategy strategy);
    191 
    192   std::map<std::string, PrefHashStoreTransaction::ValueState> check_results_;
    193   std::map<std::string, std::vector<std::string> > invalid_keys_results_;
    194   std::map<std::string, ValuePtrStrategyPair> checked_values_;
    195   std::map<std::string, ValuePtrStrategyPair> stored_values_;
    196 
    197   // Number of transactions that are expected to be performed in the scope of
    198   // this test (defaults to 1).
    199   size_t transactions_expected_;
    200 
    201   // Number of transactions that were performed via this MockPrefHashStore.
    202   // Verified to match |transactions_expected_| when this MockPrefHashStore is
    203   // deleted.
    204   size_t transactions_performed_;
    205 
    206   // Whether a transaction is currently active (only one transaction should be
    207   // active at a time).
    208   bool transaction_active_;
    209 
    210   DISALLOW_COPY_AND_ASSIGN(MockPrefHashStore);
    211 };
    212 
    213 void MockPrefHashStore::SetCheckResult(
    214     const std::string& path, PrefHashStoreTransaction::ValueState result) {
    215   check_results_.insert(std::make_pair(path, result));
    216 }
    217 
    218 void MockPrefHashStore::SetInvalidKeysResult(
    219     const std::string& path,
    220     const std::vector<std::string>& invalid_keys_result) {
    221   // Ensure |check_results_| has a CHANGED entry for |path|.
    222   std::map<std::string,
    223           PrefHashStoreTransaction::ValueState>::const_iterator result =
    224       check_results_.find(path);
    225   ASSERT_TRUE(result != check_results_.end());
    226   ASSERT_EQ(PrefHashStoreTransaction::CHANGED, result->second);
    227 
    228   invalid_keys_results_.insert(std::make_pair(path, invalid_keys_result));
    229 }
    230 
    231 scoped_ptr<PrefHashStoreTransaction> MockPrefHashStore::BeginTransaction(
    232     scoped_ptr<HashStoreContents> storage) {
    233   EXPECT_FALSE(transaction_active_);
    234   return scoped_ptr<PrefHashStoreTransaction>(
    235       new MockPrefHashStoreTransaction(this));
    236 }
    237 
    238 PrefHashStoreTransaction::ValueState MockPrefHashStore::RecordCheckValue(
    239     const std::string& path,
    240     const base::Value* value,
    241     PrefHashFilter::PrefTrackingStrategy strategy) {
    242   // Record that |path| was checked and validate that it wasn't previously
    243   // checked.
    244   EXPECT_TRUE(checked_values_.insert(
    245       std::make_pair(path, std::make_pair(value, strategy))).second);
    246   std::map<std::string,
    247            PrefHashStoreTransaction::ValueState>::const_iterator result =
    248       check_results_.find(path);
    249   if (result != check_results_.end())
    250     return result->second;
    251   return PrefHashStoreTransaction::UNCHANGED;
    252 }
    253 
    254 void MockPrefHashStore::RecordStoreHash(
    255     const std::string& path,
    256     const base::Value* new_value,
    257     PrefHashFilter::PrefTrackingStrategy strategy) {
    258   EXPECT_TRUE(stored_values_.insert(
    259       std::make_pair(path, std::make_pair(new_value, strategy))).second);
    260 }
    261 
    262 PrefHashStoreTransaction::ValueState
    263 MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue(
    264     const std::string& path, const base::Value* value) const {
    265   return outer_->RecordCheckValue(path, value,
    266                                   PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
    267 }
    268 
    269 void MockPrefHashStore::MockPrefHashStoreTransaction::StoreHash(
    270     const std::string& path,
    271     const base::Value* new_value) {
    272   outer_->RecordStoreHash(path, new_value,
    273                           PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
    274 }
    275 
    276 PrefHashStoreTransaction::ValueState
    277 MockPrefHashStore::MockPrefHashStoreTransaction::CheckSplitValue(
    278     const std::string& path,
    279     const base::DictionaryValue* initial_split_value,
    280     std::vector<std::string>* invalid_keys) const {
    281   EXPECT_TRUE(invalid_keys && invalid_keys->empty());
    282 
    283   std::map<std::string, std::vector<std::string> >::const_iterator
    284       invalid_keys_result = outer_->invalid_keys_results_.find(path);
    285   if (invalid_keys_result != outer_->invalid_keys_results_.end()) {
    286     invalid_keys->insert(invalid_keys->begin(),
    287                          invalid_keys_result->second.begin(),
    288                          invalid_keys_result->second.end());
    289   }
    290 
    291   return outer_->RecordCheckValue(path, initial_split_value,
    292                                   PrefHashFilter::TRACKING_STRATEGY_SPLIT);
    293 }
    294 
    295 void MockPrefHashStore::MockPrefHashStoreTransaction::StoreSplitHash(
    296     const std::string& path,
    297     const base::DictionaryValue* new_value) {
    298   outer_->RecordStoreHash(path, new_value,
    299                           PrefHashFilter::TRACKING_STRATEGY_SPLIT);
    300 }
    301 
    302 bool MockPrefHashStore::MockPrefHashStoreTransaction::HasHash(
    303     const std::string& path) const  {
    304   ADD_FAILURE() << "Unexpected call.";
    305   return false;
    306 }
    307 
    308 void MockPrefHashStore::MockPrefHashStoreTransaction::ImportHash(
    309     const std::string& path,
    310     const base::Value* hash)  {
    311   ADD_FAILURE() << "Unexpected call.";
    312 }
    313 
    314 void MockPrefHashStore::MockPrefHashStoreTransaction::ClearHash(
    315     const std::string& path)  {
    316   ADD_FAILURE() << "Unexpected call.";
    317 }
    318 
    319 bool MockPrefHashStore::MockPrefHashStoreTransaction::IsSuperMACValid() const {
    320   // TODO(erikwright): Test that the result of this method is reported to
    321   // Settings.HashesDictionaryTrusted.
    322   return false;
    323 }
    324 
    325 bool MockPrefHashStore::MockPrefHashStoreTransaction::StampSuperMac() {
    326   // TODO(erikwright): Test that, when there are no other changes to the store,
    327   // the result of this method determines the value of |prefs_altered| in the
    328   // |post_filter_on_load_callback| invocation.
    329   return false;
    330 }
    331 
    332 std::vector<PrefHashFilter::TrackedPreferenceMetadata> GetConfiguration(
    333     PrefHashFilter::EnforcementLevel max_enforcement_level) {
    334   std::vector<PrefHashFilter::TrackedPreferenceMetadata> configuration(
    335       kTestTrackedPrefs, kTestTrackedPrefs + arraysize(kTestTrackedPrefs));
    336   for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it =
    337            configuration.begin();
    338        it != configuration.end();
    339        ++it) {
    340     if (it->enforcement_level > max_enforcement_level)
    341       it->enforcement_level = max_enforcement_level;
    342   }
    343   return configuration;
    344 }
    345 
    346 class PrefHashFilterTest
    347     : public testing::TestWithParam<PrefHashFilter::EnforcementLevel> {
    348  public:
    349   PrefHashFilterTest() : mock_pref_hash_store_(NULL),
    350                          pref_store_contents_(new base::DictionaryValue),
    351                          last_filter_on_load_modified_prefs_(false),
    352                          reset_recorded_(false) {}
    353 
    354   virtual void SetUp() OVERRIDE {
    355     // Construct a PrefHashFilter and MockPrefHashStore for the test.
    356     InitializePrefHashFilter(GetConfiguration(GetParam()));
    357   }
    358 
    359  protected:
    360   // Initializes |pref_hash_filter_| with a PrefHashFilter that uses a
    361   // MockPrefHashStore. The raw pointer to the MockPrefHashStore (owned by the
    362   // PrefHashFilter) is stored in |mock_pref_hash_store_|.
    363   void InitializePrefHashFilter(const std::vector<
    364       PrefHashFilter::TrackedPreferenceMetadata>& configuration) {
    365     scoped_ptr<MockPrefHashStore> temp_mock_pref_hash_store(
    366         new MockPrefHashStore);
    367     mock_pref_hash_store_ = temp_mock_pref_hash_store.get();
    368     pref_hash_filter_.reset(new PrefHashFilter(
    369         temp_mock_pref_hash_store.PassAs<PrefHashStore>(),
    370         configuration,
    371         base::Bind(&PrefHashFilterTest::RecordReset, base::Unretained(this)),
    372         &mock_validation_delegate_,
    373         arraysize(kTestTrackedPrefs),
    374         true));
    375   }
    376 
    377   // Verifies whether a reset was reported by the PrefHashFiler. Also verifies
    378   // that kPreferenceResetTime was set (or not) accordingly.
    379   void VerifyRecordedReset(bool reset_expected) {
    380     EXPECT_EQ(reset_expected, reset_recorded_);
    381     EXPECT_EQ(reset_expected,
    382               pref_store_contents_->Get(prefs::kPreferenceResetTime, NULL));
    383   }
    384 
    385   // Calls FilterOnLoad() on |pref_hash_Filter_|. |pref_store_contents_| is
    386   // handed off, but should be given back to us synchronously through
    387   // GetPrefsBack() as there is no FilterOnLoadInterceptor installed on
    388   // |pref_hash_filter_|.
    389   void DoFilterOnLoad(bool expect_prefs_modifications) {
    390     pref_hash_filter_->FilterOnLoad(
    391         base::Bind(&PrefHashFilterTest::GetPrefsBack, base::Unretained(this),
    392                    expect_prefs_modifications),
    393         pref_store_contents_.Pass());
    394   }
    395 
    396   MockPrefHashStore* mock_pref_hash_store_;
    397   scoped_ptr<base::DictionaryValue> pref_store_contents_;
    398   bool last_filter_on_load_modified_prefs_;
    399   MockValidationDelegate mock_validation_delegate_;
    400   scoped_ptr<PrefHashFilter> pref_hash_filter_;
    401 
    402  private:
    403   // Stores |prefs| back in |pref_store_contents| and ensure
    404   // |expected_schedule_write| matches the reported |schedule_write|.
    405   void GetPrefsBack(bool expected_schedule_write,
    406                     scoped_ptr<base::DictionaryValue> prefs,
    407                     bool schedule_write) {
    408     pref_store_contents_ = prefs.Pass();
    409     EXPECT_TRUE(pref_store_contents_);
    410     EXPECT_EQ(expected_schedule_write, schedule_write);
    411   }
    412 
    413   void RecordReset() {
    414     // As-is |reset_recorded_| is only designed to remember a single reset, make
    415     // sure none was previously recorded.
    416     EXPECT_FALSE(reset_recorded_);
    417     reset_recorded_ = true;
    418   }
    419 
    420   bool reset_recorded_;
    421 
    422   DISALLOW_COPY_AND_ASSIGN(PrefHashFilterTest);
    423 };
    424 
    425 TEST_P(PrefHashFilterTest, EmptyAndUnchanged) {
    426   DoFilterOnLoad(false);
    427   // All paths checked.
    428   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    429             mock_pref_hash_store_->checked_paths_count());
    430   // No paths stored, since they all return |UNCHANGED|.
    431   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
    432   // Since there was nothing in |pref_store_contents_| the checked value should
    433   // have been NULL for all tracked preferences.
    434   for (size_t i = 0; i < arraysize(kTestTrackedPrefs); ++i) {
    435     ASSERT_EQ(NULL, mock_pref_hash_store_->checked_value(
    436                         kTestTrackedPrefs[i].name).first);
    437   }
    438   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    439   VerifyRecordedReset(false);
    440 
    441   // Delegate saw all paths, and all unchanged.
    442   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    443             mock_validation_delegate_.recorded_validations_count());
    444   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    445             mock_validation_delegate_.CountValidationsOfState(
    446                 PrefHashStoreTransaction::UNCHANGED));
    447 }
    448 
    449 TEST_P(PrefHashFilterTest, FilterTrackedPrefUpdate) {
    450   base::DictionaryValue root_dict;
    451   // Ownership of |string_value| is transfered to |root_dict|.
    452   base::Value* string_value = base::Value::CreateStringValue("string value");
    453   root_dict.Set(kAtomicPref, string_value);
    454 
    455   // No path should be stored on FilterUpdate.
    456   pref_hash_filter_->FilterUpdate(kAtomicPref);
    457   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
    458 
    459   // One path should be stored on FilterSerializeData.
    460   pref_hash_filter_->FilterSerializeData(&root_dict);
    461   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
    462   MockPrefHashStore::ValuePtrStrategyPair stored_value =
    463       mock_pref_hash_store_->stored_value(kAtomicPref);
    464   ASSERT_EQ(string_value, stored_value.first);
    465   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, stored_value.second);
    466 
    467   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    468   VerifyRecordedReset(false);
    469 }
    470 
    471 TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
    472   base::DictionaryValue root_dict;
    473   // Ownership of |dict_value| is transfered to |root_dict|.
    474   base::DictionaryValue* dict_value = new base::DictionaryValue;
    475   dict_value->SetString("a", "foo");
    476   dict_value->SetInteger("b", 1234);
    477   root_dict.Set(kSplitPref, dict_value);
    478 
    479   // No path should be stored on FilterUpdate.
    480   pref_hash_filter_->FilterUpdate(kSplitPref);
    481   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
    482 
    483   // One path should be stored on FilterSerializeData.
    484   pref_hash_filter_->FilterSerializeData(&root_dict);
    485   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
    486   MockPrefHashStore::ValuePtrStrategyPair stored_value =
    487        mock_pref_hash_store_->stored_value(kSplitPref);
    488   ASSERT_EQ(dict_value, stored_value.first);
    489   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value.second);
    490 
    491   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    492   VerifyRecordedReset(false);
    493 }
    494 
    495 TEST_P(PrefHashFilterTest, FilterUntrackedPrefUpdate) {
    496   base::DictionaryValue root_dict;
    497   root_dict.Set("untracked", base::Value::CreateStringValue("some value"));
    498   pref_hash_filter_->FilterUpdate("untracked");
    499 
    500   // No paths should be stored on FilterUpdate.
    501   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
    502 
    503   // Nor on FilterSerializeData.
    504   pref_hash_filter_->FilterSerializeData(&root_dict);
    505   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
    506 
    507   // No transaction should even be started on FilterSerializeData() if there are
    508   // no updates to perform.
    509   ASSERT_EQ(0u, mock_pref_hash_store_->transactions_performed());
    510 }
    511 
    512 TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) {
    513   base::DictionaryValue root_dict;
    514   // Ownership of the following values is transfered to |root_dict|.
    515   base::Value* int_value1 = base::Value::CreateIntegerValue(1);
    516   base::Value* int_value2 = base::Value::CreateIntegerValue(2);
    517   base::Value* int_value3 = base::Value::CreateIntegerValue(3);
    518   base::Value* int_value4 = base::Value::CreateIntegerValue(4);
    519   base::DictionaryValue* dict_value = new base::DictionaryValue;
    520   dict_value->Set("a", base::Value::CreateBooleanValue(true));
    521   root_dict.Set(kAtomicPref, int_value1);
    522   root_dict.Set(kAtomicPref2, int_value2);
    523   root_dict.Set(kAtomicPref3, int_value3);
    524   root_dict.Set("untracked", int_value4);
    525   root_dict.Set(kSplitPref, dict_value);
    526 
    527   // Only update kAtomicPref, kAtomicPref3, and kSplitPref.
    528   pref_hash_filter_->FilterUpdate(kAtomicPref);
    529   pref_hash_filter_->FilterUpdate(kAtomicPref3);
    530   pref_hash_filter_->FilterUpdate(kSplitPref);
    531   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
    532 
    533   // Update kAtomicPref3 again, nothing should be stored still.
    534   base::Value* int_value5 = base::Value::CreateIntegerValue(5);
    535   root_dict.Set(kAtomicPref3, int_value5);
    536   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
    537 
    538   // On FilterSerializeData, only kAtomicPref, kAtomicPref3, and kSplitPref
    539   // should get a new hash.
    540   pref_hash_filter_->FilterSerializeData(&root_dict);
    541   ASSERT_EQ(3u, mock_pref_hash_store_->stored_paths_count());
    542   MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1 =
    543       mock_pref_hash_store_->stored_value(kAtomicPref);
    544   ASSERT_EQ(int_value1, stored_value_atomic1.first);
    545   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    546             stored_value_atomic1.second);
    547   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    548 
    549   MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3 =
    550       mock_pref_hash_store_->stored_value(kAtomicPref3);
    551   ASSERT_EQ(int_value5, stored_value_atomic3.first);
    552   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    553             stored_value_atomic3.second);
    554 
    555   MockPrefHashStore::ValuePtrStrategyPair stored_value_split =
    556        mock_pref_hash_store_->stored_value(kSplitPref);
    557   ASSERT_EQ(dict_value, stored_value_split.first);
    558   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value_split.second);
    559 }
    560 
    561 TEST_P(PrefHashFilterTest, EmptyAndUnknown) {
    562   ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
    563   ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
    564   // NULL values are always trusted by the PrefHashStore.
    565   mock_pref_hash_store_->SetCheckResult(
    566       kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
    567   mock_pref_hash_store_->SetCheckResult(
    568       kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
    569   DoFilterOnLoad(false);
    570   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    571             mock_pref_hash_store_->checked_paths_count());
    572   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
    573   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    574 
    575   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
    576        mock_pref_hash_store_->stored_value(kAtomicPref);
    577   ASSERT_EQ(NULL, stored_atomic_value.first);
    578   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    579             stored_atomic_value.second);
    580 
    581   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
    582        mock_pref_hash_store_->stored_value(kSplitPref);
    583   ASSERT_EQ(NULL, stored_split_value.first);
    584   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
    585             stored_split_value.second);
    586 
    587   // Delegate saw all prefs, two of which had the expected value_state.
    588   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    589             mock_validation_delegate_.recorded_validations_count());
    590   ASSERT_EQ(2u,
    591             mock_validation_delegate_.CountValidationsOfState(
    592                 PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE));
    593   ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
    594             mock_validation_delegate_.CountValidationsOfState(
    595                 PrefHashStoreTransaction::UNCHANGED));
    596 
    597   const MockValidationDelegate::ValidationEvent* validated_split_pref =
    598       mock_validation_delegate_.GetEventForPath(kSplitPref);
    599   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
    600             validated_split_pref->strategy);
    601   EXPECT_EQ(TrackedPreferenceHelper::DONT_RESET,
    602             validated_split_pref->reset_action);
    603   const MockValidationDelegate::ValidationEvent* validated_atomic_pref =
    604       mock_validation_delegate_.GetEventForPath(kAtomicPref);
    605   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    606             validated_atomic_pref->strategy);
    607   EXPECT_EQ(TrackedPreferenceHelper::DONT_RESET,
    608             validated_atomic_pref->reset_action);
    609 }
    610 
    611 TEST_P(PrefHashFilterTest, InitialValueUnknown) {
    612   // Ownership of these values is transfered to |pref_store_contents_|.
    613   base::StringValue* string_value = new base::StringValue("string value");
    614   pref_store_contents_->Set(kAtomicPref, string_value);
    615 
    616   base::DictionaryValue* dict_value = new base::DictionaryValue;
    617   dict_value->SetString("a", "foo");
    618   dict_value->SetInteger("b", 1234);
    619   pref_store_contents_->Set(kSplitPref, dict_value);
    620 
    621   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
    622   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
    623 
    624   mock_pref_hash_store_->SetCheckResult(
    625       kAtomicPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE);
    626   mock_pref_hash_store_->SetCheckResult(
    627       kSplitPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE);
    628   // If we are enforcing, expect this to report changes.
    629   DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD);
    630   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    631             mock_pref_hash_store_->checked_paths_count());
    632   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
    633   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    634 
    635   // Delegate saw all prefs, two of which had the expected value_state.
    636   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    637             mock_validation_delegate_.recorded_validations_count());
    638   ASSERT_EQ(2u,
    639             mock_validation_delegate_.CountValidationsOfState(
    640                 PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE));
    641   ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
    642             mock_validation_delegate_.CountValidationsOfState(
    643                 PrefHashStoreTransaction::UNCHANGED));
    644 
    645   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
    646        mock_pref_hash_store_->stored_value(kAtomicPref);
    647   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
    648        mock_pref_hash_store_->stored_value(kSplitPref);
    649   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    650             stored_atomic_value.second);
    651   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
    652             stored_split_value.second);
    653   if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
    654     // Ensure the prefs were cleared and the hashes for NULL were restored if
    655     // the current enforcement level denies seeding.
    656     ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
    657     ASSERT_EQ(NULL, stored_atomic_value.first);
    658 
    659     ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
    660     ASSERT_EQ(NULL, stored_split_value.first);
    661 
    662     VerifyRecordedReset(true);
    663   } else {
    664     // Otherwise the values should have remained intact and the hashes should
    665     // have been updated to match them.
    666     const base::Value* atomic_value_in_store;
    667     ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
    668     ASSERT_EQ(string_value, atomic_value_in_store);
    669     ASSERT_EQ(string_value, stored_atomic_value.first);
    670 
    671     const base::Value* split_value_in_store;
    672     ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
    673     ASSERT_EQ(dict_value, split_value_in_store);
    674     ASSERT_EQ(dict_value, stored_split_value.first);
    675 
    676     VerifyRecordedReset(false);
    677   }
    678 }
    679 
    680 TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) {
    681   // Ownership of this value is transfered to |pref_store_contents_|.
    682   base::Value* string_value = base::Value::CreateStringValue("test");
    683   pref_store_contents_->Set(kAtomicPref, string_value);
    684 
    685   base::DictionaryValue* dict_value = new base::DictionaryValue;
    686   dict_value->SetString("a", "foo");
    687   dict_value->SetInteger("b", 1234);
    688   pref_store_contents_->Set(kSplitPref, dict_value);
    689 
    690   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
    691   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
    692 
    693   mock_pref_hash_store_->SetCheckResult(
    694       kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
    695   mock_pref_hash_store_->SetCheckResult(
    696       kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
    697   DoFilterOnLoad(false);
    698   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    699             mock_pref_hash_store_->checked_paths_count());
    700   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
    701   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    702 
    703   // Delegate saw all prefs, two of which had the expected value_state.
    704   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    705             mock_validation_delegate_.recorded_validations_count());
    706   ASSERT_EQ(2u,
    707             mock_validation_delegate_.CountValidationsOfState(
    708                 PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE));
    709   ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
    710             mock_validation_delegate_.CountValidationsOfState(
    711                 PrefHashStoreTransaction::UNCHANGED));
    712 
    713   // Seeding is always allowed for trusted unknown values.
    714   const base::Value* atomic_value_in_store;
    715   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
    716   ASSERT_EQ(string_value, atomic_value_in_store);
    717   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
    718        mock_pref_hash_store_->stored_value(kAtomicPref);
    719   ASSERT_EQ(string_value, stored_atomic_value.first);
    720   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    721             stored_atomic_value.second);
    722 
    723   const base::Value* split_value_in_store;
    724   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
    725   ASSERT_EQ(dict_value, split_value_in_store);
    726   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
    727        mock_pref_hash_store_->stored_value(kSplitPref);
    728   ASSERT_EQ(dict_value, stored_split_value.first);
    729   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
    730             stored_split_value.second);
    731 }
    732 
    733 TEST_P(PrefHashFilterTest, InitialValueChanged) {
    734   // Ownership of this value is transfered to |pref_store_contents_|.
    735   base::Value* int_value = base::Value::CreateIntegerValue(1234);
    736   pref_store_contents_->Set(kAtomicPref, int_value);
    737 
    738   base::DictionaryValue* dict_value = new base::DictionaryValue;
    739   dict_value->SetString("a", "foo");
    740   dict_value->SetInteger("b", 1234);
    741   dict_value->SetInteger("c", 56);
    742   dict_value->SetBoolean("d", false);
    743   pref_store_contents_->Set(kSplitPref, dict_value);
    744 
    745   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
    746   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
    747 
    748   mock_pref_hash_store_->SetCheckResult(kAtomicPref,
    749                                         PrefHashStoreTransaction::CHANGED);
    750   mock_pref_hash_store_->SetCheckResult(kSplitPref,
    751                                         PrefHashStoreTransaction::CHANGED);
    752 
    753   std::vector<std::string> mock_invalid_keys;
    754   mock_invalid_keys.push_back("a");
    755   mock_invalid_keys.push_back("c");
    756   mock_pref_hash_store_->SetInvalidKeysResult(kSplitPref, mock_invalid_keys);
    757 
    758   DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD);
    759   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    760             mock_pref_hash_store_->checked_paths_count());
    761   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
    762   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    763 
    764   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
    765        mock_pref_hash_store_->stored_value(kAtomicPref);
    766   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
    767        mock_pref_hash_store_->stored_value(kSplitPref);
    768   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    769             stored_atomic_value.second);
    770   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
    771             stored_split_value.second);
    772   if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
    773     // Ensure the atomic pref was cleared and the hash for NULL was restored if
    774     // the current enforcement level prevents changes.
    775     ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
    776     ASSERT_EQ(NULL, stored_atomic_value.first);
    777 
    778     // The split pref on the other hand should only have been stripped of its
    779     // invalid keys.
    780     const base::Value* split_value_in_store;
    781     ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
    782     ASSERT_EQ(2U, dict_value->size());
    783     ASSERT_FALSE(dict_value->HasKey("a"));
    784     ASSERT_TRUE(dict_value->HasKey("b"));
    785     ASSERT_FALSE(dict_value->HasKey("c"));
    786     ASSERT_TRUE(dict_value->HasKey("d"));
    787     ASSERT_EQ(dict_value, stored_split_value.first);
    788 
    789     VerifyRecordedReset(true);
    790   } else {
    791     // Otherwise the value should have remained intact and the hash should have
    792     // been updated to match it.
    793     const base::Value* atomic_value_in_store;
    794     ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
    795     ASSERT_EQ(int_value, atomic_value_in_store);
    796     ASSERT_EQ(int_value, stored_atomic_value.first);
    797 
    798     const base::Value* split_value_in_store;
    799     ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
    800     ASSERT_EQ(dict_value, split_value_in_store);
    801     ASSERT_EQ(4U, dict_value->size());
    802     ASSERT_TRUE(dict_value->HasKey("a"));
    803     ASSERT_TRUE(dict_value->HasKey("b"));
    804     ASSERT_TRUE(dict_value->HasKey("c"));
    805     ASSERT_TRUE(dict_value->HasKey("d"));
    806     ASSERT_EQ(dict_value, stored_split_value.first);
    807 
    808     VerifyRecordedReset(false);
    809   }
    810 }
    811 
    812 TEST_P(PrefHashFilterTest, EmptyCleared) {
    813   ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
    814   ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
    815   mock_pref_hash_store_->SetCheckResult(kAtomicPref,
    816                                         PrefHashStoreTransaction::CLEARED);
    817   mock_pref_hash_store_->SetCheckResult(kSplitPref,
    818                                         PrefHashStoreTransaction::CLEARED);
    819   DoFilterOnLoad(false);
    820   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    821             mock_pref_hash_store_->checked_paths_count());
    822   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
    823   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    824 
    825   // Delegate saw all prefs, two of which had the expected value_state.
    826   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    827             mock_validation_delegate_.recorded_validations_count());
    828   ASSERT_EQ(2u,
    829             mock_validation_delegate_.CountValidationsOfState(
    830                 PrefHashStoreTransaction::CLEARED));
    831   ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
    832             mock_validation_delegate_.CountValidationsOfState(
    833                 PrefHashStoreTransaction::UNCHANGED));
    834 
    835   // Regardless of the enforcement level, the only thing that should be done is
    836   // to restore the hash for NULL. The value itself should still be NULL.
    837   ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
    838   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
    839        mock_pref_hash_store_->stored_value(kAtomicPref);
    840   ASSERT_EQ(NULL, stored_atomic_value.first);
    841   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    842             stored_atomic_value.second);
    843 
    844   ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
    845   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
    846        mock_pref_hash_store_->stored_value(kSplitPref);
    847   ASSERT_EQ(NULL, stored_split_value.first);
    848   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
    849             stored_split_value.second);
    850 }
    851 
    852 TEST_P(PrefHashFilterTest, InitialValueMigrated) {
    853   // Only test atomic prefs, split prefs were introduce after the migration.
    854 
    855   // Ownership of this value is transfered to |pref_store_contents_|.
    856   base::ListValue* list_value = new base::ListValue;
    857   list_value->Append(base::Value::CreateStringValue("test"));
    858   pref_store_contents_->Set(kAtomicPref, list_value);
    859 
    860   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
    861 
    862   mock_pref_hash_store_->SetCheckResult(kAtomicPref,
    863                                         PrefHashStoreTransaction::WEAK_LEGACY);
    864 
    865   DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD);
    866   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    867             mock_pref_hash_store_->checked_paths_count());
    868   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
    869   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    870 
    871   // Delegate saw all prefs, one of which had the expected value_state.
    872   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    873             mock_validation_delegate_.recorded_validations_count());
    874   ASSERT_EQ(1u,
    875             mock_validation_delegate_.CountValidationsOfState(
    876                 PrefHashStoreTransaction::WEAK_LEGACY));
    877   ASSERT_EQ(arraysize(kTestTrackedPrefs) - 1u,
    878             mock_validation_delegate_.CountValidationsOfState(
    879                 PrefHashStoreTransaction::UNCHANGED));
    880 
    881   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
    882        mock_pref_hash_store_->stored_value(kAtomicPref);
    883   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    884             stored_atomic_value.second);
    885   if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
    886     // Ensure the pref was cleared and the hash for NULL was restored if the
    887     // current enforcement level prevents migration.
    888     ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
    889     ASSERT_EQ(NULL, stored_atomic_value.first);
    890 
    891     VerifyRecordedReset(true);
    892   } else {
    893     // Otherwise the value should have remained intact and the hash should have
    894     // been updated to match it.
    895     const base::Value* atomic_value_in_store;
    896     ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
    897     ASSERT_EQ(list_value, atomic_value_in_store);
    898     ASSERT_EQ(list_value, stored_atomic_value.first);
    899 
    900     VerifyRecordedReset(false);
    901   }
    902 }
    903 
    904 TEST_P(PrefHashFilterTest, InitialValueUnchangedLegacyId) {
    905   // Ownership of these values is transfered to |pref_store_contents_|.
    906   base::StringValue* string_value = new base::StringValue("string value");
    907   pref_store_contents_->Set(kAtomicPref, string_value);
    908 
    909   base::DictionaryValue* dict_value = new base::DictionaryValue;
    910   dict_value->SetString("a", "foo");
    911   dict_value->SetInteger("b", 1234);
    912   pref_store_contents_->Set(kSplitPref, dict_value);
    913 
    914   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
    915   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
    916 
    917   mock_pref_hash_store_->SetCheckResult(
    918       kAtomicPref, PrefHashStoreTransaction::SECURE_LEGACY);
    919   mock_pref_hash_store_->SetCheckResult(
    920       kSplitPref, PrefHashStoreTransaction::SECURE_LEGACY);
    921   DoFilterOnLoad(false);
    922   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    923             mock_pref_hash_store_->checked_paths_count());
    924   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    925 
    926   // Delegate saw all prefs, two of which had the expected value_state.
    927   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    928             mock_validation_delegate_.recorded_validations_count());
    929   ASSERT_EQ(2u,
    930             mock_validation_delegate_.CountValidationsOfState(
    931                 PrefHashStoreTransaction::SECURE_LEGACY));
    932   ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
    933             mock_validation_delegate_.CountValidationsOfState(
    934                 PrefHashStoreTransaction::UNCHANGED));
    935 
    936   // Ensure that both the atomic and split hashes were restored.
    937   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
    938 
    939   // In all cases, the values should have remained intact and the hashes should
    940   // have been updated to match them.
    941 
    942   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
    943        mock_pref_hash_store_->stored_value(kAtomicPref);
    944   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
    945             stored_atomic_value.second);
    946   const base::Value* atomic_value_in_store;
    947   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
    948   ASSERT_EQ(string_value, atomic_value_in_store);
    949   ASSERT_EQ(string_value, stored_atomic_value.first);
    950 
    951   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
    952        mock_pref_hash_store_->stored_value(kSplitPref);
    953   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
    954             stored_split_value.second);
    955   const base::Value* split_value_in_store;
    956   ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
    957   ASSERT_EQ(dict_value, split_value_in_store);
    958   ASSERT_EQ(dict_value, stored_split_value.first);
    959 
    960   VerifyRecordedReset(false);
    961 }
    962 
    963 TEST_P(PrefHashFilterTest, DontResetReportOnly) {
    964   // Ownership of these values is transfered to |pref_store_contents_|.
    965   base::Value* int_value1 = base::Value::CreateIntegerValue(1);
    966   base::Value* int_value2 = base::Value::CreateIntegerValue(2);
    967   base::Value* report_only_val = base::Value::CreateIntegerValue(3);
    968   base::DictionaryValue* report_only_split_val = new base::DictionaryValue;
    969   report_only_split_val->SetInteger("a", 1234);
    970   pref_store_contents_->Set(kAtomicPref, int_value1);
    971   pref_store_contents_->Set(kAtomicPref2, int_value2);
    972   pref_store_contents_->Set(kReportOnlyPref, report_only_val);
    973   pref_store_contents_->Set(kReportOnlySplitPref, report_only_split_val);
    974 
    975   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
    976   ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, NULL));
    977   ASSERT_TRUE(pref_store_contents_->Get(kReportOnlyPref, NULL));
    978   ASSERT_TRUE(pref_store_contents_->Get(kReportOnlySplitPref, NULL));
    979 
    980   mock_pref_hash_store_->SetCheckResult(kAtomicPref,
    981                                         PrefHashStoreTransaction::CHANGED);
    982   mock_pref_hash_store_->SetCheckResult(kAtomicPref2,
    983                                         PrefHashStoreTransaction::CHANGED);
    984   mock_pref_hash_store_->SetCheckResult(kReportOnlyPref,
    985                                         PrefHashStoreTransaction::CHANGED);
    986   mock_pref_hash_store_->SetCheckResult(kReportOnlySplitPref,
    987                                         PrefHashStoreTransaction::CHANGED);
    988 
    989   DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD);
    990   // All prefs should be checked and a new hash should be stored for each tested
    991   // pref.
    992   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    993             mock_pref_hash_store_->checked_paths_count());
    994   ASSERT_EQ(4u, mock_pref_hash_store_->stored_paths_count());
    995   ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
    996 
    997   // Delegate saw all prefs, four of which had the expected value_state.
    998   ASSERT_EQ(arraysize(kTestTrackedPrefs),
    999             mock_validation_delegate_.recorded_validations_count());
   1000   ASSERT_EQ(4u,
   1001             mock_validation_delegate_.CountValidationsOfState(
   1002                 PrefHashStoreTransaction::CHANGED));
   1003   ASSERT_EQ(arraysize(kTestTrackedPrefs) - 4u,
   1004             mock_validation_delegate_.CountValidationsOfState(
   1005                 PrefHashStoreTransaction::UNCHANGED));
   1006 
   1007   // No matter what the enforcement level is, the report only pref should never
   1008   // be reset.
   1009   ASSERT_TRUE(pref_store_contents_->Get(kReportOnlyPref, NULL));
   1010   ASSERT_TRUE(pref_store_contents_->Get(kReportOnlySplitPref, NULL));
   1011   ASSERT_EQ(report_only_val,
   1012             mock_pref_hash_store_->stored_value(kReportOnlyPref).first);
   1013   ASSERT_EQ(report_only_split_val,
   1014             mock_pref_hash_store_->stored_value(kReportOnlySplitPref).first);
   1015 
   1016   // All other prefs should have been reset if the enforcement level allows it.
   1017   if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
   1018     ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
   1019     ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref2, NULL));
   1020     ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref).first);
   1021     ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref2).first);
   1022 
   1023     VerifyRecordedReset(true);
   1024   } else {
   1025     const base::Value* value_in_store;
   1026     const base::Value* value_in_store2;
   1027     ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &value_in_store));
   1028     ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, &value_in_store2));
   1029     ASSERT_EQ(int_value1, value_in_store);
   1030     ASSERT_EQ(int_value1,
   1031               mock_pref_hash_store_->stored_value(kAtomicPref).first);
   1032     ASSERT_EQ(int_value2, value_in_store2);
   1033     ASSERT_EQ(int_value2,
   1034               mock_pref_hash_store_->stored_value(kAtomicPref2).first);
   1035 
   1036     VerifyRecordedReset(false);
   1037   }
   1038 }
   1039 
   1040 INSTANTIATE_TEST_CASE_P(
   1041     PrefHashFilterTestInstance, PrefHashFilterTest,
   1042     testing::Values(PrefHashFilter::NO_ENFORCEMENT,
   1043                     PrefHashFilter::ENFORCE_ON_LOAD));
   1044