use serde::Serialize;
use thiserror::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[repr(i32)]
pub enum ErrorCode {
Success = 1,
Failed = 0,
NotLogin = -1,
UserNotFound = -2,
UserDisabled = -3,
Forbidden = 403,
NotFound = 404,
ValidateFailed = 422,
DbError = 500,
}
impl ErrorCode {
pub fn as_i32(self) -> i32 {
self as i32
}
pub fn http_status(self) -> u16 {
match self {
ErrorCode::Success => 200,
ErrorCode::Failed => 200,
ErrorCode::NotLogin => 401,
ErrorCode::UserNotFound => 401,
ErrorCode::UserDisabled => 403,
ErrorCode::Forbidden => 403,
ErrorCode::NotFound => 404,
ErrorCode::ValidateFailed => 422,
ErrorCode::DbError => 500,
}
}
}
impl From<i32> for ErrorCode {
fn from(code: i32) -> Self {
match code {
1 => ErrorCode::Success,
0 => ErrorCode::Failed,
-1 => ErrorCode::NotLogin,
-2 => ErrorCode::UserNotFound,
-3 => ErrorCode::UserDisabled,
403 => ErrorCode::Forbidden,
404 => ErrorCode::NotFound,
422 => ErrorCode::ValidateFailed,
500 => ErrorCode::DbError,
_ => ErrorCode::Failed,
}
}
}
#[derive(Debug, Clone, Error)]
#[error("[{code}] {msg}")]
pub struct BaseException {
pub code: i32,
pub msg: String,
pub message_key: Option<String>,
}
impl BaseException {
pub fn new(code: ErrorCode, msg: impl Into<String>) -> Self {
Self {
code: code.as_i32(),
msg: msg.into(),
message_key: None,
}
}
pub fn with_message_key(mut self, key: impl Into<String>) -> Self {
self.message_key = Some(key.into());
self
}
pub fn message_key(&self) -> Option<&str> {
self.message_key.as_deref()
}
pub fn not_login(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::NotLogin, msg)
}
pub fn user_not_found(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::UserNotFound, msg)
}
pub fn user_disabled(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::UserDisabled, msg)
}
pub fn failed(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::Failed, msg)
}
pub fn forbidden(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::Forbidden, msg)
}
pub fn not_found(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::NotFound, msg)
}
pub fn validate_failed(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::ValidateFailed, msg)
}
pub fn db_error(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::DbError, msg)
}
pub fn to_json(&self) -> serde_json::Value {
serde_json::json!({
"code": self.code,
"msg": self.msg,
"data": {}
})
}
}
impl Default for BaseException {
fn default() -> Self {
Self {
code: ErrorCode::Failed.as_i32(),
msg: "invalid parameters".to_string(),
message_key: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_code_values() {
assert_eq!(ErrorCode::Success.as_i32(), 1);
assert_eq!(ErrorCode::Failed.as_i32(), 0);
assert_eq!(ErrorCode::NotLogin.as_i32(), -1);
assert_eq!(ErrorCode::UserNotFound.as_i32(), -2);
assert_eq!(ErrorCode::UserDisabled.as_i32(), -3);
assert_eq!(ErrorCode::Forbidden.as_i32(), 403);
assert_eq!(ErrorCode::NotFound.as_i32(), 404);
assert_eq!(ErrorCode::ValidateFailed.as_i32(), 422);
assert_eq!(ErrorCode::DbError.as_i32(), 500);
}
#[test]
fn test_from_i32() {
assert_eq!(ErrorCode::from(1), ErrorCode::Success);
assert_eq!(ErrorCode::from(0), ErrorCode::Failed);
assert_eq!(ErrorCode::from(-1), ErrorCode::NotLogin);
assert_eq!(ErrorCode::from(-2), ErrorCode::UserNotFound);
assert_eq!(ErrorCode::from(-3), ErrorCode::UserDisabled);
assert_eq!(ErrorCode::from(999), ErrorCode::Failed); }
#[test]
fn test_http_status() {
assert_eq!(ErrorCode::Success.http_status(), 200);
assert_eq!(ErrorCode::Failed.http_status(), 200);
assert_eq!(ErrorCode::NotLogin.http_status(), 401);
assert_eq!(ErrorCode::UserNotFound.http_status(), 401);
assert_eq!(ErrorCode::UserDisabled.http_status(), 403);
assert_eq!(ErrorCode::Forbidden.http_status(), 403);
assert_eq!(ErrorCode::NotFound.http_status(), 404);
assert_eq!(ErrorCode::ValidateFailed.http_status(), 422);
assert_eq!(ErrorCode::DbError.http_status(), 500);
}
#[test]
fn test_default() {
let ex = BaseException::default();
assert_eq!(ex.code, 0);
assert_eq!(ex.msg, "invalid parameters");
}
#[test]
fn test_not_login() {
let ex = BaseException::not_login("not_login");
assert_eq!(ex.code, -1);
assert_eq!(ex.msg, "not_login");
}
#[test]
fn test_user_not_found() {
let ex = BaseException::user_not_found("没有找到用户信息");
assert_eq!(ex.code, -2);
assert_eq!(ex.msg, "没有找到用户信息");
}
#[test]
fn test_user_disabled() {
let ex = BaseException::user_disabled("您已离职,无权使用本系统!");
assert_eq!(ex.code, -3);
assert_eq!(ex.msg, "您已离职,无权使用本系统!");
}
#[test]
fn test_failed() {
let ex = BaseException::failed("操作失败");
assert_eq!(ex.code, 0);
assert_eq!(ex.msg, "操作失败");
}
#[test]
fn test_to_json() {
let ex = BaseException::not_login("not_login");
let json = ex.to_json();
assert_eq!(json["code"], -1);
assert_eq!(json["msg"], "not_login");
assert_eq!(json["data"], serde_json::json!({}));
}
#[test]
fn test_display() {
let ex = BaseException::not_login("not_login");
assert_eq!(format!("{}", ex), "[-1] not_login");
}
#[test]
fn test_php_error_codes_coverage() {
assert_eq!(ErrorCode::Success.as_i32(), 1);
assert_eq!(ErrorCode::Failed.as_i32(), 0);
assert_eq!(ErrorCode::NotLogin.as_i32(), -1);
assert_eq!(ErrorCode::UserNotFound.as_i32(), -2);
assert_eq!(ErrorCode::UserDisabled.as_i32(), -3);
}
}