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.
5 #include "chrome/browser/prefs/pref_hash_calculator.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/values.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 TEST(PrefHashCalculatorTest
, TestCurrentAlgorithm
) {
14 base::StringValue
string_value_1("string value 1");
15 base::StringValue
string_value_2("string value 2");
16 base::DictionaryValue dictionary_value_1
;
17 dictionary_value_1
.SetInteger("int value", 1);
18 dictionary_value_1
.Set("nested empty map", new base::DictionaryValue
);
19 base::DictionaryValue dictionary_value_1_equivalent
;
20 dictionary_value_1_equivalent
.SetInteger("int value", 1);
21 base::DictionaryValue dictionary_value_2
;
22 dictionary_value_2
.SetInteger("int value", 2);
24 PrefHashCalculator
calc1("seed1", "deviceid");
25 PrefHashCalculator
calc1_dup("seed1", "deviceid");
26 PrefHashCalculator
calc2("seed2", "deviceid");
27 PrefHashCalculator
calc3("seed1", "deviceid2");
29 // Two calculators with same seed produce same hash.
30 ASSERT_EQ(calc1
.Calculate("pref_path", &string_value_1
),
31 calc1_dup
.Calculate("pref_path", &string_value_1
));
32 ASSERT_EQ(PrefHashCalculator::VALID
,
36 calc1
.Calculate("pref_path", &string_value_1
)));
38 // Different seeds, different hashes.
39 ASSERT_NE(calc1
.Calculate("pref_path", &string_value_1
),
40 calc2
.Calculate("pref_path", &string_value_1
));
41 ASSERT_EQ(PrefHashCalculator::INVALID
,
45 calc1
.Calculate("pref_path", &string_value_1
)));
47 // Different device IDs, different hashes.
48 ASSERT_NE(calc1
.Calculate("pref_path", &string_value_1
),
49 calc3
.Calculate("pref_path", &string_value_1
));
51 // Different values, different hashes.
52 ASSERT_NE(calc1
.Calculate("pref_path", &string_value_1
),
53 calc1
.Calculate("pref_path", &string_value_2
));
55 // Different paths, different hashes.
56 ASSERT_NE(calc1
.Calculate("pref_path", &string_value_1
),
57 calc1
.Calculate("pref_path_2", &string_value_1
));
59 // Works for dictionaries.
60 ASSERT_EQ(calc1
.Calculate("pref_path", &dictionary_value_1
),
61 calc1
.Calculate("pref_path", &dictionary_value_1
));
62 ASSERT_NE(calc1
.Calculate("pref_path", &dictionary_value_1
),
63 calc1
.Calculate("pref_path", &dictionary_value_2
));
65 // Empty dictionary children are pruned.
66 ASSERT_EQ(calc1
.Calculate("pref_path", &dictionary_value_1
),
67 calc1
.Calculate("pref_path", &dictionary_value_1_equivalent
));
69 // NULL value is supported.
70 ASSERT_FALSE(calc1
.Calculate("pref_path", NULL
).empty());
73 // Tests the output against a known value to catch unexpected algorithm changes.
74 // The test hashes below must NEVER be updated, the serialization algorithm used
75 // must always be able to generate data that will produce these exact hashes.
76 TEST(PrefHashCalculatorTest
, CatchHashChanges
) {
77 static const char kSeed
[] = "0123456789ABCDEF0123456789ABCDEF";
78 static const char kDeviceId
[] = "test_device_id1";
80 scoped_ptr
<base::Value
> null_value(base::Value::CreateNullValue());
81 scoped_ptr
<base::Value
> bool_value(base::Value::CreateBooleanValue(false));
82 scoped_ptr
<base::Value
> int_value(
83 base::Value::CreateIntegerValue(1234567890));
84 scoped_ptr
<base::Value
> double_value(
85 base::Value::CreateDoubleValue(123.0987654321));
86 scoped_ptr
<base::Value
> string_value(base::Value::CreateStringValue(
87 "testing with special chars:\n<>{}:^^@#$\\/"));
89 scoped_ptr
<base::DictionaryValue
> dict_value(new base::DictionaryValue
);
90 dict_value
->Set("a", new base::StringValue("foo"));
91 dict_value
->Set("d", new base::StringValue("bad"));
92 dict_value
->Set("b", new base::StringValue("bar"));
93 dict_value
->Set("c", new base::StringValue("baz"));
95 scoped_ptr
<base::ListValue
> list_value(new base::ListValue
);
96 list_value
->AppendBoolean(true);
97 list_value
->AppendInteger(100);
98 list_value
->AppendDouble(1.0);
100 ASSERT_EQ(base::Value::TYPE_NULL
, null_value
->GetType());
101 ASSERT_EQ(base::Value::TYPE_BOOLEAN
, bool_value
->GetType());
102 ASSERT_EQ(base::Value::TYPE_INTEGER
, int_value
->GetType());
103 ASSERT_EQ(base::Value::TYPE_DOUBLE
, double_value
->GetType());
104 ASSERT_EQ(base::Value::TYPE_STRING
, string_value
->GetType());
105 ASSERT_EQ(base::Value::TYPE_DICTIONARY
, dict_value
->GetType());
106 ASSERT_EQ(base::Value::TYPE_LIST
, list_value
->GetType());
108 // Test every value type independently. Intentionally omits TYPE_BINARY which
109 // isn't even allowed in JSONWriter's input.
110 static const char kExpectedNullValue
[] =
111 "C2871D0AC76176E39948C50A9A562B863E610FDA90C675A6A8AD16B4DC4F53DC";
112 EXPECT_EQ(PrefHashCalculator::VALID
,
113 PrefHashCalculator(kSeed
, kDeviceId
).Validate(
114 "pref.path", null_value
.get(), kExpectedNullValue
));
116 static const char kExpectedBooleanValue
[] =
117 "A326E2F405CFE05D08289CDADD9DB4F529592F0945A8CE204289E4C930D8AA43";
118 EXPECT_EQ(PrefHashCalculator::VALID
,
119 PrefHashCalculator(kSeed
, kDeviceId
).Validate(
120 "pref.path", bool_value
.get(), kExpectedBooleanValue
));
122 static const char kExpectedIntegerValue
[] =
123 "4B69938F802A2A26D69467F3E1E4A474F6323C64EFC54DBDB4A5708A7D005042";
124 EXPECT_EQ(PrefHashCalculator::VALID
,
125 PrefHashCalculator(kSeed
, kDeviceId
).Validate(
126 "pref.path", int_value
.get(), kExpectedIntegerValue
));
128 static const char kExpectedDoubleValue
[] =
129 "1734C9C745B9C92D896B9A710994BF1B56D55BFB0F00C207EC995152AF02F08F";
130 EXPECT_EQ(PrefHashCalculator::VALID
,
131 PrefHashCalculator(kSeed
, kDeviceId
).Validate(
132 "pref.path", double_value
.get(), kExpectedDoubleValue
));
134 static const char kExpectedStringValue
[] =
135 "154D15522C856AA944BFA5A9E3FFB46925BF2B95A10199564651CA1C13E98433";
136 EXPECT_EQ(PrefHashCalculator::VALID
,
137 PrefHashCalculator(kSeed
, kDeviceId
).Validate(
138 "pref.path", string_value
.get(), kExpectedStringValue
));
140 static const char kExpectedDictValue
[] =
141 "3F947A044DE9E421A735525385B4C789693682E6F6E3E4CB4741E58724B28F96";
142 EXPECT_EQ(PrefHashCalculator::VALID
,
143 PrefHashCalculator(kSeed
, kDeviceId
).Validate(
144 "pref.path1", dict_value
.get(), kExpectedDictValue
));
146 static const char kExpectedListValue
[] =
147 "D8137B8E767D3D910DCD3821CAC61D26ABB042E6EC406AEB0E347ED73A3A4EC1";
148 EXPECT_EQ(PrefHashCalculator::VALID
,
149 PrefHashCalculator(kSeed
, kDeviceId
).Validate(
150 "pref.path2", list_value
.get(), kExpectedListValue
));
152 // Also test every value type together in the same dictionary.
153 base::DictionaryValue everything
;
154 everything
.Set("null", null_value
.release());
155 everything
.Set("bool", bool_value
.release());
156 everything
.Set("int", int_value
.release());
157 everything
.Set("double", double_value
.release());
158 everything
.Set("string", string_value
.release());
159 everything
.Set("list", list_value
.release());
160 everything
.Set("dict", dict_value
.release());
161 static const char kExpectedEverythingValue
[] =
162 "0A546480C7AB7699779B2FCFA326D65E0AE1446EA62398AE1D338119C6913943";
163 EXPECT_EQ(PrefHashCalculator::VALID
,
164 PrefHashCalculator(kSeed
, kDeviceId
).Validate(
165 "pref.path1", &everything
, kExpectedEverythingValue
));
168 TEST(PrefHashCalculatorTest
, TestCompatibilityWithPrefMetricsService
) {
169 static const char kSeed
[] = {
170 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
171 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
172 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
173 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
174 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
175 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
176 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
177 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
179 static const char kDeviceId
[] =
180 "D730D9CBD98C734A4FB097A1922275FE9F7E026A4EA1BE0E84";
181 static const char kExpectedValue
[] =
182 "845EF34663FF8D32BE6707F40258FBA531C2BFC532E3B014AFB3476115C2A9DE";
184 base::ListValue startup_urls
;
185 startup_urls
.Set(0, new base::StringValue("http://www.chromium.org/"));
187 EXPECT_EQ(PrefHashCalculator::VALID
,
188 PrefHashCalculator(std::string(kSeed
, arraysize(kSeed
)), kDeviceId
).
189 Validate("session.startup_urls", &startup_urls
, kExpectedValue
));
192 TEST(PrefHashCalculatorTest
, TestLegacyAlgorithm
) {
193 static const char kExpectedValue
[] =
194 "C503FB7C65EEFD5C07185F616A0AA67923C069909933F362022B1F187E73E9A2";
195 static const char kDeviceId
[] = "not_used";
197 base::DictionaryValue dict
;
198 dict
.Set("a", new base::StringValue("foo"));
199 dict
.Set("d", new base::StringValue("bad"));
200 dict
.Set("b", new base::StringValue("bar"));
201 dict
.Set("c", new base::StringValue("baz"));
203 // 32 NULL bytes is the seed that was used to generate the legacy hash.
204 EXPECT_EQ(PrefHashCalculator::VALID_LEGACY
,
205 PrefHashCalculator(std::string(32u, 0), kDeviceId
).Validate(
206 "pref.path1", &dict
, kExpectedValue
));