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