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