1use std::path::PathBuf;
4
5use venus_core::graph::CellId;
6
7#[derive(Debug, thiserror::Error)]
9pub enum ServerError {
10 #[error("IO error at {path}: {message}")]
12 Io { path: PathBuf, message: String },
13
14 #[error("Core error: {0}")]
16 Core(#[from] venus_core::Error),
17
18 #[error("Cell not found: {0:?}")]
20 CellNotFound(CellId),
21
22 #[error("Execution already in progress")]
24 ExecutionInProgress,
25
26 #[error("WebSocket error: {0}")]
28 WebSocket(String),
29
30 #[error("JSON error: {0}")]
32 Json(#[from] serde_json::Error),
33
34 #[error("File watch error: {0}")]
36 Watch(String),
37
38 #[error("Execution aborted")]
40 ExecutionAborted,
41
42 #[error("Execution timed out")]
44 ExecutionTimeout,
45
46 #[error("Invalid operation: {0}")]
48 InvalidOperation(String),
49}
50
51impl From<std::io::Error> for ServerError {
52 fn from(e: std::io::Error) -> Self {
53 Self::Io {
54 path: PathBuf::new(),
55 message: e.to_string(),
56 }
57 }
58}
59
60pub type ServerResult<T> = Result<T, ServerError>;
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn test_error_display() {
69 let err = ServerError::CellNotFound(CellId::new(42));
70 assert_eq!(err.to_string(), "Cell not found: CellId(42)");
71
72 let err = ServerError::ExecutionInProgress;
73 assert_eq!(err.to_string(), "Execution already in progress");
74
75 let err = ServerError::ExecutionAborted;
76 assert_eq!(err.to_string(), "Execution aborted");
77
78 let err = ServerError::ExecutionTimeout;
79 assert_eq!(err.to_string(), "Execution timed out");
80 }
81
82 #[test]
83 fn test_io_error_conversion() {
84 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
85 let server_err: ServerError = io_err.into();
86
87 match server_err {
88 ServerError::Io { path, message } => {
89 assert_eq!(path, PathBuf::new());
90 assert!(message.contains("file not found"));
91 }
92 _ => panic!("Expected Io error"),
93 }
94 }
95
96 #[test]
97 fn test_json_error_conversion() {
98 let json_str = "{invalid json";
99 let json_err = serde_json::from_str::<serde_json::Value>(json_str).unwrap_err();
100 let server_err: ServerError = json_err.into();
101
102 assert!(matches!(server_err, ServerError::Json(_)));
103 }
104
105 #[test]
106 fn test_core_error_conversion() {
107 let core_err = venus_core::Error::CellNotFound("test_cell".to_string());
109 let server_err: ServerError = core_err.into();
110
111 assert!(matches!(server_err, ServerError::Core(_)));
112 assert!(server_err.to_string().contains("test_cell"));
113 }
114
115 #[test]
116 fn test_custom_errors() {
117 let err = ServerError::Io {
118 path: PathBuf::from("/test/file.rs"),
119 message: "Permission denied".to_string(),
120 };
121 assert!(err.to_string().contains("/test/file.rs"));
122 assert!(err.to_string().contains("Permission denied"));
123
124 let err = ServerError::Watch("debouncer failed".to_string());
125 assert_eq!(err.to_string(), "File watch error: debouncer failed");
126
127 let err = ServerError::WebSocket("connection closed".to_string());
128 assert_eq!(err.to_string(), "WebSocket error: connection closed");
129
130 let err = ServerError::InvalidOperation("Cannot delete cell with dependencies".to_string());
131 assert!(err
132 .to_string()
133 .contains("Cannot delete cell with dependencies"));
134 }
135}