Skip to main content

ash_rpc/
types.rs

1//! Core JSON-RPC 2.0 types and data structures.
2
3use serde::{Deserialize, Serialize};
4
5/// Request identifier - can be string, number, or null
6pub type RequestId = serde_json::Value;
7
8/// JSON-RPC 2.0 request message
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Request {
11    pub jsonrpc: String,
12    pub method: String,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub params: Option<serde_json::Value>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub id: Option<RequestId>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub correlation_id: Option<String>,
19}
20
21impl Request {
22    /// Create a new JSON-RPC request
23    pub fn new(method: impl Into<String>) -> Self {
24        Self {
25            jsonrpc: "2.0".to_string(),
26            method: method.into(),
27            params: None,
28            id: None,
29            correlation_id: Some(uuid::Uuid::new_v4().to_string()),
30        }
31    }
32
33    /// Add parameters to the request
34    pub fn with_params(mut self, params: serde_json::Value) -> Self {
35        self.params = Some(params);
36        self
37    }
38
39    /// Add an ID to the request
40    pub fn with_id(mut self, id: RequestId) -> Self {
41        self.id = Some(id);
42        self
43    }
44
45    /// Check if this request expects a response
46    pub fn expects_response(&self) -> bool {
47        self.id.is_some()
48    }
49
50    /// Check if this is a notification (no response expected)
51    pub fn is_notification(&self) -> bool {
52        self.id.is_none()
53    }
54
55    /// Get the method name
56    pub fn method(&self) -> &str {
57        &self.method
58    }
59
60    /// Get a reference to the parameters
61    pub fn params(&self) -> Option<&serde_json::Value> {
62        self.params.as_ref()
63    }
64
65    /// Take ownership of the parameters
66    pub fn take_params(self) -> Option<serde_json::Value> {
67        self.params
68    }
69
70    /// Get a reference to the request ID
71    pub fn id(&self) -> Option<&RequestId> {
72        self.id.as_ref()
73    }
74}
75
76/// JSON-RPC 2.0 response message
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Response {
79    pub jsonrpc: String,
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub result: Option<serde_json::Value>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub error: Option<crate::Error>,
84    pub id: Option<RequestId>,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub correlation_id: Option<String>,
87}
88
89impl Response {
90    /// Create a successful response
91    pub fn success(result: serde_json::Value, id: Option<RequestId>) -> Self {
92        Self {
93            jsonrpc: "2.0".to_string(),
94            result: Some(result),
95            error: None,
96            id,
97            correlation_id: None,
98        }
99    }
100
101    /// Create an error response
102    pub fn error(error: crate::Error, id: Option<RequestId>) -> Self {
103        Self {
104            jsonrpc: "2.0".to_string(),
105            result: None,
106            error: Some(error),
107            id,
108            correlation_id: None,
109        }
110    }
111
112    /// Check if this is a successful response
113    pub fn is_success(&self) -> bool {
114        self.error.is_none() && self.result.is_some()
115    }
116
117    /// Check if this is an error response
118    pub fn is_error(&self) -> bool {
119        self.error.is_some()
120    }
121
122    /// Get a reference to the result
123    pub fn result(&self) -> Option<&serde_json::Value> {
124        self.result.as_ref()
125    }
126
127    /// Take ownership of the result
128    pub fn take_result(self) -> Option<serde_json::Value> {
129        self.result
130    }
131
132    /// Get error information
133    pub fn error_info(&self) -> Option<&crate::Error> {
134        self.error.as_ref()
135    }
136
137    /// Take ownership of the error
138    pub fn take_error(self) -> Option<crate::Error> {
139        self.error
140    }
141
142    /// Get the response ID
143    pub fn id(&self) -> Option<&RequestId> {
144        self.id.as_ref()
145    }
146}
147
148/// JSON-RPC 2.0 error object
149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
150pub struct Error {
151    pub code: i32,
152    pub message: String,
153    #[serde(skip_serializing_if = "Option::is_none")]
154    pub data: Option<serde_json::Value>,
155}
156
157impl Error {
158    /// Create a new error
159    pub fn new(code: i32, message: impl Into<String>) -> Self {
160        Self {
161            code,
162            message: message.into(),
163            data: None,
164        }
165    }
166
167    /// Add additional data to the error
168    pub fn with_data(mut self, data: serde_json::Value) -> Self {
169        self.data = Some(data);
170        self
171    }
172
173    /// Check if this is a parse error (-32700)
174    pub fn is_parse_error(&self) -> bool {
175        self.code == crate::error_codes::PARSE_ERROR
176    }
177
178    /// Check if this is an invalid request error (-32600)
179    pub fn is_invalid_request(&self) -> bool {
180        self.code == crate::error_codes::INVALID_REQUEST
181    }
182
183    /// Check if this is a method not found error (-32601)
184    pub fn is_method_not_found(&self) -> bool {
185        self.code == crate::error_codes::METHOD_NOT_FOUND
186    }
187
188    pub fn is_invalid_params(&self) -> bool {
189        self.code == crate::error_codes::INVALID_PARAMS
190    }
191
192    pub fn is_internal_error(&self) -> bool {
193        self.code == crate::error_codes::INTERNAL_ERROR
194    }
195
196    pub fn is_server_error(&self) -> bool {
197        self.code >= -32099 && self.code <= -32000
198    }
199
200    pub fn code(&self) -> i32 {
201        self.code
202    }
203
204    pub fn message(&self) -> &str {
205        &self.message
206    }
207
208    pub fn data(&self) -> Option<&serde_json::Value> {
209        self.data.as_ref()
210    }
211
212    /// Transform this error using a custom callback function
213    ///
214    /// This allows library users to implement their own error sanitization
215    /// logic based on their security requirements.
216    ///
217    /// # Example
218    /// ```
219    /// # use ash_rpc::Error;
220    /// # const INTERNAL_ERROR: i32 = -32603;
221    /// # let error = Error::new(INTERNAL_ERROR, "Something went wrong");
222    /// let sanitized = error.sanitized_with(|err| {
223    ///     if err.code() == INTERNAL_ERROR {
224    ///         Error::new(err.code(), "Internal server error")
225    ///     } else {
226    ///         err.clone()
227    ///     }
228    /// });
229    /// ```
230    pub fn sanitized_with<F>(&self, transform: F) -> Self
231    where
232        F: FnOnce(&Self) -> Self,
233    {
234        transform(self)
235    }
236
237    /// Create a generic internal error from any std::error::Error
238    ///
239    /// This logs the full error details server-side and returns a generic error.
240    /// Use this with sanitized_with() for custom error transformation.
241    pub fn from_error_logged(error: &dyn std::error::Error) -> Self {
242        tracing::error!(
243            error = %error,
244            error_debug = ?error,
245            "internal error occurred"
246        );
247
248        Self {
249            code: crate::error_codes::INTERNAL_ERROR,
250            message: "Internal server error".to_string(),
251            data: None,
252        }
253    }
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct Notification {
258    pub jsonrpc: String,
259    pub method: String,
260    #[serde(skip_serializing_if = "Option::is_none")]
261    pub params: Option<serde_json::Value>,
262}
263
264impl Notification {
265    pub fn new(method: impl Into<String>) -> Self {
266        Self {
267            jsonrpc: "2.0".to_string(),
268            method: method.into(),
269            params: None,
270        }
271    }
272
273    pub fn with_params(mut self, params: serde_json::Value) -> Self {
274        self.params = Some(params);
275        self
276    }
277
278    pub fn method(&self) -> &str {
279        &self.method
280    }
281
282    pub fn params(&self) -> Option<&serde_json::Value> {
283        self.params.as_ref()
284    }
285
286    pub fn take_params(self) -> Option<serde_json::Value> {
287        self.params
288    }
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize)]
292#[serde(untagged)]
293pub enum Message {
294    Request(Request),
295    Response(Response),
296    Notification(Notification),
297}
298
299impl Message {
300    pub fn is_request(&self) -> bool {
301        matches!(self, Message::Request(_))
302    }
303
304    pub fn is_response(&self) -> bool {
305        matches!(self, Message::Response(_))
306    }
307
308    pub fn is_notification(&self) -> bool {
309        matches!(self, Message::Notification(_))
310    }
311
312    pub fn as_request(&self) -> Option<&Request> {
313        match self {
314            Message::Request(req) => Some(req),
315            _ => None,
316        }
317    }
318
319    pub fn as_response(&self) -> Option<&Response> {
320        match self {
321            Message::Response(resp) => Some(resp),
322            _ => None,
323        }
324    }
325
326    pub fn as_notification(&self) -> Option<&Notification> {
327        match self {
328            Message::Notification(notif) => Some(notif),
329            _ => None,
330        }
331    }
332
333    pub fn into_request(self) -> Option<Request> {
334        match self {
335            Message::Request(req) => Some(req),
336            _ => None,
337        }
338    }
339
340    pub fn into_response(self) -> Option<Response> {
341        match self {
342            Message::Response(resp) => Some(resp),
343            _ => None,
344        }
345    }
346
347    pub fn into_notification(self) -> Option<Notification> {
348        match self {
349            Message::Notification(notif) => Some(notif),
350            _ => None,
351        }
352    }
353
354    pub fn method(&self) -> Option<&str> {
355        match self {
356            Message::Request(req) => Some(&req.method),
357            Message::Notification(notif) => Some(&notif.method),
358            Message::Response(_) => None,
359        }
360    }
361
362    pub fn id(&self) -> Option<&RequestId> {
363        match self {
364            Message::Request(req) => req.id.as_ref(),
365            Message::Response(resp) => resp.id.as_ref(),
366            Message::Notification(_) => None,
367        }
368    }
369}
370
371/// Standard JSON-RPC 2.0 error codes as defined in the specification.
372///
373/// These constants provide the standard error codes that should be used
374/// for common JSON-RPC error conditions. Using these ensures compliance
375/// with the JSON-RPC 2.0 specification.
376///
377/// # Example
378/// ```rust
379/// use ash_rpc::{ErrorBuilder, error_codes};
380///
381/// let error = ErrorBuilder::new(error_codes::METHOD_NOT_FOUND, "Method not found")
382///     .build();
383/// ```
384pub mod error_codes {
385    /// Parse error - Invalid JSON was received by the server.
386    /// An error occurred on the server while parsing the JSON text.
387    pub const PARSE_ERROR: i32 = -32700;
388
389    /// Invalid Request - The JSON sent is not a valid Request object.
390    pub const INVALID_REQUEST: i32 = -32600;
391
392    /// Method not found - The method does not exist / is not available.
393    pub const METHOD_NOT_FOUND: i32 = -32601;
394
395    /// Invalid params - Invalid method parameter(s).
396    pub const INVALID_PARAMS: i32 = -32602;
397
398    /// Internal error - Internal JSON-RPC error.
399    pub const INTERNAL_ERROR: i32 = -32603;
400}
401
402#[cfg(test)]
403mod tests {
404    use super::*;
405    use serde_json::json;
406
407    // Request tests
408    #[test]
409    fn test_request_creation() {
410        let request = Request::new("test_method");
411        assert_eq!(request.jsonrpc, "2.0");
412        assert_eq!(request.method, "test_method");
413        assert!(request.params.is_none());
414        assert!(request.id.is_none());
415        assert!(request.correlation_id.is_some());
416    }
417
418    #[test]
419    fn test_request_with_params() {
420        let params = json!({"key": "value"});
421        let request = Request::new("method").with_params(params.clone());
422        assert_eq!(request.params(), Some(&params));
423    }
424
425    #[test]
426    fn test_request_with_id() {
427        let id = json!(42);
428        let request = Request::new("method").with_id(id.clone());
429        assert_eq!(request.id(), Some(&id));
430        assert!(request.expects_response());
431        assert!(!request.is_notification());
432    }
433
434    #[test]
435    fn test_request_notification() {
436        let request = Request::new("notify");
437        assert!(!request.expects_response());
438        assert!(request.is_notification());
439    }
440
441    #[test]
442    fn test_request_serialization() {
443        let request = Request::new("test")
444            .with_params(json!([1, 2, 3]))
445            .with_id(json!(1));
446
447        let serialized = serde_json::to_string(&request).unwrap();
448        let deserialized: Request = serde_json::from_str(&serialized).unwrap();
449
450        assert_eq!(request.method, deserialized.method);
451        assert_eq!(request.params, deserialized.params);
452        assert_eq!(request.id, deserialized.id);
453    }
454
455    #[test]
456    fn test_request_take_params() {
457        let params = json!([1, 2, 3]);
458        let request = Request::new("test").with_params(params.clone());
459        let taken = request.take_params();
460        assert_eq!(taken, Some(params));
461    }
462
463    // Response tests
464    #[test]
465    fn test_response_success() {
466        let result = json!({"status": "ok"});
467        let response = Response::success(result.clone(), Some(json!(1)));
468
469        assert!(response.is_success());
470        assert!(!response.is_error());
471        assert_eq!(response.result(), Some(&result));
472        assert!(response.error.is_none());
473    }
474
475    #[test]
476    fn test_response_error() {
477        let error = crate::ErrorBuilder::new(-32600, "Invalid request").build();
478        let response = Response::error(error.clone(), Some(json!(1)));
479
480        assert!(!response.is_success());
481        assert!(response.is_error());
482        assert!(response.result.is_none());
483        assert_eq!(response.error_info().unwrap().code, error.code);
484    }
485
486    #[test]
487    fn test_response_serialization() {
488        let response = Response::success(json!("result"), Some(json!(1)));
489        let serialized = serde_json::to_string(&response).unwrap();
490        let deserialized: Response = serde_json::from_str(&serialized).unwrap();
491
492        assert_eq!(response.result, deserialized.result);
493        assert_eq!(response.id, deserialized.id);
494    }
495
496    #[test]
497    fn test_response_take_result() {
498        let result = json!({"data": "value"});
499        let response = Response::success(result.clone(), Some(json!(1)));
500        let taken = response.take_result();
501        assert_eq!(taken, Some(result));
502    }
503
504    #[test]
505    fn test_response_take_error() {
506        let error = crate::ErrorBuilder::new(-32600, "Error").build();
507        let response = Response::error(error.clone(), Some(json!(1)));
508        let taken = response.take_error();
509        assert!(taken.is_some());
510        assert_eq!(taken.unwrap().code(), error.code());
511    }
512
513    // Error tests
514    #[test]
515    fn test_error_creation() {
516        let error = crate::ErrorBuilder::new(-32600, "Test error").build();
517        assert_eq!(error.code(), -32600);
518        assert_eq!(error.message(), "Test error");
519        assert!(error.data().is_none());
520    }
521
522    #[test]
523    fn test_error_with_data() {
524        let data = json!({"details": "more info"});
525        let error = crate::ErrorBuilder::new(-32000, "Error")
526            .data(data.clone())
527            .build();
528        assert_eq!(error.data(), Some(&data));
529    }
530
531    #[test]
532    fn test_error_type_checks() {
533        assert!(
534            crate::ErrorBuilder::new(error_codes::PARSE_ERROR, "msg")
535                .build()
536                .is_parse_error()
537        );
538        assert!(
539            crate::ErrorBuilder::new(error_codes::INVALID_REQUEST, "msg")
540                .build()
541                .is_invalid_request()
542        );
543        assert!(
544            crate::ErrorBuilder::new(error_codes::METHOD_NOT_FOUND, "msg")
545                .build()
546                .is_method_not_found()
547        );
548        assert!(
549            crate::ErrorBuilder::new(error_codes::INVALID_PARAMS, "msg")
550                .build()
551                .is_invalid_params()
552        );
553        assert!(
554            crate::ErrorBuilder::new(error_codes::INTERNAL_ERROR, "msg")
555                .build()
556                .is_internal_error()
557        );
558        assert!(
559            crate::ErrorBuilder::new(-32001, "msg")
560                .build()
561                .is_server_error()
562        );
563        assert!(
564            !crate::ErrorBuilder::new(-32700, "msg")
565                .build()
566                .is_server_error()
567        );
568    }
569
570    #[test]
571    fn test_error_sanitization() {
572        let error = crate::ErrorBuilder::new(
573            -32603,
574            "Internal database connection failed: postgres://user:pass@host",
575        )
576        .build();
577        let sanitized = error
578            .sanitized_with(|e| crate::ErrorBuilder::new(e.code, "Internal server error").build());
579
580        assert_eq!(sanitized.code(), error.code());
581        assert_eq!(sanitized.message(), "Internal server error");
582        assert!(!sanitized.message().contains("postgres"));
583    }
584
585    #[test]
586    fn test_error_from_std_error() {
587        let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
588        let error = Error::from_error_logged(&io_error);
589
590        assert_eq!(error.code(), error_codes::INTERNAL_ERROR);
591        assert_eq!(error.message(), "Internal server error");
592    }
593
594    // Notification tests
595    #[test]
596    fn test_notification_creation() {
597        let notification = Notification::new("notify");
598        assert_eq!(notification.jsonrpc, "2.0");
599        assert_eq!(notification.method(), "notify");
600        assert!(notification.params().is_none());
601    }
602
603    #[test]
604    fn test_notification_with_params() {
605        let params = json!({"event": "update"});
606        let notification = Notification::new("notify").with_params(params.clone());
607        assert_eq!(notification.params(), Some(&params));
608    }
609
610    #[test]
611    fn test_notification_serialization() {
612        let notification = Notification::new("event").with_params(json!([1, 2]));
613        let serialized = serde_json::to_string(&notification).unwrap();
614        let deserialized: Notification = serde_json::from_str(&serialized).unwrap();
615
616        assert_eq!(notification.method, deserialized.method);
617        assert_eq!(notification.params, deserialized.params);
618    }
619
620    #[test]
621    fn test_notification_take_params() {
622        let params = json!({"event": "data"});
623        let notification = Notification::new("notify").with_params(params.clone());
624        let taken = notification.take_params();
625        assert_eq!(taken, Some(params));
626    }
627
628    // Message tests
629    #[test]
630    fn test_message_request_variant() {
631        let request = Request::new("test");
632        let message = Message::Request(request);
633
634        assert!(message.is_request());
635        assert!(!message.is_response());
636        assert!(!message.is_notification());
637    }
638
639    #[test]
640    fn test_message_response_variant() {
641        let response = Response::success(json!("ok"), Some(json!(1)));
642        let message = Message::Response(response);
643
644        assert!(!message.is_request());
645        assert!(message.is_response());
646        assert!(!message.is_notification());
647    }
648
649    #[test]
650    fn test_message_notification_variant() {
651        let notification = Notification::new("event");
652        let message = Message::Notification(notification);
653
654        assert!(!message.is_request());
655        assert!(!message.is_response());
656        assert!(message.is_notification());
657    }
658
659    #[test]
660    fn test_message_serialization_request() {
661        let request = Request::new("test").with_id(json!(1));
662        let message = Message::Request(request);
663
664        let serialized = serde_json::to_string(&message).unwrap();
665        let deserialized: Message = serde_json::from_str(&serialized).unwrap();
666
667        assert!(deserialized.is_request());
668    }
669
670    // Additional Message method tests
671    #[test]
672    fn test_message_as_request() {
673        let request = Request::new("test");
674        let message = Message::Request(request.clone());
675
676        assert!(message.as_request().is_some());
677        assert_eq!(message.as_request().unwrap().method, "test");
678        assert!(message.as_response().is_none());
679        assert!(message.as_notification().is_none());
680    }
681
682    #[test]
683    fn test_message_as_response() {
684        let response = Response::success(json!(42), Some(json!(1)));
685        let message = Message::Response(response);
686
687        assert!(message.as_response().is_some());
688        assert!(message.as_request().is_none());
689        assert!(message.as_notification().is_none());
690    }
691
692    #[test]
693    fn test_message_as_notification() {
694        let notification = Notification::new("event");
695        let message = Message::Notification(notification);
696
697        assert!(message.as_notification().is_some());
698        assert_eq!(message.as_notification().unwrap().method, "event");
699        assert!(message.as_request().is_none());
700        assert!(message.as_response().is_none());
701    }
702
703    #[test]
704    fn test_message_into_request() {
705        let request = Request::new("test");
706        let message = Message::Request(request);
707
708        let extracted = message.into_request();
709        assert!(extracted.is_some());
710        assert_eq!(extracted.unwrap().method, "test");
711    }
712
713    #[test]
714    fn test_message_into_response() {
715        let response = Response::success(json!(true), Some(json!(1)));
716        let message = Message::Response(response);
717
718        let extracted = message.into_response();
719        assert!(extracted.is_some());
720        assert!(extracted.unwrap().is_success());
721    }
722
723    #[test]
724    fn test_message_into_notification() {
725        let notification = Notification::new("notify");
726        let message = Message::Notification(notification);
727
728        let extracted = message.into_notification();
729        assert!(extracted.is_some());
730        assert_eq!(extracted.unwrap().method, "notify");
731    }
732
733    #[test]
734    fn test_message_into_wrong_type() {
735        let message = Message::Request(Request::new("test"));
736        assert!(message.clone().into_response().is_none());
737        assert!(message.into_notification().is_none());
738    }
739
740    #[test]
741    fn test_message_method_from_request() {
742        let request = Request::new("my_method");
743        let message = Message::Request(request);
744        assert_eq!(message.method(), Some("my_method"));
745    }
746
747    #[test]
748    fn test_message_method_from_notification() {
749        let notification = Notification::new("event_method");
750        let message = Message::Notification(notification);
751        assert_eq!(message.method(), Some("event_method"));
752    }
753
754    #[test]
755    fn test_message_method_from_response() {
756        let response = Response::success(json!(1), Some(json!(1)));
757        let message = Message::Response(response);
758        assert_eq!(message.method(), None);
759    }
760
761    #[test]
762    fn test_message_id_from_request() {
763        let request = Request::new("test").with_id(json!(123));
764        let message = Message::Request(request);
765        assert_eq!(message.id(), Some(&json!(123)));
766    }
767
768    #[test]
769    fn test_message_id_from_response() {
770        let response = Response::success(json!(1), Some(json!("abc")));
771        let message = Message::Response(response);
772        assert_eq!(message.id(), Some(&json!("abc")));
773    }
774
775    #[test]
776    fn test_message_id_from_notification() {
777        let notification = Notification::new("event");
778        let message = Message::Notification(notification);
779        assert_eq!(message.id(), None);
780    }
781
782    #[test]
783    fn test_message_id_none() {
784        let request = Request::new("test"); // No ID
785        let message = Message::Request(request);
786        assert_eq!(message.id(), None);
787    }
788
789    // Additional Request tests
790    #[test]
791    fn test_request_method_accessor() {
792        let request = Request::new("get_data");
793        assert_eq!(request.method(), "get_data");
794    }
795
796    #[test]
797    fn test_request_params_accessor() {
798        let params = json!({"key": "value"});
799        let request = Request::new("test").with_params(params.clone());
800        assert_eq!(request.params(), Some(&params));
801    }
802
803    #[test]
804    fn test_request_params_none() {
805        let request = Request::new("test");
806        assert_eq!(request.params(), None);
807    }
808
809    #[test]
810    fn test_request_id_accessor() {
811        let request = Request::new("test").with_id(json!(999));
812        assert_eq!(request.id(), Some(&json!(999)));
813    }
814
815    // Additional Response tests
816    #[test]
817    fn test_response_result_accessor() {
818        let result = json!({"data": "value"});
819        let response = Response::success(result.clone(), Some(json!(1)));
820        assert_eq!(response.result(), Some(&result));
821    }
822
823    #[test]
824    fn test_response_error_info() {
825        let error = crate::ErrorBuilder::new(-32600, "Invalid Request").build();
826        let response = Response::error(error.clone(), Some(json!(1)));
827        assert!(response.error_info().is_some());
828        assert_eq!(response.error_info().unwrap().code, -32600);
829    }
830
831    #[test]
832    fn test_response_id_accessor() {
833        let response = Response::success(json!(1), Some(json!("req-id")));
834        assert_eq!(response.id(), Some(&json!("req-id")));
835    }
836
837    // Additional Error tests
838    #[test]
839    fn test_error_code_accessor() {
840        let error = crate::ErrorBuilder::new(-32001, "Custom error").build();
841        assert_eq!(error.code(), -32001);
842    }
843
844    #[test]
845    fn test_error_message_accessor() {
846        let error = crate::ErrorBuilder::new(-32002, "Test message").build();
847        assert_eq!(error.message(), "Test message");
848    }
849
850    #[test]
851    fn test_error_data_accessor() {
852        let data = json!({"detail": "info"});
853        let error = crate::ErrorBuilder::new(-32003, "Error")
854            .data(data.clone())
855            .build();
856        assert_eq!(error.data(), Some(&data));
857    }
858
859    #[test]
860    fn test_error_data_none() {
861        let error = crate::ErrorBuilder::new(-32004, "Error").build();
862        assert_eq!(error.data(), None);
863    }
864
865    #[test]
866    fn test_error_is_invalid_params() {
867        let error = crate::ErrorBuilder::new(error_codes::INVALID_PARAMS, "Invalid").build();
868        assert!(error.is_invalid_params());
869        assert!(!error.is_parse_error());
870    }
871
872    #[test]
873    fn test_error_is_internal_error() {
874        let error = crate::ErrorBuilder::new(error_codes::INTERNAL_ERROR, "Internal").build();
875        assert!(error.is_internal_error());
876        assert!(!error.is_server_error());
877    }
878
879    #[test]
880    fn test_error_is_server_error() {
881        let error = crate::ErrorBuilder::new(-32050, "Server error").build();
882        assert!(error.is_server_error());
883        assert!(!error.is_internal_error());
884
885        // Boundary tests
886        let error_min = crate::ErrorBuilder::new(-32099, "Min").build();
887        assert!(error_min.is_server_error());
888
889        let error_max = crate::ErrorBuilder::new(-32000, "Max").build();
890        assert!(error_max.is_server_error());
891
892        let error_out = crate::ErrorBuilder::new(-31999, "Out of range").build();
893        assert!(!error_out.is_server_error());
894    }
895
896    #[test]
897    fn test_error_sanitized_with() {
898        let error =
899            crate::ErrorBuilder::new(-32603, "Database connection failed: host=db.internal")
900                .build();
901        let sanitized = error.sanitized_with(|e| {
902            crate::ErrorBuilder::new(e.code(), "Internal server error").build()
903        });
904
905        assert_eq!(sanitized.code(), -32603);
906        assert_eq!(sanitized.message(), "Internal server error");
907        assert!(!sanitized.message().contains("db.internal"));
908    }
909
910    // Additional Notification tests
911    #[test]
912    fn test_notification_method_accessor() {
913        let notification = Notification::new("user_logged_in");
914        assert_eq!(notification.method(), "user_logged_in");
915    }
916
917    #[test]
918    fn test_notification_params_accessor() {
919        let params = json!({"user_id": 123});
920        let notification = Notification::new("event").with_params(params.clone());
921        assert_eq!(notification.params(), Some(&params));
922    }
923
924    #[test]
925    fn test_notification_params_none() {
926        let notification = Notification::new("ping");
927        assert_eq!(notification.params(), None);
928    }
929
930    // Error constants tests
931    #[test]
932    fn test_error_code_constants() {
933        assert_eq!(error_codes::PARSE_ERROR, -32700);
934        assert_eq!(error_codes::INVALID_REQUEST, -32600);
935        assert_eq!(error_codes::METHOD_NOT_FOUND, -32601);
936        assert_eq!(error_codes::INVALID_PARAMS, -32602);
937        assert_eq!(error_codes::INTERNAL_ERROR, -32603);
938    }
939
940    #[test]
941    fn test_error_from_std_error_logging() {
942        use std::io;
943        let io_error = io::Error::new(io::ErrorKind::NotFound, "file not found");
944        let error = Error::from_error_logged(&io_error);
945
946        assert_eq!(error.code(), error_codes::INTERNAL_ERROR);
947        assert_eq!(error.message(), "Internal server error");
948    }
949
950    #[test]
951    fn test_request_correlation_id() {
952        let request = Request::new("test");
953        // Auto-generated correlation ID
954        assert!(request.correlation_id.is_some());
955    }
956
957    #[test]
958    fn test_response_with_correlation_id() {
959        let mut response = Response::success(json!(1), Some(json!(1)));
960        response.correlation_id = Some("custom-id".to_string());
961        assert_eq!(response.correlation_id, Some("custom-id".to_string()));
962    }
963}