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.
5 #include "chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h"
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/browser/safe_browsing/incident_reporting/incident.h"
15 #include "chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h"
16 #include "chrome/common/safe_browsing/csd.pb.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
21 using ::testing::IsNull
;
22 using ::testing::NiceMock
;
23 using ::testing::WithArg
;
25 // A basic test harness that creates a delegate instance for which it stores all
26 // incidents. Tests can push data to the delegate and verify that the test
27 // instance was provided with the expected data.
28 class PreferenceValidationDelegateTest
: public testing::Test
{
30 typedef ScopedVector
<safe_browsing::Incident
> IncidentVector
;
32 PreferenceValidationDelegateTest()
33 : kPrefPath_("atomic.pref"),
34 null_value_(base::Value::CreateNullValue()) {}
36 void SetUp() override
{
37 testing::Test::SetUp();
38 invalid_keys_
.push_back(std::string("one"));
39 invalid_keys_
.push_back(std::string("two"));
40 scoped_ptr
<safe_browsing::MockIncidentReceiver
> receiver(
41 new NiceMock
<safe_browsing::MockIncidentReceiver
>());
42 ON_CALL(*receiver
, DoAddIncidentForProfile(IsNull(), _
))
43 .WillByDefault(WithArg
<1>(TakeIncidentToVector(&incidents_
)));
44 instance_
.reset(new safe_browsing::PreferenceValidationDelegate(
45 nullptr, receiver
.Pass()));
48 static void ExpectValueStatesEquate(
49 PrefHashStoreTransaction::ValueState store_state
,
51 ClientIncidentReport_IncidentData_TrackedPreferenceIncident_ValueState
53 typedef safe_browsing::
54 ClientIncidentReport_IncidentData_TrackedPreferenceIncident TPIncident
;
55 switch (store_state
) {
56 case PrefHashStoreTransaction::CLEARED
:
57 EXPECT_EQ(TPIncident::CLEARED
, incident_state
);
59 case PrefHashStoreTransaction::CHANGED
:
60 EXPECT_EQ(TPIncident::CHANGED
, incident_state
);
62 case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE
:
63 EXPECT_EQ(TPIncident::UNTRUSTED_UNKNOWN_VALUE
, incident_state
);
66 FAIL() << "unexpected store state";
71 static void ExpectKeysEquate(
72 const std::vector
<std::string
>& store_keys
,
73 const google::protobuf::RepeatedPtrField
<std::string
>& incident_keys
) {
74 ASSERT_EQ(store_keys
.size(), static_cast<size_t>(incident_keys
.size()));
75 for (int i
= 0; i
< incident_keys
.size(); ++i
) {
76 EXPECT_EQ(store_keys
[i
], incident_keys
.Get(i
));
80 const std::string kPrefPath_
;
81 IncidentVector incidents_
;
82 scoped_ptr
<base::Value
> null_value_
;
83 base::DictionaryValue dict_value_
;
84 std::vector
<std::string
> invalid_keys_
;
85 scoped_ptr
<TrackedPreferenceValidationDelegate
> instance_
;
88 // Tests that a NULL value results in an incident with no value.
89 TEST_F(PreferenceValidationDelegateTest
, NullValue
) {
90 instance_
->OnAtomicPreferenceValidation(kPrefPath_
,
92 PrefHashStoreTransaction::CLEARED
,
93 false /* is_personal */);
94 scoped_ptr
<safe_browsing::ClientIncidentReport_IncidentData
> incident(
95 incidents_
.back()->TakePayload());
96 EXPECT_FALSE(incident
->tracked_preference().has_atomic_value());
99 ClientIncidentReport_IncidentData_TrackedPreferenceIncident::CLEARED
,
100 incident
->tracked_preference().value_state());
103 // Tests that all supported value types can be stringified into an incident. The
104 // parameters for the test are the type of value to test and the expected value
106 class PreferenceValidationDelegateValues
107 : public PreferenceValidationDelegateTest
,
108 public testing::WithParamInterface
<
109 std::tr1::tuple
<base::Value::Type
, const char*> > {
111 void SetUp() override
{
112 PreferenceValidationDelegateTest::SetUp();
113 value_type_
= std::tr1::get
<0>(GetParam());
114 expected_value_
= std::tr1::get
<1>(GetParam());
117 static scoped_ptr
<base::Value
> MakeValue(base::Value::Type value_type
) {
119 switch (value_type
) {
120 case Value::TYPE_NULL
:
121 return Value::CreateNullValue();
122 case Value::TYPE_BOOLEAN
:
123 return scoped_ptr
<Value
>(new base::FundamentalValue(false));
124 case Value::TYPE_INTEGER
:
125 return scoped_ptr
<Value
>(new base::FundamentalValue(47));
126 case Value::TYPE_DOUBLE
:
127 return scoped_ptr
<Value
>(new base::FundamentalValue(0.47));
128 case Value::TYPE_STRING
:
129 return scoped_ptr
<Value
>(new base::StringValue("i have a spleen"));
130 case Value::TYPE_DICTIONARY
: {
131 scoped_ptr
<base::DictionaryValue
> value(new base::DictionaryValue());
132 value
->SetInteger("twenty-two", 22);
133 value
->SetInteger("forty-seven", 47);
136 case Value::TYPE_LIST
: {
137 scoped_ptr
<base::ListValue
> value(new base::ListValue());
138 value
->AppendInteger(22);
139 value
->AppendInteger(47);
143 ADD_FAILURE() << "unsupported value type " << value_type
;
145 return scoped_ptr
<Value
>();
148 base::Value::Type value_type_
;
149 const char* expected_value_
;
152 TEST_P(PreferenceValidationDelegateValues
, Value
) {
153 instance_
->OnAtomicPreferenceValidation(kPrefPath_
,
154 MakeValue(value_type_
).get(),
155 PrefHashStoreTransaction::CLEARED
,
156 false /* is_personal */);
157 ASSERT_EQ(1U, incidents_
.size());
158 scoped_ptr
<safe_browsing::ClientIncidentReport_IncidentData
> incident(
159 incidents_
.back()->TakePayload());
160 EXPECT_EQ(std::string(expected_value_
),
161 incident
->tracked_preference().atomic_value());
164 INSTANTIATE_TEST_CASE_P(
166 PreferenceValidationDelegateValues
,
167 // On Android, make_tuple(..., "null") doesn't compile due to the error:
168 // testing/gtest/include/gtest/internal/gtest-tuple.h:246:48:
169 // error: array used as initializer
171 std::tr1::make_tuple(base::Value::TYPE_NULL
,
172 const_cast<char*>("null")),
173 std::tr1::make_tuple(base::Value::TYPE_BOOLEAN
,
174 const_cast<char*>("false")),
175 std::tr1::make_tuple(base::Value::TYPE_INTEGER
,
176 const_cast<char*>("47")),
177 std::tr1::make_tuple(base::Value::TYPE_DOUBLE
,
178 const_cast<char*>("0.47")),
179 std::tr1::make_tuple(base::Value::TYPE_STRING
,
180 const_cast<char*>("i have a spleen")),
181 std::tr1::make_tuple(base::Value::TYPE_DICTIONARY
,
182 const_cast<char*>("{\"forty-seven\":47,\"twenty-two\":22}")),
183 std::tr1::make_tuple(base::Value::TYPE_LIST
,
184 const_cast<char*>("[22,47]"))));
186 // Tests that no incidents are reported for relevant combinations of ValueState.
187 class PreferenceValidationDelegateNoIncident
188 : public PreferenceValidationDelegateTest
,
189 public testing::WithParamInterface
<PrefHashStoreTransaction::ValueState
> {
191 void SetUp() override
{
192 PreferenceValidationDelegateTest::SetUp();
193 value_state_
= GetParam();
196 PrefHashStoreTransaction::ValueState value_state_
;
199 TEST_P(PreferenceValidationDelegateNoIncident
, Atomic
) {
200 instance_
->OnAtomicPreferenceValidation(kPrefPath_
,
203 false /* is_personal */);
204 EXPECT_EQ(0U, incidents_
.size());
207 TEST_P(PreferenceValidationDelegateNoIncident
, Split
) {
208 instance_
->OnSplitPreferenceValidation(kPrefPath_
,
212 false /* is_personal */);
213 EXPECT_EQ(0U, incidents_
.size());
216 INSTANTIATE_TEST_CASE_P(
218 PreferenceValidationDelegateNoIncident
,
219 testing::Values(PrefHashStoreTransaction::UNCHANGED
,
220 PrefHashStoreTransaction::SECURE_LEGACY
,
221 PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE
));
223 // Tests that incidents are reported for relevant combinations of ValueState and
224 // impersonal/personal.
225 class PreferenceValidationDelegateWithIncident
226 : public PreferenceValidationDelegateTest
,
227 public testing::WithParamInterface
<
228 std::tr1::tuple
<PrefHashStoreTransaction::ValueState
, bool>> {
230 void SetUp() override
{
231 PreferenceValidationDelegateTest::SetUp();
232 value_state_
= std::tr1::get
<0>(GetParam());
233 is_personal_
= std::tr1::get
<1>(GetParam());
236 PrefHashStoreTransaction::ValueState value_state_
;
240 TEST_P(PreferenceValidationDelegateWithIncident
, Atomic
) {
241 instance_
->OnAtomicPreferenceValidation(
242 kPrefPath_
, null_value_
.get(), value_state_
, is_personal_
);
243 ASSERT_EQ(1U, incidents_
.size());
244 scoped_ptr
<safe_browsing::ClientIncidentReport_IncidentData
> incident(
245 incidents_
.back()->TakePayload());
246 EXPECT_TRUE(incident
->has_tracked_preference());
247 const safe_browsing::
248 ClientIncidentReport_IncidentData_TrackedPreferenceIncident
& tp_incident
=
249 incident
->tracked_preference();
250 EXPECT_EQ(kPrefPath_
, tp_incident
.path());
251 EXPECT_EQ(0, tp_incident
.split_key_size());
253 EXPECT_TRUE(tp_incident
.has_atomic_value());
254 EXPECT_EQ(std::string("null"), tp_incident
.atomic_value());
256 EXPECT_FALSE(tp_incident
.has_atomic_value());
258 EXPECT_TRUE(tp_incident
.has_value_state());
259 ExpectValueStatesEquate(value_state_
, tp_incident
.value_state());
262 TEST_P(PreferenceValidationDelegateWithIncident
, Split
) {
263 instance_
->OnSplitPreferenceValidation(
264 kPrefPath_
, &dict_value_
, invalid_keys_
, value_state_
, is_personal_
);
265 ASSERT_EQ(1U, incidents_
.size());
266 scoped_ptr
<safe_browsing::ClientIncidentReport_IncidentData
> incident(
267 incidents_
.back()->TakePayload());
268 EXPECT_TRUE(incident
->has_tracked_preference());
269 const safe_browsing::
270 ClientIncidentReport_IncidentData_TrackedPreferenceIncident
& tp_incident
=
271 incident
->tracked_preference();
272 EXPECT_EQ(kPrefPath_
, tp_incident
.path());
273 EXPECT_FALSE(tp_incident
.has_atomic_value());
275 ExpectKeysEquate(invalid_keys_
, tp_incident
.split_key());
277 EXPECT_EQ(0, tp_incident
.split_key_size());
278 EXPECT_TRUE(tp_incident
.has_value_state());
279 ExpectValueStatesEquate(value_state_
, tp_incident
.value_state());
282 INSTANTIATE_TEST_CASE_P(
284 PreferenceValidationDelegateWithIncident
,
286 testing::Values(PrefHashStoreTransaction::CLEARED
,
287 PrefHashStoreTransaction::CHANGED
,
288 PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE
),