• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetHash(const std::string & input)31 std::string GetHash(const std::string& input) {
32   return jtl_foundation::Hasher(seed).GetHash(input);
33 }
34 
EncodeUint32(uint32 value)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<Value> json_value(ParseJson(json)); \
51     JtlInterpreter interpreter( \
52         seed, \
53         program_param, \
54         static_cast<const DictionaryValue*>(json_value.get())); \
55     interpreter.Execute()
56 
57 using base::test::ParseJson;
58 
TEST(JtlInterpreter,Store)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 
TEST(JtlInterpreter,NavigateAndStore)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 
TEST(JtlInterpreter,FailNavigate)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 
TEST(JtlInterpreter,ConsecutiveNavigate)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 
TEST(JtlInterpreter,FailConsecutiveNavigate)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 
TEST(JtlInterpreter,NavigateAnyInDictionary)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 
TEST(JtlInterpreter,NavigateAnyInList)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 
TEST(JtlInterpreter,NavigateBack)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 
TEST(JtlInterpreter,StoreTwoValues)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 
TEST(JtlInterpreter,CompareStoredMatch)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 
TEST(JtlInterpreter,CompareStoredMismatch)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 
TEST(JtlInterpreter,CompareStoredNoValueMatchingDefault)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 
TEST(JtlInterpreter,CompareStoredNoValueMismatchingDefault)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 
TEST(JtlInterpreter,CompareBool)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 
TEST(JtlInterpreter,CompareHashString)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 
TEST(JtlInterpreter,StoreNodeBool)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 
TEST(JtlInterpreter,CompareNodeToStoredBool)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 
TEST(JtlInterpreter,StoreNodeHash)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 
TEST(JtlInterpreter,CompareNodeToStoredHash)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 
TEST(JtlInterpreter,CompareSubstring)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 
TEST(JtlInterpreter,StoreNodeEffectiveSLDHash)540 TEST(JtlInterpreter, StoreNodeEffectiveSLDHash) {
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     { std::string(), "{ 'KEY_HASH_1': 'http://google.com../' }", false },
553     { std::string(), "{ 'KEY_HASH_1': 'http://foo.bar/path' }", false },
554     { std::string(), "{ 'KEY_HASH_1': 'http://bar/path' }", false },
555     { std::string(), "{ 'KEY_HASH_1': 'http://co.uk/path' }", false },
556     { std::string(), "{ 'KEY_HASH_1': 'http://127.0.0.1/path' }", false },
557     { std::string(), "{ 'KEY_HASH_1': 'file:///C:/bar.html' }", false },
558 
559     { std::string(), "{ 'KEY_HASH_1': 1 }", false },
560     { std::string(), "{ 'KEY_HASH_1': 1.2 }", false },
561     { std::string(), "{ 'KEY_HASH_1': true }", false },
562     { std::string(), "{ 'KEY_HASH_1': [1] }", false },
563     { std::string(), "{ 'KEY_HASH_1': {'a': 'b'} }", false },
564   };
565 
566   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
567     SCOPED_TRACE(testing::Message() << "Iteration " << i);
568     INIT_INTERPRETER(
569         OP_NAVIGATE(KEY_HASH_1) +
570         OP_STORE_NODE_EFFECTIVE_SLD_HASH(VAR_HASH_1) +
571         OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE),
572         cases[i].json);
573     EXPECT_EQ(JtlInterpreter::OK, interpreter.result());
574     if (cases[i].expected_success) {
575       base::ExpectDictStringValue(
576           cases[i].expected_value, *interpreter.working_memory(), VAR_HASH_1);
577       base::ExpectDictBooleanValue(
578           true, *interpreter.working_memory(), VAR_HASH_2);
579     } else {
580       EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_1));
581       EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2));
582     }
583   }
584 }
585 
TEST(JtlInterpreter,Stop)586 TEST(JtlInterpreter, Stop) {
587   INIT_INTERPRETER(
588       OP_NAVIGATE(KEY_HASH_1) +
589       OP_NAVIGATE(KEY_HASH_2) +
590       OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE) +
591       OP_STOP_EXECUTING_SENTENCE +
592       OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE),
593       "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }");
594   EXPECT_EQ(JtlInterpreter::OK, interpreter.result());
595   base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1);
596   EXPECT_FALSE(interpreter.working_memory()->HasKey(VAR_HASH_2));
597 }
598 
TEST(JtlInterpreter,EndOfSentence)599 TEST(JtlInterpreter, EndOfSentence) {
600   INIT_INTERPRETER(
601       OP_NAVIGATE(KEY_HASH_1) +
602       OP_NAVIGATE(KEY_HASH_2) +
603       OP_STORE_BOOL(VAR_HASH_1, VALUE_TRUE) +
604       OP_END_OF_SENTENCE +
605       OP_STORE_BOOL(VAR_HASH_2, VALUE_TRUE),
606       "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }");
607   EXPECT_EQ(JtlInterpreter::OK, interpreter.result());
608   base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_1);
609   base::ExpectDictBooleanValue(true, *interpreter.working_memory(), VAR_HASH_2);
610 }
611 
TEST(JtlInterpreter,InvalidBack)612 TEST(JtlInterpreter, InvalidBack) {
613   INIT_INTERPRETER(
614       OP_NAVIGATE(KEY_HASH_1) +
615       OP_NAVIGATE_BACK +
616       OP_NAVIGATE_BACK,
617       "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }");
618   EXPECT_EQ(JtlInterpreter::RUNTIME_ERROR, interpreter.result());
619 }
620 
TEST(JtlInterpreter,IncorrectPrograms)621 TEST(JtlInterpreter, IncorrectPrograms) {
622   std::string missing_hash;
623   std::string missing_bool;
624   std::string invalid_hash("123");
625   std::string invalid_bool("\x02", 1);
626   std::string invalid_operation("\x99", 1);
627   std::string programs[] = {
628     OP_NAVIGATE(missing_hash),
629     OP_NAVIGATE(invalid_hash),
630     OP_STORE_BOOL(VAR_HASH_1, invalid_bool),
631     OP_STORE_BOOL(missing_hash, VALUE_TRUE),
632     OP_STORE_BOOL(invalid_hash, VALUE_TRUE),
633     OP_COMPARE_STORED_BOOL(invalid_hash, VALUE_TRUE, VALUE_TRUE),
634     OP_COMPARE_STORED_BOOL(VAR_HASH_1, invalid_bool, VALUE_TRUE),
635     OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, invalid_bool),
636     OP_COMPARE_STORED_BOOL(VAR_HASH_1, VALUE_TRUE, missing_bool),
637     OP_STORE_NODE_BOOL(missing_hash),
638     OP_STORE_NODE_BOOL(invalid_hash),
639     OP_STORE_NODE_HASH(missing_hash),
640     OP_STORE_NODE_HASH(invalid_hash),
641     OP_COMPARE_NODE_BOOL(missing_bool),
642     OP_COMPARE_NODE_BOOL(invalid_bool),
643     OP_COMPARE_NODE_HASH(missing_hash),
644     OP_COMPARE_NODE_HASH(invalid_hash),
645     OP_COMPARE_NODE_TO_STORED_BOOL(missing_hash),
646     OP_COMPARE_NODE_TO_STORED_BOOL(invalid_hash),
647     OP_COMPARE_NODE_TO_STORED_HASH(missing_hash),
648     OP_COMPARE_NODE_TO_STORED_HASH(invalid_hash),
649     invalid_operation,
650   };
651   for (size_t i = 0; i < arraysize(programs); ++i) {
652     SCOPED_TRACE(testing::Message() << "Iteration " << i);
653     INIT_INTERPRETER(programs[i],
654                      "{ 'KEY_HASH_1': { 'KEY_HASH_2': 'VALUE_HASH_1' } }");
655     EXPECT_EQ(JtlInterpreter::PARSE_ERROR, interpreter.result());
656   }
657 }
658 
TEST(JtlInterpreter,GetOutput)659 TEST(JtlInterpreter, GetOutput) {
660   INIT_INTERPRETER(
661       OP_STORE_BOOL(GetHash("output1"), VALUE_TRUE) +
662       OP_STORE_HASH(GetHash("output2"), VALUE_HASH_1),
663       "{}");
664   bool output1 = false;
665   std::string output2;
666   EXPECT_TRUE(interpreter.GetOutputBoolean("output1", &output1));
667   EXPECT_EQ(true, output1);
668   EXPECT_TRUE(interpreter.GetOutputString("output2", &output2));
669   EXPECT_EQ(VALUE_HASH_1, output2);
670   EXPECT_FALSE(interpreter.GetOutputBoolean("outputxx", &output1));
671   EXPECT_FALSE(interpreter.GetOutputString("outputxx", &output2));
672 }
673 
674 }  // namespace
675