openvcs_core/
plugin_protocol.rs1use crate::models::VcsEvent;
2use serde::{Deserialize, Serialize};
3
4#[cfg(feature = "plugin-protocol")]
5use serde_json::Value;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct RpcRequest {
9 pub id: u64,
10 pub method: String,
11 #[serde(default)]
12 pub params: Value,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct RpcResponse {
17 pub id: u64,
18 pub ok: bool,
19 #[serde(default)]
20 pub result: Value,
21 #[serde(default)]
22 pub error: Option<String>,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
24 pub error_code: Option<String>,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub error_data: Option<Value>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30#[serde(untagged)]
31pub enum PluginMessage {
32 Request(RpcRequest),
33 Response(RpcResponse),
34 Event { event: VcsEvent },
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 #[test]
42 fn rpc_request_params_defaults_to_null() {
43 let req: RpcRequest =
44 serde_json::from_str(r#"{"id":1,"method":"ping"}"#).expect("valid request");
45 assert_eq!(req.id, 1);
46 assert_eq!(req.method, "ping");
47 assert_eq!(req.params, serde_json::Value::Null);
48 }
49
50 #[test]
51 fn rpc_response_fields_default_when_missing() {
52 let resp: RpcResponse =
53 serde_json::from_str(r#"{"id":9,"ok":true}"#).expect("valid response");
54 assert_eq!(resp.id, 9);
55 assert!(resp.ok);
56 assert_eq!(resp.result, serde_json::Value::Null);
57 assert!(resp.error.is_none());
58 assert!(resp.error_code.is_none());
59 assert!(resp.error_data.is_none());
60 }
61
62 #[test]
63 fn rpc_response_skips_optional_error_fields_when_none() {
64 let resp = RpcResponse {
65 id: 1,
66 ok: false,
67 result: serde_json::Value::Null,
68 error: Some("boom".into()),
69 error_code: None,
70 error_data: None,
71 };
72
73 let value = serde_json::to_value(&resp).expect("serializes");
74 assert!(value.get("error").is_some());
75 assert!(value.get("error_code").is_none());
76 assert!(value.get("error_data").is_none());
77 }
78
79 #[test]
80 fn plugin_message_deserializes_event_variant() {
81 let msg: PluginMessage = serde_json::from_str(r#"{"event":{"type":"info","msg":"hello"}}"#)
82 .expect("valid event message");
83
84 match msg {
85 PluginMessage::Event { event } => match event {
86 VcsEvent::Info { msg } => assert_eq!(msg, "hello"),
87 other => panic!("unexpected event: {other:?}"),
88 },
89 other => panic!("unexpected message: {other:?}"),
90 }
91 }
92}