-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[lldb-dap] Add unit test for capabilities #139835
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
[lldb-dap] Add unit test for capabilities #139835
Conversation
Add unit a test for the capabilities types.
@llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) ChangesAdd unit a test for the capabilities types. Full diff: https://github.com/llvm/llvm-project/pull/139835.diff 3 Files Affected:
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
index 8d95687e00e53..fafd061334bc9 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
@@ -165,6 +165,32 @@ json::Value toJSON(const ChecksumAlgorithm &CA) {
llvm_unreachable("unhandled checksum algorithm.");
}
+bool fromJSON(const llvm::json::Value &Params, ChecksumAlgorithm &CA,
+ llvm::json::Path P) {
+ auto rawAlgorithm = Params.getAsString();
+ if (!rawAlgorithm) {
+ P.report("expected a string");
+ return false;
+ }
+
+ std::optional<ChecksumAlgorithm> algorithm =
+ llvm::StringSwitch<std::optional<ChecksumAlgorithm>>(*rawAlgorithm)
+ .Case("MD5", eChecksumAlgorithmMD5)
+ .Case("SHA1", eChecksumAlgorithmSHA1)
+ .Case("SHA256", eChecksumAlgorithmSHA256)
+ .Case("timestamp", eChecksumAlgorithmTimestamp)
+ .Default(std::nullopt);
+
+ if (!algorithm) {
+ P.report(
+ "unexpected value, expected 'MD5', 'SHA1', 'SHA256', or 'timestamp'");
+ return false;
+ }
+
+ CA = *algorithm;
+ return true;
+}
+
json::Value toJSON(const BreakpointModeApplicability &BMA) {
switch (BMA) {
case eBreakpointModeApplicabilitySource:
@@ -304,6 +330,84 @@ static llvm::StringLiteral ToString(AdapterFeature feature) {
llvm_unreachable("unhandled adapter feature.");
}
+llvm::json::Value toJSON(const AdapterFeature &feature) {
+ return ToString(feature);
+}
+
+bool fromJSON(const llvm::json::Value &Params, AdapterFeature &feature,
+ llvm::json::Path P) {
+ auto rawFeature = Params.getAsString();
+ if (!rawFeature) {
+ P.report("expected a string");
+ return false;
+ }
+
+ std::optional<AdapterFeature> parsedFeature =
+ llvm::StringSwitch<std::optional<AdapterFeature>>(*rawFeature)
+ .Case("supportsANSIStyling", eAdapterFeatureANSIStyling)
+ .Case("supportsBreakpointLocationsRequest",
+ eAdapterFeatureBreakpointLocationsRequest)
+ .Case("supportsCancelRequest", eAdapterFeatureCancelRequest)
+ .Case("supportsClipboardContext", eAdapterFeatureClipboardContext)
+ .Case("supportsCompletionsRequest", eAdapterFeatureCompletionsRequest)
+ .Case("supportsConditionalBreakpoints",
+ eAdapterFeatureConditionalBreakpoints)
+ .Case("supportsConfigurationDoneRequest",
+ eAdapterFeatureConfigurationDoneRequest)
+ .Case("supportsDataBreakpointBytes",
+ eAdapterFeatureDataBreakpointBytes)
+ .Case("supportsDataBreakpoints", eAdapterFeatureDataBreakpoints)
+ .Case("supportsDelayedStackTraceLoading",
+ eAdapterFeatureDelayedStackTraceLoading)
+ .Case("supportsDisassembleRequest", eAdapterFeatureDisassembleRequest)
+ .Case("supportsEvaluateForHovers", eAdapterFeatureEvaluateForHovers)
+ .Case("supportsExceptionFilterOptions",
+ eAdapterFeatureExceptionFilterOptions)
+ .Case("supportsExceptionInfoRequest",
+ eAdapterFeatureExceptionInfoRequest)
+ .Case("supportsExceptionOptions", eAdapterFeatureExceptionOptions)
+ .Case("supportsFunctionBreakpoints",
+ eAdapterFeatureFunctionBreakpoints)
+ .Case("supportsGotoTargetsRequest", eAdapterFeatureGotoTargetsRequest)
+ .Case("supportsHitConditionalBreakpoints",
+ eAdapterFeatureHitConditionalBreakpoints)
+ .Case("supportsInstructionBreakpoints",
+ eAdapterFeatureInstructionBreakpoints)
+ .Case("supportsLoadedSourcesRequest",
+ eAdapterFeatureLoadedSourcesRequest)
+ .Case("supportsLogPoints", eAdapterFeatureLogPoints)
+ .Case("supportsModulesRequest", eAdapterFeatureModulesRequest)
+ .Case("supportsReadMemoryRequest", eAdapterFeatureReadMemoryRequest)
+ .Case("supportsRestartFrame", eAdapterFeatureRestartFrame)
+ .Case("supportsRestartRequest", eAdapterFeatureRestartRequest)
+ .Case("supportsSetExpression", eAdapterFeatureSetExpression)
+ .Case("supportsSetVariable", eAdapterFeatureSetVariable)
+ .Case("supportsSingleThreadExecutionRequests",
+ eAdapterFeatureSingleThreadExecutionRequests)
+ .Case("supportsStepBack", eAdapterFeatureStepBack)
+ .Case("supportsStepInTargetsRequest",
+ eAdapterFeatureStepInTargetsRequest)
+ .Case("supportsSteppingGranularity",
+ eAdapterFeatureSteppingGranularity)
+ .Case("supportsTerminateRequest", eAdapterFeatureTerminateRequest)
+ .Case("supportsTerminateThreadsRequest",
+ eAdapterFeatureTerminateThreadsRequest)
+ .Case("supportSuspendDebuggee", eAdapterFeatureSuspendDebuggee)
+ .Case("supportsValueFormattingOptions",
+ eAdapterFeatureValueFormattingOptions)
+ .Case("supportsWriteMemoryRequest", eAdapterFeatureWriteMemoryRequest)
+ .Case("supportTerminateDebuggee", eAdapterFeatureTerminateDebuggee)
+ .Default(std::nullopt);
+
+ if (!parsedFeature) {
+ P.report("unexpected value for AdapterFeature");
+ return false;
+ }
+
+ feature = *parsedFeature;
+ return true;
+}
+
json::Value toJSON(const Capabilities &C) {
json::Object result;
@@ -331,6 +435,32 @@ json::Value toJSON(const Capabilities &C) {
return result;
}
+bool fromJSON(const llvm::json::Value &Params, Capabilities &C,
+ llvm::json::Path P) {
+ auto *Object = Params.getAsObject();
+ if (!Object) {
+ P.report("expected an object");
+ return false;
+ }
+ // Check for the presence of supported features.
+ for (unsigned i = eAdapterFeatureFirst; i <= eAdapterFeatureLast; ++i) {
+ AdapterFeature feature = static_cast<AdapterFeature>(i);
+ if (Object->getBoolean(ToString(feature)))
+ C.supportedFeatures.insert(feature);
+ }
+ llvm::json::ObjectMapper O(Params, P);
+ return O &&
+ O.mapOptional("exceptionBreakpointFilters",
+ C.exceptionBreakpointFilters) &&
+ O.mapOptional("completionTriggerCharacters",
+ C.completionTriggerCharacters) &&
+ O.mapOptional("additionalModuleColumns", C.additionalModuleColumns) &&
+ O.mapOptional("supportedChecksumAlgorithms",
+ C.supportedChecksumAlgorithms) &&
+ O.mapOptional("breakpointModes", C.breakpointModes) &&
+ O.mapOptional("$__lldb_version", C.lldbExtVersion);
+}
+
bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG,
llvm::json::Path P) {
auto raw_granularity = Params.getAsString();
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index c48988a48a373..f8d2b35ce3e14 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -102,6 +102,7 @@ enum ChecksumAlgorithm : unsigned {
eChecksumAlgorithmSHA256,
eChecksumAlgorithmTimestamp
};
+bool fromJSON(const llvm::json::Value &, ChecksumAlgorithm &, llvm::json::Path);
llvm::json::Value toJSON(const ChecksumAlgorithm &);
/// Describes one or more type of breakpoint a BreakpointMode applies to. This
@@ -237,7 +238,11 @@ enum AdapterFeature : unsigned {
/// The debug adapter supports the `terminateDebuggee` attribute on the
/// `disconnect` request.
eAdapterFeatureTerminateDebuggee,
+ eAdapterFeatureFirst = eAdapterFeatureANSIStyling,
+ eAdapterFeatureLast = eAdapterFeatureTerminateDebuggee,
};
+bool fromJSON(const llvm::json::Value &, AdapterFeature &, llvm::json::Path);
+llvm::json::Value toJSON(const AdapterFeature &);
/// Information about the capabilities of a debug adapter.
struct Capabilities {
@@ -275,13 +280,15 @@ struct Capabilities {
/// @}
};
+bool fromJSON(const llvm::json::Value &, Capabilities &, llvm::json::Path);
llvm::json::Value toJSON(const Capabilities &);
enum PresentationHint : unsigned {
ePresentationHintNormal,
ePresentationHintEmphasize,
- ePresentationHintDeemphasize,
+ ePresentationHintDeemphasize
};
+bool fromJSON(const llvm::json::Value &, PresentationHint &, llvm::json::Path);
llvm::json::Value toJSON(PresentationHint hint);
/// A `Source` is a descriptor for source code. It is returned from the debug
diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp
index f5d72f06432d5..fd3e3be073183 100644
--- a/lldb/unittests/DAP/ProtocolTypesTest.cpp
+++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp
@@ -194,3 +194,100 @@ TEST(ProtocolTypesTest, DataBreakpoint) {
EXPECT_EQ(data_breakpoint_info.hitCondition,
deserialized_data_breakpoint_info->hitCondition);
}
+
+TEST(ProtocolTypesTest, Capabilities) {
+ Capabilities capabilities;
+
+ // Populate supported features.
+ capabilities.supportedFeatures.insert(eAdapterFeatureANSIStyling);
+ capabilities.supportedFeatures.insert(
+ eAdapterFeatureBreakpointLocationsRequest);
+
+ // Populate optional fields.
+ capabilities.exceptionBreakpointFilters = {
+ {{"filter1", "Filter 1", "Description 1", true, true, "Condition 1"},
+ {"filter2", "Filter 2", "Description 2", false, false, "Condition 2"}}};
+
+ capabilities.completionTriggerCharacters = {".", "->"};
+ capabilities.additionalModuleColumns = {
+ {"moduleName", "Module Name", "uppercase", eColumnTypeString, 20}};
+ capabilities.supportedChecksumAlgorithms = {eChecksumAlgorithmMD5,
+ eChecksumAlgorithmSHA256};
+ capabilities.breakpointModes = {{"hardware",
+ "Hardware Breakpoint",
+ "Description",
+ {eBreakpointModeApplicabilitySource}}};
+ capabilities.lldbExtVersion = "1.0.0";
+
+ // Perform roundtrip serialization and deserialization.
+ llvm::Expected<Capabilities> deserialized_capabilities =
+ roundtrip(capabilities);
+ ASSERT_THAT_EXPECTED(deserialized_capabilities, llvm::Succeeded());
+
+ // Verify supported features.
+ EXPECT_EQ(capabilities.supportedFeatures,
+ deserialized_capabilities->supportedFeatures);
+
+ // Verify exception breakpoint filters.
+ ASSERT_TRUE(
+ deserialized_capabilities->exceptionBreakpointFilters.has_value());
+ EXPECT_EQ(capabilities.exceptionBreakpointFilters->size(),
+ deserialized_capabilities->exceptionBreakpointFilters->size());
+ for (size_t i = 0; i < capabilities.exceptionBreakpointFilters->size(); ++i) {
+ const auto &original = capabilities.exceptionBreakpointFilters->at(i);
+ const auto &deserialized =
+ deserialized_capabilities->exceptionBreakpointFilters->at(i);
+ EXPECT_EQ(original.filter, deserialized.filter);
+ EXPECT_EQ(original.label, deserialized.label);
+ EXPECT_EQ(original.description, deserialized.description);
+ EXPECT_EQ(original.defaultState, deserialized.defaultState);
+ EXPECT_EQ(original.supportsCondition, deserialized.supportsCondition);
+ EXPECT_EQ(original.conditionDescription, deserialized.conditionDescription);
+ }
+
+ // Verify completion trigger characters.
+ ASSERT_TRUE(
+ deserialized_capabilities->completionTriggerCharacters.has_value());
+ EXPECT_EQ(capabilities.completionTriggerCharacters,
+ deserialized_capabilities->completionTriggerCharacters);
+
+ // Verify additional module columns.
+ ASSERT_TRUE(deserialized_capabilities->additionalModuleColumns.has_value());
+ EXPECT_EQ(capabilities.additionalModuleColumns->size(),
+ deserialized_capabilities->additionalModuleColumns->size());
+ for (size_t i = 0; i < capabilities.additionalModuleColumns->size(); ++i) {
+ const auto &original = capabilities.additionalModuleColumns->at(i);
+ const auto &deserialized =
+ deserialized_capabilities->additionalModuleColumns->at(i);
+ EXPECT_EQ(original.attributeName, deserialized.attributeName);
+ EXPECT_EQ(original.label, deserialized.label);
+ EXPECT_EQ(original.format, deserialized.format);
+ EXPECT_EQ(original.type, deserialized.type);
+ EXPECT_EQ(original.width, deserialized.width);
+ }
+
+ // Verify supported checksum algorithms.
+ ASSERT_TRUE(
+ deserialized_capabilities->supportedChecksumAlgorithms.has_value());
+ EXPECT_EQ(capabilities.supportedChecksumAlgorithms,
+ deserialized_capabilities->supportedChecksumAlgorithms);
+
+ // Verify breakpoint modes.
+ ASSERT_TRUE(deserialized_capabilities->breakpointModes.has_value());
+ EXPECT_EQ(capabilities.breakpointModes->size(),
+ deserialized_capabilities->breakpointModes->size());
+ for (size_t i = 0; i < capabilities.breakpointModes->size(); ++i) {
+ const auto &original = capabilities.breakpointModes->at(i);
+ const auto &deserialized =
+ deserialized_capabilities->breakpointModes->at(i);
+ EXPECT_EQ(original.mode, deserialized.mode);
+ EXPECT_EQ(original.label, deserialized.label);
+ EXPECT_EQ(original.description, deserialized.description);
+ EXPECT_EQ(original.appliesTo, deserialized.appliesTo);
+ }
+
+ // Verify lldb extension version.
+ ASSERT_TRUE(deserialized_capabilities->lldbExtVersion.has_value());
+ EXPECT_EQ(capabilities.lldbExtVersion,
+ deserialized_capabilities->lldbExtVersion);
+}
|
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 also have some tests for invalid enum cases?
Sounds good, let me cover the enum cases in a separate PR. Edit: #139848 |
Add unit a test for the capabilities types.