Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / prefs / pref_hash_filter_unittest.cc
index 63bd447..65c92ea 100644 (file)
 #include <utility>
 
 #include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "chrome/browser/prefs/pref_hash_store.h"
+#include "chrome/browser/prefs/pref_hash_store_transaction.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
-const char kTestPref[] = "pref";
-const char kTestPref2[] = "pref2";
-const char kTestPref3[] = "pref3";
+const char kAtomicPref[] = "atomic_pref";
+const char kAtomicPref2[] = "atomic_pref2";
+const char kAtomicPref3[] = "pref3";
 const char kReportOnlyPref[] = "report_only";
-
-const PrefHashFilter::TrackedPreference kTestTrackedPrefs[] = {
-  { 0, kTestPref, true },
-  { 1, kReportOnlyPref, false },
-  { 2, kTestPref2, true },
-  { 3, kTestPref3, true },
+const char kReportOnlySplitPref[] = "report_only_split_pref";
+const char kSplitPref[] = "split_pref";
+
+const PrefHashFilter::TrackedPreferenceMetadata kTestTrackedPrefs[] = {
+  {
+    0, kAtomicPref, PrefHashFilter::ENFORCE_ON_LOAD,
+    PrefHashFilter::TRACKING_STRATEGY_ATOMIC
+  },
+  {
+    1, kReportOnlyPref, PrefHashFilter::NO_ENFORCEMENT,
+    PrefHashFilter::TRACKING_STRATEGY_ATOMIC
+  },
+  {
+    2, kSplitPref, PrefHashFilter::ENFORCE_ON_LOAD,
+    PrefHashFilter::TRACKING_STRATEGY_SPLIT
+  },
+  {
+    3, kReportOnlySplitPref, PrefHashFilter::NO_ENFORCEMENT,
+    PrefHashFilter::TRACKING_STRATEGY_SPLIT
+  },
+  {
+    4, kAtomicPref2, PrefHashFilter::ENFORCE_ON_LOAD,
+    PrefHashFilter::TRACKING_STRATEGY_ATOMIC
+  },
+  {
+    5, kAtomicPref3, PrefHashFilter::ENFORCE_ON_LOAD,
+    PrefHashFilter::TRACKING_STRATEGY_ATOMIC
+  },
 };
 
 }  // namespace
