1//===-- ProtocolTypesTest.cpp -----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Protocol/ProtocolTypes.h"
10#include "Protocol/ProtocolEvents.h"
11#include "Protocol/ProtocolRequests.h"
12#include "TestingSupport/TestUtilities.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/Support/JSON.h"
15#include "llvm/Testing/Support/Error.h"
16#include "gmock/gmock.h"
17#include "gtest/gtest.h"
18#include <optional>
19
20using namespace llvm;
21using namespace lldb;
22using namespace lldb_dap;
23using namespace lldb_dap::protocol;
24using lldb_private::roundtripJSON;
25using llvm::json::parse;
26using llvm::json::Value;
27
28/// Returns a pretty printed json string of a `llvm::json::Value`.
29static std::string pp(const json::Value &E) {
30 return formatv(Fmt: "{0:2}", Vals: E).str();
31}
32
33TEST(ProtocolTypesTest, ExceptionBreakpointsFilter) {
34 ExceptionBreakpointsFilter filter;
35 filter.filter = "testFilter";
36 filter.label = "Test Filter";
37 filter.description = "This is a test filter";
38 filter.defaultState = true;
39 filter.supportsCondition = true;
40 filter.conditionDescription = "Condition for test filter";
41
42 llvm::Expected<ExceptionBreakpointsFilter> deserialized_filter =
43 roundtripJSON(input: filter);
44 ASSERT_THAT_EXPECTED(deserialized_filter, llvm::Succeeded());
45
46 EXPECT_EQ(filter.filter, deserialized_filter->filter);
47 EXPECT_EQ(filter.label, deserialized_filter->label);
48 EXPECT_EQ(filter.description, deserialized_filter->description);
49 EXPECT_EQ(filter.defaultState, deserialized_filter->defaultState);
50 EXPECT_EQ(filter.supportsCondition, deserialized_filter->supportsCondition);
51 EXPECT_EQ(filter.conditionDescription,
52 deserialized_filter->conditionDescription);
53}
54
55TEST(ProtocolTypesTest, Source) {
56 Source source;
57 source.name = "testName";
58 source.path = "/path/to/source";
59 source.sourceReference = 12345;
60 source.presentationHint = Source::eSourcePresentationHintEmphasize;
61
62 llvm::Expected<Source> deserialized_source = roundtripJSON(input: source);
63 ASSERT_THAT_EXPECTED(deserialized_source, llvm::Succeeded());
64
65 EXPECT_EQ(source.name, deserialized_source->name);
66 EXPECT_EQ(source.path, deserialized_source->path);
67 EXPECT_EQ(source.sourceReference, deserialized_source->sourceReference);
68 EXPECT_EQ(source.presentationHint, deserialized_source->presentationHint);
69}
70
71TEST(ProtocolTypesTest, ColumnDescriptor) {
72 ColumnDescriptor column;
73 column.attributeName = "moduleName";
74 column.label = "Module Name";
75 column.format = "uppercase";
76 column.type = eColumnTypeString;
77 column.width = 20;
78
79 llvm::Expected<ColumnDescriptor> deserialized_column = roundtripJSON(input: column);
80 ASSERT_THAT_EXPECTED(deserialized_column, llvm::Succeeded());
81
82 EXPECT_EQ(column.attributeName, deserialized_column->attributeName);
83 EXPECT_EQ(column.label, deserialized_column->label);
84 EXPECT_EQ(column.format, deserialized_column->format);
85 EXPECT_EQ(column.type, deserialized_column->type);
86 EXPECT_EQ(column.width, deserialized_column->width);
87}
88
89TEST(ProtocolTypesTest, BreakpointMode) {
90 BreakpointMode mode;
91 mode.mode = "testMode";
92 mode.label = "Test Mode";
93 mode.description = "This is a test mode";
94 mode.appliesTo = {eBreakpointModeApplicabilitySource,
95 eBreakpointModeApplicabilityException};
96
97 llvm::Expected<BreakpointMode> deserialized_mode = roundtripJSON(input: mode);
98 ASSERT_THAT_EXPECTED(deserialized_mode, llvm::Succeeded());
99
100 EXPECT_EQ(mode.mode, deserialized_mode->mode);
101 EXPECT_EQ(mode.label, deserialized_mode->label);
102 EXPECT_EQ(mode.description, deserialized_mode->description);
103 EXPECT_EQ(mode.appliesTo, deserialized_mode->appliesTo);
104}
105
106TEST(ProtocolTypesTest, Breakpoint) {
107 Breakpoint breakpoint;
108 breakpoint.id = 42;
109 breakpoint.verified = true;
110 breakpoint.message = "Breakpoint set successfully";
111 breakpoint.source = Source{.name: "test.cpp", .path: "/path/to/test.cpp", .sourceReference: 123,
112 .presentationHint: Source::eSourcePresentationHintNormal};
113 breakpoint.line = 10;
114 breakpoint.column = 5;
115 breakpoint.endLine = 15;
116 breakpoint.endColumn = 10;
117 breakpoint.instructionReference = "0x12345678";
118 breakpoint.offset = 4;
119 breakpoint.reason = BreakpointReason::eBreakpointReasonPending;
120
121 llvm::Expected<Breakpoint> deserialized_breakpoint =
122 roundtripJSON(input: breakpoint);
123 ASSERT_THAT_EXPECTED(deserialized_breakpoint, llvm::Succeeded());
124
125 EXPECT_EQ(breakpoint.id, deserialized_breakpoint->id);
126 EXPECT_EQ(breakpoint.verified, deserialized_breakpoint->verified);
127 EXPECT_EQ(breakpoint.message, deserialized_breakpoint->message);
128 EXPECT_EQ(breakpoint.source->name, deserialized_breakpoint->source->name);
129 EXPECT_EQ(breakpoint.source->path, deserialized_breakpoint->source->path);
130 EXPECT_EQ(breakpoint.source->sourceReference,
131 deserialized_breakpoint->source->sourceReference);
132 EXPECT_EQ(breakpoint.source->presentationHint,
133 deserialized_breakpoint->source->presentationHint);
134 EXPECT_EQ(breakpoint.line, deserialized_breakpoint->line);
135 EXPECT_EQ(breakpoint.column, deserialized_breakpoint->column);
136 EXPECT_EQ(breakpoint.endLine, deserialized_breakpoint->endLine);
137 EXPECT_EQ(breakpoint.endColumn, deserialized_breakpoint->endColumn);
138 EXPECT_EQ(breakpoint.instructionReference,
139 deserialized_breakpoint->instructionReference);
140 EXPECT_EQ(breakpoint.offset, deserialized_breakpoint->offset);
141 EXPECT_EQ(breakpoint.reason, deserialized_breakpoint->reason);
142}
143
144TEST(ProtocolTypesTest, SourceBreakpoint) {
145 SourceBreakpoint source_breakpoint;
146 source_breakpoint.line = 42;
147 source_breakpoint.column = 5;
148 source_breakpoint.condition = "x > 10";
149 source_breakpoint.hitCondition = "5";
150 source_breakpoint.logMessage = "Breakpoint hit at line 42";
151 source_breakpoint.mode = "hardware";
152
153 llvm::Expected<SourceBreakpoint> deserialized_source_breakpoint =
154 roundtripJSON(input: source_breakpoint);
155 ASSERT_THAT_EXPECTED(deserialized_source_breakpoint, llvm::Succeeded());
156
157 EXPECT_EQ(source_breakpoint.line, deserialized_source_breakpoint->line);
158 EXPECT_EQ(source_breakpoint.column, deserialized_source_breakpoint->column);
159 EXPECT_EQ(source_breakpoint.condition,
160 deserialized_source_breakpoint->condition);
161 EXPECT_EQ(source_breakpoint.hitCondition,
162 deserialized_source_breakpoint->hitCondition);
163 EXPECT_EQ(source_breakpoint.logMessage,
164 deserialized_source_breakpoint->logMessage);
165 EXPECT_EQ(source_breakpoint.mode, deserialized_source_breakpoint->mode);
166}
167
168TEST(ProtocolTypesTest, FunctionBreakpoint) {
169 FunctionBreakpoint function_breakpoint;
170 function_breakpoint.name = "myFunction";
171 function_breakpoint.condition = "x == 0";
172 function_breakpoint.hitCondition = "3";
173
174 llvm::Expected<FunctionBreakpoint> deserialized_function_breakpoint =
175 roundtripJSON(input: function_breakpoint);
176 ASSERT_THAT_EXPECTED(deserialized_function_breakpoint, llvm::Succeeded());
177
178 EXPECT_EQ(function_breakpoint.name, deserialized_function_breakpoint->name);
179 EXPECT_EQ(function_breakpoint.condition,
180 deserialized_function_breakpoint->condition);
181 EXPECT_EQ(function_breakpoint.hitCondition,
182 deserialized_function_breakpoint->hitCondition);
183}
184
185TEST(ProtocolTypesTest, DataBreakpoint) {
186 DataBreakpoint data_breakpoint_info;
187 data_breakpoint_info.dataId = "variable1";
188 data_breakpoint_info.accessType = eDataBreakpointAccessTypeReadWrite;
189 data_breakpoint_info.condition = "x > 100";
190 data_breakpoint_info.hitCondition = "10";
191
192 llvm::Expected<DataBreakpoint> deserialized_data_breakpoint_info =
193 roundtripJSON(input: data_breakpoint_info);
194 ASSERT_THAT_EXPECTED(deserialized_data_breakpoint_info, llvm::Succeeded());
195
196 EXPECT_EQ(data_breakpoint_info.dataId,
197 deserialized_data_breakpoint_info->dataId);
198 EXPECT_EQ(data_breakpoint_info.accessType,
199 deserialized_data_breakpoint_info->accessType);
200 EXPECT_EQ(data_breakpoint_info.condition,
201 deserialized_data_breakpoint_info->condition);
202 EXPECT_EQ(data_breakpoint_info.hitCondition,
203 deserialized_data_breakpoint_info->hitCondition);
204}
205
206TEST(ProtocolTypesTest, Capabilities) {
207 Capabilities capabilities;
208
209 // Populate supported features.
210 capabilities.supportedFeatures.insert(V: eAdapterFeatureANSIStyling);
211 capabilities.supportedFeatures.insert(
212 V: eAdapterFeatureBreakpointLocationsRequest);
213
214 // Populate optional fields.
215 capabilities.exceptionBreakpointFilters = {
216 {{.filter: "filter1", .label: "Filter 1", .description: "Description 1", .defaultState: true, .supportsCondition: true, .conditionDescription: "Condition 1"},
217 {.filter: "filter2", .label: "Filter 2", .description: "Description 2", .defaultState: false, .supportsCondition: false, .conditionDescription: "Condition 2"}}};
218
219 capabilities.completionTriggerCharacters = {".", "->"};
220 capabilities.additionalModuleColumns = {
221 {.attributeName: "moduleName", .label: "Module Name", .format: "uppercase", .type: eColumnTypeString, .width: 20}};
222 capabilities.supportedChecksumAlgorithms = {eChecksumAlgorithmMD5,
223 eChecksumAlgorithmSHA256};
224 capabilities.breakpointModes = {{.mode: "hardware",
225 .label: "Hardware Breakpoint",
226 .description: "Description",
227 .appliesTo: {eBreakpointModeApplicabilitySource}}};
228 capabilities.lldbExtVersion = "1.0.0";
229
230 // Perform roundtripJSON serialization and deserialization.
231 llvm::Expected<Capabilities> deserialized_capabilities =
232 roundtripJSON(input: capabilities);
233 ASSERT_THAT_EXPECTED(deserialized_capabilities, llvm::Succeeded());
234
235 // Verify supported features.
236 EXPECT_EQ(capabilities.supportedFeatures,
237 deserialized_capabilities->supportedFeatures);
238
239 // Verify exception breakpoint filters.
240 EXPECT_EQ(capabilities.exceptionBreakpointFilters.size(),
241 deserialized_capabilities->exceptionBreakpointFilters.size());
242 for (size_t i = 0; i < capabilities.exceptionBreakpointFilters.size(); ++i) {
243 const auto &original = capabilities.exceptionBreakpointFilters.at(n: i);
244 const auto &deserialized =
245 deserialized_capabilities->exceptionBreakpointFilters.at(n: i);
246 EXPECT_EQ(original.filter, deserialized.filter);
247 EXPECT_EQ(original.label, deserialized.label);
248 EXPECT_EQ(original.description, deserialized.description);
249 EXPECT_EQ(original.defaultState, deserialized.defaultState);
250 EXPECT_EQ(original.supportsCondition, deserialized.supportsCondition);
251 EXPECT_EQ(original.conditionDescription, deserialized.conditionDescription);
252 }
253
254 // Verify completion trigger characters.
255 EXPECT_EQ(capabilities.completionTriggerCharacters,
256 deserialized_capabilities->completionTriggerCharacters);
257
258 // Verify additional module columns.
259 EXPECT_EQ(capabilities.additionalModuleColumns.size(),
260 deserialized_capabilities->additionalModuleColumns.size());
261 for (size_t i = 0; i < capabilities.additionalModuleColumns.size(); ++i) {
262 const auto &original = capabilities.additionalModuleColumns.at(n: i);
263 const auto &deserialized =
264 deserialized_capabilities->additionalModuleColumns.at(n: i);
265 EXPECT_EQ(original.attributeName, deserialized.attributeName);
266 EXPECT_EQ(original.label, deserialized.label);
267 EXPECT_EQ(original.format, deserialized.format);
268 EXPECT_EQ(original.type, deserialized.type);
269 EXPECT_EQ(original.width, deserialized.width);
270 }
271
272 // Verify supported checksum algorithms.
273 EXPECT_EQ(capabilities.supportedChecksumAlgorithms,
274 deserialized_capabilities->supportedChecksumAlgorithms);
275
276 // Verify breakpoint modes.
277 EXPECT_EQ(capabilities.breakpointModes.size(),
278 deserialized_capabilities->breakpointModes.size());
279 for (size_t i = 0; i < capabilities.breakpointModes.size(); ++i) {
280 const auto &original = capabilities.breakpointModes.at(n: i);
281 const auto &deserialized = deserialized_capabilities->breakpointModes.at(n: i);
282 EXPECT_EQ(original.mode, deserialized.mode);
283 EXPECT_EQ(original.label, deserialized.label);
284 EXPECT_EQ(original.description, deserialized.description);
285 EXPECT_EQ(original.appliesTo, deserialized.appliesTo);
286 }
287
288 // Verify lldb extension version.
289 EXPECT_EQ(capabilities.lldbExtVersion,
290 deserialized_capabilities->lldbExtVersion);
291}
292
293TEST(ProtocolTypesTest, Scope) {
294 Scope scope;
295 scope.name = "Locals";
296 scope.presentationHint = Scope::eScopePresentationHintLocals;
297 scope.variablesReference = 1;
298 scope.namedVariables = 2;
299 scope.indexedVariables = std::nullopt;
300 scope.expensive = false;
301 scope.line = 2;
302 scope.column = 3;
303 scope.endLine = 10;
304 scope.endColumn = 20;
305
306 Source source;
307 source.name = "testName";
308 source.path = "/path/to/source";
309 source.sourceReference = 12345;
310 source.presentationHint = Source::eSourcePresentationHintNormal;
311 scope.source = source;
312
313 llvm::Expected<Scope> deserialized_scope = roundtripJSON(input: scope);
314 ASSERT_THAT_EXPECTED(deserialized_scope, llvm::Succeeded());
315 EXPECT_EQ(scope.name, deserialized_scope->name);
316 EXPECT_EQ(scope.presentationHint, deserialized_scope->presentationHint);
317 EXPECT_EQ(scope.variablesReference, deserialized_scope->variablesReference);
318 EXPECT_EQ(scope.namedVariables, deserialized_scope->namedVariables);
319 EXPECT_EQ(scope.indexedVariables, deserialized_scope->indexedVariables);
320 EXPECT_EQ(scope.expensive, deserialized_scope->expensive);
321 EXPECT_EQ(scope.line, deserialized_scope->line);
322 EXPECT_EQ(scope.column, deserialized_scope->column);
323 EXPECT_EQ(scope.endLine, deserialized_scope->endLine);
324 EXPECT_EQ(scope.endColumn, deserialized_scope->endColumn);
325
326 EXPECT_THAT(deserialized_scope->source.has_value(), true);
327 const Source &deserialized_source = deserialized_scope->source.value();
328
329 EXPECT_EQ(source.path, deserialized_source.path);
330 EXPECT_EQ(source.sourceReference, deserialized_source.sourceReference);
331 EXPECT_EQ(source.presentationHint, deserialized_source.presentationHint);
332}
333
334TEST(ProtocolTypesTest, PresentationHint) {
335 // Test all PresentationHint values.
336 std::vector<std::pair<Source::PresentationHint, llvm::StringRef>> test_cases =
337 {{Source::eSourcePresentationHintNormal, "normal"},
338 {Source::eSourcePresentationHintEmphasize, "emphasize"},
339 {Source::eSourcePresentationHintDeemphasize, "deemphasize"}};
340
341 for (const auto &test_case : test_cases) {
342 // Serialize the PresentationHint to JSON.
343 llvm::json::Value serialized = toJSON(test_case.first);
344 ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
345 EXPECT_EQ(serialized.getAsString(), test_case.second);
346
347 // Deserialize the JSON back to PresentationHint.
348 Source::PresentationHint deserialized;
349 llvm::json::Path::Root root;
350 ASSERT_TRUE(fromJSON(serialized, deserialized, root))
351 << llvm::toString(E: root.getError());
352 EXPECT_EQ(deserialized, test_case.first);
353 }
354
355 // Test invalid value.
356 llvm::json::Value invalid_value = "invalid_hint";
357 Source::PresentationHint deserialized_invalid;
358 llvm::json::Path::Root root;
359 EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
360}
361
362TEST(ProtocolTypesTest, SteppingGranularity) {
363 // Test all SteppingGranularity values.
364 std::vector<std::pair<SteppingGranularity, llvm::StringRef>> test_cases = {
365 {eSteppingGranularityStatement, "statement"},
366 {eSteppingGranularityLine, "line"},
367 {eSteppingGranularityInstruction, "instruction"}};
368
369 for (const auto &test_case : test_cases) {
370 // Serialize the SteppingGranularity to JSON.
371 llvm::json::Value serialized = toJSON(test_case.first);
372 ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
373 EXPECT_EQ(serialized.getAsString(), test_case.second);
374
375 // Deserialize the JSON back to SteppingGranularity.
376 SteppingGranularity deserialized;
377 llvm::json::Path::Root root;
378 ASSERT_TRUE(fromJSON(serialized, deserialized, root))
379 << llvm::toString(E: root.getError());
380 EXPECT_EQ(deserialized, test_case.first);
381 }
382
383 // Test invalid value.
384 llvm::json::Value invalid_value = "invalid_granularity";
385 SteppingGranularity deserialized_invalid;
386 llvm::json::Path::Root root;
387 EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
388}
389
390TEST(ProtocolTypesTest, BreakpointReason) {
391 // Test all BreakpointReason values.
392 std::vector<std::pair<BreakpointReason, llvm::StringRef>> test_cases = {
393 {BreakpointReason::eBreakpointReasonPending, "pending"},
394 {BreakpointReason::eBreakpointReasonFailed, "failed"}};
395
396 for (const auto &test_case : test_cases) {
397 // Serialize the BreakpointReason to JSON.
398 llvm::json::Value serialized = toJSON(test_case.first);
399 ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
400 EXPECT_EQ(serialized.getAsString(), test_case.second);
401
402 // Deserialize the JSON back to BreakpointReason.
403 BreakpointReason deserialized;
404 llvm::json::Path::Root root;
405 ASSERT_TRUE(fromJSON(serialized, deserialized, root))
406 << llvm::toString(E: root.getError());
407 EXPECT_EQ(deserialized, test_case.first);
408 }
409
410 // Test invalid value.
411 llvm::json::Value invalid_value = "invalid_reason";
412 BreakpointReason deserialized_invalid;
413 llvm::json::Path::Root root;
414 EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
415}
416
417TEST(ProtocolTypesTest, DataBreakpointAccessType) {
418 // Test all DataBreakpointAccessType values.
419 std::vector<std::pair<DataBreakpointAccessType, llvm::StringRef>> test_cases =
420 {{eDataBreakpointAccessTypeRead, "read"},
421 {eDataBreakpointAccessTypeWrite, "write"},
422 {eDataBreakpointAccessTypeReadWrite, "readWrite"}};
423
424 for (const auto &test_case : test_cases) {
425 // Serialize the DataBreakpointAccessType to JSON.
426 llvm::json::Value serialized = toJSON(test_case.first);
427 ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
428 EXPECT_EQ(serialized.getAsString(), test_case.second);
429
430 // Deserialize the JSON back to DataBreakpointAccessType.
431 DataBreakpointAccessType deserialized;
432 llvm::json::Path::Root root;
433 ASSERT_TRUE(fromJSON(serialized, deserialized, root))
434 << llvm::toString(E: root.getError());
435 EXPECT_EQ(deserialized, test_case.first);
436 }
437
438 // Test invalid value
439 llvm::json::Value invalid_value = "invalid_access_type";
440 DataBreakpointAccessType deserialized_invalid;
441 llvm::json::Path::Root root;
442 EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
443}
444
445TEST(ProtocolTypesTest, ColumnType) {
446 // Test all ColumnType values.
447 std::vector<std::pair<ColumnType, llvm::StringRef>> test_cases = {
448 {eColumnTypeString, "string"},
449 {eColumnTypeNumber, "number"},
450 {eColumnTypeBoolean, "boolean"},
451 {eColumnTypeTimestamp, "unixTimestampUTC"}};
452
453 for (const auto &test_case : test_cases) {
454 // Serialize the ColumnType to JSON.
455 llvm::json::Value serialized = toJSON(test_case.first);
456 ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
457 EXPECT_EQ(serialized.getAsString(), test_case.second);
458
459 // Deserialize the JSON back to ColumnType.
460 ColumnType deserialized;
461 llvm::json::Path::Root root;
462 ASSERT_TRUE(fromJSON(serialized, deserialized, root))
463 << llvm::toString(E: root.getError());
464 EXPECT_EQ(deserialized, test_case.first);
465 }
466
467 // Test invalid value.
468 llvm::json::Value invalid_value = "invalid_column_type";
469 ColumnType deserialized_invalid;
470 llvm::json::Path::Root root;
471 EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
472}
473
474TEST(ProtocolTypesTest, BreakpointModeApplicability) {
475 // Test all BreakpointModeApplicability values.
476 std::vector<std::pair<BreakpointModeApplicability, llvm::StringRef>>
477 test_cases = {{eBreakpointModeApplicabilitySource, "source"},
478 {eBreakpointModeApplicabilityException, "exception"},
479 {eBreakpointModeApplicabilityData, "data"},
480 {eBreakpointModeApplicabilityInstruction, "instruction"}};
481
482 for (const auto &test_case : test_cases) {
483 // Serialize the BreakpointModeApplicability to JSON.
484 llvm::json::Value serialized = toJSON(test_case.first);
485 ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
486 EXPECT_EQ(serialized.getAsString(), test_case.second);
487
488 // Deserialize the JSON back to BreakpointModeApplicability.
489 BreakpointModeApplicability deserialized;
490 llvm::json::Path::Root root;
491 ASSERT_TRUE(fromJSON(serialized, deserialized, root))
492 << llvm::toString(E: root.getError());
493 EXPECT_EQ(deserialized, test_case.first);
494 }
495
496 // Test invalid value.
497 llvm::json::Value invalid_value = "invalid_applicability";
498 BreakpointModeApplicability deserialized_invalid;
499 llvm::json::Path::Root root;
500 EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
501}
502
503TEST(ProtocolTypesTest, ChecksumAlgorithm) {
504 // Test all ChecksumAlgorithm values.
505 std::vector<std::pair<ChecksumAlgorithm, llvm::StringRef>> test_cases = {
506 {eChecksumAlgorithmMD5, "MD5"},
507 {eChecksumAlgorithmSHA1, "SHA1"},
508 {eChecksumAlgorithmSHA256, "SHA256"},
509 {eChecksumAlgorithmTimestamp, "timestamp"}};
510
511 for (const auto &test_case : test_cases) {
512 // Serialize the ChecksumAlgorithm to JSON.
513 llvm::json::Value serialized = toJSON(test_case.first);
514 ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
515 EXPECT_EQ(serialized.getAsString(), test_case.second);
516
517 // Deserialize the JSON back to ChecksumAlgorithm.
518 ChecksumAlgorithm deserialized;
519 llvm::json::Path::Root root;
520 ASSERT_TRUE(fromJSON(serialized, deserialized, root))
521 << llvm::toString(E: root.getError());
522 EXPECT_EQ(deserialized, test_case.first);
523 }
524
525 // Test invalid value.
526 llvm::json::Value invalid_value = "invalid_algorithm";
527 ChecksumAlgorithm deserialized_invalid;
528 llvm::json::Path::Root root;
529 EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
530}
531
532TEST(ProtocolTypesTest, DisassembledInstructionPresentationHint) {
533 // Test all PresentationHint values.
534 std::vector<
535 std::pair<DisassembledInstruction::PresentationHint, llvm::StringRef>>
536 test_cases = {{DisassembledInstruction::
537 eDisassembledInstructionPresentationHintNormal,
538 "normal"},
539 {DisassembledInstruction::
540 eDisassembledInstructionPresentationHintInvalid,
541 "invalid"}};
542
543 for (const auto &test_case : test_cases) {
544 // Serialize the PresentationHint to JSON.
545 llvm::json::Value serialized = toJSON(test_case.first);
546 ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
547 EXPECT_EQ(serialized.getAsString(), test_case.second);
548
549 // Deserialize the JSON back to PresentationHint.
550 DisassembledInstruction::PresentationHint deserialized;
551 llvm::json::Path::Root root;
552 ASSERT_TRUE(fromJSON(serialized, deserialized, root))
553 << llvm::toString(E: root.getError());
554 EXPECT_EQ(deserialized, test_case.first);
555 }
556
557 // Test invalid value.
558 llvm::json::Value invalid_value = "invalid_hint";
559 DisassembledInstruction::PresentationHint deserialized_invalid;
560 llvm::json::Path::Root root;
561 EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
562}
563
564TEST(ProtocolTypesTest, DisassembledInstruction) {
565 DisassembledInstruction instruction;
566 instruction.address = 0x12345678;
567 instruction.instructionBytes = "0F 1F 00";
568 instruction.instruction = "mov eax, ebx";
569 instruction.symbol = "main";
570 instruction.location = Source{.name: "test.cpp", .path: "/path/to/test.cpp", .sourceReference: 123,
571 .presentationHint: Source::eSourcePresentationHintNormal};
572 instruction.line = 10;
573 instruction.column = 5;
574 instruction.endLine = 15;
575 instruction.endColumn = 10;
576 instruction.presentationHint =
577 DisassembledInstruction::eDisassembledInstructionPresentationHintNormal;
578
579 StringLiteral json = R"({
580 "address": "0x12345678",
581 "column": 5,
582 "endColumn": 10,
583 "endLine": 15,
584 "instruction": "mov eax, ebx",
585 "instructionBytes": "0F 1F 00",
586 "line": 10,
587 "location": {
588 "name": "test.cpp",
589 "path": "/path/to/test.cpp",
590 "presentationHint": "normal",
591 "sourceReference": 123
592 },
593 "presentationHint": "normal",
594 "symbol": "main"
595})";
596
597 // Validate toJSON
598 EXPECT_EQ(json, pp(instruction));
599
600 // Validate fromJSON
601 EXPECT_THAT_EXPECTED(parse<DisassembledInstruction>(json),
602 HasValue(Value(instruction)));
603 // Validate parsing errors
604 EXPECT_THAT_EXPECTED(
605 parse<DisassembledInstruction>(R"({"address":1})",
606 "disassemblyInstruction"),
607 FailedWithMessage("expected string at disassemblyInstruction.address"));
608 EXPECT_THAT_EXPECTED(
609 parse<DisassembledInstruction>(R"({"address":"-1"})",
610 "disassemblyInstruction"),
611 FailedWithMessage(
612 "malformed memory reference at disassemblyInstruction.address"));
613 EXPECT_THAT_EXPECTED(
614 parse<DisassembledInstruction>(
615 R"({"address":"0xfffffffffffffffffffffffffff"})",
616 "disassemblyInstruction"),
617 FailedWithMessage(
618 "malformed memory reference at disassemblyInstruction.address"));
619}
620
621TEST(ProtocolTypesTest, Thread) {
622 const Thread thread{.id: 1, .name: "thr1"};
623 const StringRef json = R"({
624 "id": 1,
625 "name": "thr1"
626})";
627 // Validate toJSON
628 EXPECT_EQ(json, pp(thread));
629 // Validate fromJSON
630 EXPECT_THAT_EXPECTED(parse<Thread>(json), HasValue(Value(thread)));
631 // Validate parsing errors
632 EXPECT_THAT_EXPECTED(parse<Thread>(R"({"id":1})", "thread"),
633 FailedWithMessage("missing value at thread.name"));
634 EXPECT_THAT_EXPECTED(parse<Thread>(R"({"id":"one"})", "thread"),
635 FailedWithMessage("expected uint64_t at thread.id"));
636 EXPECT_THAT_EXPECTED(parse<Thread>(R"({"id":1,"name":false})", "thread"),
637 FailedWithMessage("expected string at thread.name"));
638}
639
640TEST(ProtocolTypesTest, ThreadResponseBody) {
641 const ThreadsResponseBody body{.threads: {{.id: 1, .name: "thr1"}, {.id: 2, .name: "thr2"}}};
642 const StringRef json = R"({
643 "threads": [
644 {
645 "id": 1,
646 "name": "thr1"
647 },
648 {
649 "id": 2,
650 "name": "thr2"
651 }
652 ]
653})";
654 // Validate toJSON
655 EXPECT_EQ(json, pp(body));
656}
657
658TEST(ProtocolTypesTest, CapabilitiesEventBody) {
659 Capabilities capabilities;
660 capabilities.supportedFeatures = {
661 eAdapterFeatureANSIStyling,
662 eAdapterFeatureBreakpointLocationsRequest,
663 };
664 CapabilitiesEventBody body;
665 body.capabilities = capabilities;
666 StringRef json = R"({
667 "capabilities": {
668 "supportsANSIStyling": true,
669 "supportsBreakpointLocationsRequest": true
670 }
671})";
672 // Validate toJSON
673 EXPECT_EQ(json, pp(body));
674}
675
676TEST(ProtocolTypesTest, ExceptionFilterOptions) {
677 EXPECT_THAT_EXPECTED(parse<ExceptionFilterOptions>(R"({"filterId":"id"})"),
678 HasValue(Value(ExceptionFilterOptions{
679 /*filterId=*/"id", /*condition=*/"", /*mode*/ ""})));
680 EXPECT_THAT_EXPECTED(
681 parse<ExceptionFilterOptions>(R"({"filterId":"id","condition":"1+2"})"),
682 HasValue(Value(ExceptionFilterOptions{
683 /*filterId=*/"id", /*condition=*/"1+2", /*mode*/ ""})));
684 EXPECT_THAT_EXPECTED(
685 parse<ExceptionFilterOptions>(
686 R"({"filterId":"id","condition":"1+2","mode":"m"})"),
687 HasValue(Value(ExceptionFilterOptions{
688 /*filterId=*/"id", /*condition=*/"1+2", /*mode*/ "m"})));
689
690 // Validate parsing errors
691 EXPECT_THAT_EXPECTED(
692 parse<ExceptionFilterOptions>(R"({})", "exceptionFilterOptions"),
693 FailedWithMessage("missing value at exceptionFilterOptions.filterId"));
694 EXPECT_THAT_EXPECTED(
695 parse<ExceptionFilterOptions>(R"({"filterId":"id","condition":42})",
696 "exceptionFilterOptions"),
697 FailedWithMessage("expected string at exceptionFilterOptions.condition"));
698 EXPECT_THAT_EXPECTED(
699 parse<ExceptionFilterOptions>(R"({"filterId":"id","mode":42})",
700 "exceptionFilterOptions"),
701 FailedWithMessage("expected string at exceptionFilterOptions.mode"));
702}
703
704TEST(ProtocolTypesTest, SetExceptionBreakpointsArguments) {
705 EXPECT_THAT_EXPECTED(
706 parse<SetExceptionBreakpointsArguments>(R"({"filters":[]})"),
707 HasValue(testing::FieldsAre(/*filters=*/testing::IsEmpty(),
708 /*filterOptions=*/testing::IsEmpty())));
709 EXPECT_THAT_EXPECTED(
710 parse<SetExceptionBreakpointsArguments>(R"({"filters":["abc"]})"),
711 HasValue(testing::FieldsAre(/*filters=*/std::vector<std::string>{"abc"},
712 /*filterOptions=*/testing::IsEmpty())));
713 EXPECT_THAT_EXPECTED(
714 parse<SetExceptionBreakpointsArguments>(
715 R"({"filters":[],"filterOptions":[{"filterId":"abc"}]})"),
716 HasValue(testing::FieldsAre(
717 /*filters=*/testing::IsEmpty(),
718 /*filterOptions=*/testing::Contains(testing::FieldsAre(
719 /*filterId=*/"abc", /*condition=*/"", /*mode=*/"")))));
720
721 // Validate parse errors
722 EXPECT_THAT_EXPECTED(parse<SetExceptionBreakpointsArguments>(R"({})"),
723 FailedWithMessage("missing value at (root).filters"));
724 EXPECT_THAT_EXPECTED(
725 parse<SetExceptionBreakpointsArguments>(R"({"filters":false})"),
726 FailedWithMessage("expected array at (root).filters"));
727}
728
729TEST(ProtocolTypesTest, SetExceptionBreakpointsResponseBody) {
730 SetExceptionBreakpointsResponseBody body;
731 Breakpoint bp;
732 bp.id = 12, bp.verified = true;
733 body.breakpoints = {bp};
734 EXPECT_EQ(R"({
735 "breakpoints": [
736 {
737 "id": 12,
738 "verified": true
739 }
740 ]
741})",
742 pp(body));
743}
744
745TEST(ProtocolTypesTest, StepInTarget) {
746 StepInTarget target;
747 target.id = 230;
748 target.label = "the_function_name";
749 target.line = 2;
750 target.column = 320;
751 target.endLine = 32;
752 target.endColumn = 23;
753
754 llvm::Expected<StepInTarget> deserialized_target = roundtripJSON(input: target);
755 ASSERT_THAT_EXPECTED(deserialized_target, llvm::Succeeded());
756
757 EXPECT_EQ(target.id, deserialized_target->id);
758 EXPECT_EQ(target.label, deserialized_target->label);
759 EXPECT_EQ(target.line, deserialized_target->line);
760 EXPECT_EQ(target.column, deserialized_target->column);
761 EXPECT_EQ(target.endLine, deserialized_target->endLine);
762 EXPECT_EQ(target.endColumn, deserialized_target->endColumn);
763}
764
765TEST(ProtocolTypesTest, ReadMemoryArguments) {
766 ReadMemoryArguments args;
767 args.count = 20;
768 args.memoryReference = 43962;
769 args.offset = 0;
770
771 llvm::Expected<ReadMemoryArguments> expected =
772 parse<ReadMemoryArguments>(JSON: R"({"memoryReference":"-4000", "count": 20})");
773 ASSERT_THAT_EXPECTED(expected, llvm::Failed());
774 expected = parse<ReadMemoryArguments>(
775 JSON: R"({"memoryReference":"0xabba", "count": 20})");
776 ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
777
778 EXPECT_EQ(args.count, expected->count);
779 EXPECT_EQ(args.memoryReference, expected->memoryReference);
780 EXPECT_EQ(args.offset, expected->offset);
781}
782
783TEST(ProtocolTypesTest, ReadMemoryResponseBody) {
784 ReadMemoryResponseBody response;
785 response.address = 0xdeadbeef;
786 const std::string data_str = "hello world!";
787 std::transform(first: data_str.begin(), last: data_str.end(),
788 result: std::back_inserter(x&: response.data),
789 unary_op: [](char letter) { return std::byte(letter); });
790 response.unreadableBytes = 1;
791
792 Expected<Value> expected = json::parse(
793 JSON: R"({ "address": "0xDEADBEEF", "data": "aGVsbG8gd29ybGQh", "unreadableBytes": 1})");
794 ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
795 EXPECT_EQ(pp(*expected), pp(response));
796}
797
798TEST(ProtocolTypesTest, Modules) {
799 Module module;
800 module.id = "AC805E8E-B6A4-CD92-4B05-5CFA7CE24AE8-8926C776";
801 module.name = "libm.so.6";
802 module.path = "/some/path/to/libm.so.6";
803 module.isOptimized = true;
804 module.isUserCode = true;
805 module.version = "0.0.1";
806 module.symbolStatus = "Symbol not found.";
807 module.symbolFilePath = "/some/file/path/to/the/symbol/module";
808 module.dateTimeStamp = "2020-12-09T16:09:53+00:00";
809 module.addressRange = "0xcafeface";
810 module.debugInfoSizeBytes = 1572864;
811
812 Expected<json::Value> expected = json::parse(
813 JSON: R"({
814 "id" : "AC805E8E-B6A4-CD92-4B05-5CFA7CE24AE8-8926C776",
815 "name": "libm.so.6",
816 "path": "/some/path/to/libm.so.6",
817 "isOptimized": true,
818 "isUserCode": true,
819 "version": "0.0.1",
820 "symbolStatus": "Symbol not found.",
821 "symbolFilePath": "/some/file/path/to/the/symbol/module",
822 "dateTimeStamp": "2020-12-09T16:09:53+00:00",
823 "addressRange": "0xcafeface",
824 "debugInfoSize": "1.5MB" })");
825 ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
826 EXPECT_EQ(pp(*expected), pp(module));
827
828 // Test without optional values.
829 module.path.clear();
830 module.isOptimized = false;
831 module.isUserCode = false;
832 module.version.clear();
833 module.symbolStatus.clear();
834 module.symbolFilePath.clear();
835 module.dateTimeStamp.clear();
836 module.addressRange.clear();
837 module.debugInfoSizeBytes = 0;
838 EXPECT_NE(pp(*expected), pp(module));
839
840 Expected<json::Value> expected_no_opt = json::parse(
841 JSON: R"({
842 "id" : "AC805E8E-B6A4-CD92-4B05-5CFA7CE24AE8-8926C776",
843 "name": "libm.so.6"})");
844 ASSERT_THAT_EXPECTED(expected_no_opt, llvm::Succeeded());
845 EXPECT_EQ(pp(*expected_no_opt), pp(module));
846}
847
848TEST(ProtocolTypesTest, ModulesArguments) {
849 ModulesArguments args;
850
851 llvm::Expected<ModulesArguments> expected = parse<ModulesArguments>(JSON: R"({})");
852 ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
853 EXPECT_EQ(args.startModule, expected->startModule);
854 EXPECT_EQ(args.moduleCount, expected->moduleCount);
855
856 // Non Default values.
857 args.startModule = 1;
858 args.moduleCount = 2;
859 llvm::Expected<ModulesArguments> expected_no_default =
860 parse<ModulesArguments>(JSON: R"({ "startModule": 1, "moduleCount": 2})");
861 ASSERT_THAT_EXPECTED(expected_no_default, llvm::Succeeded());
862 EXPECT_EQ(args.startModule, expected_no_default->startModule);
863 EXPECT_EQ(args.moduleCount, expected_no_default->moduleCount);
864}
865
866TEST(ProtocolTypesTest, ModulesResponseBody) {
867 ModulesResponseBody response;
868 Module module1;
869 module1.id = "first id";
870 module1.name = "first name";
871
872 Module module2;
873 module2.id = "second id";
874 module2.name = "second name";
875 response.modules = {std::move(module1), std::move(module2)};
876 response.totalModules = 2;
877
878 Expected<json::Value> expected = json::parse(
879 JSON: R"({
880 "modules": [
881 { "id": "first id", "name": "first name"},
882 { "id": "second id", "name": "second name"}
883 ],
884 "totalModules": 2 })");
885 ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
886 EXPECT_EQ(pp(*expected), pp(response));
887}
888
889TEST(ProtocolTypesTest, VariablePresentationHint) {
890 VariablePresentationHint hint;
891 hint.kind = "kind";
892 hint.attributes = {"a", "b", "c"};
893 hint.visibility = "public";
894 hint.lazy = true;
895
896 const StringRef json = R"({
897 "attributes": [
898 "a",
899 "b",
900 "c"
901 ],
902 "kind": "kind",
903 "lazy": true,
904 "visibility": "public"
905})";
906
907 EXPECT_EQ(pp(Value(hint)), json);
908 EXPECT_THAT_EXPECTED(json::parse(json), HasValue(Value(hint)));
909}
910
911TEST(ProtocolTypesTest, Variable) {
912 Variable var;
913 var.name = "var1";
914 var.variablesReference = 42;
915 var.value = "value";
916 var.type = "type";
917
918 VariablePresentationHint hint;
919 hint.kind = "kind";
920 var.presentationHint = std::move(hint);
921 var.evaluateName = "my_name";
922 var.namedVariables = 7;
923 var.indexedVariables = 7;
924 var.memoryReference = 291u;
925 var.declarationLocationReference = 24;
926 var.valueLocationReference = 100;
927
928 const StringRef json = R"({
929 "declarationLocationReference": 24,
930 "evaluateName": "my_name",
931 "indexedVariables": 7,
932 "memoryReference": "0x123",
933 "name": "var1",
934 "namedVariables": 7,
935 "presentationHint": {
936 "kind": "kind"
937 },
938 "type": "type",
939 "value": "value",
940 "valueLocationReference": 100,
941 "variablesReference": 42
942})";
943
944 EXPECT_EQ(pp(Value(var)), json);
945 EXPECT_THAT_EXPECTED(json::parse(json), HasValue(Value(var)));
946}
947
948TEST(ProtocolTypesTest, VariablesArguments) {
949 llvm::Expected<VariablesArguments> expected = parse<VariablesArguments>(JSON: R"({
950 "variablesReference": 42,
951 "filter": "indexed",
952 "start": 10,
953 "count": 5,
954 "format": {
955 "hex": true
956 }
957 })");
958 ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
959 EXPECT_EQ(expected->variablesReference, 42u);
960 EXPECT_EQ(expected->filter, VariablesArguments::eVariablesFilterIndexed);
961 EXPECT_EQ(expected->start, 10u);
962 EXPECT_EQ(expected->count, 5u);
963 EXPECT_EQ(expected->format->hex, true);
964
965 EXPECT_THAT_EXPECTED(
966 parse<VariablesArguments>(R"({})"),
967 FailedWithMessage("missing value at (root).variablesReference"));
968 EXPECT_THAT_EXPECTED(
969 parse<VariablesArguments>(
970 R"({"variablesReference": 42, "filter": "my-filter"})"),
971 FailedWithMessage(
972 "unexpected value, expected 'named' or 'indexed' at (root).filter"));
973}
974
975TEST(ProtocolTypesTest, VariablesResponseBody) {
976 Variable var1;
977 var1.name = "var1";
978 var1.variablesReference = 42;
979 var1.value = "<var1-value>";
980
981 Variable var2;
982 var2.name = "var2";
983 var2.variablesReference = 3;
984 var2.value = "<var2-value>";
985
986 VariablesResponseBody response{.variables: {var1, var2}};
987
988 Expected<json::Value> expected = json::parse(JSON: R"({
989 "variables": [
990 {
991 "name": "var1",
992 "value": "<var1-value>",
993 "variablesReference": 42
994 },
995 {
996 "name": "var2",
997 "value": "<var2-value>",
998 "variablesReference": 3
999 }
1000 ]
1001 })");
1002 ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
1003 EXPECT_EQ(pp(*expected), pp(response));
1004}
1005

source code of lldb/unittests/DAP/ProtocolTypesTest.cpp