1use serde::{ser::Serializer, Serialize};
2
3pub type Result<T> = std::result::Result<T, Error>;
4
5#[derive(Debug, thiserror::Error)]
6pub enum Error {
7 #[error(transparent)]
8 Io(#[from] std::io::Error),
9
10 #[error("Command analysis failed: {0}")]
11 CommandAnalysis(String),
12
13 #[error("Code generation failed: {0}")]
14 CodeGeneration(String),
15
16 #[error("Invalid project path: {0}")]
17 InvalidProjectPath(String),
18}
19
20impl Serialize for Error {
21 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
22 where
23 S: Serializer,
24 {
25 serializer.serialize_str(self.to_string().as_ref())
26 }
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32 use std::io;
33
34 mod error_variants {
35 use super::*;
36
37 #[test]
38 fn test_io_error_creation() {
39 let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
40 let err = Error::from(io_err);
41 assert!(matches!(err, Error::Io(_)));
42 assert!(err.to_string().contains("file not found"));
43 }
44
45 #[test]
46 fn test_command_analysis_error() {
47 let err = Error::CommandAnalysis("failed to parse command".to_string());
48 assert!(matches!(err, Error::CommandAnalysis(_)));
49 assert_eq!(
50 err.to_string(),
51 "Command analysis failed: failed to parse command"
52 );
53 }
54
55 #[test]
56 fn test_code_generation_error() {
57 let err = Error::CodeGeneration("template rendering failed".to_string());
58 assert!(matches!(err, Error::CodeGeneration(_)));
59 assert_eq!(
60 err.to_string(),
61 "Code generation failed: template rendering failed"
62 );
63 }
64
65 #[test]
66 fn test_invalid_project_path_error() {
67 let err = Error::InvalidProjectPath("/invalid/path".to_string());
68 assert!(matches!(err, Error::InvalidProjectPath(_)));
69 assert_eq!(err.to_string(), "Invalid project path: /invalid/path");
70 }
71 }
72
73 mod error_display {
74 use super::*;
75
76 #[test]
77 fn test_command_analysis_display() {
78 let err = Error::CommandAnalysis("test error".to_string());
79 let display = format!("{}", err);
80 assert!(display.contains("Command analysis failed"));
81 assert!(display.contains("test error"));
82 }
83
84 #[test]
85 fn test_code_generation_display() {
86 let err = Error::CodeGeneration("test error".to_string());
87 let display = format!("{}", err);
88 assert!(display.contains("Code generation failed"));
89 assert!(display.contains("test error"));
90 }
91
92 #[test]
93 fn test_invalid_project_path_display() {
94 let err = Error::InvalidProjectPath("test path".to_string());
95 let display = format!("{}", err);
96 assert!(display.contains("Invalid project path"));
97 assert!(display.contains("test path"));
98 }
99
100 #[test]
101 fn test_debug_format() {
102 let err = Error::CommandAnalysis("test".to_string());
103 let debug = format!("{:?}", err);
104 assert!(debug.contains("CommandAnalysis"));
105 }
106 }
107
108 mod serialization {
109 use super::*;
110
111 #[test]
112 fn test_serialize_command_analysis_error() {
113 let err = Error::CommandAnalysis("test error".to_string());
114 let serialized = serde_json::to_string(&err).unwrap();
115 assert!(serialized.contains("Command analysis failed"));
116 assert!(serialized.contains("test error"));
117 }
118
119 #[test]
120 fn test_serialize_code_generation_error() {
121 let err = Error::CodeGeneration("generation failed".to_string());
122 let serialized = serde_json::to_string(&err).unwrap();
123 assert!(serialized.contains("Code generation failed"));
124 assert!(serialized.contains("generation failed"));
125 }
126
127 #[test]
128 fn test_serialize_invalid_project_path_error() {
129 let err = Error::InvalidProjectPath("/bad/path".to_string());
130 let serialized = serde_json::to_string(&err).unwrap();
131 assert!(serialized.contains("Invalid project path"));
132 assert!(serialized.contains("/bad/path"));
133 }
134
135 #[test]
136 fn test_serialize_io_error() {
137 let io_err = io::Error::new(io::ErrorKind::NotFound, "not found");
138 let err = Error::from(io_err);
139 let serialized = serde_json::to_string(&err).unwrap();
140 assert!(serialized.contains("not found"));
141 }
142 }
143
144 mod result_type {
145 use super::*;
146
147 #[test]
148 fn test_result_err() {
149 let result: Result<i32> = Err(Error::CommandAnalysis("test".to_string()));
150 assert!(result.is_err());
151 }
152
153 #[test]
154 fn test_result_with_question_mark() {
155 fn test_fn() -> Result<String> {
156 let err = Error::CommandAnalysis("test".to_string());
157 Err(err)?;
158 Ok("success".to_string())
159 }
160
161 let result = test_fn();
162 assert!(result.is_err());
163 }
164 }
165
166 mod from_conversions {
167 use super::*;
168
169 #[test]
170 fn test_from_io_error() {
171 let io_err = io::Error::new(io::ErrorKind::PermissionDenied, "access denied");
172 let err: Error = io_err.into();
173 assert!(matches!(err, Error::Io(_)));
174 }
175
176 #[test]
177 fn test_io_error_kind_preserved() {
178 let io_err = io::Error::new(io::ErrorKind::NotFound, "missing");
179 let err = Error::from(io_err);
180 if let Error::Io(inner) = err {
181 assert_eq!(inner.kind(), io::ErrorKind::NotFound);
182 } else {
183 panic!("Expected Io error variant");
184 }
185 }
186 }
187}