@@ -38,12 +63,33 @@ const PrefHashFilter::TrackedPreference kTestTrackedPrefs[] = {
 // checked and stored values.
 class MockPrefHashStore : public PrefHashStore {
  public:
+  typedef std::pair<const void*, PrefHashFilter::PrefTrackingStrategy>
+      ValuePtrStrategyPair;
+
+  MockPrefHashStore() : transactions_expected_(1),
+                        transactions_performed_(0),
+                        transaction_active_(false) {}
 
-  MockPrefHashStore() {}
+  virtual ~MockPrefHashStore() {
+    EXPECT_EQ(transactions_expected_, transactions_performed_);
+    EXPECT_FALSE(transaction_active_);
+  }
 
-  // Set the result that will be returned when |path| is passed to |CheckValue|.
+  // Set the result that will be returned when |path| is passed to
+  // |CheckValue/CheckSplitValue|.
   void SetCheckResult(const std::string& path,
-                      PrefHashStore::ValueState result);
+                      PrefHashStoreTransaction::ValueState result);
+
+  // Set the invalid_keys that will be returned when |path| is passed to
+  // |CheckSplitValue|. SetCheckResult should already have been called for
+  // |path| with |result == CHANGED| for this to make any sense.
+  void SetInvalidKeysResult(
+      const std::string& path,
+      const std::vector<std::string>& invalid_keys_result);
+
+  void set_transactions_expected(size_t transactions_expected) {
+    transactions_expected_ = transactions_expected;
+  }
 
   // Returns the number of paths checked.
   size_t checked_paths_count() const {
@@ -55,67 +101,187 @@ class MockPrefHashStore : public PrefHashStore {
     return stored_values_.size();
   }
 
-  // Returns the pointer value that was passed to |CheckValue| for |path|. The
-  // returned pointer could since have been freed and is thus not safe to
-  // dereference.
-  const void* checked_value(const std::string& path) const {
-    std::map<std::string, const base::Value*>::iterator value =
+  // Returns the pointer value and strategy that was passed to
+  // |CheckHash/CheckSplitHash| for |path|. The returned pointer could since
+  // have been freed and is thus not safe to dereference.
+  ValuePtrStrategyPair checked_value(const std::string& path) const {
+    std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
         checked_values_.find(path);
     if (value != checked_values_.end())
       return value->second;
-    return reinterpret_cast<void*>(0xBAD);
+    return std::make_pair(
+               reinterpret_cast<void*>(0xBAD),
+               static_cast<PrefHashFilter::PrefTrackingStrategy>(-1));
   }
 
-  // Returns the pointer value that was passed to |StoreHash| for |path|. The
-  // returned pointer could since have been freed and is thus not safe to
-  // dereference.
-  const void* stored_value(const std::string& path) const {
-    std::map<std::string, const base::Value*>::const_iterator value =
+  // Returns the pointer value that was passed to |StoreHash/StoreSplitHash| for
+  // |path|. The returned pointer could since have been freed and is thus not
+  // safe to dereference.
+  ValuePtrStrategyPair stored_value(const std::string& path) const {
+    std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
         stored_values_.find(path);
     if (value != stored_values_.end())
       return value->second;
-    return reinterpret_cast<void*>(0xBAD);
+    return std::make_pair(
+               reinterpret_cast<void*>(0xBAD),
+               static_cast<PrefHashFilter::PrefTrackingStrategy>(-1));
   }
 
   // PrefHashStore implementation.
-  virtual bool IsInitialized() const OVERRIDE;
-  virtual PrefHashStore::ValueState CheckValue(
-      const std::string& path, const base::Value* value) const OVERRIDE;
-  virtual void StoreHash(const std::string& path,
-                         const base::Value* new_value) OVERRIDE;
+  virtual scoped_ptr<PrefHashStoreTransaction> BeginTransaction() OVERRIDE;
 
  private:
-  std::map<std::string, PrefHashStore::ValueState> check_results_;
-  mutable std::map<std::string, const base::Value*> checked_values_;
-  std::map<std::string, const base::Value*> stored_values_;
+  // A MockPrefHashStoreTransaction is handed to the caller on
+  // MockPrefHashStore::BeginTransaction(). It then stores state in its
+  // underlying MockPrefHashStore about calls it receives from that same caller
+  // which can later be verified in tests.
+  class MockPrefHashStoreTransaction : public PrefHashStoreTransaction {
+   public:
+    explicit MockPrefHashStoreTransaction(MockPrefHashStore* outer)
+        : outer_(outer) {}
+
+    virtual ~MockPrefHashStoreTransaction() {
+      outer_->transaction_active_ = false;
+      ++outer_->transactions_performed_;
+    }
+
+    // PrefHashStoreTransaction implementation.
+    virtual PrefHashStoreTransaction::ValueState CheckValue(
+        const std::string& path, const base::Value* value) const OVERRIDE;
+    virtual void StoreHash(const std::string& path,
+                           const base::Value* new_value) OVERRIDE;
+    virtual PrefHashStoreTransaction::ValueState CheckSplitValue(
+        const std::string& path,
+        const base::DictionaryValue* initial_split_value,
+        std::vector<std::string>* invalid_keys) const OVERRIDE;
+    virtual void StoreSplitHash(
+        const std::string& path,
+        const base::DictionaryValue* split_value) OVERRIDE;
+
+   private:
+    MockPrefHashStore* outer_;
+
+    DISALLOW_COPY_AND_ASSIGN(MockPrefHashStoreTransaction);
+  };
+
+  // Records a call to this mock's CheckValue/CheckSplitValue methods.
+  PrefHashStoreTransaction::ValueState RecordCheckValue(
+      const std::string& path,
+      const base::Value* value,
+      PrefHashFilter::PrefTrackingStrategy strategy);
+
+  // Records a call to this mock's StoreHash/StoreSplitHash methods.
+  void RecordStoreHash(const std::string& path,
+                       const base::Value* new_value,
+                       PrefHashFilter::PrefTrackingStrategy strategy);
+
+  std::map<std::string, PrefHashStoreTransaction::ValueState> check_results_;
+  std::map<std::string, std::vector<std::string> > invalid_keys_results_;
+  std::map<std::string, ValuePtrStrategyPair> checked_values_;
+  std::map<std::string, ValuePtrStrategyPair> stored_values_;
+
+  // Number of transactions that are expected to be performed in the scope of
+  // this test (defaults to 1).
+  size_t transactions_expected_;
+
+  // Number of transactions that were performed via this MockPrefHashStore.
+  // Verified to match |transactions_expected_| when this MockPrefHashStore is
+  // deleted.
+  size_t transactions_performed_;
+
+  // Whether a transaction is currently active (only one transaction should be
+  // active at a time).
+  bool transaction_active_;
 
   DISALLOW_COPY_AND_ASSIGN(MockPrefHashStore);
 };
 
 void MockPrefHashStore::SetCheckResult(
-    const std::string& path, PrefHashStore::ValueState result) {
+    const std::string& path, PrefHashStoreTransaction::ValueState result) {
   check_results_.insert(std::make_pair(path, result));
 }
 
-bool MockPrefHashStore::IsInitialized() const {
-  NOTREACHED();
-  return true;
+void MockPrefHashStore::SetInvalidKeysResult(
+    const std::string& path,
+    const std::vector<std::string>& invalid_keys_result) {
+  // Ensure |check_results_| has a CHANGED entry for |path|.
+  std::map<std::string,
+          PrefHashStoreTransaction::ValueState>::const_iterator result =
+      check_results_.find(path);
+  ASSERT_TRUE(result != check_results_.end());
+  ASSERT_EQ(PrefHashStoreTransaction::CHANGED, result->second);
+
+  invalid_keys_results_.insert(std::make_pair(path, invalid_keys_result));
 }
 
-PrefHashStore::ValueState MockPrefHashStore::CheckValue(
-    const std::string& path, const base::Value* value) const {
-  checked_values_.insert(std::make_pair(path, value));
+scoped_ptr<PrefHashStoreTransaction> MockPrefHashStore::BeginTransaction() {
+  EXPECT_FALSE(transaction_active_);
+  return scoped_ptr<PrefHashStoreTransaction>(
+      new MockPrefHashStoreTransaction(this));
+}
 
-  std::map<std::string, PrefHashStore::ValueState>::const_iterator result =
+PrefHashStoreTransaction::ValueState MockPrefHashStore::RecordCheckValue(
+    const std::string& path,
+    const base::Value* value,
+    PrefHashFilter::PrefTrackingStrategy strategy) {
+  // Record that |path| was checked and validate that it wasn't previously
+  // checked.
+  EXPECT_TRUE(checked_values_.insert(
+      std::make_pair(path, std::make_pair(value, strategy))).second);
+  std::map<std::string,
+           PrefHashStoreTransaction::ValueState>::const_iterator result =
       check_results_.find(path);
   if (result != check_results_.end())
     return result->second;
-  return PrefHashStore::UNCHANGED;
+  return PrefHashStoreTransaction::UNCHANGED;
+}
+
+void MockPrefHashStore::RecordStoreHash(
+    const std::string& path,
+    const base::Value* new_value,
+    PrefHashFilter::PrefTrackingStrategy strategy) {
+  EXPECT_TRUE(stored_values_.insert(
+      std::make_pair(path, std::make_pair(new_value, strategy))).second);
+}
+
+PrefHashStoreTransaction::ValueState
+MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue(
+    const std::string& path, const base::Value* value) const {
+  return outer_->RecordCheckValue(path, value,
+                                  PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
+}
+
+void MockPrefHashStore::MockPrefHashStoreTransaction::StoreHash(
+    const std::string& path,
+    const base::Value* new_value) {
+  outer_->RecordStoreHash(path, new_value,
+                          PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
+}
+
+PrefHashStoreTransaction::ValueState
+MockPrefHashStore::MockPrefHashStoreTransaction::CheckSplitValue(
+    const std::string& path,
+    const base::DictionaryValue* initial_split_value,
+    std::vector<std::string>* invalid_keys) const {
+  EXPECT_TRUE(invalid_keys && invalid_keys->empty());
+
+  std::map<std::string, std::vector<std::string> >::const_iterator
+      invalid_keys_result = outer_->invalid_keys_results_.find(path);
+  if (invalid_keys_result != outer_->invalid_keys_results_.end()) {
+    invalid_keys->insert(invalid_keys->begin(),
+                         invalid_keys_result->second.begin(),
+                         invalid_keys_result->second.end());
+  }
+
+  return outer_->RecordCheckValue(path, initial_split_value,
+                                  PrefHashFilter::TRACKING_STRATEGY_SPLIT);
 }
 
-void MockPrefHashStore::StoreHash(const std::string& path,
-                                  const base::Value* new_value) {
-  stored_values_.insert(std::make_pair(path, new_value));
+void MockPrefHashStore::MockPrefHashStoreTransaction::StoreSplitHash(
+    const std::string& path,
+    const base::DictionaryValue* new_value) {
+  outer_->RecordStoreHash(path, new_value,
+                          PrefHashFilter::TRACKING_STRATEGY_SPLIT);
 }
 
 // Creates a PrefHashFilter that uses a MockPrefHashStore. The
@@ -123,7 +289,8 @@ void MockPrefHashStore::StoreHash(const std::string& path,
 // |mock_pref_hash_store|.
 scoped_ptr<PrefHashFilter> CreatePrefHashFilter(
     PrefHashFilter::EnforcementLevel enforcement_level,
-    MockPrefHashStore** mock_pref_hash_store) {
+    MockPrefHashStore** mock_pref_hash_store,
+    const base::Closure& reset_callback) {
   scoped_ptr<MockPrefHashStore> temp_mock_pref_hash_store(
       new MockPrefHashStore);
   if (mock_pref_hash_store)
@@ -131,19 +298,26 @@ scoped_ptr<PrefHashFilter> CreatePrefHashFilter(
   return scoped_ptr<PrefHashFilter>(
       new PrefHashFilter(temp_mock_pref_hash_store.PassAs<PrefHashStore>(),
                          kTestTrackedPrefs, arraysize(kTestTrackedPrefs),
-                         arraysize(kTestTrackedPrefs),
-                         enforcement_level));
+                         arraysize(kTestTrackedPrefs), enforcement_level,
+                         reset_callback));
 }
 
 class PrefHashFilterTest
     : public testing::TestWithParam<PrefHashFilter::EnforcementLevel> {
  public:
-  PrefHashFilterTest() : mock_pref_hash_store_(NULL) {}
+  PrefHashFilterTest() : mock_pref_hash_store_(NULL), reset_event_count_(0) {}
 
   virtual void SetUp() OVERRIDE {
     // Construct a PrefHashFilter and MockPrefHashStore for the test.
-    pref_hash_filter_ = CreatePrefHashFilter(GetParam(),
-                                             &mock_pref_hash_store_);
+    pref_hash_filter_ = CreatePrefHashFilter(
+        GetParam(), &mock_pref_hash_store_,
+        base::Bind(&PrefHashFilterTest::HandleResetEvent,
+                   base::Unretained(this)));
+    reset_event_count_ = 0;
+  }
+
+  void HandleResetEvent() {
+    ++reset_event_count_;
   }
 
  protected:
@@ -151,6 +325,11 @@ class PrefHashFilterTest
   base::DictionaryValue pref_store_contents_;
   scoped_ptr<PrefHashFilter> pref_hash_filter_;
 
+  // The number of times a reset event occurs. A reset event is defined as
+  // the discovery of a set of one or more changed tracked preferences during
+  // load time.
+  int reset_event_count_;
+
   DISALLOW_COPY_AND_ASSIGN(PrefHashFilterTest);
 };
 
@@ -164,28 +343,61 @@ TEST_P(PrefHashFilterTest, EmptyAndUnchanged) {
   // Since there was nothing in |pref_store_contents_| the checked value should
   // have been NULL for all tracked preferences.
   for (size_t i = 0; i < arraysize(kTestTrackedPrefs); ++i) {
-    ASSERT_EQ(NULL,
-              mock_pref_hash_store_->checked_value(kTestTrackedPrefs[i].name));
+    ASSERT_EQ(NULL, mock_pref_hash_store_->checked_value(
+                        kTestTrackedPrefs[i].name).first);
   }
+  ASSERT_EQ(0, reset_event_count_);
 }
 
 TEST_P(PrefHashFilterTest, FilterTrackedPrefUpdate) {
   base::DictionaryValue root_dict;
   // Ownership of |string_value| is transfered to |root_dict|.
   base::Value* string_value = base::Value::CreateStringValue("string value");
-  root_dict.Set(kTestPref, string_value);
+  root_dict.Set(kAtomicPref, string_value);
+
+  // No path should be stored on FilterUpdate.
+  pref_hash_filter_->FilterUpdate(kAtomicPref);
+  ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+
+  // One path should be stored on FilterSerializeData.
+  pref_hash_filter_->FilterSerializeData(&root_dict);
+  ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
+  MockPrefHashStore::ValuePtrStrategyPair stored_value =
+      mock_pref_hash_store_->stored_value(kAtomicPref);
+  ASSERT_EQ(string_value, stored_value.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, stored_value.second);
+
+  ASSERT_EQ(0, reset_event_count_);
+}
+
+TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
+  base::DictionaryValue root_dict;
+  // Ownership of |dict_value| is transfered to |root_dict|.
+  base::DictionaryValue* dict_value = new base::DictionaryValue;
+  dict_value->SetString("a", "foo");
+  dict_value->SetInteger("b", 1234);
+  root_dict.Set(kSplitPref, dict_value);
 
   // No path should be stored on FilterUpdate.
-  pref_hash_filter_->FilterUpdate(kTestPref);
+  pref_hash_filter_->FilterUpdate(kSplitPref);
   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
 
   // One path should be stored on FilterSerializeData.
   pref_hash_filter_->FilterSerializeData(&root_dict);
   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
-  ASSERT_EQ(string_value, mock_pref_hash_store_->stored_value(kTestPref));
+  MockPrefHashStore::ValuePtrStrategyPair stored_value =
+       mock_pref_hash_store_->stored_value(kSplitPref);
+  ASSERT_EQ(dict_value, stored_value.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value.second);
+
+  ASSERT_EQ(0, reset_event_count_);
 }
 
 TEST_P(PrefHashFilterTest, FilterUntrackedPrefUpdate) {
+  // No transaction should even be started on FilterSerializeData() if there are
+  // no updates to perform.
+  mock_pref_hash_store_->set_transactions_expected(0);
+
   base::DictionaryValue root_dict;
   root_dict.Set("untracked", base::Value::CreateStringValue("some value"));
   pref_hash_filter_->FilterUpdate("untracked");
@@ -205,161 +417,316 @@ TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) {
   base::Value* int_value2 = base::Value::CreateIntegerValue(2);
   base::Value* int_value3 = base::Value::CreateIntegerValue(3);
   base::Value* int_value4 = base::Value::CreateIntegerValue(4);
-  root_dict.Set(kTestPref, int_value1);
-  root_dict.Set(kTestPref2, int_value2);
-  root_dict.Set(kTestPref3, int_value3);
+  base::DictionaryValue* dict_value = new base::DictionaryValue;
+  dict_value->Set("a", base::Value::CreateBooleanValue(true));
+  root_dict.Set(kAtomicPref, int_value1);
+  root_dict.Set(kAtomicPref2, int_value2);
+  root_dict.Set(kAtomicPref3, int_value3);
   root_dict.Set("untracked", int_value4);
+  root_dict.Set(kSplitPref, dict_value);
 
-  // Only update kTestPref and kTestPref3
-  pref_hash_filter_->FilterUpdate(kTestPref);
-  pref_hash_filter_->FilterUpdate(kTestPref3);
+  // Only update kAtomicPref, kAtomicPref3, and kSplitPref.
+  pref_hash_filter_->FilterUpdate(kAtomicPref);
+  pref_hash_filter_->FilterUpdate(kAtomicPref3);
+  pref_hash_filter_->FilterUpdate(kSplitPref);
   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
 
-  // Update kTestPref3 again, nothing should be stored still.
+  // Update kAtomicPref3 again, nothing should be stored still.
   base::Value* int_value5 = base::Value::CreateIntegerValue(5);
-  root_dict.Set(kTestPref3, int_value5);
+  root_dict.Set(kAtomicPref3, int_value5);
   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
 
-  // On FilterSerializeData, only kTestPref and kTestPref3 should get a new
-  // hash.
+  // On FilterSerializeData, only kAtomicPref, kAtomicPref3, and kSplitPref
+  // should get a new hash.
   pref_hash_filter_->FilterSerializeData(&root_dict);
-  ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
-  ASSERT_EQ(int_value1, mock_pref_hash_store_->stored_value(kTestPref));
-  ASSERT_EQ(int_value5, mock_pref_hash_store_->stored_value(kTestPref3));
+  ASSERT_EQ(3u, mock_pref_hash_store_->stored_paths_count());
+  MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1 =
+      mock_pref_hash_store_->stored_value(kAtomicPref);
+  ASSERT_EQ(int_value1, stored_value_atomic1.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
+            stored_value_atomic1.second);
+
+  MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3 =
+      mock_pref_hash_store_->stored_value(kAtomicPref3);
+  ASSERT_EQ(int_value5, stored_value_atomic3.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
+            stored_value_atomic3.second);
+
+  MockPrefHashStore::ValuePtrStrategyPair stored_value_split =
+       mock_pref_hash_store_->stored_value(kSplitPref);
+  ASSERT_EQ(dict_value, stored_value_split.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value_split.second);
 }
 
 TEST_P(PrefHashFilterTest, EmptyAndUnknown) {
-  ASSERT_FALSE(pref_store_contents_.Get(kTestPref, NULL));
+  ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
+  ASSERT_FALSE(pref_store_contents_.Get(kSplitPref, NULL));
   // NULL values are always trusted by the PrefHashStore.
-  mock_pref_hash_store_->SetCheckResult(kTestPref,
-                                        PrefHashStore::TRUSTED_UNKNOWN_VALUE);
+  mock_pref_hash_store_->SetCheckResult(
+      kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
+  mock_pref_hash_store_->SetCheckResult(
+      kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
   ASSERT_EQ(arraysize(kTestTrackedPrefs),
             mock_pref_hash_store_->checked_paths_count());
-  ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
+  ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
 
-  ASSERT_FALSE(pref_store_contents_.Get(kTestPref, NULL));
-  ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kTestPref));
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+       mock_pref_hash_store_->stored_value(kAtomicPref);
+  ASSERT_EQ(NULL, stored_atomic_value.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
+            stored_atomic_value.second);
+
+  MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+       mock_pref_hash_store_->stored_value(kSplitPref);
+  ASSERT_EQ(NULL, stored_split_value.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
+            stored_split_value.second);
 }
 
 TEST_P(PrefHashFilterTest, InitialValueUnknown) {
-  // Ownership of this value is transfered to |pref_store_contents_|.
-  base::Value* string_value = base::Value::CreateStringValue("test");
-  pref_store_contents_.Set(kTestPref, string_value);
+  // Ownership of these values is transfered to |pref_store_contents_|.
+  base::StringValue* string_value = new base::StringValue("string value");
+  pref_store_contents_.Set(kAtomicPref, string_value);
+
+  base::DictionaryValue* dict_value = new base::DictionaryValue;
+  dict_value->SetString("a", "foo");
+  dict_value->SetInteger("b", 1234);
+  pref_store_contents_.Set(kSplitPref, dict_value);
 
-  ASSERT_TRUE(pref_store_contents_.Get(kTestPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, NULL));
 
-  mock_pref_hash_store_->SetCheckResult(kTestPref,
-                                        PrefHashStore::UNTRUSTED_UNKNOWN_VALUE);
+  mock_pref_hash_store_->SetCheckResult(
+      kAtomicPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE);
+  mock_pref_hash_store_->SetCheckResult(
+      kSplitPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE);
   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
   ASSERT_EQ(arraysize(kTestTrackedPrefs),
             mock_pref_hash_store_->checked_paths_count());
-  ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
+  ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
 
-  if (GetParam() >= PrefHashFilter::ENFORCE_NO_SEEDING) {
-    // Ensure the pref was cleared and the hash for NULL was restored if the
-    // current enforcement level denies seeding.
-    ASSERT_FALSE(pref_store_contents_.Get(kTestPref, NULL));
-    ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kTestPref));
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+       mock_pref_hash_store_->stored_value(kAtomicPref);
+  MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+       mock_pref_hash_store_->stored_value(kSplitPref);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
+            stored_atomic_value.second);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
+            stored_split_value.second);
+  if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
+    // Ensure the prefs were cleared and the hashes for NULL were restored if
+    // the current enforcement level denies seeding.
+    ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
+    ASSERT_EQ(NULL, stored_atomic_value.first);
+
+    ASSERT_FALSE(pref_store_contents_.Get(kSplitPref, NULL));
+    ASSERT_EQ(NULL, stored_split_value.first);
+
+    ASSERT_EQ(1, reset_event_count_);
   } else {
-    // Otherwise the value should have remained intact and the hash should have
-    // been updated to match it.
-    const base::Value* value_in_store;
-    ASSERT_TRUE(pref_store_contents_.Get(kTestPref, &value_in_store));
-    ASSERT_EQ(string_value, value_in_store);
-    ASSERT_EQ(string_value, mock_pref_hash_store_->stored_value(kTestPref));
+    // Otherwise the values should have remained intact and the hashes should
+    // have been updated to match them.
+    const base::Value* atomic_value_in_store;
+    ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
+    ASSERT_EQ(string_value, atomic_value_in_store);
+    ASSERT_EQ(string_value, stored_atomic_value.first);
+
+    const base::Value* split_value_in_store;
+    ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
+    ASSERT_EQ(dict_value, split_value_in_store);
+    ASSERT_EQ(dict_value, stored_split_value.first);
+
+    ASSERT_EQ(0, reset_event_count_);
   }
 }
 
 TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) {
   // Ownership of this value is transfered to |pref_store_contents_|.
   base::Value* string_value = base::Value::CreateStringValue("test");
-  pref_store_contents_.Set(kTestPref, string_value);
+  pref_store_contents_.Set(kAtomicPref, string_value);
+
+  base::DictionaryValue* dict_value = new base::DictionaryValue;
+  dict_value->SetString("a", "foo");
+  dict_value->SetInteger("b", 1234);
+  pref_store_contents_.Set(kSplitPref, dict_value);
 
-  ASSERT_TRUE(pref_store_contents_.Get(kTestPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, NULL));
 
-  mock_pref_hash_store_->SetCheckResult(kTestPref,
-                                        PrefHashStore::TRUSTED_UNKNOWN_VALUE);
+  mock_pref_hash_store_->SetCheckResult(
+      kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
+  mock_pref_hash_store_->SetCheckResult(
+      kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
   ASSERT_EQ(arraysize(kTestTrackedPrefs),
             mock_pref_hash_store_->checked_paths_count());
-  ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
+  ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
 
   // Seeding is always allowed for trusted unknown values.
-  const base::Value* value_in_store;
-  ASSERT_TRUE(pref_store_contents_.Get(kTestPref, &value_in_store));
-  ASSERT_EQ(string_value, value_in_store);
-  ASSERT_EQ(string_value, mock_pref_hash_store_->stored_value(kTestPref));
+  const base::Value* atomic_value_in_store;
+  ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
+  ASSERT_EQ(string_value, atomic_value_in_store);
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+       mock_pref_hash_store_->stored_value(kAtomicPref);
+  ASSERT_EQ(string_value, stored_atomic_value.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
+            stored_atomic_value.second);
+
+  const base::Value* split_value_in_store;
+  ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
+  ASSERT_EQ(dict_value, split_value_in_store);
+  MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+       mock_pref_hash_store_->stored_value(kSplitPref);
+  ASSERT_EQ(dict_value, stored_split_value.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
+            stored_split_value.second);
 }
 
 TEST_P(PrefHashFilterTest, InitialValueChanged) {
   // Ownership of this value is transfered to |pref_store_contents_|.
   base::Value* int_value = base::Value::CreateIntegerValue(1234);
-  pref_store_contents_.Set(kTestPref, int_value);
+  pref_store_contents_.Set(kAtomicPref, int_value);
 
-  ASSERT_TRUE(pref_store_contents_.Get(kTestPref, NULL));
+  base::DictionaryValue* dict_value = new base::DictionaryValue;
+  dict_value->SetString("a", "foo");
+  dict_value->SetInteger("b", 1234);
+  dict_value->SetInteger("c", 56);
+  dict_value->SetBoolean("d", false);
+  pref_store_contents_.Set(kSplitPref, dict_value);
+
+  ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, NULL));
+
+  mock_pref_hash_store_->SetCheckResult(kAtomicPref,
+                                        PrefHashStoreTransaction::CHANGED);
+  mock_pref_hash_store_->SetCheckResult(kSplitPref,
+                                        PrefHashStoreTransaction::CHANGED);
+
+  std::vector<std::string> mock_invalid_keys;
+  mock_invalid_keys.push_back("a");
+  mock_invalid_keys.push_back("c");
+  mock_pref_hash_store_->SetInvalidKeysResult(kSplitPref, mock_invalid_keys);
 
-  mock_pref_hash_store_->SetCheckResult(kTestPref, PrefHashStore::CHANGED);
   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
   ASSERT_EQ(arraysize(kTestTrackedPrefs),
             mock_pref_hash_store_->checked_paths_count());
-  ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
+  ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
 
-  if (GetParam() >= PrefHashFilter::ENFORCE) {
-    // Ensure the pref was cleared and the hash for NULL was restored if the
-    // current enforcement level prevents changes.
-    ASSERT_FALSE(pref_store_contents_.Get(kTestPref, NULL));
-    ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kTestPref));
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+       mock_pref_hash_store_->stored_value(kAtomicPref);
+  MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+       mock_pref_hash_store_->stored_value(kSplitPref);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
+            stored_atomic_value.second);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
+            stored_split_value.second);
+  if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
+    // Ensure the atomic pref was cleared and the hash for NULL was restored if
+    // the current enforcement level prevents changes.
+    ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
+    ASSERT_EQ(NULL, stored_atomic_value.first);
+
+    // The split pref on the other hand should only have been stripped of its
+    // invalid keys.
+    const base::Value* split_value_in_store;
+    ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
+    ASSERT_EQ(2U, dict_value->size());
+    ASSERT_FALSE(dict_value->HasKey("a"));
+    ASSERT_TRUE(dict_value->HasKey("b"));
+    ASSERT_FALSE(dict_value->HasKey("c"));
+    ASSERT_TRUE(dict_value->HasKey("d"));
+    ASSERT_EQ(dict_value, stored_split_value.first);
+
+    ASSERT_EQ(1, reset_event_count_);
   } else {
     // Otherwise the value should have remained intact and the hash should have
     // been updated to match it.
-    const base::Value* value_in_store;
-    ASSERT_TRUE(pref_store_contents_.Get(kTestPref, &value_in_store));
-    ASSERT_EQ(int_value, value_in_store);
-    ASSERT_EQ(int_value, mock_pref_hash_store_->stored_value(kTestPref));
+    const base::Value* atomic_value_in_store;
+    ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
+    ASSERT_EQ(int_value, atomic_value_in_store);
+    ASSERT_EQ(int_value, stored_atomic_value.first);
+
+    const base::Value* split_value_in_store;
+    ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
+    ASSERT_EQ(dict_value, split_value_in_store);
+    ASSERT_EQ(4U, dict_value->size());
+    ASSERT_TRUE(dict_value->HasKey("a"));
+    ASSERT_TRUE(dict_value->HasKey("b"));
+    ASSERT_TRUE(dict_value->HasKey("c"));
+    ASSERT_TRUE(dict_value->HasKey("d"));
+    ASSERT_EQ(dict_value, stored_split_value.first);
+
+    ASSERT_EQ(0, reset_event_count_);
   }
 }
 
 TEST_P(PrefHashFilterTest, EmptyCleared) {
-  ASSERT_FALSE(pref_store_contents_.Get(kTestPref, NULL));
-  mock_pref_hash_store_->SetCheckResult(kTestPref, PrefHashStore::CLEARED);
+  ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
+  ASSERT_FALSE(pref_store_contents_.Get(kSplitPref, NULL));
+  mock_pref_hash_store_->SetCheckResult(kAtomicPref,
+                                        PrefHashStoreTransaction::CLEARED);
+  mock_pref_hash_store_->SetCheckResult(kSplitPref,
+                                        PrefHashStoreTransaction::CLEARED);
   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
   ASSERT_EQ(arraysize(kTestTrackedPrefs),
             mock_pref_hash_store_->checked_paths_count());
-  ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
+  ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
 
   // Regardless of the enforcement level, the only thing that should be done is
   // to restore the hash for NULL. The value itself should still be NULL.
-  ASSERT_FALSE(pref_store_contents_.Get(kTestPref, NULL));
-  ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kTestPref));
+  ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+       mock_pref_hash_store_->stored_value(kAtomicPref);
+  ASSERT_EQ(NULL, stored_atomic_value.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
+            stored_atomic_value.second);
+
+  ASSERT_FALSE(pref_store_contents_.Get(kSplitPref, NULL));
+  MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+       mock_pref_hash_store_->stored_value(kSplitPref);
+  ASSERT_EQ(NULL, stored_split_value.first);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
+            stored_split_value.second);
 }
 
