c212cfa5781ac76d452143eb03865e489f1871c1
[platform/framework/web/crosswalk.git] / src / chrome / browser / prefs / pref_hash_filter_unittest.cc
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/values.h"
21 #include "chrome/browser/prefs/pref_hash_store.h"
22 #include "chrome/browser/prefs/pref_hash_store_transaction.h"
23 #include "chrome/common/pref_names.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace {
27
28 const char kAtomicPref[] = "atomic_pref";
29 const char kAtomicPref2[] = "atomic_pref2";
30 const char kAtomicPref3[] = "pref3";
31 const char kReportOnlyPref[] = "report_only";
32 const char kReportOnlySplitPref[] = "report_only_split_pref";
33 const char kSplitPref[] = "split_pref";
34
35 const PrefHashFilter::TrackedPreferenceMetadata kTestTrackedPrefs[] = {
36   {
37     0, kAtomicPref, PrefHashFilter::ENFORCE_ON_LOAD,
38     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
39   },
40   {
41     1, kReportOnlyPref, PrefHashFilter::NO_ENFORCEMENT,
42     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
43   },
44   {
45     2, kSplitPref, PrefHashFilter::ENFORCE_ON_LOAD,
46     PrefHashFilter::TRACKING_STRATEGY_SPLIT
47   },
48   {
49     3, kReportOnlySplitPref, PrefHashFilter::NO_ENFORCEMENT,
50     PrefHashFilter::TRACKING_STRATEGY_SPLIT
51   },
52   {
53     4, kAtomicPref2, PrefHashFilter::ENFORCE_ON_LOAD,
54     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
55   },
56   {
57     5, kAtomicPref3, PrefHashFilter::ENFORCE_ON_LOAD,
58     PrefHashFilter::TRACKING_STRATEGY_ATOMIC
59   },
60 };
61
62 }  // namespace
63
64 // A PrefHashStore that allows simulation of CheckValue results and captures
65 // checked and stored values.
66 class MockPrefHashStore : public PrefHashStore {
67  public:
68   typedef std::pair<const void*, PrefHashFilter::PrefTrackingStrategy>
69       ValuePtrStrategyPair;
70
71   MockPrefHashStore() : transactions_expected_(1),
72                         transactions_performed_(0),
73                         transaction_active_(false) {}
74
75   virtual ~MockPrefHashStore() {
76     EXPECT_EQ(transactions_expected_, transactions_performed_);
77     EXPECT_FALSE(transaction_active_);
78   }
79
80   // Set the result that will be returned when |path| is passed to
81   // |CheckValue/CheckSplitValue|.
82   void SetCheckResult(const std::string& path,
83                       PrefHashStoreTransaction::ValueState result);
84
85   // Set the invalid_keys that will be returned when |path| is passed to
86   // |CheckSplitValue|. SetCheckResult should already have been called for
87   // |path| with |result == CHANGED| for this to make any sense.
88   void SetInvalidKeysResult(
89       const std::string& path,
90       const std::vector<std::string>& invalid_keys_result);
91
92   void set_transactions_expected(size_t transactions_expected) {
93     transactions_expected_ = transactions_expected;
94   }
95
96   // Returns the number of paths checked.
97   size_t checked_paths_count() const {
98     return checked_values_.size();
99   }
100
101   // Returns the number of paths stored.
102   size_t stored_paths_count() const {
103     return stored_values_.size();
104   }
105
106   // Returns the pointer value and strategy that was passed to
107   // |CheckHash/CheckSplitHash| for |path|. The returned pointer could since
108   // have been freed and is thus not safe to dereference.
109   ValuePtrStrategyPair checked_value(const std::string& path) const {
110     std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
111         checked_values_.find(path);
112     if (value != checked_values_.end())
113       return value->second;
114     return std::make_pair(
115                reinterpret_cast<void*>(0xBAD),
116                static_cast<PrefHashFilter::PrefTrackingStrategy>(-1));
117   }
118
119   // Returns the pointer value that was passed to |StoreHash/StoreSplitHash| for
120   // |path|. The returned pointer could since have been freed and is thus not
121   // safe to dereference.
122   ValuePtrStrategyPair stored_value(const std::string& path) const {
123     std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
124         stored_values_.find(path);
125     if (value != stored_values_.end())
126       return value->second;
127     return std::make_pair(
128                reinterpret_cast<void*>(0xBAD),
129                static_cast<PrefHashFilter::PrefTrackingStrategy>(-1));
130   }
131
132   // PrefHashStore implementation.
133   virtual scoped_ptr<PrefHashStoreTransaction> BeginTransaction() OVERRIDE;
134
135  private:
136   // A MockPrefHashStoreTransaction is handed to the caller on
137   // MockPrefHashStore::BeginTransaction(). It then stores state in its
138   // underlying MockPrefHashStore about calls it receives from that same caller
139   // which can later be verified in tests.
140   class MockPrefHashStoreTransaction : public PrefHashStoreTransaction {
141    public:
142     explicit MockPrefHashStoreTransaction(MockPrefHashStore* outer)
143         : outer_(outer) {}
144
145     virtual ~MockPrefHashStoreTransaction() {
146       outer_->transaction_active_ = false;
147       ++outer_->transactions_performed_;
148     }
149
150     // PrefHashStoreTransaction implementation.
151     virtual PrefHashStoreTransaction::ValueState CheckValue(
152         const std::string& path, const base::Value* value) const OVERRIDE;
153     virtual void StoreHash(const std::string& path,
154                            const base::Value* new_value) OVERRIDE;
155     virtual PrefHashStoreTransaction::ValueState CheckSplitValue(
156         const std::string& path,
157         const base::DictionaryValue* initial_split_value,
158         std::vector<std::string>* invalid_keys) const OVERRIDE;
159     virtual void StoreSplitHash(
160         const std::string& path,
161         const base::DictionaryValue* split_value) OVERRIDE;
162
163    private:
164     MockPrefHashStore* outer_;
165
166     DISALLOW_COPY_AND_ASSIGN(MockPrefHashStoreTransaction);
167   };
168
169   // Records a call to this mock's CheckValue/CheckSplitValue methods.
170   PrefHashStoreTransaction::ValueState RecordCheckValue(
171       const std::string& path,
172       const base::Value* value,
173       PrefHashFilter::PrefTrackingStrategy strategy);
174
175   // Records a call to this mock's StoreHash/StoreSplitHash methods.
176   void RecordStoreHash(const std::string& path,
177                        const base::Value* new_value,
178                        PrefHashFilter::PrefTrackingStrategy strategy);
179
180   std::map<std::string, PrefHashStoreTransaction::ValueState> check_results_;
181   std::map<std::string, std::vector<std::string> > invalid_keys_results_;
182   std::map<std::string, ValuePtrStrategyPair> checked_values_;
183   std::map<std::string, ValuePtrStrategyPair> stored_values_;
184
185   // Number of transactions that are expected to be performed in the scope of
186   // this test (defaults to 1).
187   size_t transactions_expected_;
188
189   // Number of transactions that were performed via this MockPrefHashStore.
190   // Verified to match |transactions_expected_| when this MockPrefHashStore is
191   // deleted.
192   size_t transactions_performed_;
193
194   // Whether a transaction is currently active (only one transaction should be
195   // active at a time).
196   bool transaction_active_;
197
198   DISALLOW_COPY_AND_ASSIGN(MockPrefHashStore);
199 };
200
201 void MockPrefHashStore::SetCheckResult(
202     const std::string& path, PrefHashStoreTransaction::ValueState result) {
203   check_results_.insert(std::make_pair(path, result));
204 }
205
206 void MockPrefHashStore::SetInvalidKeysResult(
207     const std::string& path,
208     const std::vector<std::string>& invalid_keys_result) {
209   // Ensure |check_results_| has a CHANGED entry for |path|.
210   std::map<std::string,
211           PrefHashStoreTransaction::ValueState>::const_iterator result =
212       check_results_.find(path);
213   ASSERT_TRUE(result != check_results_.end());
214   ASSERT_EQ(PrefHashStoreTransaction::CHANGED, result->second);
215
216   invalid_keys_results_.insert(std::make_pair(path, invalid_keys_result));
217 }
218
219 scoped_ptr<PrefHashStoreTransaction> MockPrefHashStore::BeginTransaction() {
220   EXPECT_FALSE(transaction_active_);
221   return scoped_ptr<PrefHashStoreTransaction>(
222       new MockPrefHashStoreTransaction(this));
223 }
224
225 PrefHashStoreTransaction::ValueState MockPrefHashStore::RecordCheckValue(
226     const std::string& path,
227     const base::Value* value,
228     PrefHashFilter::PrefTrackingStrategy strategy) {
229   // Record that |path| was checked and validate that it wasn't previously
230   // checked.
231   EXPECT_TRUE(checked_values_.insert(
232       std::make_pair(path, std::make_pair(value, strategy))).second);
233   std::map<std::string,
234            PrefHashStoreTransaction::ValueState>::const_iterator result =
235       check_results_.find(path);
236   if (result != check_results_.end())
237     return result->second;
238   return PrefHashStoreTransaction::UNCHANGED;
239 }
240
241 void MockPrefHashStore::RecordStoreHash(
242     const std::string& path,
243     const base::Value* new_value,
244     PrefHashFilter::PrefTrackingStrategy strategy) {
245   EXPECT_TRUE(stored_values_.insert(
246       std::make_pair(path, std::make_pair(new_value, strategy))).second);
247 }
248
249 PrefHashStoreTransaction::ValueState
250 MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue(
251     const std::string& path, const base::Value* value) const {
252   return outer_->RecordCheckValue(path, value,
253                                   PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
254 }
255
256 void MockPrefHashStore::MockPrefHashStoreTransaction::StoreHash(
257     const std::string& path,
258     const base::Value* new_value) {
259   outer_->RecordStoreHash(path, new_value,
260                           PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
261 }
262
263 PrefHashStoreTransaction::ValueState
264 MockPrefHashStore::MockPrefHashStoreTransaction::CheckSplitValue(
265     const std::string& path,
266     const base::DictionaryValue* initial_split_value,
267     std::vector<std::string>* invalid_keys) const {
268   EXPECT_TRUE(invalid_keys && invalid_keys->empty());
269
270   std::map<std::string, std::vector<std::string> >::const_iterator
271       invalid_keys_result = outer_->invalid_keys_results_.find(path);
272   if (invalid_keys_result != outer_->invalid_keys_results_.end()) {
273     invalid_keys->insert(invalid_keys->begin(),
274                          invalid_keys_result->second.begin(),
275                          invalid_keys_result->second.end());
276   }
277
278   return outer_->RecordCheckValue(path, initial_split_value,
279                                   PrefHashFilter::TRACKING_STRATEGY_SPLIT);
280 }
281
282 void MockPrefHashStore::MockPrefHashStoreTransaction::StoreSplitHash(
283     const std::string& path,
284     const base::DictionaryValue* new_value) {
285   outer_->RecordStoreHash(path, new_value,
286                           PrefHashFilter::TRACKING_STRATEGY_SPLIT);
287 }
288
289 // Creates a PrefHashFilter that uses a MockPrefHashStore. The
290 // MockPrefHashStore (owned by the PrefHashFilter) is returned in
291 // |mock_pref_hash_store|.
292 scoped_ptr<PrefHashFilter> CreatePrefHashFilter(
293     PrefHashFilter::EnforcementLevel max_enforcement_level,
294     MockPrefHashStore** mock_pref_hash_store) {
295   scoped_ptr<MockPrefHashStore> temp_mock_pref_hash_store(
296       new MockPrefHashStore);
297   if (mock_pref_hash_store)
298     *mock_pref_hash_store = temp_mock_pref_hash_store.get();
299   std::vector<PrefHashFilter::TrackedPreferenceMetadata> configuration(
300       kTestTrackedPrefs, kTestTrackedPrefs + arraysize(kTestTrackedPrefs));
301   for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it =
302            configuration.begin();
303        it != configuration.end();
304        ++it) {
305     if (it->enforcement_level > max_enforcement_level)
306       it->enforcement_level = max_enforcement_level;
307   }
308   return scoped_ptr<PrefHashFilter>(
309       new PrefHashFilter(temp_mock_pref_hash_store.PassAs<PrefHashStore>(),
310                          configuration,
311                          arraysize(kTestTrackedPrefs)));
312 }
313
314 class PrefHashFilterTest
315     : public testing::TestWithParam<PrefHashFilter::EnforcementLevel> {
316  public:
317   PrefHashFilterTest() : mock_pref_hash_store_(NULL) {}
318
319   virtual void SetUp() OVERRIDE {
320     // Construct a PrefHashFilter and MockPrefHashStore for the test.
321     pref_hash_filter_ =
322         CreatePrefHashFilter(GetParam(), &mock_pref_hash_store_);
323   }
324
325  protected:
326   bool RecordedReset() {
327     return pref_store_contents_.Get(prefs::kPreferenceResetTime, NULL);
328   }
329
330   MockPrefHashStore* mock_pref_hash_store_;
331   base::DictionaryValue pref_store_contents_;
332   scoped_ptr<PrefHashFilter> pref_hash_filter_;
333
334   DISALLOW_COPY_AND_ASSIGN(PrefHashFilterTest);
335 };
336
337 TEST_P(PrefHashFilterTest, EmptyAndUnchanged) {
338   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
339   // All paths checked.
340   ASSERT_EQ(arraysize(kTestTrackedPrefs),
341             mock_pref_hash_store_->checked_paths_count());
342   // No paths stored, since they all return |UNCHANGED|.
343   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
344   // Since there was nothing in |pref_store_contents_| the checked value should
345   // have been NULL for all tracked preferences.
346   for (size_t i = 0; i < arraysize(kTestTrackedPrefs); ++i) {
347     ASSERT_EQ(NULL, mock_pref_hash_store_->checked_value(
348                         kTestTrackedPrefs[i].name).first);
349   }
350   ASSERT_FALSE(RecordedReset());
351 }
352
353 TEST_P(PrefHashFilterTest, FilterTrackedPrefUpdate) {
354   base::DictionaryValue root_dict;
355   // Ownership of |string_value| is transfered to |root_dict|.
356   base::Value* string_value = base::Value::CreateStringValue("string value");
357   root_dict.Set(kAtomicPref, string_value);
358
359   // No path should be stored on FilterUpdate.
360   pref_hash_filter_->FilterUpdate(kAtomicPref);
361   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
362
363   // One path should be stored on FilterSerializeData.
364   pref_hash_filter_->FilterSerializeData(&root_dict);
365   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
366   MockPrefHashStore::ValuePtrStrategyPair stored_value =
367       mock_pref_hash_store_->stored_value(kAtomicPref);
368   ASSERT_EQ(string_value, stored_value.first);
369   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, stored_value.second);
370
371   ASSERT_FALSE(RecordedReset());
372 }
373
374 TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
375   base::DictionaryValue root_dict;
376   // Ownership of |dict_value| is transfered to |root_dict|.
377   base::DictionaryValue* dict_value = new base::DictionaryValue;
378   dict_value->SetString("a", "foo");
379   dict_value->SetInteger("b", 1234);
380   root_dict.Set(kSplitPref, dict_value);
381
382   // No path should be stored on FilterUpdate.
383   pref_hash_filter_->FilterUpdate(kSplitPref);
384   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
385
386   // One path should be stored on FilterSerializeData.
387   pref_hash_filter_->FilterSerializeData(&root_dict);
388   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
389   MockPrefHashStore::ValuePtrStrategyPair stored_value =
390        mock_pref_hash_store_->stored_value(kSplitPref);
391   ASSERT_EQ(dict_value, stored_value.first);
392   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value.second);
393
394   ASSERT_FALSE(RecordedReset());
395 }
396
397 TEST_P(PrefHashFilterTest, FilterUntrackedPrefUpdate) {
398   // No transaction should even be started on FilterSerializeData() if there are
399   // no updates to perform.
400   mock_pref_hash_store_->set_transactions_expected(0);
401
402   base::DictionaryValue root_dict;
403   root_dict.Set("untracked", base::Value::CreateStringValue("some value"));
404   pref_hash_filter_->FilterUpdate("untracked");
405
406   // No paths should be stored on FilterUpdate.
407   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
408
409   // Nor on FilterSerializeData.
410   pref_hash_filter_->FilterSerializeData(&root_dict);
411   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
412 }
413
414 TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) {
415   base::DictionaryValue root_dict;
416   // Ownership of the following values is transfered to |root_dict|.
417   base::Value* int_value1 = base::Value::CreateIntegerValue(1);
418   base::Value* int_value2 = base::Value::CreateIntegerValue(2);
419   base::Value* int_value3 = base::Value::CreateIntegerValue(3);
420   base::Value* int_value4 = base::Value::CreateIntegerValue(4);
421   base::DictionaryValue* dict_value = new base::DictionaryValue;
422   dict_value->Set("a", base::Value::CreateBooleanValue(true));
423   root_dict.Set(kAtomicPref, int_value1);
424   root_dict.Set(kAtomicPref2, int_value2);
425   root_dict.Set(kAtomicPref3, int_value3);
426   root_dict.Set("untracked", int_value4);
427   root_dict.Set(kSplitPref, dict_value);
428
429   // Only update kAtomicPref, kAtomicPref3, and kSplitPref.
430   pref_hash_filter_->FilterUpdate(kAtomicPref);
431   pref_hash_filter_->FilterUpdate(kAtomicPref3);
432   pref_hash_filter_->FilterUpdate(kSplitPref);
433   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
434
435   // Update kAtomicPref3 again, nothing should be stored still.
436   base::Value* int_value5 = base::Value::CreateIntegerValue(5);
437   root_dict.Set(kAtomicPref3, int_value5);
438   ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
439
440   // On FilterSerializeData, only kAtomicPref, kAtomicPref3, and kSplitPref
441   // should get a new hash.
442   pref_hash_filter_->FilterSerializeData(&root_dict);
443   ASSERT_EQ(3u, mock_pref_hash_store_->stored_paths_count());
444   MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1 =
445       mock_pref_hash_store_->stored_value(kAtomicPref);
446   ASSERT_EQ(int_value1, stored_value_atomic1.first);
447   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
448             stored_value_atomic1.second);
449
450   MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3 =
451       mock_pref_hash_store_->stored_value(kAtomicPref3);
452   ASSERT_EQ(int_value5, stored_value_atomic3.first);
453   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
454             stored_value_atomic3.second);
455
456   MockPrefHashStore::ValuePtrStrategyPair stored_value_split =
457        mock_pref_hash_store_->stored_value(kSplitPref);
458   ASSERT_EQ(dict_value, stored_value_split.first);
459   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value_split.second);
460 }
461
462 TEST_P(PrefHashFilterTest, EmptyAndUnknown) {
463   ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
464   ASSERT_FALSE(pref_store_contents_.Get(kSplitPref, NULL));
465   // NULL values are always trusted by the PrefHashStore.
466   mock_pref_hash_store_->SetCheckResult(
467       kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
468   mock_pref_hash_store_->SetCheckResult(
469       kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
470   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
471   ASSERT_EQ(arraysize(kTestTrackedPrefs),
472             mock_pref_hash_store_->checked_paths_count());
473   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
474
475   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
476        mock_pref_hash_store_->stored_value(kAtomicPref);
477   ASSERT_EQ(NULL, stored_atomic_value.first);
478   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
479             stored_atomic_value.second);
480
481   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
482        mock_pref_hash_store_->stored_value(kSplitPref);
483   ASSERT_EQ(NULL, stored_split_value.first);
484   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
485             stored_split_value.second);
486 }
487
488 TEST_P(PrefHashFilterTest, InitialValueUnknown) {
489   // Ownership of these values is transfered to |pref_store_contents_|.
490   base::StringValue* string_value = new base::StringValue("string value");
491   pref_store_contents_.Set(kAtomicPref, string_value);
492
493   base::DictionaryValue* dict_value = new base::DictionaryValue;
494   dict_value->SetString("a", "foo");
495   dict_value->SetInteger("b", 1234);
496   pref_store_contents_.Set(kSplitPref, dict_value);
497
498   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
499   ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, NULL));
500
501   mock_pref_hash_store_->SetCheckResult(
502       kAtomicPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE);
503   mock_pref_hash_store_->SetCheckResult(
504       kSplitPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE);
505   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
506   ASSERT_EQ(arraysize(kTestTrackedPrefs),
507             mock_pref_hash_store_->checked_paths_count());
508   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
509
510   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
511        mock_pref_hash_store_->stored_value(kAtomicPref);
512   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
513        mock_pref_hash_store_->stored_value(kSplitPref);
514   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
515             stored_atomic_value.second);
516   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
517             stored_split_value.second);
518   if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
519     // Ensure the prefs were cleared and the hashes for NULL were restored if
520     // the current enforcement level denies seeding.
521     ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
522     ASSERT_EQ(NULL, stored_atomic_value.first);
523
524     ASSERT_FALSE(pref_store_contents_.Get(kSplitPref, NULL));
525     ASSERT_EQ(NULL, stored_split_value.first);
526
527     ASSERT_TRUE(RecordedReset());
528   } else {
529     // Otherwise the values should have remained intact and the hashes should
530     // have been updated to match them.
531     const base::Value* atomic_value_in_store;
532     ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
533     ASSERT_EQ(string_value, atomic_value_in_store);
534     ASSERT_EQ(string_value, stored_atomic_value.first);
535
536     const base::Value* split_value_in_store;
537     ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
538     ASSERT_EQ(dict_value, split_value_in_store);
539     ASSERT_EQ(dict_value, stored_split_value.first);
540
541     ASSERT_FALSE(RecordedReset());
542   }
543 }
544
545 TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) {
546   // Ownership of this value is transfered to |pref_store_contents_|.
547   base::Value* string_value = base::Value::CreateStringValue("test");
548   pref_store_contents_.Set(kAtomicPref, string_value);
549
550   base::DictionaryValue* dict_value = new base::DictionaryValue;
551   dict_value->SetString("a", "foo");
552   dict_value->SetInteger("b", 1234);
553   pref_store_contents_.Set(kSplitPref, dict_value);
554
555   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
556   ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, NULL));
557
558   mock_pref_hash_store_->SetCheckResult(
559       kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
560   mock_pref_hash_store_->SetCheckResult(
561       kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE);
562   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
563   ASSERT_EQ(arraysize(kTestTrackedPrefs),
564             mock_pref_hash_store_->checked_paths_count());
565   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
566
567   // Seeding is always allowed for trusted unknown values.
568   const base::Value* atomic_value_in_store;
569   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
570   ASSERT_EQ(string_value, atomic_value_in_store);
571   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
572        mock_pref_hash_store_->stored_value(kAtomicPref);
573   ASSERT_EQ(string_value, stored_atomic_value.first);
574   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
575             stored_atomic_value.second);
576
577   const base::Value* split_value_in_store;
578   ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
579   ASSERT_EQ(dict_value, split_value_in_store);
580   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
581        mock_pref_hash_store_->stored_value(kSplitPref);
582   ASSERT_EQ(dict_value, stored_split_value.first);
583   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
584             stored_split_value.second);
585 }
586
587 TEST_P(PrefHashFilterTest, InitialValueChanged) {
588   // Ownership of this value is transfered to |pref_store_contents_|.
589   base::Value* int_value = base::Value::CreateIntegerValue(1234);
590   pref_store_contents_.Set(kAtomicPref, int_value);
591
592   base::DictionaryValue* dict_value = new base::DictionaryValue;
593   dict_value->SetString("a", "foo");
594   dict_value->SetInteger("b", 1234);
595   dict_value->SetInteger("c", 56);
596   dict_value->SetBoolean("d", false);
597   pref_store_contents_.Set(kSplitPref, dict_value);
598
599   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
600   ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, NULL));
601
602   mock_pref_hash_store_->SetCheckResult(kAtomicPref,
603                                         PrefHashStoreTransaction::CHANGED);
604   mock_pref_hash_store_->SetCheckResult(kSplitPref,
605                                         PrefHashStoreTransaction::CHANGED);
606
607   std::vector<std::string> mock_invalid_keys;
608   mock_invalid_keys.push_back("a");
609   mock_invalid_keys.push_back("c");
610   mock_pref_hash_store_->SetInvalidKeysResult(kSplitPref, mock_invalid_keys);
611
612   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
613   ASSERT_EQ(arraysize(kTestTrackedPrefs),
614             mock_pref_hash_store_->checked_paths_count());
615   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
616
617   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
618        mock_pref_hash_store_->stored_value(kAtomicPref);
619   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
620        mock_pref_hash_store_->stored_value(kSplitPref);
621   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
622             stored_atomic_value.second);
623   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
624             stored_split_value.second);
625   if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
626     // Ensure the atomic pref was cleared and the hash for NULL was restored if
627     // the current enforcement level prevents changes.
628     ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
629     ASSERT_EQ(NULL, stored_atomic_value.first);
630
631     // The split pref on the other hand should only have been stripped of its
632     // invalid keys.
633     const base::Value* split_value_in_store;
634     ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
635     ASSERT_EQ(2U, dict_value->size());
636     ASSERT_FALSE(dict_value->HasKey("a"));
637     ASSERT_TRUE(dict_value->HasKey("b"));
638     ASSERT_FALSE(dict_value->HasKey("c"));
639     ASSERT_TRUE(dict_value->HasKey("d"));
640     ASSERT_EQ(dict_value, stored_split_value.first);
641
642     ASSERT_TRUE(RecordedReset());
643   } else {
644     // Otherwise the value should have remained intact and the hash should have
645     // been updated to match it.
646     const base::Value* atomic_value_in_store;
647     ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
648     ASSERT_EQ(int_value, atomic_value_in_store);
649     ASSERT_EQ(int_value, stored_atomic_value.first);
650
651     const base::Value* split_value_in_store;
652     ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
653     ASSERT_EQ(dict_value, split_value_in_store);
654     ASSERT_EQ(4U, dict_value->size());
655     ASSERT_TRUE(dict_value->HasKey("a"));
656     ASSERT_TRUE(dict_value->HasKey("b"));
657     ASSERT_TRUE(dict_value->HasKey("c"));
658     ASSERT_TRUE(dict_value->HasKey("d"));
659     ASSERT_EQ(dict_value, stored_split_value.first);
660
661     ASSERT_FALSE(RecordedReset());
662   }
663 }
664
665 TEST_P(PrefHashFilterTest, EmptyCleared) {
666   ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
667   ASSERT_FALSE(pref_store_contents_.Get(kSplitPref, NULL));
668   mock_pref_hash_store_->SetCheckResult(kAtomicPref,
669                                         PrefHashStoreTransaction::CLEARED);
670   mock_pref_hash_store_->SetCheckResult(kSplitPref,
671                                         PrefHashStoreTransaction::CLEARED);
672   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
673   ASSERT_EQ(arraysize(kTestTrackedPrefs),
674             mock_pref_hash_store_->checked_paths_count());
675   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
676
677   // Regardless of the enforcement level, the only thing that should be done is
678   // to restore the hash for NULL. The value itself should still be NULL.
679   ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
680   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
681        mock_pref_hash_store_->stored_value(kAtomicPref);
682   ASSERT_EQ(NULL, stored_atomic_value.first);
683   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
684             stored_atomic_value.second);
685
686   ASSERT_FALSE(pref_store_contents_.Get(kSplitPref, NULL));
687   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
688        mock_pref_hash_store_->stored_value(kSplitPref);
689   ASSERT_EQ(NULL, stored_split_value.first);
690   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
691             stored_split_value.second);
692 }
693
694 TEST_P(PrefHashFilterTest, InitialValueMigrated) {
695   // Only test atomic prefs, split prefs were introduce after the migration.
696
697   // Ownership of this value is transfered to |pref_store_contents_|.
698   base::ListValue* list_value = new base::ListValue;
699   list_value->Append(base::Value::CreateStringValue("test"));
700   pref_store_contents_.Set(kAtomicPref, list_value);
701
702   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
703
704   mock_pref_hash_store_->SetCheckResult(kAtomicPref,
705                                         PrefHashStoreTransaction::WEAK_LEGACY);
706   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
707   ASSERT_EQ(arraysize(kTestTrackedPrefs),
708             mock_pref_hash_store_->checked_paths_count());
709   ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
710
711   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
712        mock_pref_hash_store_->stored_value(kAtomicPref);
713   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
714             stored_atomic_value.second);
715   if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
716     // Ensure the pref was cleared and the hash for NULL was restored if the
717     // current enforcement level prevents migration.
718     ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
719     ASSERT_EQ(NULL, stored_atomic_value.first);
720
721     ASSERT_TRUE(RecordedReset());
722   } else {
723     // Otherwise the value should have remained intact and the hash should have
724     // been updated to match it.
725     const base::Value* atomic_value_in_store;
726     ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
727     ASSERT_EQ(list_value, atomic_value_in_store);
728     ASSERT_EQ(list_value, stored_atomic_value.first);
729
730     ASSERT_FALSE(RecordedReset());
731   }
732 }
733
734 TEST_P(PrefHashFilterTest, InitialValueUnchangedLegacyId) {
735   // Ownership of these values is transfered to |pref_store_contents_|.
736   base::StringValue* string_value = new base::StringValue("string value");
737   pref_store_contents_.Set(kAtomicPref, string_value);
738
739   base::DictionaryValue* dict_value = new base::DictionaryValue;
740   dict_value->SetString("a", "foo");
741   dict_value->SetInteger("b", 1234);
742   pref_store_contents_.Set(kSplitPref, dict_value);
743
744   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
745   ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, NULL));
746
747   mock_pref_hash_store_->SetCheckResult(
748       kAtomicPref, PrefHashStoreTransaction::SECURE_LEGACY);
749   mock_pref_hash_store_->SetCheckResult(
750       kSplitPref, PrefHashStoreTransaction::SECURE_LEGACY);
751   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
752   ASSERT_EQ(arraysize(kTestTrackedPrefs),
753             mock_pref_hash_store_->checked_paths_count());
754
755   // Ensure that both the atomic and split hashes were restored.
756   ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
757
758   // In all cases, the values should have remained intact and the hashes should
759   // have been updated to match them.
760
761   MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
762        mock_pref_hash_store_->stored_value(kAtomicPref);
763   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
764             stored_atomic_value.second);
765   const base::Value* atomic_value_in_store;
766   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &atomic_value_in_store));
767   ASSERT_EQ(string_value, atomic_value_in_store);
768   ASSERT_EQ(string_value, stored_atomic_value.first);
769
770   MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
771        mock_pref_hash_store_->stored_value(kSplitPref);
772   ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT,
773             stored_split_value.second);
774   const base::Value* split_value_in_store;
775   ASSERT_TRUE(pref_store_contents_.Get(kSplitPref, &split_value_in_store));
776   ASSERT_EQ(dict_value, split_value_in_store);
777   ASSERT_EQ(dict_value, stored_split_value.first);
778
779   ASSERT_FALSE(RecordedReset());
780 }
781
782 TEST_P(PrefHashFilterTest, DontResetReportOnly) {
783   // Ownership of these values is transfered to |pref_store_contents_|.
784   base::Value* int_value1 = base::Value::CreateIntegerValue(1);
785   base::Value* int_value2 = base::Value::CreateIntegerValue(2);
786   base::Value* report_only_val = base::Value::CreateIntegerValue(3);
787   base::DictionaryValue* report_only_split_val = new base::DictionaryValue;
788   report_only_split_val->SetInteger("a", 1234);
789   pref_store_contents_.Set(kAtomicPref, int_value1);
790   pref_store_contents_.Set(kAtomicPref2, int_value2);
791   pref_store_contents_.Set(kReportOnlyPref, report_only_val);
792   pref_store_contents_.Set(kReportOnlySplitPref, report_only_split_val);
793
794   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, NULL));
795   ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref2, NULL));
796   ASSERT_TRUE(pref_store_contents_.Get(kReportOnlyPref, NULL));
797   ASSERT_TRUE(pref_store_contents_.Get(kReportOnlySplitPref, NULL));
798
799   mock_pref_hash_store_->SetCheckResult(kAtomicPref,
800                                         PrefHashStoreTransaction::CHANGED);
801   mock_pref_hash_store_->SetCheckResult(kAtomicPref2,
802                                         PrefHashStoreTransaction::CHANGED);
803   mock_pref_hash_store_->SetCheckResult(kReportOnlyPref,
804                                         PrefHashStoreTransaction::CHANGED);
805   mock_pref_hash_store_->SetCheckResult(kReportOnlySplitPref,
806                                         PrefHashStoreTransaction::CHANGED);
807   pref_hash_filter_->FilterOnLoad(&pref_store_contents_);
808   // All prefs should be checked and a new hash should be stored for each tested
809   // pref.
810   ASSERT_EQ(arraysize(kTestTrackedPrefs),
811             mock_pref_hash_store_->checked_paths_count());
812   ASSERT_EQ(4u, mock_pref_hash_store_->stored_paths_count());
813
814   // No matter what the enforcement level is, the report only pref should never
815   // be reset.
816   ASSERT_TRUE(pref_store_contents_.Get(kReportOnlyPref, NULL));
817   ASSERT_TRUE(pref_store_contents_.Get(kReportOnlySplitPref, NULL));
818   ASSERT_EQ(report_only_val,
819             mock_pref_hash_store_->stored_value(kReportOnlyPref).first);
820   ASSERT_EQ(report_only_split_val,
821             mock_pref_hash_store_->stored_value(kReportOnlySplitPref).first);
822
823   // All other prefs should have been reset if the enforcement level allows it.
824   if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) {
825     ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref, NULL));
826     ASSERT_FALSE(pref_store_contents_.Get(kAtomicPref2, NULL));
827     ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref).first);
828     ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref2).first);
829
830     ASSERT_TRUE(RecordedReset());
831   } else {
832     const base::Value* value_in_store;
833     const base::Value* value_in_store2;
834     ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref, &value_in_store));
835     ASSERT_TRUE(pref_store_contents_.Get(kAtomicPref2, &value_in_store2));
836     ASSERT_EQ(int_value1, value_in_store);
837     ASSERT_EQ(int_value1,
838               mock_pref_hash_store_->stored_value(kAtomicPref).first);
839     ASSERT_EQ(int_value2, value_in_store2);
840     ASSERT_EQ(int_value2,
841               mock_pref_hash_store_->stored_value(kAtomicPref2).first);
842
843     ASSERT_FALSE(RecordedReset());
844   }
845 }
846
847 INSTANTIATE_TEST_CASE_P(
848     PrefHashFilterTestInstance, PrefHashFilterTest,
849     testing::Values(PrefHashFilter::NO_ENFORCEMENT,
850                     PrefHashFilter::ENFORCE_ON_LOAD));