use std::path::PathBuf;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, VeltrixError>;
#[derive(Debug, Error)]
pub enum VeltrixError {
#[error("io failed: {source}")]
Io {
#[from]
source: std::io::Error,
},
#[error("missing environment variable `{name}`")]
EnvMissing { name: &'static str },
#[error("invalid environment variable `{name}`: {reason}")]
EnvInvalid { name: &'static str, reason: String },
#[error("invalid config: {reason}")]
ConfigInvalid { reason: String },
#[error("invalid path `{path}`: {reason}")]
InvalidPath { path: PathBuf, reason: String },
#[error("parsing failed: {0}")]
Parsing(String),
#[error("{service} service failed: {reason}")]
Service { service: String, reason: String },
#[error("socket failed: {reason}")]
Socket { reason: String },
#[error("http request failed with status {status}: {reason}")]
Http { status: u16, reason: String },
#[error("authentication failed: {reason}")]
Auth { reason: String },
#[error("validation failed for `{field}`: {reason}")]
Validation { field: String, reason: String },
}
impl VeltrixError {
pub fn env_missing(name: &'static str) -> Self {
Self::EnvMissing { name }
}
pub fn env_invalid(name: &'static str, reason: impl Into<String>) -> Self {
Self::EnvInvalid {
name,
reason: reason.into(),
}
}
pub fn config_invalid(reason: impl Into<String>) -> Self {
Self::ConfigInvalid {
reason: reason.into(),
}
}
pub fn invalid_path(path: impl Into<PathBuf>, reason: impl Into<String>) -> Self {
Self::InvalidPath {
path: path.into(),
reason: reason.into(),
}
}
pub fn parsing(reason: impl Into<String>) -> Self {
Self::Parsing(reason.into())
}
pub fn service(service: impl Into<String>, reason: impl Into<String>) -> Self {
Self::Service {
service: service.into(),
reason: reason.into(),
}
}
pub fn socket(reason: impl Into<String>) -> Self {
Self::Socket {
reason: reason.into(),
}
}
pub fn http(status: u16, reason: impl Into<String>) -> Self {
Self::Http {
status,
reason: reason.into(),
}
}
pub fn auth(reason: impl Into<String>) -> Self {
Self::Auth {
reason: reason.into(),
}
}
pub fn validation(field: impl Into<String>, reason: impl Into<String>) -> Self {
Self::Validation {
field: field.into(),
reason: reason.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io;
#[test]
fn io_error_converts_to_veltrix_error() {
let io_err = io::Error::new(io::ErrorKind::NotFound, "test error");
let veltrix_err: VeltrixError = io_err.into();
assert!(veltrix_err.to_string().contains("test error"));
}
#[test]
fn env_missing_message() {
let err = VeltrixError::env_missing("HOME");
assert_eq!(err.to_string(), "missing environment variable `HOME`");
}
#[test]
fn env_invalid_message() {
let err = VeltrixError::env_invalid("HOME", "must be absolute");
assert_eq!(
err.to_string(),
"invalid environment variable `HOME`: must be absolute"
);
}
#[test]
fn config_invalid_message() {
let err = VeltrixError::config_invalid("missing required field");
assert_eq!(err.to_string(), "invalid config: missing required field");
}
#[test]
fn invalid_path_message() {
let err = VeltrixError::invalid_path("relative/path", "must be absolute");
assert!(err.to_string().contains("relative/path"));
assert!(err.to_string().contains("must be absolute"));
}
#[test]
fn parsing_message() {
let err = VeltrixError::parsing("invalid json");
assert_eq!(err.to_string(), "parsing failed: invalid json");
}
#[test]
fn service_message() {
let err = VeltrixError::service("podman", "command failed");
assert_eq!(err.to_string(), "podman service failed: command failed");
}
#[test]
fn socket_message() {
let err = VeltrixError::socket("connection refused");
assert_eq!(err.to_string(), "socket failed: connection refused");
}
#[test]
fn http_message() {
let err = VeltrixError::http(401, "unauthorized");
assert_eq!(
err.to_string(),
"http request failed with status 401: unauthorized"
);
}
#[test]
fn auth_message() {
let err = VeltrixError::auth("missing token");
assert_eq!(err.to_string(), "authentication failed: missing token");
}
#[test]
fn validation_message() {
let err = VeltrixError::validation("name", "must not be empty");
assert_eq!(
err.to_string(),
"validation failed for `name`: must not be empty"
);
}
#[test]
fn result_type_is_correct() {
fn returns_result() -> Result<String> {
Ok("success".to_string())
}
assert!(returns_result().is_ok());
}
}