languagetool_rust/
error.rs

1//! Error and Result structure used all across this crate.
2
3use std::process::ExitStatus;
4
5/// Enumeration of all possible error types.
6#[derive(Debug, thiserror::Error)]
7pub enum Error {
8    /// Error from the command line parsing (see [`clap::Error`]).
9    #[cfg(feature = "cli")]
10    #[error(transparent)]
11    Cli(#[from] clap::Error),
12
13    /// Error when a process command was not found.
14    #[error("command not found: {0}")]
15    CommandNotFound(String),
16
17    /// Error from a command line process (see [`std::process::Command`]).
18    #[error("command failed: {0:?}")]
19    ExitStatus(String),
20
21    /// Error specifying an invalid
22    /// [`DataAnnotation`](`crate::api::check::DataAnnotation`).
23    #[error("invalid request: {0}")]
24    InvalidDataAnnotation(String),
25
26    /// Error from checking if `filename` exists and is a actually a file.
27    #[error("invalid filename (got '{0}', does not exist or is not a file)")]
28    InvalidFilename(String),
29
30    /// Error specifying an invalid request.
31    #[error("invalid request: {0}")]
32    InvalidRequest(String),
33
34    /// Error specifying an invalid value.
35    #[error("invalid value: {0:?}")]
36    InvalidValue(String),
37
38    /// Error from reading and writing to IO (see [`std::io::Error`]).
39    #[error(transparent)]
40    IO(#[from] std::io::Error),
41
42    /// Error when joining multiple futures.
43    #[cfg(feature = "multithreaded")]
44    #[error(transparent)]
45    JoinError(#[from] tokio::task::JoinError),
46
47    /// Error from parsing JSON (see [`serde_json::Error`]).
48    #[error(transparent)]
49    JSON(#[from] serde_json::Error),
50
51    /// Error while parsing Action.
52    #[error("could not parse {0:?} in a Docker action")]
53    ParseAction(String),
54
55    /// Any other error from requests (see [`reqwest::Error`]).
56    #[error(transparent)]
57    Reqwest(#[from] reqwest::Error),
58
59    /// Error from reading environ variable (see [`std::env::VarError`]).
60    #[error(transparent)]
61    VarError(#[from] std::env::VarError),
62}
63
64/// Result type alias with error type defined above (see [`Error`]]).
65pub type Result<T> = std::result::Result<T, Error>;
66
67#[allow(dead_code)]
68pub(crate) fn exit_status_error(exit_status: &ExitStatus) -> Result<()> {
69    match exit_status.success() {
70        true => Ok(()),
71        false => {
72            match exit_status.code() {
73                Some(code) => {
74                    Err(Error::ExitStatus(format!(
75                        "Process terminated with exit code: {code}"
76                    )))
77                },
78                None => {
79                    Err(Error::ExitStatus(
80                        "Process terminated by signal".to_string(),
81                    ))
82                },
83            }
84        },
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use assert_matches::assert_matches;
91
92    use crate::error::Error;
93    #[cfg(feature = "cli")]
94    use clap::Command;
95
96    #[cfg(feature = "cli")]
97    #[test]
98    fn test_error_cli() {
99        let result =
100            Command::new("").try_get_matches_from(vec!["some", "args", "that", "should", "fail"]);
101        assert!(result.is_err());
102
103        let error: Error = result.unwrap_err().into();
104
105        assert_matches!(error, Error::Cli(_));
106    }
107
108    #[test]
109    fn test_error_json() {
110        let result = serde_json::from_str::<serde_json::Value>("invalid JSON");
111        assert!(result.is_err());
112
113        let error: Error = result.unwrap_err().into();
114
115        assert_matches!(error, Error::JSON(_));
116    }
117
118    #[test]
119    fn test_error_io() {
120        let result = std::fs::read_to_string("");
121        assert!(result.is_err());
122
123        let error: Error = result.unwrap_err().into();
124
125        assert_matches!(error, Error::IO(_));
126    }
127
128    #[test]
129    fn test_error_invalid_request() {
130        let result = crate::api::check::Request::new().try_get_text();
131        assert!(result.is_err());
132
133        let error: Error = result.unwrap_err().into();
134
135        assert_matches!(error, Error::InvalidRequest(_));
136    }
137
138    #[test]
139    fn test_error_invalid_value() {
140        let result = crate::api::server::parse_port("test");
141        assert!(result.is_err());
142
143        let error: Error = result.unwrap_err().into();
144
145        assert_matches!(error, Error::InvalidValue(_));
146    }
147
148    #[tokio::test]
149    async fn test_error_reqwest() {
150        let result = reqwest::get("").await;
151        let error: Error = result.unwrap_err().into();
152
153        assert_matches!(error, Error::Reqwest(_));
154    }
155}