Skip to main content

yesser_todo_errors/
db_error.rs

1use thiserror::Error;
2
3#[derive(Debug, Error)]
4pub enum DatabaseError {
5    #[error("A JSON deserialization error occured: {0}")]
6    JsonError(serde_json::Error),
7
8    #[error("An error occurred while writing to config file or directory: {0}")]
9    IOError(std::io::Error),
10
11    #[error("Could not get user config directory location")]
12    UserDirsError,
13}
14
15impl From<serde_json::Error> for DatabaseError {
16    /// Convert a `serde_json::Error` into `DatabaseError::JsonError`.
17    ///
18    /// # Examples
19    ///
20    /// ```
21    /// use yesser_todo_errors::db_error::DatabaseError;
22    /// let serde_err = serde_json::from_str::<serde_json::Value>("not json").unwrap_err();
23    /// let db_err = DatabaseError::from(serde_err);
24    /// assert!(matches!(db_err, DatabaseError::JsonError(_)));
25    /// ```
26    fn from(value: serde_json::Error) -> Self {
27        Self::JsonError(value)
28    }
29}
30
31impl From<std::io::Error> for DatabaseError {
32    /// Convert an `std::io::Error` into a `DatabaseError::IOError`.
33    ///
34    /// # Examples
35    ///
36    /// ```
37    /// use yesser_todo_errors::db_error::DatabaseError;
38    /// let io_err = std::io::Error::new(std::io::ErrorKind::Other, "oops");
39    /// let db_err = DatabaseError::from(io_err);
40    /// match db_err {
41    ///     DatabaseError::IOError(e) => assert_eq!(e.to_string(), "oops"),
42    ///     _ => panic!("expected IOError"),
43    /// }
44    /// ```
45    fn from(err: std::io::Error) -> Self {
46        Self::IOError(err)
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use std::io::ErrorKind;
54
55    #[test]
56    fn test_from_json_error() {
57        let json_err = serde_json::from_str::<serde_json::Value>("not valid json").unwrap_err();
58        let db_err = DatabaseError::from(json_err);
59        assert!(matches!(db_err, DatabaseError::JsonError(_)));
60    }
61
62    #[test]
63    fn test_from_io_error() {
64        let io_err = std::io::Error::new(ErrorKind::NotFound, "file not found");
65        let db_err = DatabaseError::from(io_err);
66        match db_err {
67            DatabaseError::IOError(e) => {
68                assert_eq!(e.kind(), ErrorKind::NotFound);
69                assert_eq!(e.to_string(), "file not found");
70            }
71            _ => panic!("expected IOError"),
72        }
73    }
74
75    #[test]
76    fn test_json_error_display() {
77        let json_err = serde_json::from_str::<serde_json::Value>("{bad json}").unwrap_err();
78        let db_err = DatabaseError::JsonError(json_err);
79        let display = format!("{}", db_err);
80        assert!(display.contains("JSON deserialization error occured"));
81    }
82
83    #[test]
84    fn test_io_error_display() {
85        let io_err = std::io::Error::new(ErrorKind::PermissionDenied, "access denied");
86        let db_err = DatabaseError::IOError(io_err);
87        let display = format!("{}", db_err);
88        assert!(display.contains("error occurred while writing to config file or directory"));
89        assert!(display.contains("access denied"));
90    }
91
92    #[test]
93    fn test_user_dirs_error_display() {
94        let db_err = DatabaseError::UserDirsError;
95        let display = format!("{}", db_err);
96        assert_eq!(display, "Could not get user config directory location");
97    }
98
99    #[test]
100    fn test_database_error_is_error_trait() {
101        fn assert_error<T: std::error::Error>() {}
102        assert_error::<DatabaseError>();
103    }
104
105    #[test]
106    fn test_database_error_debug() {
107        let db_err = DatabaseError::UserDirsError;
108        let debug_str = format!("{:?}", db_err);
109        assert!(debug_str.contains("UserDirsError"));
110    }
111
112    #[test]
113    fn test_from_various_io_error_kinds() {
114        let error_kinds = vec![
115            ErrorKind::NotFound,
116            ErrorKind::PermissionDenied,
117            ErrorKind::AlreadyExists,
118            ErrorKind::WouldBlock,
119        ];
120
121        for kind in error_kinds {
122            let io_err = std::io::Error::new(kind, "test error");
123            let db_err = DatabaseError::from(io_err);
124            match db_err {
125                DatabaseError::IOError(e) => assert_eq!(e.kind(), kind),
126                _ => panic!("expected IOError for kind {:?}", kind),
127            }
128        }
129    }
130
131    #[test]
132    fn test_json_error_from_invalid_types() {
133        let json_err = serde_json::from_str::<Vec<String>>("{\"not\": \"an array\"}").unwrap_err();
134        let db_err = DatabaseError::from(json_err);
135        assert!(matches!(db_err, DatabaseError::JsonError(_)));
136    }
137}