human_errors/
helpers.rs

1pub use super::Error;
2use std::error;
3
4/// A basic error triggered by something the user has done.
5///
6/// Constructs a new [Error] describing a failure which was the result of an
7/// action that the user has taken. This error includes a description of what
8/// occurred, as well as some advice for the user to try to mitigate the problem.
9///
10/// # Examples
11/// ```
12/// use human_errors;
13///
14/// human_errors::user(
15///   "We could not open the config file you provided.",
16///   "Make sure that the file exists and is readable by the application.",
17/// );
18/// ```
19pub fn user(description: &str, advice: &str) -> Error {
20    Error::UserError(description.to_string(), advice.to_string(), None, None)
21}
22
23/// An error triggered by something the user has done, with a deeper cause.
24///
25/// Constructs a new [Error] describing a failure which was the result of an
26/// action that the user has taken. This error includes a description of what
27/// occurred, as well as some advice for the user to try to mitigate the problem.
28/// It also includes the details of another error which resulted in this failure,
29/// as well as any advice that error may provide.
30///
31/// # Examples
32/// ```
33/// use human_errors;
34///
35/// human_errors::user_with_cause(
36///   "We could not open the config file you provided.",
37///   "Make sure that you've specified a valid config file with the --config option.",
38///   human_errors::user(
39///     "We could not find a file at /home/user/.config/demo.yml",
40///     "Make sure that the file exists and is readable by the application."
41///   )
42/// );
43/// ```
44pub fn user_with_cause(description: &str, advice: &str, cause: Error) -> Error {
45    Error::UserError(
46        description.to_string(),
47        advice.to_string(),
48        Some(Box::from(cause)),
49        None,
50    )
51}
52
53/// An error triggered by something the user has done, with a deeper cause.
54///
55/// Constructs a new [Error] describing a failure which was the result of an
56/// action that the user has taken. This error includes a description of what
57/// occurred, as well as some advice for the user to try to mitigate the problem.
58/// It also includes the details of another error which resulted in this failure.
59///
60/// **NOTE**: The internal error may be any type which may be converted into a [Box<std::error::Error>].
61///
62/// # Examples
63/// ```
64/// use human_errors;
65///
66/// human_errors::user_with_internal(
67///   "We could not open the config file you provided.",
68///   "Make sure that the file exists and is readable by the application.",
69///   human_errors::detailed_message("ENOENT 2: No such file or directory")
70/// );
71/// ```
72pub fn user_with_internal<T>(description: &str, advice: &str, internal: T) -> Error
73where
74    T: Into<Box<dyn error::Error + Send + Sync>>,
75{
76    Error::UserError(
77        description.to_string(),
78        advice.to_string(),
79        None,
80        Some(internal.into()),
81    )
82}
83
84/// An error triggered by the system rather than the user.
85///
86/// Constructs a new [Error] describing a failure which was the result of a failure
87/// in the system, rather than a user's action. This error includes a description of what
88/// occurred, as well as some advice for the user to try to mitigate the problem.
89///
90/// # Examples
91/// ```
92/// use human_errors;
93///
94/// human_errors::system(
95///   "We could not open the config file you provided.",
96///   "Make sure that the file exists and is readable by the application."
97/// );
98/// ```
99pub fn system(description: &str, advice: &str) -> Error {
100    Error::SystemError(description.to_string(), advice.to_string(), None, None)
101}
102
103/// An error triggered by the system rather than the user, with a deeper cause.
104///
105/// Constructs a new [Error] describing a failure which was the result of a failure
106/// in the system, rather than a user's action. This error includes a description of what
107/// occurred, as well as some advice for the user to try to mitigate the problem.
108/// It also includes the details of another error which resulted in this failure,
109/// as well as any advice that error may provide.
110///
111/// # Examples
112/// ```
113/// use human_errors;
114///
115/// human_errors::system_with_cause(
116///   "We could not open the config file you provided.",
117///   "Make sure that you've specified a valid config file with the --config option.",
118///   human_errors::system(
119///     "We could not find a file at /home/user/.config/demo.yml",
120///     "Make sure that the file exists and is readable by the application."
121///   )
122/// );
123/// ```
124pub fn system_with_cause(description: &str, advice: &str, cause: Error) -> Error {
125    Error::SystemError(
126        description.to_string(),
127        advice.to_string(),
128        Some(Box::from(cause)),
129        None,
130    )
131}
132
133/// An error triggered by the system rather than the user, with a deeper cause.
134///
135/// Constructs a new [Error] describing a failure which was the result of a failure
136/// in the system, rather than a user's action. This error includes a description of what
137/// occurred, as well as some advice for the user to try to mitigate the problem.
138/// It also includes the details of another error which resulted in this failure.
139///
140/// **NOTE**: The internal error may be any type which may be converted into a [Box<std::error::Error>].
141///
142/// # Examples
143/// ```
144/// use human_errors;
145///
146/// human_errors::system_with_internal(
147///   "We could not open the config file you provided.",
148///   "Make sure that the file exists and is readable by the application.",
149///   human_errors::detailed_message("ENOENT 2: No such file or directory")
150/// );
151/// ```
152pub fn system_with_internal<T>(description: &str, advice: &str, internal: T) -> Error
153where
154    T: Into<Box<dyn error::Error + Send + Sync>>,
155{
156    Error::SystemError(
157        description.to_string(),
158        advice.to_string(),
159        None,
160        Some(internal.into()),
161    )
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    #[test]
169    fn test_description() {
170        assert_eq!(
171            user(
172                "Something bad happened",
173                "Avoid bad things happening in future"
174            )
175            .description(),
176            "Something bad happened"
177        );
178
179        assert_eq!(
180            system(
181                "Something bad happened",
182                "Avoid bad things happening in future"
183            )
184            .description(),
185            "Something bad happened"
186        );
187    }
188
189    #[test]
190    fn test_message_basic() {
191        assert_eq!(
192            user(
193                "Something bad happened.",
194                "Avoid bad things happening in future"
195            )
196            .message(),
197            "Oh no! Something bad happened.\n\nTo try and fix this, you can:\n - Avoid bad things happening in future"
198        );
199
200        assert_eq!(
201            system(
202                "Something bad happened.",
203                "Avoid bad things happening in future"
204            )
205            .message(),
206            "Whoops! Something bad happened. (This isn't your fault)\n\nTo try and fix this, you can:\n - Avoid bad things happening in future"
207        );
208    }
209
210    #[test]
211    fn test_message_cause() {
212        assert_eq!(
213            user_with_cause(
214                "Something bad happened.",
215                "Avoid bad things happening in future",
216                user("You got rate limited by GitHub.", "Wait a few minutes and try again.")
217            )
218            .message(),
219            "Oh no! Something bad happened.\n\nThis was caused by:\n - You got rate limited by GitHub.\n\nTo try and fix this, you can:\n - Wait a few minutes and try again.\n - Avoid bad things happening in future"
220        );
221
222        assert_eq!(
223            system_with_cause(
224                "Something bad happened.",
225                "Avoid bad things happening in future",
226                system("You got rate limited by GitHub.", "Wait a few minutes and try again.")
227            )
228            .message(),
229            "Whoops! Something bad happened. (This isn't your fault)\n\nThis was caused by:\n - You got rate limited by GitHub.\n\nTo try and fix this, you can:\n - Wait a few minutes and try again.\n - Avoid bad things happening in future"
230        );
231    }
232
233    #[test]
234    fn test_message_empty_causes() {
235        assert_eq!(
236            user_with_cause(
237                "Something bad happened.",
238                "",
239                user("You got rate limited by GitHub.", "Wait a few minutes and try again.")
240            )
241            .message(),
242            "Oh no! Something bad happened.\n\nThis was caused by:\n - You got rate limited by GitHub.\n\nTo try and fix this, you can:\n - Wait a few minutes and try again."
243        );
244    }
245}