Skip to content

[lldb-dap] Add unit test for ColumnDescriptor, BreakpointMode and Breakpoint #139627

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
merged 1 commit into from
May 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,28 @@ json::Value toJSON(const ExceptionBreakpointsFilter &EBF) {
return result;
}

bool fromJSON(const json::Value &Params, ColumnType &CT, json::Path P) {
auto rawColumnType = Params.getAsString();
if (!rawColumnType) {
P.report("expected a string");
return false;
}
std::optional<ColumnType> columnType =
StringSwitch<std::optional<ColumnType>>(*rawColumnType)
.Case("string", eColumnTypeString)
.Case("number", eColumnTypeNumber)
.Case("boolean", eColumnTypeBoolean)
.Case("unixTimestampUTC ", eColumnTypeTimestamp)
.Default(std::nullopt);
if (!columnType) {
P.report("unexpected value, expected 'string', 'number', 'boolean', or "
"'unixTimestampUTC'");
return false;
}
CT = *columnType;
return true;
}

json::Value toJSON(const ColumnType &T) {
switch (T) {
case eColumnTypeString:
Expand All @@ -108,6 +130,14 @@ json::Value toJSON(const ColumnType &T) {
llvm_unreachable("unhandled column type.");
}

bool fromJSON(const llvm::json::Value &Params, ColumnDescriptor &CD,
llvm::json::Path P) {
llvm::json::ObjectMapper O(Params, P);
return O && O.map("attributeName", CD.attributeName) &&
O.map("label", CD.label) && O.mapOptional("format", CD.format) &&
O.mapOptional("type", CD.type) && O.mapOptional("width", CD.width);
}

json::Value toJSON(const ColumnDescriptor &CD) {
json::Object result{{"attributeName", CD.attributeName}, {"label", CD.label}};

Expand Down Expand Up @@ -149,6 +179,30 @@ json::Value toJSON(const BreakpointModeApplicability &BMA) {
llvm_unreachable("unhandled breakpoint mode applicability.");
}

bool fromJSON(const llvm::json::Value &Params, BreakpointModeApplicability &BMA,
llvm::json::Path P) {
auto rawApplicability = Params.getAsString();
if (!rawApplicability) {
P.report("expected a string");
return false;
}
std::optional<BreakpointModeApplicability> applicability =
llvm::StringSwitch<std::optional<BreakpointModeApplicability>>(
*rawApplicability)
.Case("source", eBreakpointModeApplicabilitySource)
.Case("exception", eBreakpointModeApplicabilityException)
.Case("data", eBreakpointModeApplicabilityData)
.Case("instruction", eBreakpointModeApplicabilityInstruction)
.Default(std::nullopt);
if (!applicability) {
P.report("unexpected value, expected 'source', 'exception', 'data', or "
"'instruction'");
return false;
}
BMA = *applicability;
return true;
}

json::Value toJSON(const BreakpointMode &BM) {
json::Object result{
{"mode", BM.mode},
Expand All @@ -162,6 +216,14 @@ json::Value toJSON(const BreakpointMode &BM) {
return result;
}

bool fromJSON(const llvm::json::Value &Params, BreakpointMode &BM,
llvm::json::Path P) {
llvm::json::ObjectMapper O(Params, P);
return O && O.map("mode", BM.mode) && O.map("label", BM.label) &&
O.mapOptional("description", BM.description) &&
O.map("appliesTo", BM.appliesTo);
}

static llvm::StringLiteral ToString(AdapterFeature feature) {
switch (feature) {
case eAdapterFeatureANSIStyling:
Expand Down Expand Up @@ -320,6 +382,26 @@ llvm::json::Value toJSON(const BreakpointReason &BR) {
llvm_unreachable("unhandled breakpoint reason.");
}

bool fromJSON(const llvm::json::Value &Params, BreakpointReason &BR,
llvm::json::Path P) {
auto rawReason = Params.getAsString();
if (!rawReason) {
P.report("expected a string");
return false;
}
std::optional<BreakpointReason> reason =
llvm::StringSwitch<std::optional<BreakpointReason>>(*rawReason)
.Case("pending", BreakpointReason::eBreakpointReasonPending)
.Case("failed", BreakpointReason::eBreakpointReasonFailed)
.Default(std::nullopt);
if (!reason) {
P.report("unexpected value, expected 'pending' or 'failed'");
return false;
}
BR = *reason;
return true;
}

json::Value toJSON(const Breakpoint &BP) {
json::Object result{{"verified", BP.verified}};

Expand Down Expand Up @@ -348,6 +430,20 @@ json::Value toJSON(const Breakpoint &BP) {
return result;
}

bool fromJSON(const llvm::json::Value &Params, Breakpoint &BP,
llvm::json::Path P) {
llvm::json::ObjectMapper O(Params, P);
return O && O.mapOptional("id", BP.id) && O.map("verified", BP.verified) &&
O.mapOptional("message", BP.message) &&
O.mapOptional("source", BP.source) && O.mapOptional("line", BP.line) &&
O.mapOptional("column", BP.column) &&
O.mapOptional("endLine", BP.endLine) &&
O.mapOptional("endColumn", BP.endColumn) &&
O.mapOptional("instructionReference", BP.instructionReference) &&
O.mapOptional("offset", BP.offset) &&
O.mapOptional("reason", BP.reason);
}

bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB,
llvm::json::Path P) {
json::ObjectMapper O(Params, P);
Expand Down
8 changes: 8 additions & 0 deletions lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ enum ColumnType : unsigned {
eColumnTypeBoolean,
eColumnTypeTimestamp
};
bool fromJSON(const llvm::json::Value &, ColumnType &, llvm::json::Path);
llvm::json::Value toJSON(const ColumnType &);

/// A ColumnDescriptor specifies what module attribute to show in a column of
/// the modules view, how to format it, and what the column’s label should be.
Expand All @@ -89,6 +91,7 @@ struct ColumnDescriptor {
/// Width of this column in characters (hint only).
std::optional<int> width;
};
bool fromJSON(const llvm::json::Value &, ColumnDescriptor &, llvm::json::Path);
llvm::json::Value toJSON(const ColumnDescriptor &);

/// Names of checksum algorithms that may be supported by a debug adapter.
Expand All @@ -114,6 +117,8 @@ enum BreakpointModeApplicability : unsigned {
/// In `InstructionBreakpoint`'s.
eBreakpointModeApplicabilityInstruction
};
bool fromJSON(const llvm::json::Value &, BreakpointModeApplicability &,
llvm::json::Path);
llvm::json::Value toJSON(const BreakpointModeApplicability &);

/// A `BreakpointMode` is provided as a option when setting breakpoints on
Expand All @@ -133,6 +138,7 @@ struct BreakpointMode {
/// Describes one or more type of breakpoint this mode applies to.
std::vector<BreakpointModeApplicability> appliesTo;
};
bool fromJSON(const llvm::json::Value &, BreakpointMode &, llvm::json::Path);
llvm::json::Value toJSON(const BreakpointMode &);

/// Debug Adapter Features flags supported by lldb-dap.
Expand Down Expand Up @@ -364,6 +370,7 @@ enum class BreakpointReason : unsigned {
/// adapter does not believe it can be verified without intervention.
eBreakpointReasonFailed,
};
bool fromJSON(const llvm::json::Value &, BreakpointReason &, llvm::json::Path);
llvm::json::Value toJSON(const BreakpointReason &);

/// Information about a breakpoint created in `setBreakpoints`,
Expand Down Expand Up @@ -415,6 +422,7 @@ struct Breakpoint {
/// should omit this property.
std::optional<BreakpointReason> reason;
};
bool fromJSON(const llvm::json::Value &, Breakpoint &, llvm::json::Path);
llvm::json::Value toJSON(const Breakpoint &);

/// Properties of a breakpoint or logpoint passed to the `setBreakpoints`
Expand Down
72 changes: 72 additions & 0 deletions lldb/unittests/DAP/ProtocolTypesTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,75 @@ TEST(ProtocolTypesTest, Source) {
EXPECT_EQ(source.sourceReference, deserialized_source->sourceReference);
EXPECT_EQ(source.presentationHint, deserialized_source->presentationHint);
}

TEST(ProtocolTypesTest, ColumnDescriptor) {
ColumnDescriptor column;
column.attributeName = "moduleName";
column.label = "Module Name";
column.format = "uppercase";
column.type = eColumnTypeString;
column.width = 20;

llvm::Expected<ColumnDescriptor> deserialized_column = roundtrip(column);
ASSERT_THAT_EXPECTED(deserialized_column, llvm::Succeeded());

EXPECT_EQ(column.attributeName, deserialized_column->attributeName);
EXPECT_EQ(column.label, deserialized_column->label);
EXPECT_EQ(column.format, deserialized_column->format);
EXPECT_EQ(column.type, deserialized_column->type);
EXPECT_EQ(column.width, deserialized_column->width);
}

TEST(ProtocolTypesTest, BreakpointMode) {
BreakpointMode mode;
mode.mode = "testMode";
mode.label = "Test Mode";
mode.description = "This is a test mode";
mode.appliesTo = {eBreakpointModeApplicabilitySource,
eBreakpointModeApplicabilityException};

llvm::Expected<BreakpointMode> deserialized_mode = roundtrip(mode);
ASSERT_THAT_EXPECTED(deserialized_mode, llvm::Succeeded());

EXPECT_EQ(mode.mode, deserialized_mode->mode);
EXPECT_EQ(mode.label, deserialized_mode->label);
EXPECT_EQ(mode.description, deserialized_mode->description);
EXPECT_EQ(mode.appliesTo, deserialized_mode->appliesTo);
}

TEST(ProtocolTypesTest, Breakpoint) {
Breakpoint breakpoint;
breakpoint.id = 42;
breakpoint.verified = true;
breakpoint.message = "Breakpoint set successfully";
breakpoint.source =
Source{"test.cpp", "/path/to/test.cpp", 123, ePresentationHintNormal};
breakpoint.line = 10;
breakpoint.column = 5;
breakpoint.endLine = 15;
breakpoint.endColumn = 10;
breakpoint.instructionReference = "0x12345678";
breakpoint.offset = 4;
breakpoint.reason = BreakpointReason::eBreakpointReasonPending;

llvm::Expected<Breakpoint> deserialized_breakpoint = roundtrip(breakpoint);
ASSERT_THAT_EXPECTED(deserialized_breakpoint, llvm::Succeeded());

EXPECT_EQ(breakpoint.id, deserialized_breakpoint->id);
EXPECT_EQ(breakpoint.verified, deserialized_breakpoint->verified);
EXPECT_EQ(breakpoint.message, deserialized_breakpoint->message);
EXPECT_EQ(breakpoint.source->name, deserialized_breakpoint->source->name);
EXPECT_EQ(breakpoint.source->path, deserialized_breakpoint->source->path);
EXPECT_EQ(breakpoint.source->sourceReference,
deserialized_breakpoint->source->sourceReference);
EXPECT_EQ(breakpoint.source->presentationHint,
deserialized_breakpoint->source->presentationHint);
EXPECT_EQ(breakpoint.line, deserialized_breakpoint->line);
EXPECT_EQ(breakpoint.column, deserialized_breakpoint->column);
EXPECT_EQ(breakpoint.endLine, deserialized_breakpoint->endLine);
EXPECT_EQ(breakpoint.endColumn, deserialized_breakpoint->endColumn);
EXPECT_EQ(breakpoint.instructionReference,
deserialized_breakpoint->instructionReference);
EXPECT_EQ(breakpoint.offset, deserialized_breakpoint->offset);
EXPECT_EQ(breakpoint.reason, deserialized_breakpoint->reason);
}
Loading