Home | History | Annotate | Download | only in profile_resetter
      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
    690