-TEST_P(PrefHashFilterTest, EmptyMigrated) {
+TEST_P(PrefHashFilterTest, InitialValueMigrated) {
+  // Only test atomic prefs, split prefs were introduce after the migration.
+
   // Ownership of this value is transfered to |pref_store_contents_|.
   base::ListValue* list_value = new base::ListValue;
   list_value->Append(base::Value::CreateStringValue("test"));
-  pref_store_contents_.Set(kTestPref, list_value);
+  pref_store_contents_.Set(kAtomicPref, list_value);
 
-  ASSERT_TRUE(pref_store_contents_.Get(kTestPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
 
-  mock_pref_hash_store_->SetCheckResult(kTestPref, PrefHashStore::MIGRATED);
+  mock_pref_hash_store_->SetCheckResult(kAtomicPref,
+                                        PrefHashStoreTransaction::MIGRATED);
   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
   ASSERT_EQ(arraysize(kTestTrackedPrefs),
             mock_pref_hash_store_->checked_paths_count());
   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
 
-  if (GetParam() >= PrefHashFilter::ENFORCE_NO_SEEDING_NO_MIGRATION) {
+  MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+       mock_pref_hash_store_->stored_value(kAtomicPref);
+  ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
+            stored_atomic_value.second);
+  if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
     // Ensure the pref was cleared and the hash for NULL was restored if the
     // current enforcement level prevents migration.
-    ASSERT_FALSE(pref_store_contents_.Get(kTestPref, NULL));
-    ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kTestPref));
+    ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
+    ASSERT_EQ(NULL, stored_atomic_value.first);
+
+    ASSERT_EQ(1, reset_event_count_);
   } else {
     // Otherwise the value should have remained intact and the hash should have
     // been updated to match it.
-    const base::Value* value_in_store;
-    ASSERT_TRUE(pref_store_contents_.Get(kTestPref, &value_in_store));
-    ASSERT_EQ(list_value, value_in_store);
-    ASSERT_EQ(list_value, mock_pref_hash_store_->stored_value(kTestPref));
+    const base::Value* atomic_value_in_store;
+    ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
+    ASSERT_EQ(list_value, atomic_value_in_store);
+    ASSERT_EQ(list_value, stored_atomic_value.first);
+
+    ASSERT_EQ(0, reset_event_count_);
   }
 }
 
