OLD | NEW |
| (Empty) |
1 // Copyright 2011 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/profile_resetter/jtl_interpreter.h" | |
6 | |
7 #include <numeric> | |
8 | |
9 #include "base/strings/string_util.h" | |
10 #include "base/test/values_test_util.h" | |
11 #include "chrome/browser/profile_resetter/jtl_foundation.h" | |
12 #include "chrome/browser/profile_resetter/jtl_instructions.h" | |
13 #include "crypto/hmac.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 | |
16 namespace { | |
17 | |
18 const char seed[] = "foobar"; | |
19 | |
20 #define KEY_HASH_1 GetHash("KEY_HASH_1") | |
21 #define KEY_HASH_2 GetHash("KEY_HASH_2") | |
22 #define KEY_HASH_3 GetHash("KEY_HASH_3") | |
23 #define KEY_HASH_4 GetHash("KEY_HASH_4") | |
24 | |
25 #define VALUE_HASH_1 GetHash("VALUE_HASH_1") | |
26 #define VALUE_HASH_2 GetHash("VALUE_HASH_2") | |
27 | |
28 #define VAR_HASH_1 "01234567890123456789012345678901" | |
29 #define VAR_HASH_2 "12345678901234567890123456789012" | |
30 | |
31 std::string GetHash(const std::string& input) { | |
32 return jtl_foundation::Hasher(seed).GetHash(input); | |
33 } | |
34 | |
35 std::string EncodeUint32(uint32 value) { | |
36 std::string bytecode; | |
37 for (int i = 0; i < 4; ++i) { | |
38 bytecode.push_back(static_cast<char>(value & 0xFFu)); | |
39 value >>= 8; | |
40 } | |
41 return bytecode; | |
42 } | |
43 | |
44 // escaped_json_param may contain ' characters that are replaced with ". This | |
45 // makes the code more readable because we need less escaping. | |
46 #define INIT_INTERPRETER(program_param, escaped_json_param) \ | |
47 const char* escaped_json = escaped_json_param; \ | |
48 std::string json; \ | |
49 base::ReplaceChars(escaped_json, "'", "\"", &json); \ | |
50 scoped_ptr<base::Value> json_value(ParseJson(json)); \ | |
51 JtlInterpreter interpreter( \ | |
52 seed, \ | |
53 program_param, \ | |
54 static_cast<const base::DictionaryValue*>(json_value.get())); \ | |
55 interpreter.Execute() | |
56 | |
57 using base::test::ParseJson; | |
58 | |
59 TEST(JtlInterpreter, Store) { | |
60 INIT_INTERPRETER( | |
61 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
62 "{ 'KEY_HASH_1': 'VALUE_HASH_1' }"); | |
63 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
64 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
65 } | |
66 | |
67 TEST(JtlInterpreter, NavigateAndStore) { | |
68 INIT_INTERPRETER( | |
69 OP_NAVIGATE(KEY_HASH_1) + | |
70 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
71 "{ 'KEY_HASH_1': 'VALUE_HASH_1' }"); | |
72 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
73 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
74 } | |
75 | |
76 TEST(JtlInterpreter, FailNavigate) { | |
77 INIT_INTERPRETER( | |
78 OP_NAVIGATE(KEY_HASH_2) + | |
79 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
80 "{ 'KEY_HASH_1': 'VALUE_HASH_1' }"); | |
81 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
82 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
83 } | |
84 | |
85 TEST(JtlInterpreter, ConsecutiveNavigate) { | |
86 INIT_INTERPRETER( | |
87 OP_NAVIGATE(KEY_HASH_1) + | |
88 OP_NAVIGATE(KEY_HASH_2) + | |
89 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
90 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
91 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
92 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
93 } | |
94 | |
95 TEST(JtlInterpreter, FailConsecutiveNavigate) { | |
96 INIT_INTERPRETER( | |
97 OP_NAVIGATE(KEY_HASH_1) + | |
98 OP_NAVIGATE(KEY_HASH_2) + | |
99 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
100 "{ 'KEY_HASH_1': 'foo' }"); | |
101 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
102 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
103 } | |
104 | |
105 TEST(JtlInterpreter, NavigateAnyInDictionary) { | |
106 INIT_INTERPRETER( | |
107 OP_NAVIGATE(KEY_HASH_1) + | |
108 OP_NAVIGATE_ANY + | |
109 OP_NAVIGATE(KEY_HASH_4) + | |
110 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
111 "{ 'KEY_HASH_1':" | |
112 " { 'KEY_HASH_2': {'KEY_HASH_3': 'VALUE_HASH_1' }," | |
113 " 'KEY_HASH_3': {'KEY_HASH_4': 'VALUE_HASH_1' }" | |
114 " } }"); | |
115 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
116 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
117 } | |
118 | |
119 TEST(JtlInterpreter, NavigateAnyInList) { | |
120 INIT_INTERPRETER( | |
121 OP_NAVIGATE(KEY_HASH_1) + | |
122 OP_NAVIGATE_ANY + | |
123 OP_NAVIGATE(KEY_HASH_4) + | |
124 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
125 "{ 'KEY_HASH_1':" | |
126 " [ {'KEY_HASH_3': 'VALUE_HASH_1' }," | |
127 " {'KEY_HASH_4': 'VALUE_HASH_1' }" | |
128 " ] }"); | |
129 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
130 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
131 } | |
132 | |
133 TEST(JtlInterpreter, NavigateBack) { | |
134 INIT_INTERPRETER( | |
135 OP_NAVIGATE(KEY_HASH_1) + | |
136 OP_NAVIGATE(KEY_HASH_2) + | |
137 OP_NAVIGATE_BACK + | |
138 OP_NAVIGATE(KEY_HASH_3) + | |
139 OP_NAVIGATE(KEY_HASH_4) + | |
140 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
141 "{ 'KEY_HASH_1':" | |
142 " { 'KEY_HASH_2': {'KEY_HASH_3': 'VALUE_HASH_1' }," | |
143 " 'KEY_HASH_3': {'KEY_HASH_4': 'VALUE_HASH_1' }" | |
144 " } }"); | |
145 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
146 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
147 } | |
148 | |
149 TEST(JtlInterpreter, StoreTwoValues) { | |
150 INIT_INTERPRETER( | |
151 OP_NAVIGATE(KEY_HASH_1) + | |
152 OP_NAVIGATE(KEY_HASH_2) + | |
153 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE) + | |
154 OP_STORE_HASH(VAR_HASH_2, VALUE_HASH_1), | |
155 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
156 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
157 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
158 base::ExpectDictStringValue(VALUE_HASH_1, *interpreter.working_memory(), | |
159 VAR_HASH_2); | |
160 } | |
161 | |
162 TEST(JtlInterpreter, CompareStoredMatch) { | |
163 INIT_INTERPRETER( | |
164 OP_NAVIGATE(KEY_HASH_1) + | |
165 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE) + | |
166 OP_NAVIGATE(KEY_HASH_2) + | |
167 OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, VALUE_FALSE) + | |
168 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
169 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
170 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
171 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
172 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_2); | |
173 } | |
174 | |
175 TEST(JtlInterpreter, CompareStoredMismatch) { | |
176 INIT_INTERPRETER( | |
177 OP_NAVIGATE(KEY_HASH_1) + | |
178 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE) + | |
179 OP_NAVIGATE(KEY_HASH_2) + | |
180 OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_FALSE, VALUE_TRUE) + | |
181 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
182 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
183 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
184 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
185 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2)); | |
186 } | |
187 | |
188 TEST(JtlInterpreter, CompareStoredNoValueMatchingDefault) { | |
189 INIT_INTERPRETER( | |
190 OP_NAVIGATE(KEY_HASH_1) + | |
191 OP_NAVIGATE(KEY_HASH_2) + | |
192 OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, VALUE_TRUE) + | |
193 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
194 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
195 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
196 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_2); | |
197 } | |
198 | |
199 TEST(JtlInterpreter, CompareStoredNoValueMismatchingDefault) { | |
200 INIT_INTERPRETER( | |
201 OP_NAVIGATE(KEY_HASH_1) + | |
202 OP_NAVIGATE(KEY_HASH_2) + | |
203 OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, VALUE_FALSE) + | |
204 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
205 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
206 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
207 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2)); | |
208 } | |
209 | |
210 TEST(JtlInterpreter, CompareBool) { | |
211 struct TestCase { | |
212 std::string expected_value; | |
213 const char* json; | |
214 bool expected_success; | |
215 } cases[] = { | |
216 { VALUE_TRUE, "{ 'KEY_HASH_1': true }", true }, | |
217 { VALUE_FALSE, "{ 'KEY_HASH_1': false }", true }, | |
218 { VALUE_TRUE, "{ 'KEY_HASH_1': false }", false }, | |
219 { VALUE_TRUE, "{ 'KEY_HASH_1': 'abc' }", false }, | |
220 { VALUE_TRUE, "{ 'KEY_HASH_1': 1 }", false }, | |
221 { VALUE_TRUE, "{ 'KEY_HASH_1': 1.2 }", false }, | |
222 { VALUE_TRUE, "{ 'KEY_HASH_1': [1] }", false }, | |
223 { VALUE_TRUE, "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
224 }; | |
225 | |
226 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
227 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
228 INIT_INTERPRETER( | |
229 OP_NAVIGATE(KEY_HASH_1) + | |
230 OP_COMPARE_NODE_BOOL(cases[i].expected_value) + | |
231 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
232 cases[i].json); | |
233 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
234 if (cases[i].expected_success) { | |
235 base::ExpectDictBooleanValue( | |
236 true, *interpreter.working_memory(), VAR_HASH_1); | |
237 } else { | |
238 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
239 } | |
240 } | |
241 } | |
242 | |
243 TEST(JtlInterpreter, CompareHashString) { | |
244 struct TestCase { | |
245 std::string expected_value; | |
246 const char* json; | |
247 bool expected_success; | |
248 } cases[] = { | |
249 { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", true }, | |
250 { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", false }, | |
251 { VALUE_HASH_1, "{ 'KEY_HASH_1': true }", false }, | |
252 { VALUE_HASH_1, "{ 'KEY_HASH_1': 1 }", false }, | |
253 { VALUE_HASH_1, "{ 'KEY_HASH_1': 1.1 }", false }, | |
254 { VALUE_HASH_1, "{ 'KEY_HASH_1': [1] }", false }, | |
255 { VALUE_HASH_1, "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
256 | |
257 { GetHash("1.2"), "{ 'KEY_HASH_1': 1.2 }", true }, | |
258 { GetHash("1.2"), "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false }, | |
259 { GetHash("1.2"), "{ 'KEY_HASH_1': true }", false }, | |
260 { GetHash("1.2"), "{ 'KEY_HASH_1': 1 }", false }, | |
261 { GetHash("1.2"), "{ 'KEY_HASH_1': 1.3 }", false }, | |
262 { GetHash("1.2"), "{ 'KEY_HASH_1': [1] }", false }, | |
263 { GetHash("1.2"), "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
264 | |
265 { GetHash("1"), "{ 'KEY_HASH_1': 1 }", true }, | |
266 { GetHash("1"), "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false }, | |
267 { GetHash("1"), "{ 'KEY_HASH_1': true }", false }, | |
268 { GetHash("1"), "{ 'KEY_HASH_1': 2 }", false }, | |
269 { GetHash("1"), "{ 'KEY_HASH_1': 1.1 }", false }, | |
270 { GetHash("1"), "{ 'KEY_HASH_1': [1] }", false }, | |
271 { GetHash("1"), "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
272 }; | |
273 | |
274 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
275 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
276 INIT_INTERPRETER( | |
277 OP_NAVIGATE(KEY_HASH_1) + | |
278 OP_COMPARE_NODE_HASH(cases[i].expected_value) + | |
279 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
280 cases[i].json); | |
281 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
282 if (cases[i].expected_success) { | |
283 base::ExpectDictBooleanValue( | |
284 true, *interpreter.working_memory(), VAR_HASH_1); | |
285 } else { | |
286 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
287 } | |
288 } | |
289 | |
290 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
291 SCOPED_TRACE(testing::Message() << "Negated, Iteration " << i); | |
292 INIT_INTERPRETER( | |
293 OP_NAVIGATE(KEY_HASH_1) + | |
294 OP_COMPARE_NODE_HASH_NOT(cases[i].expected_value) + | |
295 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
296 cases[i].json); | |
297 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
298 if (!cases[i].expected_success) { | |
299 base::ExpectDictBooleanValue( | |
300 true, *interpreter.working_memory(), VAR_HASH_1); | |
301 } else { | |
302 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
303 } | |
304 } | |
305 } | |
306 | |
307 TEST(JtlInterpreter, StoreNodeBool) { | |
308 struct TestCase { | |
309 bool expected_value; | |
310 const char* json; | |
311 bool expected_success; | |
312 } cases[] = { | |
313 { true, "{ 'KEY_HASH_1': true }", true }, | |
314 { false, "{ 'KEY_HASH_1': false }", true }, | |
315 { false, "{ 'KEY_HASH_1': 'abc' }", false }, | |
316 { false, "{ 'KEY_HASH_1': 1 }", false }, | |
317 { false, "{ 'KEY_HASH_1': 1.2 }", false }, | |
318 { false, "{ 'KEY_HASH_1': [1] }", false }, | |
319 { false, "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
320 }; | |
321 | |
322 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
323 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
324 INIT_INTERPRETER( | |
325 OP_NAVIGATE(KEY_HASH_1) + | |
326 OP_STORE_NODE_BOOL(VAR_HASH_1) + | |
327 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
328 cases[i].json); | |
329 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
330 if (cases[i].expected_success) { | |
331 base::ExpectDictBooleanValue( | |
332 cases[i].expected_value, *interpreter.working_memory(), VAR_HASH_1); | |
333 base::ExpectDictBooleanValue( | |
334 true, *interpreter.working_memory(), VAR_HASH_2); | |
335 } else { | |
336 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
337 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2)); | |
338 } | |
339 } | |
340 } | |
341 | |
342 TEST(JtlInterpreter, CompareNodeToStoredBool) { | |
343 struct TestCase { | |
344 std::string stored_value; | |
345 const char* json; | |
346 bool expected_success; | |
347 } cases[] = { | |
348 { VALUE_TRUE, "{ 'KEY_HASH_1': true }", true }, | |
349 { VALUE_FALSE, "{ 'KEY_HASH_1': false }", true }, | |
350 { VALUE_FALSE, "{ 'KEY_HASH_1': true }", false }, | |
351 { std::string(), "{ 'KEY_HASH_1': true }", false }, | |
352 | |
353 { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false }, | |
354 { GetHash("1"), "{ 'KEY_HASH_1': 1 }", false }, | |
355 { GetHash("1.2"), "{ 'KEY_HASH_1': 1.2 }", false }, | |
356 | |
357 { VALUE_HASH_1, "{ 'KEY_HASH_1': true }", false }, | |
358 { GetHash("1"), "{ 'KEY_HASH_1': true }", false }, | |
359 { GetHash("1.2"), "{ 'KEY_HASH_1': true }", false }, | |
360 | |
361 { VALUE_TRUE, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false }, | |
362 { VALUE_TRUE, "{ 'KEY_HASH_1': 1 }", false }, | |
363 { VALUE_TRUE, "{ 'KEY_HASH_1': 1.2 }", false }, | |
364 { VALUE_TRUE, "{ 'KEY_HASH_1': [1] }", false }, | |
365 { VALUE_TRUE, "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
366 }; | |
367 | |
368 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
369 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
370 std::string store_op; | |
371 if (cases[i].stored_value == VALUE_TRUE || | |
372 cases[i].stored_value == VALUE_FALSE) | |
373 store_op = OP_STORE_BOOL(VAR_HASH_1, cases[i].stored_value); | |
374 else if (!cases[i].stored_value.empty()) | |
375 store_op = OP_STORE_HASH(VAR_HASH_1, cases[i].stored_value); | |
376 INIT_INTERPRETER( | |
377 store_op + | |
378 OP_NAVIGATE(KEY_HASH_1) + | |
379 OP_COMPARE_NODE_TO_STORED_BOOL(VAR_HASH_1) + | |
380 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
381 cases[i].json); | |
382 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
383 if (cases[i].expected_success) { | |
384 base::ExpectDictBooleanValue( | |
385 true, *interpreter.working_memory(), VAR_HASH_2); | |
386 } else { | |
387 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2)); | |
388 } | |
389 } | |
390 } | |
391 | |
392 TEST(JtlInterpreter, StoreNodeHash) { | |
393 struct TestCase { | |
394 std::string expected_value; | |
395 const char* json; | |
396 bool expected_success; | |
397 } cases[] = { | |
398 { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", true }, | |
399 { VALUE_HASH_2, "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", true }, | |
400 { GetHash("1"), "{ 'KEY_HASH_1': 1 }", true }, | |
401 { GetHash("1.2"), "{ 'KEY_HASH_1': 1.2 }", true }, | |
402 { std::string(), "{ 'KEY_HASH_1': true }", false }, | |
403 { std::string(), "{ 'KEY_HASH_1': [1] }", false }, | |
404 { std::string(), "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
405 }; | |
406 | |
407 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
408 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
409 INIT_INTERPRETER( | |
410 OP_NAVIGATE(KEY_HASH_1) + | |
411 OP_STORE_NODE_HASH(VAR_HASH_1) + | |
412 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
413 cases[i].json); | |
414 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
415 if (cases[i].expected_success) { | |
416 base::ExpectDictStringValue( | |
417 cases[i].expected_value, *interpreter.working_memory(), VAR_HASH_1); | |
418 base::ExpectDictBooleanValue( | |
419 true, *interpreter.working_memory(), VAR_HASH_2); | |
420 } else { | |
421 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
422 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2)); | |
423 } | |
424 } | |
425 } | |
426 | |
427 TEST(JtlInterpreter, CompareNodeToStoredHash) { | |
428 struct TestCase { | |
429 std::string stored_value; | |
430 const char* json; | |
431 bool expected_success; | |
432 } cases[] = { | |
433 { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", true }, | |
434 { VALUE_HASH_2, "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", true }, | |
435 { std::string(), "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", false }, | |
436 { VALUE_HASH_1, "{ 'KEY_HASH_1': 'VALUE_HASH_2' }", false }, | |
437 { VALUE_HASH_1, "{ 'KEY_HASH_1': true }", false }, | |
438 { VALUE_HASH_1, "{ 'KEY_HASH_1': 1 }", false }, | |
439 { VALUE_HASH_1, "{ 'KEY_HASH_1': 1.1 }", false }, | |
440 { VALUE_HASH_1, "{ 'KEY_HASH_1': [1] }", false }, | |
441 { VALUE_HASH_1, "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
442 | |
443 { GetHash("1.2"), "{ 'KEY_HASH_1': 1.2 }", true }, | |
444 { GetHash("1.3"), "{ 'KEY_HASH_1': 1.3 }", true }, | |
445 { std::string(), "{ 'KEY_HASH_1': 1.2 }", false }, | |
446 { GetHash("1.2"), "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false }, | |
447 { GetHash("1.2"), "{ 'KEY_HASH_1': true }", false }, | |
448 { GetHash("1.2"), "{ 'KEY_HASH_1': 1 }", false }, | |
449 { GetHash("1.2"), "{ 'KEY_HASH_1': 1.3 }", false }, | |
450 { GetHash("1.2"), "{ 'KEY_HASH_1': [1] }", false }, | |
451 { GetHash("1.2"), "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
452 | |
453 { GetHash("1"), "{ 'KEY_HASH_1': 1 }", true }, | |
454 { GetHash("2"), "{ 'KEY_HASH_1': 2 }", true }, | |
455 { std::string(), "{ 'KEY_HASH_1': 2 }", false }, | |
456 { GetHash("1"), "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false }, | |
457 { GetHash("1"), "{ 'KEY_HASH_1': true }", false }, | |
458 { GetHash("1"), "{ 'KEY_HASH_1': 2 }", false }, | |
459 { GetHash("1"), "{ 'KEY_HASH_1': 1.1 }", false }, | |
460 { GetHash("1"), "{ 'KEY_HASH_1': [1] }", false }, | |
461 { GetHash("1"), "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
462 | |
463 { VALUE_TRUE, "{ 'KEY_HASH_1': 'VALUE_HASH_1' }", false }, | |
464 { VALUE_TRUE, "{ 'KEY_HASH_1': 1 }", false }, | |
465 { VALUE_TRUE, "{ 'KEY_HASH_1': 1.3 }", false }, | |
466 { VALUE_TRUE, "{ 'KEY_HASH_1': [1] }", false }, | |
467 { VALUE_TRUE, "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
468 | |
469 { VALUE_TRUE, "{ 'KEY_HASH_1': true }", false }, | |
470 { VALUE_FALSE, "{ 'KEY_HASH_1': false }", false }, | |
471 }; | |
472 | |
473 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
474 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
475 std::string store_op; | |
476 if (cases[i].stored_value == VALUE_TRUE || | |
477 cases[i].stored_value == VALUE_FALSE) | |
478 store_op = OP_STORE_BOOL(VAR_HASH_1, cases[i].stored_value); | |
479 else if (!cases[i].stored_value.empty()) | |
480 store_op = OP_STORE_HASH(VAR_HASH_1, cases[i].stored_value); | |
481 INIT_INTERPRETER( | |
482 store_op + | |
483 OP_NAVIGATE(KEY_HASH_1) + | |
484 OP_COMPARE_NODE_TO_STORED_HASH(VAR_HASH_1) + | |
485 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
486 cases[i].json); | |
487 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
488 if (cases[i].expected_success) { | |
489 base::ExpectDictBooleanValue( | |
490 true, *interpreter.working_memory(), VAR_HASH_2); | |
491 } else { | |
492 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2)); | |
493 } | |
494 } | |
495 } | |
496 | |
497 TEST(JtlInterpreter, CompareSubstring) { | |
498 struct TestCase { | |
499 std::string pattern; | |
500 const char* json; | |
501 bool expected_success; | |
502 } cases[] = { | |
503 { "abc", "{ 'KEY_HASH_1': 'abcdefghijklmnopqrstuvwxyz' }", true }, | |
504 { "xyz", "{ 'KEY_HASH_1': 'abcdefghijklmnopqrstuvwxyz' }", true }, | |
505 { "m", "{ 'KEY_HASH_1': 'abcdefghijklmnopqrstuvwxyz' }", true }, | |
506 { "abc", "{ 'KEY_HASH_1': 'abc' }", true }, | |
507 { "cba", "{ 'KEY_HASH_1': 'abcdefghijklmnopqrstuvwxyz' }", false }, | |
508 { "acd", "{ 'KEY_HASH_1': 'abcdefghijklmnopqrstuvwxyz' }", false }, | |
509 { "waaaaaaay_too_long", "{ 'KEY_HASH_1': 'abc' }", false }, | |
510 | |
511 { VALUE_HASH_1, "{ 'KEY_HASH_1': true }", false }, | |
512 { VALUE_HASH_1, "{ 'KEY_HASH_1': 1 }", false }, | |
513 { VALUE_HASH_1, "{ 'KEY_HASH_1': 1.1 }", false }, | |
514 { VALUE_HASH_1, "{ 'KEY_HASH_1': [1] }", false }, | |
515 { VALUE_HASH_1, "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
516 }; | |
517 | |
518 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
519 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
520 std::string pattern = cases[i].pattern; | |
521 uint32 pattern_sum = std::accumulate( | |
522 pattern.begin(), pattern.end(), static_cast<uint32>(0u)); | |
523 INIT_INTERPRETER( | |
524 OP_NAVIGATE(KEY_HASH_1) + | |
525 OP_COMPARE_NODE_SUBSTRING(GetHash(pattern), | |
526 EncodeUint32(pattern.size()), | |
527 EncodeUint32(pattern_sum)) + | |
528 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE), | |
529 cases[i].json); | |
530 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
531 if (cases[i].expected_success) { | |
532 base::ExpectDictBooleanValue( | |
533 true, *interpreter.working_memory(), VAR_HASH_1); | |
534 } else { | |
535 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
536 } | |
537 } | |
538 } | |
539 | |
540 TEST(JtlInterpreter, StoreNodeRegisterableDomainHash) { | |
541 struct TestCase { | |
542 std::string expected_value; | |
543 const char* json; | |
544 bool expected_success; | |
545 } cases[] = { | |
546 { GetHash("google"), "{ 'KEY_HASH_1': 'http://google.com/path' }", true }, | |
547 { GetHash("google"), "{ 'KEY_HASH_1': 'http://mail.google.com/' }", true }, | |
548 { GetHash("google"), "{ 'KEY_HASH_1': 'http://google.co.uk/' }", true }, | |
549 { GetHash("google"), "{ 'KEY_HASH_1': 'http://google.com./' }", true }, | |
550 { GetHash("google"), "{ 'KEY_HASH_1': 'http://..google.com/' }", true }, | |
551 | |
552 { GetHash("foo"), "{ 'KEY_HASH_1': 'http://foo.bar/path' }", true }, | |
553 { GetHash("foo"), "{ 'KEY_HASH_1': 'http://sub.foo.bar' }", true }, | |
554 { GetHash("foo"), "{ 'KEY_HASH_1': 'http://foo.appspot.com/' }", true }, | |
555 { GetHash("foo"), "{ 'KEY_HASH_1': 'http://sub.foo.appspot.com' }", true }, | |
556 | |
557 { std::string(), "{ 'KEY_HASH_1': 'http://google.com../' }", false }, | |
558 | |
559 { std::string(), "{ 'KEY_HASH_1': 'http://bar/path' }", false }, | |
560 { std::string(), "{ 'KEY_HASH_1': 'http://co.uk/path' }", false }, | |
561 { std::string(), "{ 'KEY_HASH_1': 'http://appspot.com/path' }", false }, | |
562 { std::string(), "{ 'KEY_HASH_1': 'http://127.0.0.1/path' }", false }, | |
563 { std::string(), "{ 'KEY_HASH_1': 'file:///C:/bar.html' }", false }, | |
564 | |
565 { std::string(), "{ 'KEY_HASH_1': 1 }", false }, | |
566 { std::string(), "{ 'KEY_HASH_1': 1.2 }", false }, | |
567 { std::string(), "{ 'KEY_HASH_1': true }", false }, | |
568 { std::string(), "{ 'KEY_HASH_1': [1] }", false }, | |
569 { std::string(), "{ 'KEY_HASH_1': {'a': 'b'} }", false }, | |
570 }; | |
571 | |
572 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
573 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
574 INIT_INTERPRETER( | |
575 OP_NAVIGATE(KEY_HASH_1) + | |
576 OP_STORE_NODE_REGISTERABLE_DOMAIN_HASH(VAR_HASH_1) + | |
577 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
578 cases[i].json); | |
579 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
580 if (cases[i].expected_success) { | |
581 base::ExpectDictStringValue( | |
582 cases[i].expected_value, *interpreter.working_memory(), VAR_HASH_1); | |
583 base::ExpectDictBooleanValue( | |
584 true, *interpreter.working_memory(), VAR_HASH_2); | |
585 } else { | |
586 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1)); | |
587 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2)); | |
588 } | |
589 } | |
590 } | |
591 | |
592 TEST(JtlInterpreter, Stop) { | |
593 INIT_INTERPRETER( | |
594 OP_NAVIGATE(KEY_HASH_1) + | |
595 OP_NAVIGATE(KEY_HASH_2) + | |
596 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE) + | |
597 OP_STOP_EXECUTING_SENTENCE + | |
598 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
599 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
600 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
601 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
602 EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2)); | |
603 } | |
604 | |
605 TEST(JtlInterpreter, EndOfSentence) { | |
606 INIT_INTERPRETER( | |
607 OP_NAVIGATE(KEY_HASH_1) + | |
608 OP_NAVIGATE(KEY_HASH_2) + | |
609 OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE) + | |
610 OP_END_OF_SENTENCE + | |
611 OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE), | |
612 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
613 EXPECT_EQ(JtlInterpreter::OK, interpreter.result()); | |
614 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1); | |
615 base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_2); | |
616 } | |
617 | |
618 TEST(JtlInterpreter, InvalidBack) { | |
619 INIT_INTERPRETER( | |
620 OP_NAVIGATE(KEY_HASH_1) + | |
621 OP_NAVIGATE_BACK + | |
622 OP_NAVIGATE_BACK, | |
623 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
624 EXPECT_EQ(JtlInterpreter::RUNTIME_ERROR, interpreter.result()); | |
625 } | |
626 | |
627 TEST(JtlInterpreter, IncorrectPrograms) { | |
628 std::string missing_hash; | |
629 std::string missing_bool; | |
630 std::string invalid_hash("123"); | |
631 std::string invalid_bool("\x02", 1); | |
632 std::string invalid_operation("\x99", 1); | |
633 std::string programs[] = { | |
634 OP_NAVIGATE(missing_hash), | |
635 OP_NAVIGATE(invalid_hash), | |
636 OP_STORE_BOOL(VAR_HASH_1, invalid_bool), | |
637 OP_STORE_BOOL(missing_hash, VALUE_TRUE), | |
638 OP_STORE_BOOL(invalid_hash, VALUE_TRUE), | |
639 OP_COMPARE_STORED_BOOL(invalid_hash, VALUE_TRUE, VALUE_TRUE), | |
640 OP_COMPARE_STORED_BOOL(VAR_HASH_1, invalid_bool, VALUE_TRUE), | |
641 OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, invalid_bool), | |
642 OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, missing_bool), | |
643 OP_STORE_NODE_BOOL(missing_hash), | |
644 OP_STORE_NODE_BOOL(invalid_hash), | |
645 OP_STORE_NODE_HASH(missing_hash), | |
646 OP_STORE_NODE_HASH(invalid_hash), | |
647 OP_COMPARE_NODE_BOOL(missing_bool), | |
648 OP_COMPARE_NODE_BOOL(invalid_bool), | |
649 OP_COMPARE_NODE_HASH(missing_hash), | |
650 OP_COMPARE_NODE_HASH(invalid_hash), | |
651 OP_COMPARE_NODE_TO_STORED_BOOL(missing_hash), | |
652 OP_COMPARE_NODE_TO_STORED_BOOL(invalid_hash), | |
653 OP_COMPARE_NODE_TO_STORED_HASH(missing_hash), | |
654 OP_COMPARE_NODE_TO_STORED_HASH(invalid_hash), | |
655 invalid_operation, | |
656 }; | |
657 for (size_t i = 0; i < arraysize(programs); ++i) { | |
658 SCOPED_TRACE(testing::Message() << "Iteration " << i); | |
659 INIT_INTERPRETER(programs[i], | |
660 "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }"); | |
661 EXPECT_EQ(JtlInterpreter::PARSE_ERROR, interpreter.result()); | |
662 } | |
663 } | |
664 | |
665 TEST(JtlInterpreter, GetOutput) { | |
666 INIT_INTERPRETER( | |
667 OP_STORE_BOOL(GetHash("output1"), VALUE_TRUE) + | |
668 OP_STORE_HASH(GetHash("output2"), VALUE_HASH_1), | |
669 "{}"); | |
670 bool output1 = false; | |
671 std::string output2; | |
672 EXPECT_TRUE(interpreter.GetOutputBoolean("output1", &output1)); | |
673 EXPECT_EQ(true, output1); | |
674 EXPECT_TRUE(interpreter.GetOutputString("output2", &output2)); | |
675 EXPECT_EQ(VALUE_HASH_1, output2); | |
676 EXPECT_FALSE(interpreter.GetOutputBoolean("outputxx", &output1)); | |
677 EXPECT_FALSE(interpreter.GetOutputString("outputxx", &output2)); | |
678 } | |
679 | |
680 TEST(JtlInterpreter, CalculateProgramChecksum) { | |
681 const char kTestSeed[] = "Irrelevant seed value."; | |
682 const char kTestProgram[] = "The quick brown fox jumps over the lazy dog."; | |
683 // This program is invalid, but we are not actually executing it. | |
684 base::DictionaryValue input; | |
685 JtlInterpreter interpreter(kTestSeed, kTestProgram, &input); | |
686 EXPECT_EQ(0xef537f, interpreter.CalculateProgramChecksum()); | |
687 } | |
688 | |
689 } // namespace | |
OLD | NEW |