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 "components/user_prefs/tracked/pref_hash_calculator.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_util.h"
11 #include "base/values.h"
12 #include "testing/gtest/include/gtest/gtest.h"
14 TEST(PrefHashCalculatorTest
, TestCurrentAlgorithm
) {
15 base::StringValue
string_value_1("string value 1");
16 base::StringValue
string_value_2("string value 2");
17 base::DictionaryValue dictionary_value_1
;
18 dictionary_value_1
.SetInteger("int value", 1);
19 dictionary_value_1
.Set("nested empty map", new base::DictionaryValue
);
20 base::DictionaryValue dictionary_value_1_equivalent
;
21 dictionary_value_1_equivalent
.SetInteger("int value", 1);
22 base::DictionaryValue dictionary_value_2
;
23 dictionary_value_2
.SetInteger("int value", 2);
25 PrefHashCalculator
calc1("seed1", "deviceid");
26 PrefHashCalculator
calc1_dup("seed1", "deviceid");
27 PrefHashCalculator
calc2("seed2", "deviceid");
28 PrefHashCalculator
calc3("seed1", "deviceid2");
30 // Two calculators with same seed produce same hash.
31 ASSERT_EQ(calc1
.Calculate("pref_path", &string_value_1
),
32 calc1_dup
.Calculate("pref_path", &string_value_1
));
33 ASSERT_EQ(PrefHashCalculator::VALID
,
34 calc1_dup
.Validate("pref_path", &string_value_1
,
35 calc1
.Calculate("pref_path", &string_value_1
)));
37 // Different seeds, different hashes.
38 ASSERT_NE(calc1
.Calculate("pref_path", &string_value_1
),
39 calc2
.Calculate("pref_path", &string_value_1
));
40 ASSERT_EQ(PrefHashCalculator::INVALID
,
41 calc2
.Validate("pref_path", &string_value_1
,
42 calc1
.Calculate("pref_path", &string_value_1
)));
44 // Different device IDs, different hashes.
45 ASSERT_NE(calc1
.Calculate("pref_path", &string_value_1
),
46 calc3
.Calculate("pref_path", &string_value_1
));
48 // Different values, different hashes.
49 ASSERT_NE(calc1
.Calculate("pref_path", &string_value_1
),
50 calc1
.Calculate("pref_path", &string_value_2
));
52 // Different paths, different hashes.
53 ASSERT_NE(calc1
.Calculate("pref_path", &string_value_1
),
54 calc1
.Calculate("pref_path_2", &string_value_1
));
56 // Works for dictionaries.
57 ASSERT_EQ(calc1
.Calculate("pref_path", &dictionary_value_1
),
58 calc1
.Calculate("pref_path", &dictionary_value_1
));
59 ASSERT_NE(calc1
.Calculate("pref_path", &dictionary_value_1
),
60 calc1
.Calculate("pref_path", &dictionary_value_2
));
62 // Empty dictionary children are pruned.
63 ASSERT_EQ(calc1
.Calculate("pref_path", &dictionary_value_1
),
64 calc1
.Calculate("pref_path", &dictionary_value_1_equivalent
));
66 // NULL value is supported.
67 ASSERT_FALSE(calc1
.Calculate("pref_path", NULL
).empty());
70 // Tests the output against a known value to catch unexpected algorithm changes.
71 // The test hashes below must NEVER be updated, the serialization algorithm used
72 // must always be able to generate data that will produce these exact hashes.
73 TEST(PrefHashCalculatorTest
, CatchHashChanges
) {
74 static const char kSeed
[] = "0123456789ABCDEF0123456789ABCDEF";
75 static const char kDeviceId
[] = "test_device_id1";
77 scoped_ptr
<base::Value
> null_value
= base::Value::CreateNullValue();
78 scoped_ptr
<base::Value
> bool_value(new base::FundamentalValue(false));
79 scoped_ptr
<base::Value
> int_value(new base::FundamentalValue(1234567890));
80 scoped_ptr
<base::Value
> double_value(
81 new base::FundamentalValue(123.0987654321));
82 scoped_ptr
<base::Value
> string_value(
83 new base::StringValue("testing with special chars:\n<>{}:^^@#$\\/"));
85 // For legacy reasons, we have to support pruning of empty lists/dictionaries
86 // and nested empty ists/dicts in the hash generation algorithm.
87 scoped_ptr
<base::DictionaryValue
> nested_empty_dict(
88 new base::DictionaryValue
);
89 nested_empty_dict
->Set("a", new base::DictionaryValue
);
90 nested_empty_dict
->Set("b", new base::ListValue
);
91 scoped_ptr
<base::ListValue
> nested_empty_list(new base::ListValue
);
92 nested_empty_list
->Append(new base::DictionaryValue
);
93 nested_empty_list
->Append(new base::ListValue
);
94 nested_empty_list
->Append(nested_empty_dict
->DeepCopy());
96 // A dictionary with an empty dictionary, an empty list, and nested empty
97 // dictionaries/lists in it.
98 scoped_ptr
<base::DictionaryValue
> dict_value(new base::DictionaryValue
);
99 dict_value
->Set("a", new base::StringValue("foo"));
100 dict_value
->Set("d", new base::ListValue
);
101 dict_value
->Set("b", new base::DictionaryValue
);
102 dict_value
->Set("c", new base::StringValue("baz"));
103 dict_value
->Set("e", nested_empty_dict
.release());
104 dict_value
->Set("f", nested_empty_list
.release());
106 scoped_ptr
<base::ListValue
> list_value(new base::ListValue
);
107 list_value
->AppendBoolean(true);
108 list_value
->AppendInteger(100);
109 list_value
->AppendDouble(1.0);
111 ASSERT_EQ(base::Value::TYPE_NULL
, null_value
->GetType());
112 ASSERT_EQ(base::Value::TYPE_BOOLEAN
, bool_value
->GetType());
113 ASSERT_EQ(base::Value::TYPE_INTEGER
, int_value
->GetType());
114 ASSERT_EQ(base::Value::TYPE_DOUBLE
, double_value
->GetType());
115 ASSERT_EQ(base::Value::TYPE_STRING
, string_value
->GetType());
116 ASSERT_EQ(base::Value::TYPE_DICTIONARY
, dict_value
->GetType());
117 ASSERT_EQ(base::Value::TYPE_LIST
, list_value
->GetType());
119 // Test every value type independently. Intentionally omits TYPE_BINARY which
120 // isn't even allowed in JSONWriter's input.
121 static const char kExpectedNullValue
[] =
122 "82A9F3BBC7F9FF84C76B033C854E79EEB162783FA7B3E99FF9372FA8E12C44F7";
123 EXPECT_EQ(PrefHashCalculator::VALID
,
124 PrefHashCalculator(kSeed
, kDeviceId
)
125 .Validate("pref.path", null_value
.get(), kExpectedNullValue
));
127 static const char kExpectedBooleanValue
[] =
128 "A520D8F43EA307B0063736DC9358C330539D0A29417580514C8B9862632C4CCC";
130 PrefHashCalculator::VALID
,
131 PrefHashCalculator(kSeed
, kDeviceId
)
132 .Validate("pref.path", bool_value
.get(), kExpectedBooleanValue
));
134 static const char kExpectedIntegerValue
[] =
135 "8D60DA1F10BF5AA29819D2D66D7CCEF9AABC5DA93C11A0D2BD21078D63D83682";
136 EXPECT_EQ(PrefHashCalculator::VALID
,
137 PrefHashCalculator(kSeed
, kDeviceId
)
138 .Validate("pref.path", int_value
.get(), kExpectedIntegerValue
));
140 static const char kExpectedDoubleValue
[] =
141 "C9D94772516125BEEDAE68C109D44BC529E719EE020614E894CC7FB4098C545D";
143 PrefHashCalculator::VALID
,
144 PrefHashCalculator(kSeed
, kDeviceId
)
145 .Validate("pref.path", double_value
.get(), kExpectedDoubleValue
));
147 static const char kExpectedStringValue
[] =
148 "05ACCBD3B05C45C36CD06190F63EC577112311929D8380E26E5F13182EB68318";
150 PrefHashCalculator::VALID
,
151 PrefHashCalculator(kSeed
, kDeviceId
)
152 .Validate("pref.path", string_value
.get(), kExpectedStringValue
));
154 static const char kExpectedDictValue
[] =
155 "7A84DCC710D796C771F789A4DA82C952095AA956B6F1667EE42D0A19ECAA3C4A";
156 EXPECT_EQ(PrefHashCalculator::VALID
,
157 PrefHashCalculator(kSeed
, kDeviceId
)
158 .Validate("pref.path", dict_value
.get(), kExpectedDictValue
));
160 static const char kExpectedListValue
[] =
161 "8D5A25972DF5AE20D041C780E7CA54E40F614AD53513A0724EE8D62D4F992740";
162 EXPECT_EQ(PrefHashCalculator::VALID
,
163 PrefHashCalculator(kSeed
, kDeviceId
)
164 .Validate("pref.path", list_value
.get(), kExpectedListValue
));
166 // Also test every value type together in the same dictionary.
167 base::DictionaryValue everything
;
168 everything
.Set("null", null_value
.release());
169 everything
.Set("bool", bool_value
.release());
170 everything
.Set("int", int_value
.release());
171 everything
.Set("double", double_value
.release());
172 everything
.Set("string", string_value
.release());
173 everything
.Set("list", list_value
.release());
174 everything
.Set("dict", dict_value
.release());
175 static const char kExpectedEverythingValue
[] =
176 "B97D09BE7005693574DCBDD03D8D9E44FB51F4008B73FB56A49A9FA671A1999B";
177 EXPECT_EQ(PrefHashCalculator::VALID
,
178 PrefHashCalculator(kSeed
, kDeviceId
)
179 .Validate("pref.path", &everything
, kExpectedEverythingValue
));
182 TEST(PrefHashCalculatorTest
, TestCompatibilityWithLegacyPrefMetricsServiceId
) {
183 static const char kSeed
[] = {
184 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
185 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
186 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
187 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
188 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
189 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
190 static const char kDeviceId
[] =
191 "D730D9CBD98C734A4FB097A1922275FE9F7E026A4EA1BE0E84";
192 static const char kExpectedValue
[] =
193 "845EF34663FF8D32BE6707F40258FBA531C2BFC532E3B014AFB3476115C2A9DE";
195 base::ListValue startup_urls
;
196 startup_urls
.Set(0, new base::StringValue("http://www.chromium.org/"));
199 PrefHashCalculator::VALID_SECURE_LEGACY
,
200 PrefHashCalculator(std::string(kSeed
, arraysize(kSeed
)), kDeviceId
)
201 .Validate("session.startup_urls", &startup_urls
, kExpectedValue
));