@@ -368,68 +735,67 @@ TEST_P(PrefHashFilterTest, DontResetReportOnly) {
   base::Value* int_value1 = base::Value::CreateIntegerValue(1);
   base::Value* int_value2 = base::Value::CreateIntegerValue(2);
   base::Value* report_only_val = base::Value::CreateIntegerValue(3);
-  pref_store_contents_.Set(kTestPref, int_value1);
-  pref_store_contents_.Set(kTestPref2, int_value2);
+  base::DictionaryValue* report_only_split_val = new base::DictionaryValue;
+  report_only_split_val->SetInteger("a", 1234);
+  pref_store_contents_.Set(kAtomicPref, int_value1);
+  pref_store_contents_.Set(kAtomicPref2, int_value2);
   pref_store_contents_.Set(kReportOnlyPref, report_only_val);
+  pref_store_contents_.Set(kReportOnlySplitPref, report_only_split_val);
 
-  ASSERT_TRUE(pref_store_contents_.Get(kTestPref, NULL));
-  ASSERT_TRUE(pref_store_contents_.Get(kTestPref2, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref2, NULL));
   ASSERT_TRUE(pref_store_contents_.Get(kReportOnlyPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kReportOnlySplitPref, NULL));
 
-  mock_pref_hash_store_->SetCheckResult(kTestPref, PrefHashStore::CHANGED);
-  mock_pref_hash_store_->SetCheckResult(kTestPref2, PrefHashStore::CHANGED);
+  mock_pref_hash_store_->SetCheckResult(kAtomicPref,
+                                        PrefHashStoreTransaction::CHANGED);
+  mock_pref_hash_store_->SetCheckResult(kAtomicPref2,
+                                        PrefHashStoreTransaction::CHANGED);
   mock_pref_hash_store_->SetCheckResult(kReportOnlyPref,
-                                        PrefHashStore::CHANGED);
+                                        PrefHashStoreTransaction::CHANGED);
+  mock_pref_hash_store_->SetCheckResult(kReportOnlySplitPref,
+                                        PrefHashStoreTransaction::CHANGED);
   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
   // All prefs should be checked and a new hash should be stored for each tested
   // pref.
   ASSERT_EQ(arraysize(kTestTrackedPrefs),
             mock_pref_hash_store_->checked_paths_count());
