1use std::path::PathBuf;
2
3use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum BvrError {
7 #[error("io error: {0}")]
8 Io(#[from] std::io::Error),
9
10 #[error("json parse error: {0}")]
11 Json(#[from] serde_json::Error),
12
13 #[error("sqlite error: {0}")]
14 Sqlite(#[from] rusqlite::Error),
15
16 #[error("beads directory not found: {0}")]
17 MissingBeadsDir(PathBuf),
18
19 #[error("no beads JSONL file found in {0}")]
20 MissingBeadsFile(PathBuf),
21
22 #[error("invalid issue data: {0}")]
23 InvalidIssue(String),
24
25 #[error("invalid argument: {0}")]
26 InvalidArgument(String),
27
28 #[error("tui runtime error: {0}")]
29 Tui(String),
30}
31
32pub type Result<T> = std::result::Result<T, BvrError>;
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn io_error_display_includes_source() {
40 let err = BvrError::Io(std::io::Error::new(std::io::ErrorKind::NotFound, "gone"));
41 assert!(err.to_string().contains("io error"));
42 assert!(err.to_string().contains("gone"));
43 }
44
45 #[test]
46 fn json_error_converts_from_serde() {
47 let bad_json = "{{invalid";
48 let result: std::result::Result<serde_json::Value, _> = serde_json::from_str(bad_json);
49 let serde_err = result.unwrap_err();
50 let err: BvrError = serde_err.into();
51 assert!(err.to_string().contains("json parse error"));
52 }
53
54 #[test]
55 fn sqlite_error_converts_from_rusqlite() {
56 let conn = rusqlite::Connection::open_in_memory().expect("open in-memory sqlite");
57 let sqlite_err = conn
58 .execute("SELECT definitely_not_valid_sql", [])
59 .expect_err("invalid SQL should fail");
60 let err: BvrError = sqlite_err.into();
61 assert!(err.to_string().contains("sqlite error"));
62 }
63
64 #[test]
65 fn missing_beads_dir_shows_path() {
66 let err = BvrError::MissingBeadsDir(PathBuf::from("/tmp/nope"));
67 assert!(err.to_string().contains("/tmp/nope"));
68 }
69
70 #[test]
71 fn missing_beads_file_shows_path() {
72 let err = BvrError::MissingBeadsFile(PathBuf::from("/tmp/.beads"));
73 assert!(err.to_string().contains("/tmp/.beads"));
74 }
75
76 #[test]
77 fn invalid_issue_shows_detail() {
78 let err = BvrError::InvalidIssue("bad id".to_string());
79 assert!(err.to_string().contains("bad id"));
80 }
81
82 #[test]
83 fn invalid_argument_shows_detail() {
84 let err = BvrError::InvalidArgument("--unknown".to_string());
85 assert!(err.to_string().contains("--unknown"));
86 }
87
88 #[test]
89 fn tui_error_shows_detail() {
90 let err = BvrError::Tui("render crash".to_string());
91 assert!(err.to_string().contains("render crash"));
92 }
93
94 #[test]
95 fn error_debug_format_works() {
96 let err = BvrError::InvalidArgument("test".to_string());
97 let debug_str = format!("{err:?}");
98 assert!(debug_str.contains("InvalidArgument"));
99 }
100}