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