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

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 2 simple bugs 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;
battre 2013/01/16 15:41:10 nit: initialize with NULL?
Jeffrey Yasskin 2013/01/16 23:11:14 Sure, that might fix a problem with some gcc build
39 if (error_on_key &&
40 condition.GetAsDictionary(&dict) &&
41 dict->HasKey(error_on_key)) {
42 *error = "Found error key";
43 return scoped_ptr<RecordingCondition>();
44 }
45
46 scoped_ptr<RecordingCondition> result(new RecordingCondition());
47 result->factory = url_matcher_condition_factory;
48 result->value.reset(condition.DeepCopy());
49 return result.Pass();
50 }
51
52 static const char* error_on_key;
53 };
54 const char* RecordingCondition::error_on_key = NULL;
battre 2013/01/16 15:41:10 I think it might be nicer to have error_on_key a c
Jeffrey Yasskin 2013/01/16 23:11:14 Ok.
55 typedef DeclarativeConditionSet<RecordingCondition> RecordingConditionSet;
56
57 TEST(DeclarativeConditionTest, ErrorConditionSet) {
58 URLMatcher matcher;
59 RecordingConditionSet::AnyVector conditions;
60 conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"key\": 1}"))));
61 conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"bad_key\": 2}"))));
62 RecordingCondition::error_on_key = "bad_key";
63
64 std::string error;
65 scoped_ptr<RecordingConditionSet> result =
66 RecordingConditionSet::Create(matcher.condition_factory(),
67 conditions, &error);
68 EXPECT_EQ("Found error key", error);
69 ASSERT_FALSE(result);
70 }
71
72 TEST(DeclarativeConditionTest, CreateConditionSet) {
73 URLMatcher matcher;
74 RecordingConditionSet::AnyVector conditions;
75 conditions.push_back(make_linked_ptr(new Any(ParseJson("{\"key\": 1}"))));
76 conditions.push_back(make_linked_ptr(new Any(ParseJson("[\"val1\", 2]"))));
77 RecordingCondition::error_on_key = NULL;
78
79 // Test insertion
80 std::string error;
81 scoped_ptr<RecordingConditionSet> result =
82 RecordingConditionSet::Create(matcher.condition_factory(),
83 conditions, &error);
84 EXPECT_EQ("", error);
85 ASSERT_TRUE(result);
86 EXPECT_EQ(2u, result->conditions().size());
87
88 EXPECT_EQ(matcher.condition_factory(), result->conditions()[0]->factory);
89 EXPECT_TRUE(ParseJson("{\"key\": 1}")->Equals(
90 result->conditions()[0]->value.get()));
91 }
92
93 struct FulfillableCondition {
94 typedef int MatchData;
95
96 scoped_refptr<URLMatcherConditionSet> condition_set;
97 int condition_set_id;
98 int max_value;
99
100 URLMatcherConditionSet::ID url_matcher_condition_set_id() const {
101 return condition_set_id;
102 }
103
104 bool has_url_matcher_condition_set() const {
105 return true;
106 }
107
108 scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set() const {
109 return condition_set;
110 }
111
112 void GetURLMatcherConditionSets(
113 URLMatcherConditionSet::Vector* condition_sets) const {
114 condition_sets->push_back(condition_set);
115 }
116
117 bool IsFulfilled(const std::set<URLMatcherConditionSet::ID>& url_matches,
118 int match_data) const {
battre 2013/01/16 15:41:10 nit/opt: replace int with MatchData?
Jeffrey Yasskin 2013/01/16 23:11:14 MatchData mostly exists to communicate with the te
119 return ContainsKey(url_matches, condition_set_id) &&
120 match_data <= max_value;
121 }
122
123 static scoped_ptr<FulfillableCondition> Create(
124 URLMatcherConditionFactory* url_matcher_condition_factory,
125 const base::Value& condition,
126 std::string* error) {
127 scoped_ptr<FulfillableCondition> result(new FulfillableCondition());
128 const base::DictionaryValue* dict;
129 if (!condition.GetAsDictionary(&dict)) {
130 *error = "Expected dict";
131 return result.Pass();
132 }
133 if (!dict->GetInteger("url_id", &result->condition_set_id))
134 *error = "Expected integer at ['url_id']";
135 if (!dict->GetInteger("max", &result->max_value))
136 *error = "Expected integer at ['max']";
137 result->condition_set = new URLMatcherConditionSet(
138 result->condition_set_id,
139 URLMatcherConditionSet::Conditions());
140 return result.Pass();
141 }
142 };
143
144 TEST(DeclarativeConditionTest, FulfilConditionSet) {
battre 2013/01/16 15:41:10 sp: Fulfill
Jeffrey Yasskin 2013/01/16 23:11:14 But http://en.wiktionary.org/wiki/fulfil. I guess
145 typedef DeclarativeConditionSet<FulfillableCondition> FulfillableConditionSet;
146 FulfillableConditionSet::AnyVector conditions;
147 conditions.push_back(make_linked_ptr(new Any(ParseJson(
148 "{\"url_id\": 1, \"max\": 3}"))));
149 conditions.push_back(make_linked_ptr(new Any(ParseJson(
150 "{\"url_id\": 2, \"max\": 5}"))));
151 conditions.push_back(make_linked_ptr(new Any(ParseJson(
152 "{\"url_id\": 3, \"max\": 1}"))));
153
154 // Test insertion
155 std::string error;
156 scoped_ptr<FulfillableConditionSet> result =
157 FulfillableConditionSet::Create(NULL, conditions, &error);
158 ASSERT_EQ("", error);
159 ASSERT_TRUE(result);
160 EXPECT_EQ(3u, result->conditions().size());
161
162 std::set<URLMatcherConditionSet::ID> url_matches;
163 url_matches.insert(1);
164 EXPECT_TRUE(result->IsFulfilled(1, url_matches, 3));
165 EXPECT_FALSE(result->IsFulfilled(2, url_matches, 3));
166 EXPECT_FALSE(result->IsFulfilled(1, url_matches, 4));
167 url_matches.insert(2);
168 EXPECT_TRUE(result->IsFulfilled(2, url_matches, 4));
169 url_matches.clear();
170 url_matches.insert(3);
171 EXPECT_FALSE(result->IsFulfilled(3, url_matches, 2));
battre 2013/01/16 15:41:10 does this test anything that is not tested in line
Jeffrey Yasskin 2013/01/16 23:11:14 I guess not.
172
173 // Check the condition sets:
174 URLMatcherConditionSet::Vector condition_sets;
175 result->GetURLMatcherConditionSets(&condition_sets);
176 ASSERT_EQ(3U, condition_sets.size());
177 EXPECT_EQ(1, condition_sets[0]->id());
178 EXPECT_EQ(2, condition_sets[1]->id());
179 EXPECT_EQ(3, condition_sets[2]->id());
180 }
181
182 // DeclarativeAction
183
184 struct SummingAction {
185 typedef int ApplyInfo;
186
187 int increment;
188 int min_priority;
189
190 static scoped_ptr<SummingAction> Create(const base::Value& action,
191 std::string* error,
192 bool* bad_message) {
193 scoped_ptr<SummingAction> result(new SummingAction());
194 const base::DictionaryValue* dict = NULL;
195 EXPECT_TRUE(action.GetAsDictionary(&dict));
196 if (dict->HasKey("error")) {
197 EXPECT_TRUE(dict->GetString("error", error));
198 return result.Pass();
199 }
200 if (dict->HasKey("bad")) {
201 *bad_message = true;
202 return result.Pass();
203 }
204
205 EXPECT_TRUE(dict->GetInteger("value", &result->increment));
206 dict->GetInteger("priority", &result->min_priority);
207 return result.Pass();
208 }
209
210 void Apply(const std::string& extension_id,
211 const base::Time& install_time,
212 int* sum) const {
battre 2013/01/16 15:41:10 nit: replace int with ApplyInfo?
Jeffrey Yasskin 2013/01/16 23:11:14 ApplyInfo mostly exists to communicate with the te
213 *sum += increment;
214 }
215
216 int GetMinimumPriority() const {
217 return min_priority;
218 }
219 };
220 typedef DeclarativeActionSet<SummingAction> SummingActionSet;
221
222 TEST(DeclarativeActionTest, ErrorActionSet) {
223 SummingActionSet::AnyVector actions;
224 actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 1}"))));
225 actions.push_back(make_linked_ptr(new Any(ParseJson(
226 "{\"error\": \"the error\"}"))));
227
228 std::string error;
229 bool bad = false;
230 scoped_ptr<SummingActionSet> result =
231 SummingActionSet::Create(actions, &error, &bad);
232 EXPECT_EQ("the error", error);
233 EXPECT_FALSE(bad);
234 EXPECT_FALSE(result);
235
236 actions.clear();
237 actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 1}"))));
238 actions.push_back(make_linked_ptr(new Any(ParseJson("{\"bad\": 3}"))));
239 result = SummingActionSet::Create(actions, &error, &bad);
240 EXPECT_EQ("", error);
241 EXPECT_TRUE(bad);
242 EXPECT_FALSE(result);
243 }
244
245 TEST(DeclarativeActionTest, ApplyActionSet) {
246 SummingActionSet::AnyVector actions;
247 actions.push_back(make_linked_ptr(new Any(ParseJson(
248 "{\"value\": 1,"
249 " \"priority\": 5}"))));
250 actions.push_back(make_linked_ptr(new Any(ParseJson("{\"value\": 2}"))));
251
252 // Test insertion
253 std::string error;
254 bool bad = false;
255 scoped_ptr<SummingActionSet> result =
256 SummingActionSet::Create(actions, &error, &bad);
257 EXPECT_EQ("", error);
258 EXPECT_FALSE(bad);
259 ASSERT_TRUE(result);
260 EXPECT_EQ(2u, result->actions().size());
261
262 int sum = 0;
263 result->Apply("ext_id", base::Time(), &sum);
264 EXPECT_EQ(3, sum);
265 EXPECT_EQ(5, result->GetMinimumPriority());
266 }
267
268 TEST(DeclarativeRuleTest, Create) {
269 typedef DeclarativeRule<FulfillableCondition, SummingAction> Rule;
270 linked_ptr<Rule::JsonRule> json_rule(new Rule::JsonRule);
271 ASSERT_TRUE(Rule::JsonRule::Populate(
272 *ParseJson("{ \n"
273 " \"id\": \"rule1\", \n"
274 " \"conditions\": [ \n"
275 " {\"url_id\": 1, \"max\": 3}, \n"
276 " {\"url_id\": 2, \"max\": 5}, \n"
277 " ], \n"
278 " \"actions\": [ \n"
279 " { \n"
280 " \"value\": 2 \n"
281 " } \n"
282 " ], \n"
283 " \"priority\": 200 \n"
284 "}"),
285 json_rule.get()));
286
287 const char kExtensionId[] = "ext1";
288
289 base::Time install_time = base::Time::Now();
290
291 URLMatcher matcher;
292 std::string error;
293 scoped_ptr<Rule> rule(Rule::Create(matcher.condition_factory(), kExtensionId,
294 install_time, json_rule, NULL, &error));
295 EXPECT_EQ("", error);
296 ASSERT_TRUE(rule.get());
297
298 EXPECT_EQ(kExtensionId, rule->id().first);
299 EXPECT_EQ("rule1", rule->id().second);
300
301 EXPECT_EQ(200, rule->priority());
302
303 const Rule::ConditionSet& condition_set = rule->conditions();
304 const Rule::ConditionSet::Conditions conditions =
battre 2013/01/16 15:41:10 nit: Conditions&
Jeffrey Yasskin 2013/01/16 23:11:14 Done.
305 condition_set.conditions();
306 ASSERT_EQ(2u, conditions.size());
307 EXPECT_EQ(3, conditions[0]->max_value);
308 EXPECT_EQ(5, conditions[1]->max_value);
309
310 const Rule::ActionSet& action_set = rule->actions();
311 const Rule::ActionSet::Actions& actions = action_set.actions();
312 ASSERT_EQ(1u, actions.size());
313 EXPECT_EQ(2, actions[0]->increment);
314
315 int sum = 0;
316 rule->Apply(&sum);
317 EXPECT_EQ(2, sum);
318 }
319
320 bool AtLeastOneConditionAndAction(
321 DeclarativeConditionSet<FulfillableCondition>* conditions,
322 DeclarativeActionSet<SummingAction>* actions,
323 std::string* error) {
324 if (conditions->conditions().size() < 1) {
battre 2013/01/16 15:41:10 nit: replace .size() < 1 with .empty()?
Jeffrey Yasskin 2013/01/16 23:11:14 Done.
325 *error = "No conditions";
326 return false;
327 }
328 if (actions->actions().size() < 1) {
battre 2013/01/16 15:41:10 dito
329 *error = "No actions";
battre 2013/01/16 15:41:10 this path is never exercised -> remove
Jeffrey Yasskin 2013/01/16 23:11:14 Done.
330 return false;
331 }
332 return true;
333 }
334
335 TEST(DeclarativeRuleTest, CheckConsistency) {
336 typedef DeclarativeRule<FulfillableCondition, SummingAction> Rule;
337 URLMatcher matcher;
338 std::string error;
339 linked_ptr<Rule::JsonRule> json_rule(new Rule::JsonRule);
340 const char kExtensionId[] = "ext1";
341
342 ASSERT_TRUE(Rule::JsonRule::Populate(
343 *ParseJson("{ \n"
344 " \"id\": \"rule1\", \n"
345 " \"conditions\": [ \n"
346 " {\"url_id\": 1, \"max\": 3}, \n"
347 " {\"url_id\": 2, \"max\": 5}, \n"
348 " ], \n"
349 " \"actions\": [ \n"
350 " { \n"
351 " \"value\": 2 \n"
352 " } \n"
353 " ], \n"
354 " \"priority\": 200 \n"
355 "}"),
356 json_rule.get()));
357 scoped_ptr<Rule> rule(
358 Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(),
359 json_rule, &AtLeastOneConditionAndAction, &error));
360 EXPECT_TRUE(rule);
361 EXPECT_EQ("", error);
362
363 ASSERT_TRUE(Rule::JsonRule::Populate(
364 *ParseJson("{ \n"
365 " \"id\": \"rule1\", \n"
366 " \"conditions\": [ \n"
367 " ], \n"
368 " \"actions\": [ \n"
369 " { \n"
370 " \"value\": 2 \n"
371 " } \n"
372 " ], \n"
373 " \"priority\": 200 \n"
374 "}"),
375 json_rule.get()));
376 rule = Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(),
377 json_rule, &AtLeastOneConditionAndAction, &error);
378 EXPECT_FALSE(rule);
379 EXPECT_EQ("No conditions", error);
380 }
381
382 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698