-  ASSERT_EQ(3u, mock_pref_hash_store_->stored_paths_count());
+  ASSERT_EQ(4u, mock_pref_hash_store_->stored_paths_count());
 
   // No matter what the enforcement level is, the report only pref should never
   // be reset.
   ASSERT_TRUE(pref_store_contents_.Get(kReportOnlyPref, NULL));
+  ASSERT_TRUE(pref_store_contents_.Get(kReportOnlySplitPref, NULL));
   ASSERT_EQ(report_only_val,
-            mock_pref_hash_store_->stored_value(kReportOnlyPref));
+            mock_pref_hash_store_->stored_value(kReportOnlyPref).first);
+  ASSERT_EQ(report_only_split_val,
+            mock_pref_hash_store_->stored_value(kReportOnlySplitPref).first);
 
   // All other prefs should have been reset if the enforcement level allows it.
-  if (GetParam() >= PrefHashFilter::ENFORCE) {
-    ASSERT_FALSE(pref_store_contents_.Get(kTestPref, NULL));
-    ASSERT_FALSE(pref_store_contents_.Get(kTestPref2, NULL));
-    ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kTestPref));
-    ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kTestPref2));
+  if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
+    ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
+    ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref2, NULL));
+    ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref).first);
+    ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref2).first);
+
+    ASSERT_EQ(1, reset_event_count_);
   } else {
     const base::Value* value_in_store;
     const base::Value* value_in_store2;
-    ASSERT_TRUE(pref_store_contents_.Get(kTestPref, &value_in_store));
-    ASSERT_TRUE(pref_store_contents_.Get(kTestPref2, &value_in_store2));
+    ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &value_in_store));
+    ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref2, &value_in_store2));
     ASSERT_EQ(int_value1, value_in_store);
