Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc

Issue 11572061: Create DeclarativeConditionSet, DeclarativeActionSet, and DeclarativeRule templates (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix kalman's nit Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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/extensions/api/declarative/declarative_rule.h"
6
7 #include "base/message_loop.h"
8 #include "base/test/values_test_util.h"
9 #include "base/values.h"
10 #include "chrome/common/extensions/matcher/url_matcher_constants.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace extensions {
15
16 using json_schema_compiler::any::Any;
17 using base::test::ParseJson;
18
19 struct RecordingCondition {
20 typedef int MatchData;
21
22 URLMatcherConditionFactory* factory;
23 scoped_ptr<base::Value> value;
24
25 void GetURLMatcherConditionSets(
26 URLMatcherConditionSet::Vector* condition_sets) const {
27 // No condition sets.
28 }
29
30 bool has_url_matcher_condition_set() const {
31 return false;
32 }
33
34 static scoped_ptr<RecordingCondition> Create(
35 URLMatcherConditionFactory* url_matcher_condition_factory,
36 const base::Value& condition,
37 std::string* error) {
38 const base::DictionaryValue* dict = NULL;
39 if (condition.GetAsDictionary(&dict) && dict->HasKey("bad_key")) {
40 *error = "Found error key";
41 return scoped_ptr<RecordingCondition>();
42 }
43
44 scoped_ptr<RecordingCondition> result(new RecordingCondition());
45 result->factory = url_matcher_condition_factory;
46 result->value.reset(condition.DeepCopy());
47 return result.Pass();
48 }
49 };
50 typedef DeclarativeConditionSet<RecordingCondition> RecordingConditionSet;
51
52 TEST(DeclarativeConditionTest, ErrorConditionSet) {
53 URLMatcher matcher;
54 RecordingConditionSet::AnyVector conditions;
55 conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"key\": 1}"))));
56 conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"bad_key\": 2}"))));
57
58 std::string error;
59 scoped_ptr<RecordingConditionSet> result =
60 RecordingConditionSet::Create(matcher.condition_factory(),
61 conditions, &error);
62 EXPECT_EQ("Found error key", error);
63 ASSERT_FALSE(result);
64 }
65
66 TEST(DeclarativeConditionTest, CreateConditionSet) {
67 URLMatcher matcher;
68 RecordingConditionSet::AnyVector conditions;
69 conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"key\": 1}"))));
70 conditions.push_back(make_linked_ptr(new Any(ParseJson("[\"val1\", 2]"))));
71
72 // Test insertion
73 std::string error;
74 scoped_ptr<RecordingConditionSet> result =
75 RecordingConditionSet::Create(matcher.condition_factory(),
76 conditions, &error);
77 EXPECT_EQ("", error);
78 ASSERT_TRUE(result);
79 EXPECT_EQ(2u, result->conditions().size());
80
81 EXPECT_EQ(matcher.condition_factory(), result->conditions()[0]->factory);
82 EXPECT_TRUE(ParseJson("{\"key\": 1}")->Equals(
83 result->conditions()[0]->value.get()));
84 }
85
86 struct FulfillableCondition {
87 typedef int MatchData;
88
89 scoped_refptr<URLMatcherConditionSet> condition_set;
90 int condition_set_id;
91 int max_value;
92
93 URLMatcherConditionSet::ID url_matcher_condition_set_id() const {
94 return condition_set_id;
95 }
96
97 bool has_url_matcher_condition_set() const {
98 return true;
99 }
100
101 scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set() const {
102 return condition_set;
103 }
104
105 void GetURLMatcherConditionSets(
106 URLMatcherConditionSet::Vector* condition_sets) const {
107 if (condition_set)
108 condition_sets->push_back(condition_set);
109 }
110
111 bool IsFulfilled(const std::set<URLMatcherConditionSet::ID>& url_matches,
112 int match_data) const {
113 if (condition_set_id != -1 && !ContainsKey(url_matches, condition_set_id))
114 return false;
115 return match_data <= max_value;
116 }
117
118 static scoped_ptr<FulfillableCondition> Create(
119 URLMatcherConditionFactory* url_matcher_condition_factory,
120 const base::Value& condition,
121 std::string* error) {
122 scoped_ptr<FulfillableCondition> result(new FulfillableCondition());
123 const base::DictionaryValue* dict;
124 if (!condition.GetAsDictionary(&dict)) {
125 *error = "Expected dict";
126 return result.Pass();
127 }
128 if (!dict->GetInteger("url_id", &result->condition_set_id))
129 result->condition_set_id = -1;
130 if (!dict->GetInteger("max", &result->max_value))
131 *error = "Expected integer at ['max']";
132 if (result->condition_set_id != -1) {
133 result->condition_set = new URLMatcherConditionSet(
134 result->condition_set_id,
135 URLMatcherConditionSet::Conditions());
136 }
137 return result.Pass();
138 }
139 };
140
141 TEST(DeclarativeConditionTest, FulfillConditionSet) {
142 typedef DeclarativeConditionSet<FulfillableCondition> FulfillableConditionSet;
143 FulfillableConditionSet::AnyVector conditions;
144 conditions.push_back(make_linked_ptr(new Any(ParseJson(
145 "{\"url_id\": 1, \"max\": 3}"))));
146 conditions.push_back(make_linked_ptr(new Any(ParseJson(
147 "{\"url_id\": 2, \"max\": 5}"))));
148 conditions.push_back(make_linked_ptr(new Any(ParseJson(
149 "{\"url_id\": 3, \"max\": 1}"))));
150 conditions.push_back(make_linked_ptr(new Any(ParseJson(
151 "{\"max\": -5}")))); // No url.
152
153 // Test insertion
154 std::string error;
155 scoped_ptr<FulfillableConditionSet> result =
156 FulfillableConditionSet::Create(NULL, conditions, &error);
157 ASSERT_EQ("", error);
158 ASSERT_TRUE(result);
159 EXPECT_EQ(4u, result->conditions().size());
160
161 std::set<URLMatcherConditionSet::ID> url_matches;
162 EXPECT_FALSE(result->IsFulfilled(1, url_matches, 0))
163 << "Testing an ID that's not in url_matches forwards to the Condition, "
164 << "which doesn't match.";
165 EXPECT_FALSE(result->IsFulfilled(-1, url_matches, 0))
166 << "Testing the 'no ID' value tries to match the 4th condition, but "
167 << "its max is too low.";
168 EXPECT_TRUE(result->IsFulfilled(-1, url_matches, -5))
169 << "Testing the 'no ID' value tries to match the 4th condition, and "
170 << "this value is low enough.";
171
172 url_matches.insert(1);
173 EXPECT_TRUE(result->IsFulfilled(1, url_matches, 3))
174 << "Tests a condition with a url matcher, for a matching value.";
175 EXPECT_FALSE(result->IsFulfilled(1, url_matches, 4))
176 << "Tests a condition with a url matcher, for a non-matching value "
177 << "that would match a different condition.";
178 url_matches.insert(2);
179 EXPECT_TRUE(result->IsFulfilled(2, url_matches, 4))
180 << "Tests with 2 elements in the match set.";
181
182 // Check the condition sets:
183 URLMatcherConditionSet::Vector condition_sets;
184 result->GetURLMatcherConditionSets(&condition_sets);
185 ASSERT_EQ(3U, condition_sets.size());
186 EXPECT_EQ(1, condition_sets[0]->id());
187 EXPECT_EQ(2, condition_sets[1]->id());
188 EXPECT_EQ(3, condition_sets[2]->id());
189 }
190
191 // DeclarativeAction
192
193 struct SummingAction {
194 typedef int ApplyInfo;
195
196 int increment;
197 int min_priority;
198
199 static scoped_ptr<SummingAction> Create(const base::Value& action,
200 std::string* error,
201 bool* bad_message) {
202 scoped_ptr<SummingAction> result(new SummingAction());
203 const base::DictionaryValue* dict = NULL;
204 EXPECT_TRUE(action.GetAsDictionary(&dict));
205 if (dict->HasKey("error")) {
206 EXPECT_TRUE(dict->GetString("error", error));
207 return result.Pass();
208 }
209 if (dict->HasKey("bad")) {
210 *bad_message = true;
211 return result.Pass();
212 }
213
214 EXPECT_TRUE(dict->GetInteger("value", &result->increment));
215 dict->GetInteger("priority", &result->min_priority);
216 return result.Pass();
217 }
218
219 void Apply(const std::string& extension_id,
220 const base::Time& install_time,
221 int* sum) const {
222 *sum += increment;
223 }
224
225 int GetMinimumPriority() const {
226 return min_priority;
227 }
228 };
229 typedef DeclarativeActionSet<SummingAction> SummingActionSet;
230
231 TEST(DeclarativeActionTest, ErrorActionSet) {
232 SummingActionSet::AnyVector actions;
233 actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 1}"))));
234 actions.push_back(make_linked_ptr(new Any(ParseJson(
235 "{\"error\": \"the error\"}"))));
236
237 std::string error;
238 bool bad = false;
239 scoped_ptr<SummingActionSet> result =
240 SummingActionSet::Create(actions, &error, &bad);
241 EXPECT_EQ("the error", error);
242 EXPECT_FALSE(bad);
243 EXPECT_FALSE(result);
244
245 actions.clear();
246 actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 1}"))));
247 actions.push_back(make_linked_ptr(new Any(ParseJson("{\"bad\": 3}"))));
248 result = SummingActionSet::Create(actions, &error, &bad);
249 EXPECT_EQ("", error);
250 EXPECT_TRUE(bad);
251 EXPECT_FALSE(result);
252 }
253
254 TEST(DeclarativeActionTest, ApplyActionSet) {
255 SummingActionSet::AnyVector actions;
256 actions.push_back(make_linked_ptr(new Any(ParseJson(
257 "{\"value\": 1,"
258 " \"priority\": 5}"))));
259 actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 2}"))));
260
261 // Test insertion
262 std::string error;
263 bool bad = false;
264 scoped_ptr<SummingActionSet> result =
265 SummingActionSet::Create(actions, &error, &bad);
266 EXPECT_EQ("", error);
267 EXPECT_FALSE(bad);
268 ASSERT_TRUE(result);
269 EXPECT_EQ(2u, result->actions().size());
270
271 int sum = 0;
272 result->Apply("ext_id", base::Time(), &sum);
273 EXPECT_EQ(3, sum);
274 EXPECT_EQ(5, result->GetMinimumPriority());
275 }
276
277 TEST(DeclarativeRuleTest, Create) {
278 typedef DeclarativeRule<FulfillableCondition, SummingAction> Rule;
279 linked_ptr<Rule::JsonRule> json_rule(new Rule::JsonRule);
280 ASSERT_TRUE(Rule::JsonRule::Populate(
281 *ParseJson("{ \n"
282 " \"id\": \"rule1\", \n"
283 " \"conditions\": [ \n"
284 " {\"url_id\": 1, \"max\": 3}, \n"
285 " {\"url_id\": 2, \"max\": 5}, \n"
286 " ], \n"
287 " \"actions\": [ \n"
288 " { \n"
289 " \"value\": 2 \n"
290 " } \n"
291 " ], \n"
292 " \"priority\": 200 \n"
293 "}"),
294 json_rule.get()));
295
296 const char kExtensionId[] = "ext1";
297
298 base::Time install_time = base::Time::Now();
299
300 URLMatcher matcher;
301 std::string error;
302 scoped_ptr<Rule> rule(Rule::Create(matcher.condition_factory(), kExtensionId,
303 install_time, json_rule, NULL, &error));
304 EXPECT_EQ("", error);
305 ASSERT_TRUE(rule.get());
306
307 EXPECT_EQ(kExtensionId, rule->id().first);
308 EXPECT_EQ("rule1", rule->id().second);
309
310 EXPECT_EQ(200, rule->priority());
311
312 const Rule::ConditionSet& condition_set = rule->conditions();
313 const Rule::ConditionSet::Conditions& conditions =
314 condition_set.conditions();
315 ASSERT_EQ(2u, conditions.size());
316 EXPECT_EQ(3, conditions[0]->max_value);
317 EXPECT_EQ(5, conditions[1]->max_value);
318
319 const Rule::ActionSet& action_set = rule->actions();
320 const Rule::ActionSet::Actions& actions = action_set.actions();
321 ASSERT_EQ(1u, actions.size());
322 EXPECT_EQ(2, actions[0]->increment);
323
324 int sum = 0;
325 rule->Apply(&sum);
326 EXPECT_EQ(2, sum);
327 }
328
329 bool AtLeastOneCondition(
330 const DeclarativeConditionSet<FulfillableCondition>* conditions,
331 const DeclarativeActionSet<SummingAction>* actions,
332 std::string* error) {
333 if (conditions->conditions().empty()) {
334 *error = "No conditions";
335 return false;
336 }
337 return true;
338 }
339
340 TEST(DeclarativeRuleTest, CheckConsistency) {
341 typedef DeclarativeRule<FulfillableCondition, SummingAction> Rule;
342 URLMatcher matcher;
343 std::string error;
344 linked_ptr<Rule::JsonRule> json_rule(new Rule::JsonRule);
345 const char kExtensionId[] = "ext1";
346
347 ASSERT_TRUE(Rule::JsonRule::Populate(
348 *ParseJson("{ \n"
349 " \"id\": \"rule1\", \n"
350 " \"conditions\": [ \n"
351 " {\"url_id\": 1, \"max\": 3}, \n"
352 " {\"url_id\": 2, \"max\": 5}, \n"
353 " ], \n"
354 " \"actions\": [ \n"
355 " { \n"
356 " \"value\": 2 \n"
357 " } \n"
358 " ], \n"
359 " \"priority\": 200 \n"
360 "}"),
361 json_rule.get()));
362 scoped_ptr<Rule> rule(
363 Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(),
364 json_rule, &AtLeastOneCondition, &error));
365 EXPECT_TRUE(rule);
366 EXPECT_EQ("", error);
367
368 ASSERT_TRUE(Rule::JsonRule::Populate(
369 *ParseJson("{ \n"
370 " \"id\": \"rule1\", \n"
371 " \"conditions\": [ \n"
372 " ], \n"
373 " \"actions\": [ \n"
374 " { \n"
375 " \"value\": 2 \n"
376 " } \n"
377 " ], \n"
378 " \"priority\": 200 \n"
379 "}"),
380 json_rule.get()));
381 rule = Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(),
382 json_rule, &AtLeastOneCondition, &error);
383 EXPECT_FALSE(rule);
384 EXPECT_EQ("No conditions", error);
385 }
386
387 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698