OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/safe_browsing/preference_validation_delegate.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/compiler_specific.h" | |
12 #include "base/memory/scoped_vector.h" | |
13 #include "base/values.h" | |
14 #include "chrome/common/safe_browsing/csd.pb.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 | |
17 // A basic test harness that creates a delegate instance for which it stores all | |
18 // incidents. Tests can push data to the delegate and verify that the test | |
19 // instance was provided with the expected data. | |
20 class PreferenceValidationDelegateTest : public testing::Test { | |
21 protected: | |
22 typedef ScopedVector<safe_browsing::ClientIncidentReport_IncidentData> | |
23 IncidentVector; | |
24 | |
25 PreferenceValidationDelegateTest() | |
26 : kPrefPath_("atomic.pref"), | |
27 null_value_(base::Value::CreateNullValue()) {} | |
28 | |
29 virtual void SetUp() OVERRIDE { | |
30 testing::Test::SetUp(); | |
31 invalid_keys_.push_back(std::string("one")); | |
32 invalid_keys_.push_back(std::string("two")); | |
33 instance_.reset(new safe_browsing::PreferenceValidationDelegate( | |
34 base::Bind(&PreferenceValidationDelegateTest::AddIncident, | |
35 base::Unretained(this)))); | |
36 } | |
37 | |
38 void AddIncident( | |
39 scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> data) { | |
40 incidents_.push_back(data.release()); | |
41 } | |
42 | |
43 static void ExpectValueStatesEquate( | |
44 PrefHashStoreTransaction::ValueState store_state, | |
45 safe_browsing:: | |
46 ClientIncidentReport_IncidentData_TrackedPreferenceIncident_ValueState | |
47 incident_state) { | |
48 typedef safe_browsing:: | |
49 ClientIncidentReport_IncidentData_TrackedPreferenceIncident TPIncident; | |
50 switch (store_state) { | |
51 case PrefHashStoreTransaction::CLEARED: | |
52 EXPECT_EQ(TPIncident::CLEARED, incident_state); | |
53 break; | |
54 case PrefHashStoreTransaction::CHANGED: | |
55 EXPECT_EQ(TPIncident::CHANGED, incident_state); | |
56 break; | |
57 case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE: | |
58 EXPECT_EQ(TPIncident::UNTRUSTED_UNKNOWN_VALUE, incident_state); | |
59 break; | |
60 default: | |
61 FAIL() << "unexpected store state"; | |
62 break; | |
63 } | |
64 } | |
65 | |
66 static void ExpectKeysEquate( | |
67 const std::vector<std::string>& store_keys, | |
68 const google::protobuf::RepeatedPtrField<std::string>& incident_keys) { | |
69 ASSERT_EQ(store_keys.size(), static_cast<size_t>(incident_keys.size())); | |
70 for (int i = 0; i < incident_keys.size(); ++i) { | |
71 EXPECT_EQ(store_keys[i], incident_keys.Get(i)); | |
72 } | |
73 } | |
74 | |
75 const std::string kPrefPath_; | |
76 IncidentVector incidents_; | |
77 scoped_ptr<base::Value> null_value_; | |
78 base::DictionaryValue dict_value_; | |
79 std::vector<std::string> invalid_keys_; | |
80 scoped_ptr<TrackedPreferenceValidationDelegate> instance_; | |
81 }; | |
82 | |
83 // Tests that a NULL value results in an incident with no value. | |
84 TEST_F(PreferenceValidationDelegateTest, NullValue) { | |
85 instance_->OnAtomicPreferenceValidation(kPrefPath_, | |
86 NULL, | |
87 PrefHashStoreTransaction::CLEARED, | |
88 TrackedPreferenceHelper::DONT_RESET); | |
89 safe_browsing::ClientIncidentReport_IncidentData* incident = | |
90 incidents_.back(); | |
91 EXPECT_FALSE(incident->tracked_preference().has_atomic_value()); | |
92 EXPECT_EQ( | |
93 safe_browsing:: | |
94 ClientIncidentReport_IncidentData_TrackedPreferenceIncident::CLEARED, | |
95 incident->tracked_preference().value_state()); | |
96 } | |
97 | |
98 // Tests that all supported value types can be stringified into an incident. The | |
99 // parameters for the test are the type of value to test and the expected value | |
100 // string. | |
101 class PreferenceValidationDelegateValues | |
102 : public PreferenceValidationDelegateTest, | |
103 public testing::WithParamInterface< | |
104 std::tr1::tuple<base::Value::Type, const char*> > { | |
105 protected: | |
106 virtual void SetUp() OVERRIDE { | |
107 PreferenceValidationDelegateTest::SetUp(); | |
108 value_type_ = std::tr1::get<0>(GetParam()); | |
109 expected_value_ = std::tr1::get<1>(GetParam()); | |
110 } | |
111 | |
112 static scoped_ptr<base::Value> MakeValue(base::Value::Type value_type) { | |
113 using base::Value; | |
114 switch (value_type) { | |
115 case Value::TYPE_NULL: | |
116 return make_scoped_ptr(Value::CreateNullValue()); | |
117 case Value::TYPE_BOOLEAN: | |
118 return scoped_ptr<Value>(new base::FundamentalValue(false)); | |
119 case Value::TYPE_INTEGER: | |
120 return scoped_ptr<Value>(new base::FundamentalValue(47)); | |
121 case Value::TYPE_DOUBLE: | |
122 return scoped_ptr<Value>(new base::FundamentalValue(0.47)); | |
123 case Value::TYPE_STRING: | |
124 return scoped_ptr<Value>(new base::StringValue("i have a spleen")); | |
125 case Value::TYPE_DICTIONARY: { | |
126 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); | |
127 value->SetInteger("twenty-two", 22); | |
128 value->SetInteger("forty-seven", 47); | |
129 return value.PassAs<Value>(); | |
130 } | |
131 case Value::TYPE_LIST: { | |
132 scoped_ptr<base::ListValue> value(new base::ListValue()); | |
133 value->AppendInteger(22); | |
134 value->AppendInteger(47); | |
135 return value.PassAs<Value>(); | |
136 } | |
137 default: | |
138 ADD_FAILURE() << "unsupported value type " << value_type; | |
139 } | |
140 return scoped_ptr<Value>(); | |
141 } | |
142 | |
143 base::Value::Type value_type_; | |
144 const char* expected_value_; | |
145 }; | |
146 | |
147 TEST_P(PreferenceValidationDelegateValues, Value) { | |
148 instance_->OnAtomicPreferenceValidation(kPrefPath_, | |
149 MakeValue(value_type_).get(), | |
150 PrefHashStoreTransaction::CLEARED, | |
151 TrackedPreferenceHelper::DONT_RESET); | |
152 ASSERT_EQ(1U, incidents_.size()); | |
153 safe_browsing::ClientIncidentReport_IncidentData* incident = | |
154 incidents_.back(); | |
155 EXPECT_EQ(std::string(expected_value_), | |
156 incident->tracked_preference().atomic_value()); | |
157 } | |
158 | |
159 INSTANTIATE_TEST_CASE_P( | |
160 Values, | |
161 PreferenceValidationDelegateValues, | |
162 // On Android, make_tuple(..., "null") doesn't compile due to the error: | |
163 // testing/gtest/include/gtest/internal/gtest-tuple.h:246:48: | |
164 // error: array used as initializer | |
165 testing::Values( | |
166 std::tr1::make_tuple(base::Value::TYPE_NULL, | |
167 const_cast<char*>("null")), | |
168 std::tr1::make_tuple(base::Value::TYPE_BOOLEAN, | |
169 const_cast<char*>("false")), | |
170 std::tr1::make_tuple(base::Value::TYPE_INTEGER, | |
171 const_cast<char*>("47")), | |
172 std::tr1::make_tuple(base::Value::TYPE_DOUBLE, | |
173 const_cast<char*>("0.47")), | |
174 std::tr1::make_tuple(base::Value::TYPE_STRING, | |
175 const_cast<char*>("i have a spleen")), | |
176 std::tr1::make_tuple(base::Value::TYPE_DICTIONARY, | |
177 const_cast<char*>("{\"forty-seven\":47,\"twenty-two\":22}")), | |
178 std::tr1::make_tuple(base::Value::TYPE_LIST, | |
179 const_cast<char*>("[22,47]")))); | |
180 | |
181 // Tests that no incidents are reported for relevant combinations of ValueState. | |
182 class PreferenceValidationDelegateNoIncident | |
183 : public PreferenceValidationDelegateTest, | |
184 public testing::WithParamInterface<PrefHashStoreTransaction::ValueState> { | |
185 protected: | |
186 virtual void SetUp() OVERRIDE { | |
187 PreferenceValidationDelegateTest::SetUp(); | |
188 value_state_ = GetParam(); | |
189 } | |
190 | |
191 PrefHashStoreTransaction::ValueState value_state_; | |
192 }; | |
193 | |
194 TEST_P(PreferenceValidationDelegateNoIncident, Atomic) { | |
195 instance_->OnAtomicPreferenceValidation(kPrefPath_, | |
196 null_value_.get(), | |
197 value_state_, | |
198 TrackedPreferenceHelper::DONT_RESET); | |
199 EXPECT_EQ(0U, incidents_.size()); | |
200 } | |
201 | |
202 TEST_P(PreferenceValidationDelegateNoIncident, Split) { | |
203 instance_->OnSplitPreferenceValidation(kPrefPath_, | |
204 &dict_value_, | |
205 invalid_keys_, | |
206 value_state_, | |
207 TrackedPreferenceHelper::DONT_RESET); | |
208 EXPECT_EQ(0U, incidents_.size()); | |
209 } | |
210 | |
211 INSTANTIATE_TEST_CASE_P( | |
212 NoIncident, | |
213 PreferenceValidationDelegateNoIncident, | |
214 testing::Values(PrefHashStoreTransaction::UNCHANGED, | |
215 PrefHashStoreTransaction::SECURE_LEGACY, | |
216 PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE)); | |
217 | |
218 // Tests that incidents are reported for relevant combinations of ValueState and | |
219 // ResetAction. | |
220 class PreferenceValidationDelegateWithIncident | |
221 : public PreferenceValidationDelegateTest, | |
222 public testing::WithParamInterface< | |
223 std::tr1::tuple<PrefHashStoreTransaction::ValueState, | |
224 TrackedPreferenceHelper::ResetAction> > { | |
225 protected: | |
226 virtual void SetUp() OVERRIDE { | |
227 PreferenceValidationDelegateTest::SetUp(); | |
228 value_state_ = std::tr1::get<0>(GetParam()); | |
229 reset_action_ = std::tr1::get<1>(GetParam()); | |
230 } | |
231 | |
232 PrefHashStoreTransaction::ValueState value_state_; | |
233 TrackedPreferenceHelper::ResetAction reset_action_; | |
234 }; | |
235 | |
236 TEST_P(PreferenceValidationDelegateWithIncident, Atomic) { | |
237 instance_->OnAtomicPreferenceValidation( | |
238 kPrefPath_, null_value_.get(), value_state_, reset_action_); | |
239 ASSERT_EQ(1U, incidents_.size()); | |
240 safe_browsing::ClientIncidentReport_IncidentData* incident = | |
241 incidents_.back(); | |
242 EXPECT_TRUE(incident->has_tracked_preference()); | |
243 const safe_browsing:: | |
244 ClientIncidentReport_IncidentData_TrackedPreferenceIncident& tp_incident = | |
245 incident->tracked_preference(); | |
246 EXPECT_EQ(kPrefPath_, tp_incident.path()); | |
247 EXPECT_EQ(0, tp_incident.split_key_size()); | |
248 EXPECT_TRUE(tp_incident.has_atomic_value()); | |
249 EXPECT_EQ(std::string("null"), tp_incident.atomic_value()); | |
250 EXPECT_TRUE(tp_incident.has_value_state()); | |
251 ExpectValueStatesEquate(value_state_, tp_incident.value_state()); | |
252 } | |
253 | |
254 TEST_P(PreferenceValidationDelegateWithIncident, Split) { | |
255 instance_->OnSplitPreferenceValidation( | |
256 kPrefPath_, &dict_value_, invalid_keys_, value_state_, reset_action_); | |
257 ASSERT_EQ(1U, incidents_.size()); | |
258 safe_browsing::ClientIncidentReport_IncidentData* incident = | |
259 incidents_.back(); | |
260 EXPECT_TRUE(incident->has_tracked_preference()); | |
261 const safe_browsing:: | |
262 ClientIncidentReport_IncidentData_TrackedPreferenceIncident& tp_incident = | |
263 incident->tracked_preference(); | |
264 EXPECT_EQ(kPrefPath_, tp_incident.path()); | |
265 EXPECT_FALSE(tp_incident.has_atomic_value()); | |
266 ExpectKeysEquate(invalid_keys_, tp_incident.split_key()); | |
267 EXPECT_TRUE(tp_incident.has_value_state()); | |
268 ExpectValueStatesEquate(value_state_, tp_incident.value_state()); | |
269 } | |
270 | |
271 INSTANTIATE_TEST_CASE_P( | |
272 WithIncident, | |
273 PreferenceValidationDelegateWithIncident, | |
274 testing::Combine( | |
275 testing::Values(PrefHashStoreTransaction::CLEARED, | |
276 PrefHashStoreTransaction::CHANGED, | |
277 PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE), | |
278 testing::Values(TrackedPreferenceHelper::WANTED_RESET, | |
279 TrackedPreferenceHelper::DO_RESET))); | |
OLD | NEW |