1use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum ImportError {
7 #[error("refusing to import a symlinked settings file: {0}")]
8 SymlinkRejected(String),
9
10 #[error("settings import needs explicit approval for this source path: {0}")]
11 ConsentRequired(String),
12
13 #[error("unknown import product `{0}` (supported: claude, opencode, grok, codex)")]
14 UnknownProduct(String),
15
16 #[error("failed to parse {path}: {message}")]
17 Parse { path: String, message: String },
18
19 #[error("I/O error: {0}")]
20 Io(#[from] std::io::Error),
21
22 #[error("JSON error: {0}")]
23 Json(#[from] serde_json::Error),
24
25 #[error("TOML error: {0}")]
26 Toml(#[from] toml::de::Error),
27
28 #[error("{0}")]
29 Msg(String),
30}
31
32pub type Result<T> = std::result::Result<T, ImportError>;
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn error_display() {
40 assert!(
41 ImportError::UnknownProduct("x".into())
42 .to_string()
43 .contains("claude")
44 );
45 assert!(
46 ImportError::ConsentRequired("/tmp/a".into())
47 .to_string()
48 .contains("approval")
49 );
50 assert!(
51 ImportError::SymlinkRejected("/tmp/b".into())
52 .to_string()
53 .contains("symlink")
54 );
55 assert!(
56 ImportError::Parse {
57 path: "a.json".into(),
58 message: "nope".into()
59 }
60 .to_string()
61 .contains("a.json")
62 );
63 assert!(ImportError::Msg("x".into()).to_string().contains('x'));
64 let io = ImportError::from(std::io::Error::other("io"));
65 assert!(io.to_string().contains("I/O"));
66 let json = ImportError::from(serde_json::from_str::<u8>("x").unwrap_err());
67 assert!(json.to_string().contains("JSON"));
68 let toml = ImportError::from(toml::from_str::<toml::Value>("[[[").unwrap_err());
69 assert!(toml.to_string().contains("TOML"));
70 }
71}