mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: Reland of https://github.com/facebook/react-native/issues/32895 with fix for optional params object. Original description: I was looking at the hermes chrome devtools integration and noticed requests to `Runtime.getHeapUsage` which was not implemented. When implemented it will show a summary of memory usage of the javascript instance in devtools. <img width="325" alt="image" src="https://user-images.githubusercontent.com/2677334/149637113-e1d95d26-9e26-46c2-9be6-47d22284f15f.png"> ## Changelog [General] [Added] - Implement Runtime.getHeapUsage for hermes chrome inspector Pull Request resolved: https://github.com/facebook/react-native/pull/33173 Test Plan: I was able to reproduce the issue that caused the initial PR to be reverted using the resume request in Flipper. Pausing JS execution then resuming it will cause it to crash before this change, and works fine after. Before <img width="912" alt="image" src="https://user-images.githubusercontent.com/2677334/149637073-15f4e1fa-8183-42dc-8673-d4371731415c.png"> After <img width="1076" alt="image" src="https://user-images.githubusercontent.com/2677334/149637085-579dee8f-5efb-4658-b0a8-2400bd119924.png"> Reviewed By: jpporto Differential Revision: D34446672 Pulled By: ShikaSD fbshipit-source-id: 6e26b8d53cd88cddded36437c72a01822551b9d0
1533 lines
47 KiB
C++
1533 lines
47 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include <hermes/inspector/chrome/MessageTypes.h>
|
|
|
|
#include <iostream>
|
|
|
|
#include <folly/dynamic.h>
|
|
#include <folly/json.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
namespace facebook {
|
|
namespace hermes {
|
|
namespace inspector {
|
|
namespace chrome {
|
|
namespace message {
|
|
|
|
using folly::dynamic;
|
|
|
|
TEST(MessageTests, testSerializeSomeFieldsInRequest) {
|
|
debugger::SetBreakpointByUrlRequest req;
|
|
// req.id should default to 0
|
|
req.lineNumber = 2;
|
|
req.url = "http://example.com/example.js";
|
|
|
|
dynamic result = req.toDynamic();
|
|
dynamic expected = folly::parseJson(R"({
|
|
"id": 0,
|
|
"method": "Debugger.setBreakpointByUrl",
|
|
"params": {
|
|
"lineNumber": 2,
|
|
"url": "http://example.com/example.js"
|
|
}
|
|
})");
|
|
EXPECT_EQ(result, expected);
|
|
}
|
|
|
|
TEST(MessageTests, testDeserializeSomeFieldsInRequest) {
|
|
dynamic message = folly::parseJson(R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.setBreakpointByUrl",
|
|
"params": {
|
|
"lineNumber": 42,
|
|
"url": "http://example.com"
|
|
}
|
|
}
|
|
)");
|
|
debugger::SetBreakpointByUrlRequest req(message);
|
|
|
|
EXPECT_EQ(req.toDynamic(), message);
|
|
EXPECT_EQ(req.id, 10);
|
|
EXPECT_EQ(req.method, "Debugger.setBreakpointByUrl");
|
|
EXPECT_EQ(req.lineNumber, 42);
|
|
EXPECT_FALSE(req.columnNumber.hasValue());
|
|
EXPECT_FALSE(req.condition.hasValue());
|
|
EXPECT_EQ(req.url, "http://example.com");
|
|
EXPECT_FALSE(req.urlRegex.hasValue());
|
|
}
|
|
|
|
TEST(MessageTests, testSerializeAllFieldsInRequest) {
|
|
debugger::SetBreakpointByUrlRequest req;
|
|
req.id = 1;
|
|
req.lineNumber = 2;
|
|
req.columnNumber = 3;
|
|
req.condition = "foo == 42";
|
|
req.url = "http://example.com/example.js";
|
|
req.urlRegex = "http://example.com/.*";
|
|
|
|
dynamic result = req.toDynamic();
|
|
dynamic expected = folly::parseJson(R"({
|
|
"id": 1,
|
|
"method": "Debugger.setBreakpointByUrl",
|
|
"params": {
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"condition": "foo == 42",
|
|
"url": "http://example.com/example.js",
|
|
"urlRegex": "http://example.com/.*"
|
|
}
|
|
})");
|
|
EXPECT_EQ(result, expected);
|
|
}
|
|
|
|
TEST(MessageTests, testDeserializeAllFieldsInRequest) {
|
|
dynamic message = folly::parseJson(R"({
|
|
"id": 1,
|
|
"method": "Debugger.setBreakpointByUrl",
|
|
"params": {
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"condition": "foo == 42",
|
|
"url": "http://example.com/example.js",
|
|
"urlRegex": "http://example.com/.*"
|
|
}
|
|
})");
|
|
debugger::SetBreakpointByUrlRequest req(message);
|
|
|
|
EXPECT_EQ(req.id, 1);
|
|
EXPECT_EQ(req.method, "Debugger.setBreakpointByUrl");
|
|
EXPECT_EQ(req.lineNumber, 2);
|
|
EXPECT_EQ(req.columnNumber, 3);
|
|
EXPECT_EQ(req.condition, "foo == 42");
|
|
EXPECT_EQ(req.url, "http://example.com/example.js");
|
|
EXPECT_EQ(req.urlRegex, "http://example.com/.*");
|
|
}
|
|
|
|
TEST(MessageTests, testSerializeResponse) {
|
|
debugger::Location location;
|
|
location.scriptId = "myScriptId";
|
|
location.lineNumber = 2;
|
|
location.columnNumber = 3;
|
|
|
|
debugger::SetBreakpointByUrlResponse resp;
|
|
resp.id = 1;
|
|
resp.breakpointId = "myBreakpointId";
|
|
resp.locations = {location};
|
|
|
|
dynamic result = resp.toDynamic();
|
|
dynamic expected = folly::parseJson(R"({
|
|
"id": 1,
|
|
"result": {
|
|
"breakpointId": "myBreakpointId",
|
|
"locations": [
|
|
{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
}
|
|
]
|
|
}
|
|
})");
|
|
EXPECT_EQ(result, expected);
|
|
}
|
|
|
|
TEST(MessageTests, testDeserializeResponse) {
|
|
dynamic message = folly::parseJson(R"({
|
|
"id": 1,
|
|
"result": {
|
|
"breakpointId": "myBreakpointId",
|
|
"locations": [
|
|
{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
}
|
|
]
|
|
}
|
|
})");
|
|
debugger::SetBreakpointByUrlResponse resp(message);
|
|
EXPECT_EQ(resp.toDynamic(), message);
|
|
EXPECT_EQ(resp.id, 1);
|
|
EXPECT_EQ(resp.breakpointId, "myBreakpointId");
|
|
EXPECT_EQ(resp.locations.size(), 1);
|
|
EXPECT_EQ(resp.locations[0].lineNumber, 2);
|
|
EXPECT_EQ(resp.locations[0].columnNumber, 3);
|
|
EXPECT_EQ(resp.locations[0].scriptId, "myScriptId");
|
|
}
|
|
|
|
TEST(MessageTests, testSerializeNotification) {
|
|
debugger::Location startLocation;
|
|
startLocation.lineNumber = 1;
|
|
startLocation.scriptId = "script1";
|
|
|
|
debugger::Location endLocation;
|
|
endLocation.lineNumber = 2;
|
|
endLocation.scriptId = "script2";
|
|
|
|
debugger::Scope scope;
|
|
scope.type = "closure";
|
|
scope.object.type = "object";
|
|
scope.object.subtype = "regexp";
|
|
scope.object.className = "RegExp";
|
|
scope.object.value = dynamic::object("foo", "bar");
|
|
scope.object.unserializableValue = "nope";
|
|
scope.object.description = "myDesc";
|
|
scope.object.objectId = "id1";
|
|
scope.name = "myScope";
|
|
scope.startLocation = startLocation;
|
|
scope.endLocation = endLocation;
|
|
|
|
debugger::CallFrame frame;
|
|
frame.callFrameId = "callFrame1";
|
|
frame.functionName = "foo1";
|
|
frame.location.scriptId = "script1";
|
|
frame.location.lineNumber = 3;
|
|
frame.location.columnNumber = 4;
|
|
frame.url = "foo.js";
|
|
frame.scopeChain = std::vector<debugger::Scope>{scope};
|
|
frame.thisObj.type = "function";
|
|
|
|
debugger::PausedNotification note;
|
|
note.callFrames = std::vector<debugger::CallFrame>{frame};
|
|
note.reason = "debugCommand";
|
|
note.data = dynamic::object("foo", "bar");
|
|
note.hitBreakpoints = std::vector<std::string>{"a", "b"};
|
|
|
|
dynamic result = note.toDynamic();
|
|
dynamic expected = folly::parseJson(R"({
|
|
"method": "Debugger.paused",
|
|
"params": {
|
|
"callFrames": [
|
|
{
|
|
"callFrameId": "callFrame1",
|
|
"functionName": "foo1",
|
|
"location": {
|
|
"scriptId": "script1",
|
|
"lineNumber": 3,
|
|
"columnNumber": 4
|
|
},
|
|
"url": "foo.js",
|
|
"scopeChain": [
|
|
{
|
|
"type": "closure",
|
|
"object": {
|
|
"type": "object",
|
|
"subtype": "regexp",
|
|
"className": "RegExp",
|
|
"value": { "foo": "bar" },
|
|
"unserializableValue": "nope",
|
|
"description": "myDesc",
|
|
"objectId": "id1"
|
|
},
|
|
"name": "myScope",
|
|
"startLocation": {
|
|
"lineNumber": 1,
|
|
"scriptId": "script1"
|
|
},
|
|
"endLocation": {
|
|
"lineNumber": 2,
|
|
"scriptId": "script2"
|
|
}
|
|
}
|
|
],
|
|
"this": { "type": "function" }
|
|
}
|
|
],
|
|
"reason": "debugCommand",
|
|
"data": {
|
|
"foo": "bar"
|
|
},
|
|
"hitBreakpoints": [ "a", "b" ]
|
|
}
|
|
})");
|
|
EXPECT_EQ(result, expected);
|
|
}
|
|
|
|
TEST(MessageTests, testDeserializeNotification) {
|
|
dynamic message = folly::parseJson(R"({
|
|
"method": "Debugger.paused",
|
|
"params": {
|
|
"callFrames": [
|
|
{
|
|
"callFrameId": "callFrame1",
|
|
"functionName": "foo1",
|
|
"location": {
|
|
"scriptId": "script1",
|
|
"lineNumber": 3,
|
|
"columnNumber": 4
|
|
},
|
|
"url": "foo.js",
|
|
"scopeChain": [
|
|
{
|
|
"type": "closure",
|
|
"object": {
|
|
"type": "object",
|
|
"subtype": "regexp",
|
|
"className": "RegExp",
|
|
"value": { "foo": "bar" },
|
|
"unserializableValue": "nope",
|
|
"description": "myDesc",
|
|
"objectId": "id1"
|
|
},
|
|
"name": "myScope",
|
|
"startLocation": {
|
|
"lineNumber": 1,
|
|
"scriptId": "script1"
|
|
},
|
|
"endLocation": {
|
|
"lineNumber": 2,
|
|
"scriptId": "script2"
|
|
}
|
|
}
|
|
],
|
|
"this": { "type": "function" }
|
|
}
|
|
],
|
|
"reason": "debugCommand",
|
|
"data": {
|
|
"foo": "bar"
|
|
},
|
|
"hitBreakpoints": [ "a", "b" ]
|
|
}
|
|
})");
|
|
debugger::PausedNotification note(message);
|
|
|
|
EXPECT_EQ(note.method, "Debugger.paused");
|
|
EXPECT_EQ(note.callFrames.size(), 1);
|
|
EXPECT_EQ(note.reason, "debugCommand");
|
|
EXPECT_EQ(note.data, static_cast<dynamic>(dynamic::object("foo", "bar")));
|
|
auto expectedHitBreakpoints = std::vector<std::string>{"a", "b"};
|
|
EXPECT_EQ(note.hitBreakpoints, expectedHitBreakpoints);
|
|
|
|
debugger::CallFrame &callFrame = note.callFrames[0];
|
|
EXPECT_EQ(callFrame.callFrameId, "callFrame1");
|
|
EXPECT_EQ(callFrame.functionName, "foo1");
|
|
EXPECT_EQ(callFrame.location.scriptId, "script1");
|
|
EXPECT_EQ(callFrame.location.lineNumber, 3);
|
|
EXPECT_EQ(callFrame.location.columnNumber, 4);
|
|
EXPECT_EQ(callFrame.url, "foo.js");
|
|
EXPECT_EQ(callFrame.scopeChain.size(), 1);
|
|
EXPECT_EQ(callFrame.thisObj.type, "function");
|
|
|
|
debugger::Scope &scope = callFrame.scopeChain[0];
|
|
EXPECT_EQ(scope.type, "closure");
|
|
EXPECT_EQ(scope.object.type, "object");
|
|
EXPECT_EQ(scope.object.subtype, "regexp");
|
|
EXPECT_EQ(scope.object.className, "RegExp");
|
|
EXPECT_EQ(
|
|
scope.object.value, static_cast<dynamic>(dynamic::object("foo", "bar")));
|
|
EXPECT_EQ(scope.object.unserializableValue, "nope");
|
|
EXPECT_EQ(scope.object.description, "myDesc");
|
|
EXPECT_EQ(scope.object.objectId, "id1");
|
|
EXPECT_EQ(scope.name, "myScope");
|
|
|
|
debugger::Location &startLocation = scope.startLocation.value();
|
|
EXPECT_EQ(startLocation.lineNumber, 1);
|
|
EXPECT_FALSE(startLocation.columnNumber.hasValue());
|
|
EXPECT_EQ(startLocation.scriptId, "script1");
|
|
|
|
debugger::Location &endLocation = scope.endLocation.value();
|
|
EXPECT_EQ(endLocation.lineNumber, 2);
|
|
EXPECT_FALSE(endLocation.columnNumber.hasValue());
|
|
EXPECT_EQ(endLocation.scriptId, "script2");
|
|
}
|
|
|
|
TEST(MessageTests, TestSerializeAsyncStackTrace) {
|
|
runtime::StackTrace stack;
|
|
stack.description = "childStack";
|
|
stack.parent = std::make_unique<runtime::StackTrace>();
|
|
stack.parent->description = "parentStack";
|
|
|
|
dynamic result = stack.toDynamic();
|
|
dynamic expected = folly::parseJson(R"({
|
|
"description": "childStack",
|
|
"callFrames": [],
|
|
"parent": {
|
|
"description": "parentStack",
|
|
"callFrames": []
|
|
}
|
|
})");
|
|
EXPECT_EQ(result, expected);
|
|
}
|
|
|
|
TEST(MessageTests, TestDeserializeAsyncStackTrace) {
|
|
dynamic message = folly::parseJson(R"({
|
|
"description": "childStack",
|
|
"callFrames": [],
|
|
"parent": {
|
|
"description": "parentStack",
|
|
"callFrames": []
|
|
}
|
|
})");
|
|
runtime::StackTrace stack(message);
|
|
|
|
EXPECT_EQ(stack.description, "childStack");
|
|
EXPECT_EQ(stack.callFrames.size(), 0);
|
|
EXPECT_EQ(stack.parent->description, "parentStack");
|
|
EXPECT_EQ(stack.parent->callFrames.size(), 0);
|
|
}
|
|
|
|
TEST(MessageTests, TestRequestFromJson) {
|
|
std::unique_ptr<Request> baseReq1 = Request::fromJsonThrowOnError(R"({
|
|
"id": 1,
|
|
"method": "Debugger.enable"
|
|
})");
|
|
auto req1 = static_cast<debugger::EnableRequest *>(baseReq1.get());
|
|
EXPECT_EQ(req1->id, 1);
|
|
EXPECT_EQ(req1->method, "Debugger.enable");
|
|
|
|
std::unique_ptr<Request> baseReq2 = Request::fromJsonThrowOnError(R"({
|
|
"id": 2,
|
|
"method": "Debugger.removeBreakpoint",
|
|
"params": {
|
|
"breakpointId": "foobar"
|
|
}
|
|
})");
|
|
auto req2 = static_cast<debugger::RemoveBreakpointRequest *>(baseReq2.get());
|
|
EXPECT_EQ(req2->id, 2);
|
|
EXPECT_EQ(req2->method, "Debugger.removeBreakpoint");
|
|
EXPECT_EQ(req2->breakpointId, "foobar");
|
|
|
|
folly::Try<std::unique_ptr<Request>> invalidReq =
|
|
Request::fromJson("invalid");
|
|
EXPECT_TRUE(invalidReq.hasException());
|
|
}
|
|
|
|
TEST(MessageTests, TestBreakpointRequestFromJSON) {
|
|
std::unique_ptr<Request> baseReq = Request::fromJsonThrowOnError(R"({
|
|
"id": 1,
|
|
"method": "Debugger.setBreakpoint",
|
|
"params": {
|
|
"location": {
|
|
"scriptId": "23",
|
|
"lineNumber": 45,
|
|
"columnNumber": 67
|
|
}
|
|
}
|
|
})");
|
|
auto req = static_cast<debugger::SetBreakpointRequest *>(baseReq.get());
|
|
EXPECT_EQ(req->location.scriptId, "23");
|
|
EXPECT_EQ(req->location.lineNumber, 45);
|
|
EXPECT_EQ(req->location.columnNumber.value(), 67);
|
|
}
|
|
|
|
struct MyHandler : public NoopRequestHandler {
|
|
void handle(const debugger::EnableRequest &req) override {
|
|
enableReq = req;
|
|
}
|
|
|
|
void handle(const debugger::RemoveBreakpointRequest &req) override {
|
|
removeReq = req;
|
|
}
|
|
|
|
debugger::EnableRequest enableReq;
|
|
debugger::RemoveBreakpointRequest removeReq;
|
|
};
|
|
|
|
TEST(MessageTests, TestRequestHandler) {
|
|
MyHandler handler;
|
|
|
|
std::unique_ptr<Request> enableReq = Request::fromJsonThrowOnError(R"({
|
|
"id": 1,
|
|
"method": "Debugger.enable"
|
|
})");
|
|
enableReq->accept(handler);
|
|
|
|
EXPECT_EQ(handler.enableReq.id, 1);
|
|
EXPECT_EQ(handler.enableReq.method, "Debugger.enable");
|
|
|
|
std::unique_ptr<Request> removeReq = Request::fromJsonThrowOnError(R"({
|
|
"id": 2,
|
|
"method": "Debugger.removeBreakpoint",
|
|
"params": {
|
|
"breakpointId": "foobar"
|
|
}
|
|
})");
|
|
removeReq->accept(handler);
|
|
|
|
EXPECT_EQ(handler.removeReq.id, 2);
|
|
EXPECT_EQ(handler.removeReq.method, "Debugger.removeBreakpoint");
|
|
EXPECT_EQ(handler.removeReq.breakpointId, "foobar");
|
|
}
|
|
|
|
TEST(MessageTests, testEnableRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.enable"
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::EnableRequest *resolvedReq =
|
|
dynamic_cast<debugger::EnableRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::EnableRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.enable");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
}
|
|
|
|
TEST(MessageTests, testDisableRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.disable"
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::DisableRequest *resolvedReq =
|
|
dynamic_cast<debugger::DisableRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::DisableRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.disable");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
}
|
|
|
|
TEST(MessageTests, testEvaluateOnCallFrameRequestMinimal) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.evaluateOnCallFrame",
|
|
"params":{
|
|
"callFrameId" : "42",
|
|
"expression": "Foo Bar"
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::EvaluateOnCallFrameRequest *resolvedReq =
|
|
dynamic_cast<debugger::EvaluateOnCallFrameRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::EvaluateOnCallFrameRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.evaluateOnCallFrame");
|
|
EXPECT_EQ(resolvedReq->callFrameId, "42");
|
|
EXPECT_EQ(resolvedReq->expression, "Foo Bar");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->callFrameId, deserializedReq.callFrameId);
|
|
EXPECT_EQ(resolvedReq->expression, deserializedReq.expression);
|
|
|
|
EXPECT_FALSE(resolvedReq->objectGroup.hasValue());
|
|
EXPECT_FALSE(resolvedReq->includeCommandLineAPI.hasValue());
|
|
EXPECT_FALSE(resolvedReq->silent.hasValue());
|
|
EXPECT_FALSE(resolvedReq->returnByValue.hasValue());
|
|
EXPECT_FALSE(resolvedReq->throwOnSideEffect.hasValue());
|
|
}
|
|
|
|
TEST(MessageTests, testEvaluateOnCallFrameRequestFull) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.evaluateOnCallFrame",
|
|
"params":{
|
|
"callFrameId" : "42",
|
|
"expression": "Foo Bar",
|
|
"objectGroup" : "FooBarGroup",
|
|
"includeCommandLineAPI" : false,
|
|
"silent" : true,
|
|
"returnByValue" : false,
|
|
"throwOnSideEffect" : true
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::EvaluateOnCallFrameRequest *resolvedReq =
|
|
dynamic_cast<debugger::EvaluateOnCallFrameRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::EvaluateOnCallFrameRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics, resolvedReq is correct
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.evaluateOnCallFrame");
|
|
EXPECT_EQ(resolvedReq->callFrameId, "42");
|
|
EXPECT_EQ(resolvedReq->expression, "Foo Bar");
|
|
|
|
EXPECT_TRUE(resolvedReq->objectGroup.hasValue());
|
|
EXPECT_TRUE(resolvedReq->includeCommandLineAPI.hasValue());
|
|
EXPECT_TRUE(resolvedReq->silent.hasValue());
|
|
EXPECT_TRUE(resolvedReq->returnByValue.hasValue());
|
|
EXPECT_TRUE(resolvedReq->throwOnSideEffect.hasValue());
|
|
|
|
EXPECT_TRUE(resolvedReq->objectGroup.value() == "FooBarGroup");
|
|
EXPECT_TRUE(resolvedReq->includeCommandLineAPI.value() == false);
|
|
EXPECT_TRUE(resolvedReq->silent.value() == true);
|
|
EXPECT_TRUE(resolvedReq->returnByValue.value() == false);
|
|
EXPECT_TRUE(resolvedReq->throwOnSideEffect.value() == true);
|
|
|
|
// Specifics, resolvedReq and deserialized match
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->callFrameId, deserializedReq.callFrameId);
|
|
EXPECT_EQ(resolvedReq->expression, deserializedReq.expression);
|
|
EXPECT_EQ(
|
|
resolvedReq->objectGroup.value(), deserializedReq.objectGroup.value());
|
|
EXPECT_EQ(
|
|
resolvedReq->includeCommandLineAPI.value(),
|
|
deserializedReq.includeCommandLineAPI.value());
|
|
EXPECT_EQ(resolvedReq->silent.value(), deserializedReq.silent.value());
|
|
EXPECT_EQ(
|
|
resolvedReq->returnByValue.value(),
|
|
deserializedReq.returnByValue.value());
|
|
EXPECT_EQ(
|
|
resolvedReq->throwOnSideEffect.value(),
|
|
deserializedReq.throwOnSideEffect.value());
|
|
}
|
|
|
|
TEST(MessageTests, testPauseRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.pause"
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::PauseRequest *resolvedReq =
|
|
dynamic_cast<debugger::PauseRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::PauseRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.pause");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
}
|
|
|
|
TEST(MessageTests, testRemoveBreakpointRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.removeBreakpoint",
|
|
"params":{
|
|
"breakpointId" : "42"
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::RemoveBreakpointRequest *resolvedReq =
|
|
dynamic_cast<debugger::RemoveBreakpointRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::RemoveBreakpointRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.removeBreakpoint");
|
|
EXPECT_TRUE(resolvedReq->breakpointId == "42");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->breakpointId, deserializedReq.breakpointId);
|
|
}
|
|
|
|
TEST(MessageTests, testResumeRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.resume",
|
|
"params": {
|
|
"terminateOnResume": false
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::ResumeRequest *resolvedReq =
|
|
dynamic_cast<debugger::ResumeRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::ResumeRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.resume");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
}
|
|
|
|
TEST(MessageTests, testSetBreakpointRequestMinimal) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.setBreakpoint",
|
|
"params":{
|
|
"location" :
|
|
{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
}
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::SetBreakpointRequest *resolvedReq =
|
|
dynamic_cast<debugger::SetBreakpointRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetBreakpointRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
debugger::Location location;
|
|
location.scriptId = "myScriptId";
|
|
location.lineNumber = 2;
|
|
location.columnNumber = 3;
|
|
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.setBreakpoint");
|
|
EXPECT_EQ(resolvedReq->location.scriptId, "myScriptId");
|
|
EXPECT_EQ(resolvedReq->location.lineNumber, 2);
|
|
EXPECT_EQ(resolvedReq->location.columnNumber, 3);
|
|
|
|
EXPECT_FALSE(resolvedReq->condition.hasValue());
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->location.scriptId, deserializedReq.location.scriptId);
|
|
EXPECT_EQ(
|
|
resolvedReq->location.lineNumber, deserializedReq.location.lineNumber);
|
|
EXPECT_EQ(
|
|
resolvedReq->location.columnNumber,
|
|
deserializedReq.location.columnNumber);
|
|
}
|
|
|
|
TEST(MessageTests, testSetBreakpointRequestFull) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.setBreakpoint",
|
|
"params":{
|
|
"location" :
|
|
{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
},
|
|
"condition": "FooBarCondition"
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::SetBreakpointRequest *resolvedReq =
|
|
dynamic_cast<debugger::SetBreakpointRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetBreakpointRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.setBreakpoint");
|
|
EXPECT_EQ(resolvedReq->location.scriptId, "myScriptId");
|
|
EXPECT_EQ(resolvedReq->location.lineNumber, 2);
|
|
EXPECT_EQ(resolvedReq->location.columnNumber, 3);
|
|
|
|
EXPECT_TRUE(resolvedReq->condition.hasValue());
|
|
EXPECT_EQ(resolvedReq->condition.value(), "FooBarCondition");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->location.scriptId, deserializedReq.location.scriptId);
|
|
EXPECT_EQ(
|
|
resolvedReq->location.lineNumber, deserializedReq.location.lineNumber);
|
|
EXPECT_EQ(
|
|
resolvedReq->location.columnNumber,
|
|
deserializedReq.location.columnNumber);
|
|
EXPECT_EQ(resolvedReq->condition.value(), deserializedReq.condition.value());
|
|
}
|
|
|
|
TEST(MessageTests, testSetBreakpointByUrlRequestMinimal) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 1,
|
|
"method": "Debugger.setBreakpointByUrl",
|
|
"params": {
|
|
"lineNumber": 2
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::SetBreakpointByUrlRequest *resolvedReq =
|
|
dynamic_cast<debugger::SetBreakpointByUrlRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetBreakpointByUrlRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 1);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.setBreakpointByUrl");
|
|
EXPECT_EQ(resolvedReq->lineNumber, 2);
|
|
|
|
EXPECT_FALSE(resolvedReq->condition.hasValue());
|
|
EXPECT_FALSE(resolvedReq->columnNumber.hasValue());
|
|
EXPECT_FALSE(resolvedReq->url.hasValue());
|
|
EXPECT_FALSE(resolvedReq->urlRegex.hasValue());
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->lineNumber, deserializedReq.lineNumber);
|
|
}
|
|
|
|
TEST(MessageTests, testSetBreakpointByUrlRequestFull) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 1,
|
|
"method": "Debugger.setBreakpointByUrl",
|
|
"params": {
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"condition": "foo == 42",
|
|
"url": "http://example.com/example.js",
|
|
"urlRegex": "http://example.com/.*"
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::SetBreakpointByUrlRequest *resolvedReq =
|
|
dynamic_cast<debugger::SetBreakpointByUrlRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetBreakpointByUrlRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 1);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.setBreakpointByUrl");
|
|
EXPECT_EQ(resolvedReq->lineNumber, 2);
|
|
|
|
EXPECT_TRUE(resolvedReq->condition.hasValue());
|
|
EXPECT_EQ(resolvedReq->condition.value(), "foo == 42");
|
|
EXPECT_TRUE(resolvedReq->columnNumber.hasValue());
|
|
EXPECT_EQ(resolvedReq->columnNumber.value(), 3);
|
|
EXPECT_TRUE(resolvedReq->url.hasValue());
|
|
EXPECT_EQ(resolvedReq->url.value(), "http://example.com/example.js");
|
|
EXPECT_TRUE(resolvedReq->urlRegex.hasValue());
|
|
EXPECT_EQ(resolvedReq->urlRegex.value(), "http://example.com/.*");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->lineNumber, deserializedReq.lineNumber);
|
|
EXPECT_EQ(resolvedReq->condition.value(), deserializedReq.condition.value());
|
|
EXPECT_EQ(
|
|
resolvedReq->columnNumber.value(), deserializedReq.columnNumber.value());
|
|
EXPECT_EQ(resolvedReq->url.value(), deserializedReq.url.value());
|
|
EXPECT_EQ(resolvedReq->urlRegex.value(), deserializedReq.urlRegex.value());
|
|
}
|
|
|
|
TEST(MessageTests, testSetBreakpointsActiveRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 1,
|
|
"method": "Debugger.setBreakpointsActive",
|
|
"params": {
|
|
"active": true
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::SetBreakpointsActiveRequest *resolvedReq =
|
|
dynamic_cast<debugger::SetBreakpointsActiveRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetBreakpointsActiveRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 1);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.setBreakpointsActive");
|
|
EXPECT_EQ(resolvedReq->active, true);
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->active, deserializedReq.active);
|
|
}
|
|
|
|
TEST(MessageTests, testSetInstrumentationBreakpointRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 1,
|
|
"method": "Debugger.setInstrumentationBreakpoint",
|
|
"params": {
|
|
"instrumentation": "TODO: THIS SHOUD NOT BE ACCEPTED BY ENUM"
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::SetInstrumentationBreakpointRequest *resolvedReq =
|
|
dynamic_cast<debugger::SetInstrumentationBreakpointRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetInstrumentationBreakpointRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 1);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.setInstrumentationBreakpoint");
|
|
EXPECT_EQ(
|
|
resolvedReq->instrumentation, "TODO: THIS SHOUD NOT BE ACCEPTED BY ENUM");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->instrumentation, deserializedReq.instrumentation);
|
|
}
|
|
|
|
TEST(MessageTests, testSetPauseOnExceptionsRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 1,
|
|
"method": "Debugger.setPauseOnExceptions",
|
|
"params": {
|
|
"state": "TODO: THIS SHOUD NOT BE ACCEPTED BY ENUM"
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::SetPauseOnExceptionsRequest *resolvedReq =
|
|
dynamic_cast<debugger::SetPauseOnExceptionsRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetPauseOnExceptionsRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 1);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.setPauseOnExceptions");
|
|
EXPECT_EQ(resolvedReq->state, "TODO: THIS SHOUD NOT BE ACCEPTED BY ENUM");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
EXPECT_EQ(resolvedReq->state, deserializedReq.state);
|
|
}
|
|
|
|
TEST(MessageTests, testStepIntoRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.stepInto"
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::StepIntoRequest *resolvedReq =
|
|
dynamic_cast<debugger::StepIntoRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::StepIntoRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.stepInto");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
}
|
|
|
|
TEST(MessageTests, testStepOutRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.stepOut"
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::StepOutRequest *resolvedReq =
|
|
dynamic_cast<debugger::StepOutRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::StepOutRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.stepOut");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
}
|
|
|
|
TEST(MessageTests, testStepOverRequest) {
|
|
std::string message = R"(
|
|
{
|
|
"id": 10,
|
|
"method": "Debugger.stepOver"
|
|
}
|
|
)";
|
|
|
|
// Builder does not throw
|
|
auto req = Request::fromJsonThrowOnError(message);
|
|
debugger::StepOverRequest *resolvedReq =
|
|
dynamic_cast<debugger::StepOverRequest *>(req.get());
|
|
|
|
// Builder returns correct type
|
|
EXPECT_FALSE(resolvedReq == nullptr);
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::StepOverRequest deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(resolvedReq->id, 10);
|
|
EXPECT_EQ(resolvedReq->method, "Debugger.stepOver");
|
|
|
|
EXPECT_EQ(resolvedReq->id, deserializedReq.id);
|
|
EXPECT_EQ(resolvedReq->method, deserializedReq.method);
|
|
}
|
|
|
|
TEST(MessageTests, testEvaluateOnCallFrameResponseMinimal) {
|
|
std::string message = R"(
|
|
{
|
|
"result":
|
|
{
|
|
"result":{
|
|
"type": "string"
|
|
}
|
|
},
|
|
"id":2
|
|
}
|
|
)";
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::EvaluateOnCallFrameResponse deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
EXPECT_FALSE(deserializedReq.result.subtype.hasValue());
|
|
EXPECT_FALSE(deserializedReq.result.value.hasValue());
|
|
EXPECT_FALSE(deserializedReq.result.unserializableValue.hasValue());
|
|
EXPECT_FALSE(deserializedReq.result.description.hasValue());
|
|
EXPECT_FALSE(deserializedReq.result.objectId.hasValue());
|
|
|
|
// Specifics
|
|
EXPECT_EQ(deserializedReq.id, 2);
|
|
EXPECT_EQ(deserializedReq.result.type, "string");
|
|
}
|
|
|
|
TEST(MessageTests, testEvaluateOnCallFrameResponseFull) {
|
|
std::string message = R"(
|
|
{
|
|
"result":
|
|
{
|
|
"result":{
|
|
"type": "string",
|
|
"subtype": "SuperString",
|
|
"value": {"foobarkey": "foobarval"},
|
|
"unserializableValue": "unserializableValueVal",
|
|
"description": "A Wonderful desc",
|
|
"objectId": "AnObjectID"
|
|
}
|
|
},
|
|
"id":2
|
|
}
|
|
)";
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::EvaluateOnCallFrameResponse deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
EXPECT_TRUE(deserializedReq.result.subtype.hasValue());
|
|
EXPECT_TRUE(deserializedReq.result.value.hasValue());
|
|
EXPECT_TRUE(deserializedReq.result.unserializableValue.hasValue());
|
|
EXPECT_TRUE(deserializedReq.result.description.hasValue());
|
|
EXPECT_TRUE(deserializedReq.result.objectId.hasValue());
|
|
|
|
EXPECT_EQ(deserializedReq.result.subtype.value(), "SuperString");
|
|
EXPECT_EQ(
|
|
deserializedReq.result.value.value(),
|
|
folly::parseJson(R"({"foobarkey": "foobarval"})"));
|
|
EXPECT_EQ(
|
|
deserializedReq.result.unserializableValue.value(),
|
|
"unserializableValueVal");
|
|
EXPECT_EQ(deserializedReq.result.description.value(), "A Wonderful desc");
|
|
EXPECT_EQ(deserializedReq.result.objectId.value(), "AnObjectID");
|
|
|
|
// Specifics
|
|
EXPECT_EQ(deserializedReq.id, 2);
|
|
EXPECT_EQ(deserializedReq.result.type, "string");
|
|
}
|
|
|
|
TEST(MessageTests, testSetBreakpointByUrlResponse) {
|
|
std::string message = R"({
|
|
"id": 1,
|
|
"result":{
|
|
"breakpointId": "myBreakpointId",
|
|
"locations": [
|
|
{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
}
|
|
]
|
|
}
|
|
})";
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetBreakpointByUrlResponse deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(deserializedReq.id, 1);
|
|
EXPECT_EQ(deserializedReq.breakpointId, "myBreakpointId");
|
|
EXPECT_EQ(deserializedReq.locations.size(), 1);
|
|
EXPECT_EQ(deserializedReq.locations[0].lineNumber, 2);
|
|
EXPECT_EQ(deserializedReq.locations[0].columnNumber, 3);
|
|
EXPECT_EQ(deserializedReq.locations[0].scriptId, "myScriptId");
|
|
}
|
|
|
|
TEST(MessageTests, testSetBreakpointResponse) {
|
|
std::string message = R"({
|
|
"id": 1,
|
|
"result":{
|
|
"breakpointId": "myBreakpointId",
|
|
"actualLocation":
|
|
{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
}
|
|
}
|
|
})";
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetBreakpointResponse deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(deserializedReq.breakpointId, "myBreakpointId");
|
|
EXPECT_EQ(deserializedReq.actualLocation.lineNumber, 2);
|
|
EXPECT_EQ(deserializedReq.actualLocation.columnNumber, 3);
|
|
EXPECT_EQ(deserializedReq.actualLocation.scriptId, "myScriptId");
|
|
EXPECT_EQ(deserializedReq.id, 1);
|
|
}
|
|
|
|
TEST(MessageTests, testSetInstrumentationBreakpointResponse) {
|
|
std::string message = R"({
|
|
"id": 1,
|
|
"result":{
|
|
"breakpointId": "myBreakpointId"
|
|
}
|
|
})";
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::SetInstrumentationBreakpointResponse deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(deserializedReq.breakpointId, "myBreakpointId");
|
|
EXPECT_EQ(deserializedReq.id, 1);
|
|
}
|
|
|
|
TEST(MessageTests, testBreakpointResolvedNotification) {
|
|
std::string message = R"(
|
|
{
|
|
"method": "Debugger.breakpointResolved",
|
|
"params":{
|
|
"breakpointId" : "42",
|
|
"location":
|
|
{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
}
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::BreakpointResolvedNotification deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(deserializedReq.method, "Debugger.breakpointResolved");
|
|
EXPECT_EQ(deserializedReq.breakpointId, "42");
|
|
EXPECT_EQ(deserializedReq.location.lineNumber, 2);
|
|
EXPECT_EQ(deserializedReq.location.columnNumber, 3);
|
|
EXPECT_EQ(deserializedReq.location.scriptId, "myScriptId");
|
|
}
|
|
|
|
TEST(MessageTests, testPauseNotificationMinimal) {
|
|
std::string message = R"(
|
|
{
|
|
"method": "Debugger.paused",
|
|
"params":{
|
|
"reason": "Some Valid Reason",
|
|
"callFrames":[
|
|
{
|
|
"callFrameId": "aCallFrameId",
|
|
"functionName": "aFunctionName",
|
|
"location":{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
},
|
|
"url": "aURL",
|
|
"scopeChain": [
|
|
{
|
|
"type": "aType",
|
|
"object": {
|
|
"type": "aRemoteObjectType"
|
|
}
|
|
}
|
|
],
|
|
"this": {
|
|
"type": "aType"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::PausedNotification deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
EXPECT_FALSE(deserializedReq.callFrames[0].functionLocation.hasValue());
|
|
EXPECT_FALSE(deserializedReq.callFrames[0].returnValue.hasValue());
|
|
EXPECT_FALSE(deserializedReq.asyncStackTrace.hasValue());
|
|
EXPECT_FALSE(deserializedReq.hitBreakpoints.hasValue());
|
|
EXPECT_FALSE(deserializedReq.data.hasValue());
|
|
|
|
// Specifics
|
|
EXPECT_EQ(deserializedReq.method, "Debugger.paused");
|
|
EXPECT_EQ(deserializedReq.reason, "Some Valid Reason");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].functionName, "aFunctionName");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].callFrameId, "aCallFrameId");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].url, "aURL");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].location.lineNumber, 2);
|
|
EXPECT_EQ(deserializedReq.callFrames[0].location.columnNumber, 3);
|
|
EXPECT_EQ(deserializedReq.callFrames[0].location.scriptId, "myScriptId");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].scopeChain[0].type, "aType");
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].scopeChain[0].object.type,
|
|
"aRemoteObjectType");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].thisObj.type, "aType");
|
|
}
|
|
|
|
TEST(MessageTests, testPauseNotificationFull) {
|
|
std::string message = R"(
|
|
{
|
|
"method": "Debugger.paused",
|
|
"params":{
|
|
"reason": "Some Valid Reason",
|
|
"callFrames":[
|
|
{
|
|
"functionLocation": {
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
},
|
|
"returnValue" : {
|
|
"type": "aRemoteObjectType",
|
|
"subtype": "subtype",
|
|
"className":"className",
|
|
"value": "value",
|
|
"unserializableValue": "unserializableValue",
|
|
"description": "description",
|
|
"objectId": "objectId"
|
|
},
|
|
"callFrameId": "aCallFrameId",
|
|
"functionName": "aFunctionName",
|
|
"location":{
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId"
|
|
},
|
|
"url": "aURL",
|
|
"scopeChain": [
|
|
{
|
|
"type": "aType",
|
|
"object": {
|
|
"type": "aRemoteObjectType"
|
|
}
|
|
}
|
|
],
|
|
"this": {
|
|
"type": "aType"
|
|
}
|
|
}
|
|
],
|
|
"data": {"dataKey": "dataVal"},
|
|
"hitBreakpoints": [
|
|
"foo","bar"
|
|
],
|
|
"asyncStackTrace":{
|
|
"description": "an asyncStackTrace Desc",
|
|
"callFrames":[
|
|
{
|
|
"functionName": "aFunctionName",
|
|
"lineNumber": 2,
|
|
"columnNumber": 3,
|
|
"scriptId": "myScriptId",
|
|
"url": "aURL"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
)";
|
|
|
|
folly::Optional<debugger::Location> functionLocation;
|
|
folly::Optional<runtime::RemoteObject> returnValue;
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::PausedNotification deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Check optionnals
|
|
// ----------------
|
|
EXPECT_TRUE(deserializedReq.callFrames[0].functionLocation.hasValue());
|
|
EXPECT_TRUE(deserializedReq.callFrames[0].returnValue.hasValue());
|
|
EXPECT_TRUE(deserializedReq.asyncStackTrace.hasValue());
|
|
EXPECT_TRUE(deserializedReq.hitBreakpoints.hasValue());
|
|
EXPECT_TRUE(deserializedReq.data.hasValue());
|
|
|
|
EXPECT_TRUE(
|
|
deserializedReq.callFrames[0].returnValue.value().subtype.hasValue());
|
|
EXPECT_TRUE(
|
|
deserializedReq.callFrames[0].returnValue.value().className.hasValue());
|
|
EXPECT_TRUE(deserializedReq.callFrames[0]
|
|
.returnValue.value()
|
|
.unserializableValue.hasValue());
|
|
EXPECT_TRUE(
|
|
deserializedReq.callFrames[0].returnValue.value().value.hasValue());
|
|
EXPECT_TRUE(
|
|
deserializedReq.callFrames[0].returnValue.value().description.hasValue());
|
|
EXPECT_TRUE(
|
|
deserializedReq.callFrames[0].returnValue.value().objectId.hasValue());
|
|
|
|
// Check optionnals Values
|
|
// -----------------------
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].functionLocation.value().lineNumber, 2);
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].functionLocation.value().columnNumber, 3);
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].functionLocation.value().scriptId,
|
|
"myScriptId");
|
|
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().type,
|
|
"aRemoteObjectType");
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().subtype.hasValue(),
|
|
true);
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().subtype.value(),
|
|
"subtype");
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().className.hasValue(),
|
|
true);
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().className.value(),
|
|
"className");
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().value.hasValue(), true);
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().value.value(), "value");
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0]
|
|
.returnValue.value()
|
|
.unserializableValue.hasValue(),
|
|
true);
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0]
|
|
.returnValue.value()
|
|
.unserializableValue.value(),
|
|
"unserializableValue");
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().description.hasValue(),
|
|
true);
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().description.value(),
|
|
"description");
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().objectId.hasValue(),
|
|
true);
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].returnValue.value().objectId.value(),
|
|
"objectId");
|
|
|
|
EXPECT_EQ(deserializedReq.hitBreakpoints.value()[0], "foo");
|
|
EXPECT_EQ(deserializedReq.hitBreakpoints.value()[1], "bar");
|
|
|
|
EXPECT_EQ(
|
|
deserializedReq.data.value(),
|
|
folly::parseJson(R"({"dataKey": "dataVal"})"));
|
|
|
|
// Check Compulsory
|
|
// ----------------
|
|
EXPECT_EQ(deserializedReq.method, "Debugger.paused");
|
|
EXPECT_EQ(deserializedReq.reason, "Some Valid Reason");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].functionName, "aFunctionName");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].callFrameId, "aCallFrameId");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].url, "aURL");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].location.lineNumber, 2);
|
|
EXPECT_EQ(deserializedReq.callFrames[0].location.columnNumber, 3);
|
|
EXPECT_EQ(deserializedReq.callFrames[0].location.scriptId, "myScriptId");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].scopeChain[0].type, "aType");
|
|
EXPECT_EQ(
|
|
deserializedReq.callFrames[0].scopeChain[0].object.type,
|
|
"aRemoteObjectType");
|
|
EXPECT_EQ(deserializedReq.callFrames[0].thisObj.type, "aType");
|
|
}
|
|
|
|
TEST(MessageTests, testResumedNotification) {
|
|
std::string message = R"(
|
|
{
|
|
"method": "Debugger.resumed"
|
|
}
|
|
)";
|
|
|
|
// Serialize and Deserialize are inverse functions
|
|
dynamic messageJSON = folly::parseJson(message);
|
|
debugger::ResumedNotification deserializedReq(messageJSON);
|
|
EXPECT_EQ(deserializedReq.toDynamic(), messageJSON);
|
|
|
|
// Specifics
|
|
EXPECT_EQ(deserializedReq.method, "Debugger.resumed");
|
|
}
|
|
|
|
} // namespace message
|
|
} // namespace chrome
|
|
} // namespace inspector
|
|
} // namespace hermes
|
|
} // namespace facebook
|