use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
#[error("request failed")]
Reqwest(#[from] reqwest::Error),
#[error("invalid proxy: {proxy}: {source}")]
InvalidProxy {
proxy: String,
#[source]
source: Box<dyn std::error::Error + Send + Sync + 'static>,
},
#[error("failed to build the underlying client")]
Build(#[source] reqwest::Error),
}
impl Error {
pub(crate) fn invalid_proxy(proxy: impl Into<String>, reason: impl Into<String>) -> Self {
Error::InvalidProxy {
proxy: proxy.into(),
source: Box::new(ProxyReason(reason.into())),
}
}
}
#[derive(Debug)]
struct ProxyReason(String);
impl std::fmt::Display for ProxyReason {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl std::error::Error for ProxyReason {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn build_error_keeps_its_source() {
let inner = reqwest::Proxy::all("http://[").unwrap_err();
let err = Error::Build(inner);
assert!(std::error::Error::source(&err).is_some());
assert_eq!(err.to_string(), "failed to build the underlying client");
}
#[test]
fn reqwest_display_is_bare() {
let inner = reqwest::Proxy::all("http://[").unwrap_err();
let err = Error::from(inner);
assert!(std::error::Error::source(&err).is_some());
assert_eq!(err.to_string(), "request failed");
}
#[test]
fn invalid_proxy_keeps_its_source() {
let err = Error::invalid_proxy("http://proxy.example", "not a valid proxy URL");
assert!(std::error::Error::source(&err).is_some());
assert_eq!(
err.to_string(),
"invalid proxy: http://proxy.example: not a valid proxy URL"
);
}
}