pub type VResult<T> = Result<T, VersionError>;
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, thiserror::Error)]
pub enum VersionError {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Utf8(#[from] std::string::FromUtf8Error),
#[error(transparent)]
Env(#[from] std::env::VarError),
#[error(transparent)]
ParseInt(#[from] std::num::ParseIntError),
#[error(transparent)]
StripPrefix(#[from] std::path::StripPrefixError),
#[error("{0}")]
Message(String),
#[error("git command failed: {0}")]
GitCommand(String),
}
impl VersionError {
pub fn new(err: impl std::error::Error + Send + Sync + 'static) -> Self {
Self::Message(err.to_string())
}
}
impl From<String> for VersionError {
fn from(s: String) -> Self {
Self::Message(s)
}
}
impl From<&str> for VersionError {
fn from(s: &str) -> Self {
Self::Message(s.to_string())
}
}
impl From<std::convert::Infallible> for VersionError {
fn from(_: std::convert::Infallible) -> Self {
unreachable!()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_string() {
let err = VersionError::from("test error".to_string());
assert!(matches!(err, VersionError::Message(ref s) if s == "test error"));
assert!(err.to_string().contains("test error"));
}
#[test]
fn test_from_str() {
let err: VersionError = "test error".into();
assert!(matches!(err, VersionError::Message(ref s) if s == "test error"));
}
#[test]
fn test_from_io_error() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let err = VersionError::from(io_err);
assert!(matches!(err, VersionError::Io(_)));
assert!(!err.to_string().is_empty());
}
#[test]
fn test_git_command_error() {
let err = VersionError::GitCommand("something failed".to_string());
assert!(err.to_string().contains("git command failed"));
}
#[test]
fn test_error_chain() {
let err = VersionError::Message("test".to_string());
let _: &dyn std::error::Error = &err;
}
}