Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[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

Merged

Conversation

JDevlieghere
Copy link
Member

Add unit a test for the capabilities types.

Add unit a test for the capabilities types.
@llvmbot
Copy link
Member

llvmbot commented May 14, 2025

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

Changes

Add unit a test for the capabilities types.


Full diff: https://github.com/llvm/llvm-project/pull/139835.diff

3 Files Affected:

  • (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp (+130)
  • (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.h (+8-1)
  • (modified) lldb/unittests/DAP/ProtocolTypesTest.cpp (+97)
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);
+}

Copy link
Contributor

@ashgti ashgti left a 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?

@JDevlieghere
Copy link
Member Author

JDevlieghere commented May 14, 2025

Should we also have some tests for invalid enum cases?

Sounds good, let me cover the enum cases in a separate PR.

Edit: #139848

@JDevlieghere JDevlieghere merged commit ad2f703 into llvm:main May 14, 2025
11 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.