every_other_token/
error.rs1use thiserror::Error;
8
9#[derive(Debug, Error)]
12pub enum EotError {
13 #[error("API key not set: {0}")]
15 ApiKeyMissing(String),
16
17 #[error("invalid transform '{0}': {1}")]
19 InvalidTransform(String, String),
20
21 #[error("provider HTTP {status} from {url}")]
23 ProviderHttp { status: u16, url: String },
24
25 #[error("provider JSON parse error: {0}")]
27 ProviderJson(String),
28
29 #[error("HTTP client error: {0}")]
31 Http(#[from] reqwest::Error),
32
33 #[error("JSON error: {0}")]
35 Json(#[from] serde_json::Error),
36
37 #[error("I/O error: {0}")]
39 Io(#[from] std::io::Error),
40
41 #[error("database error: {0}")]
43 Database(#[from] rusqlite::Error),
44
45 #[error("{0}")]
48 Other(String),
49}
50
51impl From<Box<dyn std::error::Error + Send + Sync>> for EotError {
52 fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
53 EotError::Other(e.to_string())
54 }
55}
56
57impl From<Box<dyn std::error::Error>> for EotError {
58 fn from(e: Box<dyn std::error::Error>) -> Self {
59 EotError::Other(e.to_string())
60 }
61}
62
63impl From<String> for EotError {
64 fn from(s: String) -> Self {
65 EotError::Other(s)
66 }
67}
68
69impl From<&str> for EotError {
70 fn from(s: &str) -> Self {
71 EotError::Other(s.to_string())
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_api_key_missing_message() {
81 let e = EotError::ApiKeyMissing("OPENAI_API_KEY".to_string());
82 assert!(e.to_string().contains("OPENAI_API_KEY"));
83 }
84
85 #[test]
86 fn test_invalid_transform_message() {
87 let e = EotError::InvalidTransform("foo".to_string(), "unknown".to_string());
88 assert!(e.to_string().contains("foo"));
89 assert!(e.to_string().contains("unknown"));
90 }
91
92 #[test]
93 fn test_provider_http_message() {
94 let e = EotError::ProviderHttp {
95 status: 429,
96 url: "https://api.openai.com".to_string(),
97 };
98 let msg = e.to_string();
99 assert!(msg.contains("429"));
100 assert!(msg.contains("openai.com"));
101 }
102
103 #[test]
104 fn test_other_wraps_string() {
105 let e: EotError = EotError::from("something went wrong");
106 assert_eq!(e.to_string(), "something went wrong");
107 }
108
109 #[test]
110 fn test_from_string() {
111 let e: EotError = "my error".to_string().into();
112 assert_eq!(e.to_string(), "my error");
113 }
114
115 #[test]
116 fn test_io_error_wraps() {
117 let io = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
118 let e = EotError::Io(io);
119 assert!(e.to_string().contains("file missing"));
120 }
121
122 #[test]
123 fn test_provider_json_message() {
124 let e = EotError::ProviderJson("unexpected field".to_string());
125 assert!(e.to_string().contains("unexpected field"));
126 }
127
128 #[test]
129 fn test_json_error_wraps() {
130 let json_err = serde_json::from_str::<serde_json::Value>("{{invalid").unwrap_err();
131 let e = EotError::Json(json_err);
132 assert!(e.to_string().contains("JSON error"));
133 }
134
135 #[test]
136 fn test_debug_format() {
137 let e = EotError::ApiKeyMissing("TEST_KEY".to_string());
138 let debug = format!("{:?}", e);
139 assert!(debug.contains("ApiKeyMissing"));
140 }
141}