francoisgib_webserver 1.0.3

HTTP Webserver
Documentation
use serde::Serialize;
use strum_macros::{Display, EnumString};

use super::errors::HttpError;

/// HTTP status codes used in responses.
///
/// This enum represents common HTTP status codes.
/// It derives:
/// - `Display` for pretty-printing (e.g., "OK", "NOT FOUND").
/// - `EnumString` for parsing from string to enum (case-insensitive).
/// - `Serialize` for JSON serialization.
///
/// Status codes are case-insensitive when parsed from strings.
/// It uses strum to convert string to enum variants.
#[derive(Debug, Display, EnumString, PartialEq, Clone, Copy, Serialize)]
#[strum(serialize_all = "UPPERCASE", ascii_case_insensitive)]
pub enum HttpStatus {
    Ok = 200,

    Created = 201,

    #[strum(serialize = "PARTIAL CONTENT")]
    PartialContent = 206,

    #[strum(serialize = "NOT MODIFIED")]
    NotModified = 304,

    #[strum(serialize = "BAD REQUEST")]
    BadRequest = 400,

    Unauthorized = 401,

    Forbidden = 403,

    #[strum(serialize = "NOT FOUND")]
    NotFound = 404,

    #[strum(serialize = "METHOD NOT ALLOWED")]
    MethodNotAllowed = 405,

    #[strum(serialize = "INTERNAL SERVER ERROR")]
    InternalServerError = 500,

    #[strum(serialize = "NOT IMPLEMENTED")]
    NotImplemented = 501,

    #[strum(serialize = "HTTP VERSION NOT SUPPORTED")]
    HttpVersionNotSupported = 505,
}

/// Converts an `HttpError` into a corresponding `HttpStatus`.
///
/// This allows mapping internal server errors to HTTP response codes easily.
impl From<HttpError> for HttpStatus {
    fn from(error: HttpError) -> Self {
        match error {
            HttpError::NotFound => HttpStatus::NotFound,
            HttpError::MethodNotAllowed => HttpStatus::MethodNotAllowed,
            HttpError::HttpVersionNotSupported => HttpStatus::HttpVersionNotSupported,
            HttpError::InternalServerError => HttpStatus::InternalServerError,
            HttpError::BadRequest => HttpStatus::BadRequest,
            HttpError::NotImplemented => HttpStatus::NotImplemented,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;
    use strum::ParseError;

    #[test]
    fn test_http_error_to_status_mapping() {
        assert_eq!(HttpStatus::from(HttpError::NotFound), HttpStatus::NotFound);
        assert_eq!(
            HttpStatus::from(HttpError::MethodNotAllowed),
            HttpStatus::MethodNotAllowed
        );
        assert_eq!(
            HttpStatus::from(HttpError::HttpVersionNotSupported),
            HttpStatus::HttpVersionNotSupported
        );
        assert_eq!(
            HttpStatus::from(HttpError::InternalServerError),
            HttpStatus::InternalServerError
        );
        assert_eq!(
            HttpStatus::from(HttpError::BadRequest),
            HttpStatus::BadRequest
        );
        assert_eq!(
            HttpStatus::from(HttpError::NotImplemented),
            HttpStatus::NotImplemented
        );
    }

    #[test]
    fn test_status_display() {
        assert_eq!(HttpStatus::Ok.to_string(), "OK");
        assert_eq!(HttpStatus::NotFound.to_string(), "NOT FOUND");
        assert_eq!(
            HttpStatus::InternalServerError.to_string(),
            "INTERNAL SERVER ERROR"
        );
    }

    #[test]
    fn test_status_from_str() {
        assert_eq!(HttpStatus::from_str("ok").unwrap(), HttpStatus::Ok);
        assert_eq!(
            HttpStatus::from_str("NOT FOUND").unwrap(),
            HttpStatus::NotFound
        );
        assert_eq!(
            HttpStatus::from_str("bad request").unwrap(),
            HttpStatus::BadRequest
        );
        assert_eq!(
            HttpStatus::from_str("HTTP VERSION NOT SUPPORTED").unwrap(),
            HttpStatus::HttpVersionNotSupported
        );
    }

    #[test]
    fn test_invalid_status_from_str() {
        let result = HttpStatus::from_str("not_a_status");
        assert!(matches!(result, Err(ParseError::VariantNotFound)));
    }
}