use thiserror::Error;
#[derive(Debug, Error)]
pub enum ForgeError {
#[error("not found: {0}")]
NotFound(String),
#[error("bad request: {0}")]
BadRequest(String),
#[error("invalid path: {0}")]
PathTraversal(String),
#[error("unauthorised: {0}")]
Unauthorised(String),
#[error("forbidden: {0}")]
Forbidden(String),
#[error("conflict: {0}")]
Conflict(String),
#[error("unsupported: {0}")]
Unsupported(String),
#[error("git: {0}")]
Git(#[from] solid_pod_rs_git::error::GitError),
#[error("i/o: {0}")]
Io(#[from] std::io::Error),
#[error("serialisation: {0}")]
Serde(#[from] serde_json::Error),
#[error("backend: {0}")]
Backend(String),
}
impl ForgeError {
#[must_use]
pub fn status_code(&self) -> u16 {
match self {
ForgeError::NotFound(_) => 404,
ForgeError::BadRequest(_) | ForgeError::PathTraversal(_) => 400,
ForgeError::Unauthorised(_) => 401,
ForgeError::Forbidden(_) => 403,
ForgeError::Conflict(_) => 409,
ForgeError::Unsupported(_) => 501,
ForgeError::Git(g) => g.status_code(),
ForgeError::Io(_) | ForgeError::Serde(_) | ForgeError::Backend(_) => 500,
}
}
#[must_use]
pub fn to_response(&self) -> crate::ForgeResponse {
crate::ForgeResponse::error(self.status_code(), self.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn status_mapping() {
assert_eq!(ForgeError::NotFound("x".into()).status_code(), 404);
assert_eq!(ForgeError::BadRequest("x".into()).status_code(), 400);
assert_eq!(ForgeError::PathTraversal("x".into()).status_code(), 400);
assert_eq!(ForgeError::Unauthorised("x".into()).status_code(), 401);
assert_eq!(ForgeError::Forbidden("x".into()).status_code(), 403);
assert_eq!(ForgeError::Conflict("x".into()).status_code(), 409);
assert_eq!(ForgeError::Unsupported("x".into()).status_code(), 501);
assert_eq!(ForgeError::Backend("x".into()).status_code(), 500);
}
#[test]
fn git_error_status_propagates() {
let g = solid_pod_rs_git::error::GitError::NotARepository("r".into());
let e = ForgeError::Git(g);
assert_eq!(e.status_code(), 404);
}
}