| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "include/dart_debugger_api.h" | 5 #include "include/dart_debugger_api.h" |
| 6 #include "vm/dart_api_impl.h" | 6 #include "vm/dart_api_impl.h" |
| 7 #include "vm/dart_entry.h" | 7 #include "vm/dart_entry.h" |
| 8 #include "vm/debugger.h" | 8 #include "vm/debugger.h" |
| 9 #include "vm/globals.h" | 9 #include "vm/globals.h" |
| 10 #include "vm/message_handler.h" | 10 #include "vm/message_handler.h" |
| 11 #include "vm/object_id_ring.h" |
| 11 #include "vm/os.h" | 12 #include "vm/os.h" |
| 12 #include "vm/port.h" | 13 #include "vm/port.h" |
| 13 #include "vm/service.h" | 14 #include "vm/service.h" |
| 14 #include "vm/unit_test.h" | 15 #include "vm/unit_test.h" |
| 15 | 16 |
| 16 namespace dart { | 17 namespace dart { |
| 17 | 18 |
| 18 class ServiceTestMessageHandler : public MessageHandler { | 19 class ServiceTestMessageHandler : public MessageHandler { |
| 19 public: | 20 public: |
| 20 ServiceTestMessageHandler() : _msg(NULL) {} | 21 ServiceTestMessageHandler() : _msg(NULL) {} |
| (...skipping 10 matching lines...) Expand all Loading... |
| 31 // Parse the message. | 32 // Parse the message. |
| 32 SnapshotReader reader(message->data(), message->len(), | 33 SnapshotReader reader(message->data(), message->len(), |
| 33 Snapshot::kMessage, Isolate::Current()); | 34 Snapshot::kMessage, Isolate::Current()); |
| 34 const Object& response_obj = Object::Handle(reader.ReadObject()); | 35 const Object& response_obj = Object::Handle(reader.ReadObject()); |
| 35 String& response = String::Handle(); | 36 String& response = String::Handle(); |
| 36 response ^= response_obj.raw(); | 37 response ^= response_obj.raw(); |
| 37 _msg = strdup(response.ToCString()); | 38 _msg = strdup(response.ToCString()); |
| 38 return true; | 39 return true; |
| 39 } | 40 } |
| 40 | 41 |
| 42 // Removes a given json key:value from _msg. |
| 43 void filterMsg(const char* key) { |
| 44 int key_len = strlen(key); |
| 45 int old_len = strlen(_msg); |
| 46 char* new_msg = reinterpret_cast<char*>(malloc(old_len + 1)); |
| 47 int old_pos = 0; |
| 48 int new_pos = 0; |
| 49 while (_msg[old_pos] != '\0') { |
| 50 if (_msg[old_pos] == '\"') { |
| 51 old_pos++; |
| 52 if ((old_len - old_pos) > key_len && |
| 53 strncmp(&_msg[old_pos], key, key_len) == 0 && |
| 54 _msg[old_pos + key_len + 2] == '\"') { |
| 55 old_pos += (key_len + 2); |
| 56 // Skip until next , or }. |
| 57 while (_msg[old_pos] != '\0' && |
| 58 _msg[old_pos] != ',' && |
| 59 _msg[old_pos] != '}') { |
| 60 old_pos++; |
| 61 } |
| 62 if (_msg[old_pos] == ',') { |
| 63 old_pos++; |
| 64 } |
| 65 } else { |
| 66 new_msg[new_pos] = '\"';; |
| 67 new_pos++; |
| 68 } |
| 69 } else { |
| 70 new_msg[new_pos] = _msg[old_pos]; |
| 71 new_pos++; |
| 72 old_pos++; |
| 73 } |
| 74 } |
| 75 new_msg[new_pos] = '\0'; |
| 76 free(_msg); |
| 77 _msg = new_msg; |
| 78 } |
| 79 |
| 41 const char* msg() const { return _msg; } | 80 const char* msg() const { return _msg; } |
| 42 | 81 |
| 43 private: | 82 private: |
| 44 char* _msg; | 83 char* _msg; |
| 45 }; | 84 }; |
| 46 | 85 |
| 47 | 86 |
| 48 static RawInstance* Eval(Dart_Handle lib, const char* expr) { | 87 static RawInstance* Eval(Dart_Handle lib, const char* expr) { |
| 49 Dart_Handle result = Dart_EvaluateExpr(lib, NewString(expr)); | 88 Dart_Handle result = Dart_EvaluateExpr(lib, NewString(expr)); |
| 50 EXPECT_VALID(result); | 89 EXPECT_VALID(result); |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 Service::HandleIsolateMessage(isolate, service_msg); | 330 Service::HandleIsolateMessage(isolate, service_msg); |
| 292 handler.HandleNextMessage(); | 331 handler.HandleNextMessage(); |
| 293 EXPECT_STREQ("{\"type\":\"Error\",\"id\":\"\"," | 332 EXPECT_STREQ("{\"type\":\"Error\",\"id\":\"\"," |
| 294 "\"message\":\"Unrecognized subcommand 'nosferatu'\"," | 333 "\"message\":\"Unrecognized subcommand 'nosferatu'\"," |
| 295 "\"request\":{\"arguments\":[\"debug\",\"nosferatu\"]," | 334 "\"request\":{\"arguments\":[\"debug\",\"nosferatu\"]," |
| 296 "\"option_keys\":[],\"option_values\":[]}}", | 335 "\"option_keys\":[],\"option_values\":[]}}", |
| 297 handler.msg()); | 336 handler.msg()); |
| 298 } | 337 } |
| 299 | 338 |
| 300 | 339 |
| 340 TEST_CASE(Service_Objects) { |
| 341 // TODO(turnidge): Extend this test to cover a non-trivial stack trace. |
| 342 const char* kScript = |
| 343 "var port;\n" // Set to our mock port by C++. |
| 344 "var validId;\n" // Set to a valid object id by C++. |
| 345 "\n" |
| 346 "main() {\n" |
| 347 "}"; |
| 348 |
| 349 Isolate* isolate = Isolate::Current(); |
| 350 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); |
| 351 EXPECT_VALID(lib); |
| 352 |
| 353 // Build a mock message handler and wrap it in a dart port. |
| 354 ServiceTestMessageHandler handler; |
| 355 Dart_Port port_id = PortMap::CreatePort(&handler); |
| 356 Dart_Handle port = |
| 357 Api::NewHandle(isolate, DartLibraryCalls::NewSendPort(port_id)); |
| 358 EXPECT_VALID(port); |
| 359 EXPECT_VALID(Dart_SetField(lib, NewString("port"), port)); |
| 360 |
| 361 ObjectIdRing* ring = isolate->object_id_ring(); |
| 362 const String& str = String::Handle(String::New("value")); |
| 363 intptr_t str_id = ring->GetIdForObject(str.raw()); |
| 364 Dart_Handle valid_id = Dart_NewInteger(str_id); |
| 365 EXPECT_VALID(valid_id); |
| 366 EXPECT_VALID(Dart_SetField(lib, NewString("validId"), valid_id)); |
| 367 |
| 368 Instance& service_msg = Instance::Handle(); |
| 369 |
| 370 // null |
| 371 service_msg = Eval(lib, "[port, ['objects', 'null'], [], []]"); |
| 372 Service::HandleIsolateMessage(isolate, service_msg); |
| 373 handler.HandleNextMessage(); |
| 374 handler.filterMsg("name"); |
| 375 EXPECT_STREQ( |
| 376 "{\"type\":\"Null\",\"id\":\"objects\\/null\"," |
| 377 "\"preview\":\"null\"}", |
| 378 handler.msg()); |
| 379 |
| 380 // not initialized |
| 381 service_msg = Eval(lib, "[port, ['objects', 'not-initialized'], [], []]"); |
| 382 Service::HandleIsolateMessage(isolate, service_msg); |
| 383 handler.HandleNextMessage(); |
| 384 handler.filterMsg("name"); |
| 385 EXPECT_STREQ( |
| 386 "{\"type\":\"Null\",\"id\":\"objects\\/not-initialized\"," |
| 387 "\"preview\":\"<not initialized>\"}", |
| 388 handler.msg()); |
| 389 |
| 390 // being initialized |
| 391 service_msg = Eval(lib, "[port, ['objects', 'being-initialized'], [], []]"); |
| 392 Service::HandleIsolateMessage(isolate, service_msg); |
| 393 handler.HandleNextMessage(); |
| 394 handler.filterMsg("name"); |
| 395 EXPECT_STREQ( |
| 396 "{\"type\":\"Null\",\"id\":\"objects\\/being-initialized\"," |
| 397 "\"preview\":\"<being initialized>\"}", |
| 398 handler.msg()); |
| 399 |
| 400 // optimized out |
| 401 service_msg = Eval(lib, "[port, ['objects', 'optimized-out'], [], []]"); |
| 402 Service::HandleIsolateMessage(isolate, service_msg); |
| 403 handler.HandleNextMessage(); |
| 404 handler.filterMsg("name"); |
| 405 EXPECT_STREQ( |
| 406 "{\"type\":\"Null\",\"id\":\"objects\\/optimized-out\"," |
| 407 "\"preview\":\"<optimized out>\"}", |
| 408 handler.msg()); |
| 409 |
| 410 // collected |
| 411 service_msg = Eval(lib, "[port, ['objects', 'collected'], [], []]"); |
| 412 Service::HandleIsolateMessage(isolate, service_msg); |
| 413 handler.HandleNextMessage(); |
| 414 handler.filterMsg("name"); |
| 415 EXPECT_STREQ( |
| 416 "{\"type\":\"Null\",\"id\":\"objects\\/collected\"," |
| 417 "\"preview\":\"<collected>\"}", |
| 418 handler.msg()); |
| 419 |
| 420 // expired |
| 421 service_msg = Eval(lib, "[port, ['objects', 'expired'], [], []]"); |
| 422 Service::HandleIsolateMessage(isolate, service_msg); |
| 423 handler.HandleNextMessage(); |
| 424 handler.filterMsg("name"); |
| 425 EXPECT_STREQ( |
| 426 "{\"type\":\"Null\",\"id\":\"objects\\/expired\"," |
| 427 "\"preview\":\"<expired>\"}", |
| 428 handler.msg()); |
| 429 |
| 430 // bool |
| 431 service_msg = Eval(lib, "[port, ['objects', 'bool-true'], [], []]"); |
| 432 Service::HandleIsolateMessage(isolate, service_msg); |
| 433 handler.HandleNextMessage(); |
| 434 handler.filterMsg("name"); |
| 435 EXPECT_STREQ( |
| 436 "{\"type\":\"Bool\",\"id\":\"objects\\/bool-true\"," |
| 437 "\"class\":{\"type\":\"@Class\",\"id\":\"classes\\/46\"," |
| 438 "\"user_name\":\"bool\"},\"preview\":\"true\"}", |
| 439 handler.msg()); |
| 440 |
| 441 // int |
| 442 service_msg = Eval(lib, "[port, ['objects', 'int-123'], [], []]"); |
| 443 Service::HandleIsolateMessage(isolate, service_msg); |
| 444 handler.HandleNextMessage(); |
| 445 handler.filterMsg("name"); |
| 446 EXPECT_STREQ( |
| 447 "{\"type\":\"Smi\",\"id\":\"objects\\/int-123\"," |
| 448 "\"class\":{\"type\":\"@Class\",\"id\":\"classes\\/42\"," |
| 449 "\"user_name\":\"int\"},\"preview\":\"123\"}", |
| 450 handler.msg()); |
| 451 |
| 452 // object id ring / valid |
| 453 service_msg = Eval(lib, "[port, ['objects', '$validId'], [], []]"); |
| 454 Service::HandleIsolateMessage(isolate, service_msg); |
| 455 handler.HandleNextMessage(); |
| 456 handler.filterMsg("name"); |
| 457 EXPECT_STREQ( |
| 458 "{\"type\":\"String\",\"id\":\"objects\\/1\"," |
| 459 "\"class\":{\"type\":\"@Class\",\"id\":\"classes\\/60\"," |
| 460 "\"user_name\":\"String\"},\"preview\":\"\\\"value\\\"\"," |
| 461 "\"fields\":[],\"size\":24}", |
| 462 handler.msg()); |
| 463 |
| 464 // object id ring / invalid => expired |
| 465 service_msg = Eval(lib, "[port, ['objects', '99999999'], [], []]"); |
| 466 Service::HandleIsolateMessage(isolate, service_msg); |
| 467 handler.HandleNextMessage(); |
| 468 handler.filterMsg("name"); |
| 469 EXPECT_STREQ( |
| 470 "{\"type\":\"Null\",\"id\":\"objects\\/expired\"," |
| 471 "\"preview\":\"<expired>\"}", |
| 472 handler.msg()); |
| 473 |
| 474 // expired/eval => error |
| 475 service_msg = Eval(lib, "[port, ['objects', 'expired', 'eval'], [], []]"); |
| 476 Service::HandleIsolateMessage(isolate, service_msg); |
| 477 handler.HandleNextMessage(); |
| 478 handler.filterMsg("name"); |
| 479 EXPECT_STREQ( |
| 480 "{\"type\":\"Error\",\"id\":\"\"," |
| 481 "\"message\":\"expected at most 2 arguments but found 3\\n\"," |
| 482 "\"request\":{\"arguments\":[\"objects\",\"expired\",\"eval\"]," |
| 483 "\"option_keys\":[],\"option_values\":[]}}", |
| 484 handler.msg()); |
| 485 |
| 486 // int/eval => good |
| 487 service_msg = Eval(lib, |
| 488 "[port, ['objects', 'int-123', 'eval'], " |
| 489 "['expr'], ['this+99']]"); |
| 490 Service::HandleIsolateMessage(isolate, service_msg); |
| 491 handler.HandleNextMessage(); |
| 492 handler.filterMsg("name"); |
| 493 EXPECT_STREQ( |
| 494 "{\"type\":\"@Smi\",\"id\":\"objects\\/int-222\"," |
| 495 "\"class\":{\"type\":\"@Class\",\"id\":\"classes\\/42\"," |
| 496 "\"user_name\":\"int\"},\"preview\":\"222\"}", |
| 497 handler.msg()); |
| 498 |
| 499 // object id ring / invalid => expired |
| 500 service_msg = Eval(lib, "[port, ['objects', '99999999', 'eval'], " |
| 501 "['expr'], ['this']]"); |
| 502 Service::HandleIsolateMessage(isolate, service_msg); |
| 503 handler.HandleNextMessage(); |
| 504 handler.filterMsg("name"); |
| 505 EXPECT_STREQ( |
| 506 "{\"type\":\"Error\",\"id\":\"\",\"kind\":\"EvalExpired\"," |
| 507 "\"message\":\"attempt to evaluate against expired object\\n\"," |
| 508 "\"request\":{\"arguments\":[\"objects\",\"99999999\",\"eval\"]," |
| 509 "\"option_keys\":[\"expr\"],\"option_values\":[\"this\"]}}", |
| 510 handler.msg()); |
| 511 |
| 512 // Extra arg to eval. |
| 513 service_msg = Eval(lib, |
| 514 "[port, ['objects', 'int-123', 'eval', 'foo'], " |
| 515 "['expr'], ['this+99']]"); |
| 516 Service::HandleIsolateMessage(isolate, service_msg); |
| 517 handler.HandleNextMessage(); |
| 518 handler.filterMsg("name"); |
| 519 EXPECT_STREQ( |
| 520 "{\"type\":\"Error\",\"id\":\"\"," |
| 521 "\"message\":\"expected at most 3 arguments but found 4\\n\"," |
| 522 "\"request\":{\"arguments\":[\"objects\",\"int-123\",\"eval\",\"foo\"]," |
| 523 "\"option_keys\":[\"expr\"],\"option_values\":[\"this+99\"]}}", |
| 524 handler.msg()); |
| 525 } |
| 526 |
| 527 |
| 528 |
| 301 TEST_CASE(Service_Classes) { | 529 TEST_CASE(Service_Classes) { |
| 302 const char* kScript = | 530 const char* kScript = |
| 303 "var port;\n" // Set to our mock port by C++. | 531 "var port;\n" // Set to our mock port by C++. |
| 304 "\n" | 532 "\n" |
| 305 "class A {\n" | 533 "class A {\n" |
| 306 " var a;\n" | 534 " var a;\n" |
| 307 " dynamic b() {}\n" | 535 " dynamic b() {}\n" |
| 308 " dynamic c() {\n" | 536 " dynamic c() {\n" |
| 309 " var d = () { b(); };\n" | 537 " var d = () { b(); };\n" |
| 310 " return d;\n" | 538 " return d;\n" |
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 Service::HandleIsolateMessage(isolate, service_msg); | 979 Service::HandleIsolateMessage(isolate, service_msg); |
| 752 handler.HandleNextMessage(); | 980 handler.HandleNextMessage(); |
| 753 EXPECT_STREQ("alpha", handler.msg()); | 981 EXPECT_STREQ("alpha", handler.msg()); |
| 754 service_msg = Eval(lib, "[port, ['beta'], [], []]"); | 982 service_msg = Eval(lib, "[port, ['beta'], [], []]"); |
| 755 Service::HandleIsolateMessage(isolate, service_msg); | 983 Service::HandleIsolateMessage(isolate, service_msg); |
| 756 handler.HandleNextMessage(); | 984 handler.HandleNextMessage(); |
| 757 EXPECT_STREQ("beta", handler.msg()); | 985 EXPECT_STREQ("beta", handler.msg()); |
| 758 } | 986 } |
| 759 | 987 |
| 760 } // namespace dart | 988 } // namespace dart |
| OLD | NEW |