use std::io;
use http::uri::InvalidUri;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("auth error: {0}")]
Auth(String),
#[error("conversion error: {0}")]
Conversion(String),
#[error("http error: {0}")]
Http(#[from] reqwest::Error),
#[error("http build error: {0}")]
HttpBuild(#[from] http::Error),
#[error("internal error: {0}")]
Internal(String),
#[error("io error: {0}")]
Io(#[from] io::Error),
#[error("s3 error {code}: {message}")]
S3 {
code: String,
message: String,
},
#[error("invalid uri: {0}")]
Uri(#[from] InvalidUri),
#[error("walk error: {0}")]
Walk(#[from] walkdir::Error),
}
pub type Result<T> = core::result::Result<T, Error>;
pub(crate) fn missing_env(name: &str) -> Error {
Error::Auth(format!("{name} not set"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn missing_env_formats_var_name() {
let err = missing_env("MY_VAR");
match err {
Error::Auth(msg) => assert_eq!(msg, "MY_VAR not set"),
other => panic!("expected Auth, got {other:?}"),
}
}
#[test]
fn display_auth_error() {
let err = Error::Auth("creds expired".into());
assert_eq!(format!("{err}"), "auth error: creds expired");
}
#[test]
fn display_s3_error() {
let err = Error::S3 {
code: "NoSuchKey".into(),
message: "not found".into(),
};
assert_eq!(format!("{err}"), "s3 error NoSuchKey: not found");
}
#[test]
fn display_conversion_error() {
let err = Error::Conversion("bad utf8".into());
assert_eq!(format!("{err}"), "conversion error: bad utf8");
}
#[test]
fn display_internal_error() {
let err = Error::Internal("task panicked".into());
assert_eq!(format!("{err}"), "internal error: task panicked");
}
#[test]
fn display_io_error() {
let err = Error::Io(io::Error::new(io::ErrorKind::NotFound, "gone"));
let display = format!("{err}");
assert!(display.contains("io error"), "got: {display}");
}
#[test]
fn from_io_error() {
let io_err = io::Error::new(io::ErrorKind::PermissionDenied, "nope");
let err: Error = io_err.into();
assert!(matches!(err, Error::Io(_)));
}
#[test]
fn from_walkdir_error() {
let walk = walkdir::WalkDir::new("/nonexistent_s3z_test_path_12345");
for entry in walk {
if let Err(e) = entry {
let err: Error = e.into();
assert!(matches!(err, Error::Walk(_)));
return;
}
}
}
}