Author: Jonas Devlieghere
Date: 2025-05-13T22:51:03-07:00
New Revision: ad2f7034a2823f2366e55a5758c1c623b9348746

URL: 
https://github.com/llvm/llvm-project/commit/ad2f7034a2823f2366e55a5758c1c623b9348746
DIFF: 
https://github.com/llvm/llvm-project/commit/ad2f7034a2823f2366e55a5758c1c623b9348746.diff

LOG: [lldb-dap] Add unit test for capabilities (#139835)

Add unit a test for the capabilities type.

Added: 
    

Modified: 
    lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
    lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
    lldb/unittests/DAP/ProtocolTypesTest.cpp

Removed: 
    


################################################################################
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);
+}


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to