1pub mod events;
2pub mod requests;
3pub mod responses;
4pub mod types;
5
6mod utils;
7
8use events::Event;
9use requests::Request;
10use responses::Response;
11use serde::{Deserialize, Serialize};
12use std::fmt::Display;
13
14pub type SequenceNumber = u64;
15
16#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
18pub struct ProtocolMessage {
19 pub seq: SequenceNumber,
21
22 #[serde(flatten)]
23 pub content: ProtocolMessageContent,
24}
25
26impl ProtocolMessage {
27 pub fn new(seq: SequenceNumber, content: impl Into<ProtocolMessageContent>) -> ProtocolMessage {
28 ProtocolMessage {
29 seq,
30 content: content.into(),
31 }
32 }
33}
34
35impl Display for ProtocolMessage {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 let json = serde_json::to_string(&self).unwrap();
38 write!(f, "Content-Length: {}\r\n\r\n{}", json.len(), json)
39 }
40}
41
42#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
43#[serde(rename_all = "camelCase", tag = "type")]
44pub enum ProtocolMessageContent {
45 Request(Request),
47
48 Response(Response),
50
51 Event(Event),
53}
54
55#[cfg(test)]
56mod tests {
57 use serde_json::{Map, Number, Value};
58
59 use super::*;
60 use crate::{events::*, requests::*, responses::*, types::*};
61 use std::{collections::HashMap, iter::FromIterator};
62
63 #[test]
64 fn test_deserialize_request_initialize() {
65 let json = r#"{
67 "command": "initialize",
68 "arguments": {
69 "clientID": "vscode",
70 "clientName": "Visual Studio Code",
71 "adapterID": "mock",
72 "pathFormat": "path",
73 "linesStartAt1": true,
74 "columnsStartAt1": true,
75 "supportsVariableType": true,
76 "supportsVariablePaging": true,
77 "supportsRunInTerminalRequest": true,
78 "locale": "de",
79 "supportsProgressReporting": true,
80 "supportsInvalidatedEvent": true
81 },
82 "type": "request",
83 "seq": 1
84 }"#;
85
86 let actual = serde_json::from_str::<ProtocolMessage>(&json).unwrap();
88
89 assert_eq!(
91 actual,
92 ProtocolMessage {
93 seq: 1,
94 content: InitializeRequestArguments::builder()
95 .client_id(Some("vscode".to_string()))
96 .client_name(Some("Visual Studio Code".to_string()))
97 .adapter_id("mock".to_string())
98 .locale(Some("de".to_string()))
99 .lines_start_at_1(true)
100 .columns_start_at_1(true)
101 .path_format(PathFormat::Path)
102 .supports_variable_type(true)
103 .supports_variable_paging(true)
104 .supports_run_in_terminal_request(true)
105 .supports_memory_references(false)
106 .supports_progress_reporting(true)
107 .supports_invalidated_event(true)
108 .build()
109 .into()
110 }
111 );
112 }
113
114 #[test]
115 fn test_serialize_request_initialize() {
116 let under_test = ProtocolMessage {
118 seq: 1,
119 content: ProtocolMessageContent::Request(Request::Initialize(
120 InitializeRequestArguments::builder()
121 .client_id(Some("vscode".to_string()))
122 .client_name(Some("Visual Studio Code".to_string()))
123 .adapter_id("mock".to_string())
124 .locale(Some("de".to_string()))
125 .lines_start_at_1(true)
126 .columns_start_at_1(true)
127 .path_format(PathFormat::Path)
128 .supports_variable_type(true)
129 .supports_variable_paging(true)
130 .supports_run_in_terminal_request(true)
131 .supports_memory_references(false)
132 .supports_progress_reporting(true)
133 .supports_invalidated_event(true)
134 .build(),
135 )),
136 };
137
138 let actual = serde_json::to_string_pretty(&under_test).unwrap();
140
141 assert_eq!(
143 actual,
144 r#"{
145 "seq": 1,
146 "type": "request",
147 "command": "initialize",
148 "arguments": {
149 "clientID": "vscode",
150 "clientName": "Visual Studio Code",
151 "adapterID": "mock",
152 "locale": "de",
153 "linesStartAt1": true,
154 "columnsStartAt1": true,
155 "supportsVariableType": true,
156 "supportsVariablePaging": true,
157 "supportsRunInTerminalRequest": true,
158 "supportsProgressReporting": true,
159 "supportsInvalidatedEvent": true
160 }
161}"#
162 );
163 }
164
165 #[test]
166 fn test_deserialize_response_initialize() {
167 let json = r#"{
169 "seq": 1,
170 "type": "response",
171 "request_seq": 1,
172 "success": true,
173 "command": "initialize",
174 "body": {
175 "supportsConfigurationDoneRequest": true,
176 "supportsFunctionBreakpoints": true,
177 "supportsConditionalBreakpoints": true,
178 "supportsHitConditionalBreakpoints": true,
179 "supportsDataBreakpoints": true,
180 "supportsInstructionBreakpoints": true
181 }
182 }"#;
183
184 let actual = serde_json::from_str::<ProtocolMessage>(json).unwrap();
186
187 assert_eq!(
189 actual,
190 ProtocolMessage {
191 seq: 1,
192 content: ProtocolMessageContent::Response(Response {
193 request_seq: 1,
194 result: Ok(SuccessResponse::Initialize(
195 Capabilities::builder()
196 .supports_configuration_done_request(true)
197 .supports_function_breakpoints(true)
198 .supports_conditional_breakpoints(true)
199 .supports_hit_conditional_breakpoints(true)
200 .supports_data_breakpoints(true)
201 .supports_instruction_breakpoints(true)
202 .build()
203 ))
204 })
205 }
206 )
207 }
208
209 #[test]
210 fn test_serialize_response_initialize() {
211 let under_test = ProtocolMessage {
213 seq: 1,
214 content: ProtocolMessageContent::Response(Response {
215 request_seq: 1,
216 result: Ok(SuccessResponse::Initialize(
217 Capabilities::builder()
218 .supports_configuration_done_request(true)
219 .supports_function_breakpoints(true)
220 .supports_conditional_breakpoints(true)
221 .supports_hit_conditional_breakpoints(true)
222 .supports_data_breakpoints(true)
223 .supports_instruction_breakpoints(true)
224 .build(),
225 )),
226 }),
227 };
228
229 let actual = serde_json::to_string_pretty(&under_test).unwrap();
231
232 assert_eq!(
234 actual,
235 r#"{
236 "seq": 1,
237 "type": "response",
238 "request_seq": 1,
239 "success": true,
240 "command": "initialize",
241 "body": {
242 "supportsConfigurationDoneRequest": true,
243 "supportsFunctionBreakpoints": true,
244 "supportsConditionalBreakpoints": true,
245 "supportsHitConditionalBreakpoints": true,
246 "supportsDataBreakpoints": true,
247 "supportsInstructionBreakpoints": true
248 }
249}"#
250 )
251 }
252
253 #[test]
254 fn test_deserialize_response_error() {
255 let json = r#"{
257 "seq": 1,
258 "type": "response",
259 "request_seq": 2,
260 "success": false,
261 "command": "initialize",
262 "message": "Something went wrong",
263 "body": {
264 "error": {
265 "id": 3,
266 "format": "This thing went wrong"
267 }
268 }
269 }"#;
270
271 let actual = serde_json::from_str::<ProtocolMessage>(json).unwrap();
273
274 assert_eq!(
276 actual,
277 ProtocolMessage {
278 seq: 1,
279 content: ProtocolMessageContent::Response(Response {
280 request_seq: 2,
281 result: Err(ErrorResponse::builder()
282 .command("initialize".to_string())
283 .message("Something went wrong".to_string())
284 .body(ErrorResponseBody::new(Some(
285 Message::builder()
286 .id(3)
287 .format("This thing went wrong".to_string())
288 .variables(HashMap::new())
289 .send_telemetry(false)
290 .show_user(false)
291 .url(None)
292 .url_label(None)
293 .build()
294 )))
295 .build())
296 })
297 }
298 )
299 }
300
301 #[test]
302 fn test_serialize_response_error() {
303 let under_test = ProtocolMessage {
305 seq: 1,
306 content: ProtocolMessageContent::Response(Response {
307 request_seq: 2,
308 result: Err(ErrorResponse::builder()
309 .command("initialize".to_string())
310 .message("Something went wrong".to_string())
311 .body(ErrorResponseBody::new(Some(
312 Message::builder()
313 .id(3)
314 .format("This thing went wrong".to_string())
315 .variables(HashMap::new())
316 .send_telemetry(false)
317 .show_user(false)
318 .url(None)
319 .url_label(None)
320 .build(),
321 )))
322 .build()),
323 }),
324 };
325
326 let actual = serde_json::to_string_pretty(&under_test).unwrap();
328
329 assert_eq!(
331 actual,
332 r#"{
333 "seq": 1,
334 "type": "response",
335 "request_seq": 2,
336 "success": false,
337 "command": "initialize",
338 "message": "Something went wrong",
339 "body": {
340 "error": {
341 "id": 3,
342 "format": "This thing went wrong"
343 }
344 }
345}"#
346 )
347 }
348
349 #[test]
350 fn test_deserialize_event_exited() {
351 let json = r#"{
353 "seq": 1,
354 "type": "event",
355 "event": "exited",
356 "body": {
357 "exitCode": 0
358 }
359 }"#;
360
361 let actual = serde_json::from_str::<ProtocolMessage>(json).unwrap();
363
364 assert_eq!(
366 actual,
367 ProtocolMessage {
368 seq: 1,
369 content: ExitedEventBody::builder().exit_code(0).build().into()
370 }
371 )
372 }
373
374 #[test]
375 fn test_serialize_event_exited() {
376 let under_test = ProtocolMessage {
378 seq: 1,
379 content: ExitedEventBody::builder().exit_code(0).build().into(),
380 };
381
382 let actual = serde_json::to_string_pretty(&under_test).unwrap();
384
385 assert_eq!(
387 actual,
388 r#"{
389 "seq": 1,
390 "type": "event",
391 "event": "exited",
392 "body": {
393 "exitCode": 0
394 }
395}"#
396 )
397 }
398
399 #[test]
400 fn test_deserialize_request_launch_with_additional_attributes() {
401 let json = r#"{
403 "command": "launch",
404 "arguments": {
405 "noDebug": true,
406 "__restart": "Some Value",
407 "bli": { "foo": "bar" },
408 "bla": 1,
409 "blub": true
410 },
411 "type": "request",
412 "seq": 1
413 }"#;
414
415 let actual = serde_json::from_str::<ProtocolMessage>(&json).unwrap();
417
418 assert_eq!(
420 actual,
421 ProtocolMessage {
422 seq: 1,
423 content: ProtocolMessageContent::Request(Request::Launch(
424 LaunchRequestArguments::builder()
425 .no_debug(true)
426 .restart(Some(Value::String("Some Value".to_string())))
427 .additional_attributes(Map::from_iter([
428 (
429 "bli".to_string(),
430 Value::Object(Map::from_iter([(
431 "foo".to_string(),
432 Value::String("bar".to_string())
433 )]))
434 ),
435 ("bla".to_string(), Value::Number(Number::from(1))),
436 ("blub".to_string(), Value::Bool(true))
437 ]))
438 .build()
439 ))
440 }
441 );
442 }
443
444 #[test]
445 fn test_serialize_request_launch_with_additional_attributes() {
446 let under_test = ProtocolMessage {
448 seq: 1,
449 content: ProtocolMessageContent::Request(Request::Launch(
450 LaunchRequestArguments::builder()
451 .no_debug(true)
452 .restart(Some(Value::String("Some Value".to_string())))
453 .additional_attributes(Map::from_iter([
454 (
455 "bli".to_string(),
456 Value::Object(Map::from_iter([(
457 "foo".to_string(),
458 Value::String("bar".to_string()),
459 )])),
460 ),
461 ("bla".to_string(), Value::Number(Number::from(1))),
462 ("blub".to_string(), Value::Bool(true)),
463 ]))
464 .build(),
465 )),
466 };
467
468 let actual = serde_json::to_string_pretty(&under_test).unwrap();
470
471 assert_eq!(
473 actual,
474 r#"{
475 "seq": 1,
476 "type": "request",
477 "command": "launch",
478 "arguments": {
479 "noDebug": true,
480 "__restart": "Some Value",
481 "bli": {
482 "foo": "bar"
483 },
484 "bla": 1,
485 "blub": true
486 }
487}"#
488 );
489 }
490
491 #[test]
492 fn test_deserialize_request_launch_without_additional_attributes() {
493 let json = r#"{
495 "seq": 1,
496 "type": "request",
497 "command": "launch",
498 "arguments": {}
499 }"#;
500
501 let actual = serde_json::from_str::<ProtocolMessage>(&json).unwrap();
503
504 assert_eq!(
506 actual,
507 ProtocolMessage {
508 seq: 1,
509 content: ProtocolMessageContent::Request(Request::Launch(
510 LaunchRequestArguments::builder().build()
511 ))
512 }
513 );
514 }
515
516 #[test]
517 fn test_serialize_request_launch_without_additional_attributes() {
518 let under_test = ProtocolMessage {
520 seq: 1,
521 content: ProtocolMessageContent::Request(Request::Launch(
522 LaunchRequestArguments::builder().build(),
523 )),
524 };
525
526 let actual = serde_json::to_string_pretty(&under_test).unwrap();
528
529 assert_eq!(
531 actual,
532 r#"{
533 "seq": 1,
534 "type": "request",
535 "command": "launch",
536 "arguments": {}
537}"#
538 );
539 }
540}