-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[lldb-dap] Add unit tests for protocol types #139502
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) ChangesAdd unit tests for serializing and deserializing protocol types. Full diff: https://github.com/llvm/llvm-project/pull/139502.diff 2 Files Affected:
diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt
index 4bbb552be9f34..62318d2ecbad3 100644
--- a/lldb/unittests/DAP/CMakeLists.txt
+++ b/lldb/unittests/DAP/CMakeLists.txt
@@ -1,6 +1,7 @@
add_lldb_unittest(DAPTests
JSONUtilsTest.cpp
LLDBUtilsTest.cpp
+ ProtocolTypesTest.cpp
LINK_LIBS
lldbDAP
diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp
new file mode 100644
index 0000000000000..b64810dc713af
--- /dev/null
+++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp
@@ -0,0 +1,268 @@
+//===-- ProtocolTypesTest.cpp -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Protocol/ProtocolTypes.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_dap;
+using namespace lldb_dap::protocol;
+
+TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) {
+ ExceptionBreakpointsFilter filter;
+ filter.filter = "testFilter";
+ filter.label = "Test Filter";
+ filter.description = "This is a test filter";
+ filter.defaultState = true;
+ filter.supportsCondition = true;
+ filter.conditionDescription = "Condition for test filter";
+
+ llvm::json::Value value = toJSON(filter);
+ const json::Object *obj = value.getAsObject();
+ ASSERT_NE(obj, nullptr);
+
+ EXPECT_EQ(obj->getString("filter"), "testFilter");
+ EXPECT_EQ(obj->getString("label"), "Test Filter");
+ EXPECT_EQ(obj->getString("description"), "This is a test filter");
+ EXPECT_EQ(obj->getBoolean("default"), true);
+ EXPECT_EQ(obj->getBoolean("supportsCondition"), true);
+ EXPECT_EQ(obj->getString("conditionDescription"),
+ "Condition for test filter");
+}
+
+TEST(ProtocolTypesTest, ColumnDescriptor) {
+ ColumnDescriptor column;
+ column.attributeName = "testAttribute";
+ column.label = "Test Label";
+ column.format = "testFormat";
+ column.type = eColumnTypeString;
+ column.width = 20;
+
+ llvm::json::Value value = toJSON(column);
+ const json::Object *obj = value.getAsObject();
+ ASSERT_NE(obj, nullptr);
+
+ EXPECT_EQ(obj->getString("attributeName"), "testAttribute");
+ EXPECT_EQ(obj->getString("label"), "Test Label");
+ EXPECT_EQ(obj->getString("format"), "testFormat");
+ EXPECT_EQ(obj->getString("type"), "string");
+ EXPECT_EQ(obj->getInteger("width"), 20);
+}
+
+TEST(ProtocolTypesTest, BreakpointMode) {
+ BreakpointMode mode;
+ mode.mode = "testMode";
+ mode.label = "Test Label";
+ mode.description = "This is a test description";
+ mode.appliesTo = {eBreakpointModeApplicabilitySource,
+ eBreakpointModeApplicabilityException};
+
+ llvm::json::Value value = toJSON(mode);
+ const json::Object *obj = value.getAsObject();
+ ASSERT_NE(obj, nullptr);
+
+ EXPECT_EQ(obj->getString("mode"), "testMode");
+ EXPECT_EQ(obj->getString("label"), "Test Label");
+ EXPECT_EQ(obj->getString("description"), "This is a test description");
+
+ const auto *appliesToArray = obj->getArray("appliesTo");
+ ASSERT_NE(appliesToArray, nullptr);
+ ASSERT_EQ(appliesToArray->size(), 2UL);
+ EXPECT_EQ(appliesToArray->front().getAsString(), "source");
+ EXPECT_EQ(appliesToArray->back().getAsString(), "exception");
+}
+
+TEST(ProtocolTypesTest, Capabilities) {
+ Capabilities capabilities;
+ capabilities.supportedFeatures = {eAdapterFeatureANSIStyling,
+ eAdapterFeatureTerminateRequest};
+ capabilities.exceptionBreakpointFilters = {
+ {"filter1", "Filter 1", "Description 1", true, true, "Condition 1"},
+ {"filter2", "Filter 2", "Description 2", false, false, "Condition 2"}};
+ capabilities.completionTriggerCharacters = {"."};
+ capabilities.additionalModuleColumns = {
+ {"attribute1", "Label 1", "Format 1", eColumnTypeString, 10},
+ {"attribute2", "Label 2", "Format 2", eColumnTypeNumber, 20}};
+ capabilities.supportedChecksumAlgorithms = {eChecksumAlgorithmMD5,
+ eChecksumAlgorithmSHA256};
+ capabilities.breakpointModes = {{"mode1",
+ "Mode 1",
+ "Description 1",
+ {eBreakpointModeApplicabilitySource}},
+ {"mode2",
+ "Mode 2",
+ "Description 2",
+ {eBreakpointModeApplicabilityException}}};
+ capabilities.lldbExtVersion = "1.0.0";
+
+ llvm::json::Value value = toJSON(capabilities);
+ const json::Object *obj = value.getAsObject();
+ ASSERT_NE(obj, nullptr);
+
+ // Verify supported features.
+ EXPECT_EQ(obj->getBoolean("supportsANSIStyling"), true);
+ EXPECT_EQ(obj->getBoolean("supportsTerminateRequest"), true);
+
+ // Verify exception breakpoint filters.
+ const auto *filtersArray = obj->getArray("exceptionBreakpointFilters");
+ ASSERT_NE(filtersArray, nullptr);
+ ASSERT_EQ(filtersArray->size(), 2UL);
+ const auto *filter1 = filtersArray->front().getAsObject();
+ ASSERT_NE(filter1, nullptr);
+ EXPECT_EQ(filter1->getString("filter"), "filter1");
+ EXPECT_EQ(filter1->getString("label"), "Filter 1");
+ EXPECT_EQ(filter1->getString("description"), "Description 1");
+ EXPECT_EQ(filter1->getBoolean("default"), true);
+ EXPECT_EQ(filter1->getBoolean("supportsCondition"), true);
+ EXPECT_EQ(filter1->getString("conditionDescription"), "Condition 1");
+
+ const auto *filter2 = filtersArray->back().getAsObject();
+ ASSERT_NE(filter2, nullptr);
+ EXPECT_EQ(filter2->getString("filter"), "filter2");
+ EXPECT_EQ(filter2->getString("label"), "Filter 2");
+ EXPECT_EQ(filter2->getString("description"), "Description 2");
+ EXPECT_EQ(filter2->getBoolean("default"), false);
+ EXPECT_EQ(filter2->getBoolean("supportsCondition"), false);
+ EXPECT_EQ(filter2->getString("conditionDescription"), "Condition 2");
+
+ // Verify completion trigger characters.
+ const auto *completionArray = obj->getArray("completionTriggerCharacters");
+ ASSERT_NE(completionArray, nullptr);
+ ASSERT_EQ(completionArray->size(), 1UL);
+ EXPECT_EQ(completionArray->front().getAsString(), ".");
+
+ // Verify additional module columns.
+ const auto *columnsArray = obj->getArray("additionalModuleColumns");
+ ASSERT_NE(columnsArray, nullptr);
+ ASSERT_EQ(columnsArray->size(), 2UL);
+ const auto *column1 = columnsArray->front().getAsObject();
+ ASSERT_NE(column1, nullptr);
+ EXPECT_EQ(column1->getString("attributeName"), "attribute1");
+ EXPECT_EQ(column1->getString("label"), "Label 1");
+ EXPECT_EQ(column1->getString("format"), "Format 1");
+ EXPECT_EQ(column1->getString("type"), "string");
+ EXPECT_EQ(column1->getInteger("width"), 10);
+
+ const auto *column2 = columnsArray->back().getAsObject();
+ ASSERT_NE(column2, nullptr);
+ EXPECT_EQ(column2->getString("attributeName"), "attribute2");
+ EXPECT_EQ(column2->getString("label"), "Label 2");
+ EXPECT_EQ(column2->getString("format"), "Format 2");
+ EXPECT_EQ(column2->getString("type"), "number");
+ EXPECT_EQ(column2->getInteger("width"), 20);
+
+ // Verify supported checksum algorithms.
+ const auto *checksumArray = obj->getArray("supportedChecksumAlgorithms");
+ ASSERT_NE(checksumArray, nullptr);
+ ASSERT_EQ(checksumArray->size(), 2UL);
+ EXPECT_EQ(checksumArray->front().getAsString(), "MD5");
+ EXPECT_EQ(checksumArray->back().getAsString(), "SHA256");
+
+ // Verify breakpoint modes.
+ const auto *modesArray = obj->getArray("breakpointModes");
+ ASSERT_NE(modesArray, nullptr);
+ ASSERT_EQ(modesArray->size(), 2UL);
+ const auto *mode1 = modesArray->front().getAsObject();
+ ASSERT_NE(mode1, nullptr);
+ EXPECT_EQ(mode1->getString("mode"), "mode1");
+ EXPECT_EQ(mode1->getString("label"), "Mode 1");
+ EXPECT_EQ(mode1->getString("description"), "Description 1");
+ const auto *appliesTo1 = mode1->getArray("appliesTo");
+ ASSERT_NE(appliesTo1, nullptr);
+ ASSERT_EQ(appliesTo1->size(), 1UL);
+ EXPECT_EQ(appliesTo1->front().getAsString(), "source");
+
+ const auto *mode2 = modesArray->back().getAsObject();
+ ASSERT_NE(mode2, nullptr);
+ EXPECT_EQ(mode2->getString("mode"), "mode2");
+ EXPECT_EQ(mode2->getString("label"), "Mode 2");
+ EXPECT_EQ(mode2->getString("description"), "Description 2");
+ const auto *appliesTo2 = mode2->getArray("appliesTo");
+ ASSERT_NE(appliesTo2, nullptr);
+ ASSERT_EQ(appliesTo2->size(), 1UL);
+ EXPECT_EQ(appliesTo2->front().getAsString(), "exception");
+
+ // Verify lldb extension version.
+ EXPECT_EQ(obj->getString("$__lldb_version"), "1.0.0");
+}
+
+TEST(ProtocolTypesTest, Source) {
+ Source source;
+ source.name = "testName";
+ source.path = "/path/to/source";
+ source.sourceReference = 12345;
+ source.presentationHint = ePresentationHintEmphasize;
+
+ llvm::json::Value value = toJSON(source);
+
+ Source deserialized_source;
+ llvm::json::Path::Root root;
+ ASSERT_TRUE(fromJSON(value, deserialized_source, root));
+
+ ASSERT_EQ(source.name, deserialized_source.name);
+ ASSERT_EQ(source.path, deserialized_source.path);
+ ASSERT_EQ(source.sourceReference, deserialized_source.sourceReference);
+ ASSERT_EQ(source.presentationHint, deserialized_source.presentationHint);
+}
+
+TEST(ProtocolTypesTest, BreakpointLocation) {
+ BreakpointLocation location;
+ location.line = 42;
+ location.column = 5;
+ location.endLine = 50;
+ location.endColumn = 10;
+
+ llvm::json::Value value = toJSON(location);
+ const json::Object *obj = value.getAsObject();
+ ASSERT_NE(obj, nullptr);
+
+ EXPECT_EQ(obj->getInteger("line"), 42);
+ EXPECT_EQ(obj->getInteger("column"), 5);
+ EXPECT_EQ(obj->getInteger("endLine"), 50);
+ EXPECT_EQ(obj->getInteger("endColumn"), 10);
+}
+
+TEST(ProtocolTypesTest, Breakpoint) {
+ Breakpoint breakpoint;
+ breakpoint.id = 1;
+ breakpoint.verified = true;
+ breakpoint.message = "Breakpoint set successfully";
+ breakpoint.source = {"testSource", "/path/to/source", 12345,
+ ePresentationHintNormal};
+ breakpoint.line = 42;
+ breakpoint.column = 5;
+ breakpoint.endLine = 50;
+ breakpoint.endColumn = 10;
+ breakpoint.instructionReference = "0x1234";
+ breakpoint.offset = -4;
+ breakpoint.reason = BreakpointReason::eBreakpointReasonPending;
+
+ llvm::json::Value value = toJSON(breakpoint);
+ const json::Object *obj = value.getAsObject();
+ ASSERT_NE(obj, nullptr);
+
+ EXPECT_EQ(obj->getInteger("id"), 1);
+ EXPECT_EQ(obj->getBoolean("verified"), true);
+ EXPECT_EQ(obj->getString("message"), "Breakpoint set successfully");
+
+ const auto *source_obj = obj->getObject("source");
+ ASSERT_NE(source_obj, nullptr);
+ EXPECT_EQ(source_obj->getString("name"), "testSource");
+ EXPECT_EQ(source_obj->getString("path"), "/path/to/source");
+ EXPECT_EQ(source_obj->getInteger("sourceReference"), 12345);
+ EXPECT_EQ(source_obj->getString("presentationHint"), "normal");
+
+ EXPECT_EQ(obj->getInteger("line"), 42);
+ EXPECT_EQ(obj->getInteger("column"), 5);
+ EXPECT_EQ(obj->getInteger("endLine"), 50);
+ EXPECT_EQ(obj->getInteger("endColumn"), 10);
+ EXPECT_EQ(obj->getString("instructionReference"), "0x1234");
+ EXPECT_EQ(obj->getInteger("offset"), -4);
+ EXPECT_EQ(obj->getString("reason"), "pending");
+}
\ No newline at end of file
|
LGTM. tiny nit for concrete types |
@da-viper I don't see your comment, is it possible it wasn't submitted? |
const json::Object *obj = value.getAsObject(); | ||
ASSERT_NE(obj, nullptr); | ||
|
||
EXPECT_EQ(obj->getString("filter"), "testFilter"); | ||
EXPECT_EQ(obj->getString("label"), "Test Filter"); | ||
EXPECT_EQ(obj->getString("description"), "This is a test filter"); | ||
EXPECT_EQ(obj->getBoolean("default"), true); | ||
EXPECT_EQ(obj->getBoolean("supportsCondition"), true); | ||
EXPECT_EQ(obj->getString("conditionDescription"), | ||
"Condition for test filter"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we make a helper for matching these with a string literal? Something like:
MATCHER_P(equalToDAP, msg,
"Protocol Message " + llvm::to_string(msg)) {
if (toJSON(arg) != json::parse(msg)) {
*result_listener << llvm::formatv("expected:\n{0:2}\ngot\n{1:2}",
toJSON(msg), toJSON(arg))
.str();
return false;
}
return true;
}
And then use:
EXPECT_THAT(filter, equalToDAP(R"json({"filter": "testFilter",...})json"));
I think that might help improve the brevity of these tests and help account for some additional fields or defaults that may appear in some structs.
We might be able to make the test case into a vector<pair<protocol::Message, string>>
to make it easier to add cases as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about ways to make the test easier to write. I'm not super thrilled about putting JSON into the tests but maybe it's not worse than how verbose the current approach is. I think my preference would be to have what I did for the Source
struct: if every type has both a fromJSON and toJSON, then we can just roundtrip every object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make it more of a convention to have both going forward for testing purposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, if that's the direction, let me start by landing the Source
test and we can support the other types in a similar fashion as we add support for serialization.
Add unit tests for serializing and deserializing protocol types.
5fdd0d6
to
aaae07d
Compare
Updated the PR and settled on the roundtrip approach for |
Add unit tests for serializing and deserializing protocol types.