use std::{str::Utf8Error, string::FromUtf8Error};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Invalid arguments: {0}")]
InvalidArguments(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Execution failure: {0}")]
ExecutionFailure(String),
#[error("Object read error: {0}")]
ObjectReadError(#[from] object::read::Error),
#[error("Object write error: {0}")]
ObjectWriteError(#[from] object::write::Error),
#[error("String error: {0}")]
StringError(String),
#[error("Unsupported binary format: {0}")]
UnsupportedBinaryFormat(String),
#[error("Missing file: {0}")]
MissingFile(String),
#[error("Configuration error: {0}")]
ConfigError(String),
#[error("Unknown error: {0}")]
Unknown(String),
}
impl From<Utf8Error> for Error {
fn from(value: Utf8Error) -> Self {
Self::StringError(format!("{}", value))
}
}
impl From<FromUtf8Error> for Error {
fn from(value: FromUtf8Error) -> Self {
Self::StringError(format!("{}", value))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn utf8_errors_convert_to_string_errors() {
let invalid: Vec<u8> = vec![0x66, 0x6f, 0x80];
let utf8_err = std::str::from_utf8(&invalid).unwrap_err();
let err: Error = utf8_err.into();
assert!(matches!(err, Error::StringError(_)));
assert!(err.to_string().contains("String error"));
let from_utf8_err = String::from_utf8(invalid.clone()).unwrap_err();
let err: Error = from_utf8_err.into();
assert!(matches!(err, Error::StringError(_)));
}
#[test]
fn every_variant_renders_a_message() {
let cases = [
Error::InvalidArguments("a".into()),
Error::ExecutionFailure("b".into()),
Error::StringError("c".into()),
Error::UnsupportedBinaryFormat("d".into()),
Error::MissingFile("e".into()),
Error::ConfigError("f".into()),
Error::Unknown("g".into()),
Error::Io(std::io::Error::other("h")),
];
for err in cases {
assert!(!err.to_string().is_empty(), "empty Display for {err:?}");
}
}
}