use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("transport error: {0}")]
Transport(#[from] tonic::transport::Error),
#[error("gRPC error: {0}")]
Grpc(#[source] Box<tonic::Status>),
#[error("auth error: {0}")]
Auth(String),
#[error("invalid endpoint URI: {0}")]
InvalidUri(String),
#[error("invalid metadata value: {0}")]
InvalidMetadata(#[from] tonic::metadata::errors::InvalidMetadataValue),
}
impl From<tonic::Status> for Error {
fn from(s: tonic::Status) -> Self {
Self::Grpc(Box::new(s))
}
}
impl Error {
pub fn auth(msg: impl Into<String>) -> Self {
Self::Auth(msg.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_status() {
let status = tonic::Status::not_found("not found");
let err = Error::from(status);
assert!(matches!(err, Error::Grpc(_)));
}
#[test]
fn from_invalid_metadata() {
let bad: Result<tonic::metadata::MetadataValue<tonic::metadata::Ascii>, _> = "\x00".parse();
let err = Error::from(bad.unwrap_err());
assert!(matches!(err, Error::InvalidMetadata(_)));
}
#[test]
fn invalid_uri_holds_message() {
let err = Error::InvalidUri("not a uri".to_string());
assert!(err.to_string().contains("not a uri"));
}
#[test]
fn auth_constructor() {
let err = Error::auth("token expired");
assert!(matches!(err, Error::Auth(_)));
assert_eq!(err.to_string(), "auth error: token expired");
}
}