-    ASSERT_EQ(int_value1, mock_pref_hash_store_->stored_value(kTestPref));
+    ASSERT_EQ(int_value1,
+              mock_pref_hash_store_->stored_value(kAtomicPref).first);
     ASSERT_EQ(int_value2, value_in_store2);
-    ASSERT_EQ(int_value2, mock_pref_hash_store_->stored_value(kTestPref2));
-  }
-}
+    ASSERT_EQ(int_value2,
+              mock_pref_hash_store_->stored_value(kAtomicPref2).first);
 
-// This is a hack to allow testing::Range to iterate over enum values in
-// PrefHashFilter::EnforcementLevel. This is required as
-// testing::internals::RangeGenerator used by testing::Range needs to be able
-// to do |i = i + step| where i is an EnforcementLevel and |step| is 1 by
-// default; |enum + 1| results in an |int| type, not an |enum|, and there is no
-// implicit conversion from |int| to |enum|. This hack works around this
-// limitation by making |step| an |EnforcementLevelIncrement| which forces the
-// explicit cast in the overloaded operator+ below and makes |i = i + step| a
-// valid statement.
-class EnforcementLevelIncrement {};
-PrefHashFilter::EnforcementLevel operator+(
-    PrefHashFilter::EnforcementLevel current_level,
-    const EnforcementLevelIncrement& /* increment */) {
-  return static_cast<PrefHashFilter::EnforcementLevel>(current_level + 1);
+    ASSERT_EQ(0, reset_event_count_);
+  }
 }
 
 INSTANTIATE_TEST_CASE_P(
-    PrefEnforcementLevels, PrefHashFilterTest,
-    testing::Range(PrefHashFilter::NO_ENFORCEMENT,
-                   static_cast<PrefHashFilter::EnforcementLevel>(
-                       PrefHashFilter::ENFORCE_ALL + 1),
-                   EnforcementLevelIncrement()));
+    PrefHashFilterTestInstance, PrefHashFilterTest,
+    testing::Values(PrefHashFilter::NO_ENFORCEMENT,
+                    PrefHashFilter::ENFORCE_ON_LOAD));