sw-errors 0.0.8

A library for error parsing and pretty-printing, used across the swtools toolset.
Documentation
use crate::errors::errors_type::ErrorsType;

/// A struct serving as a wrapper for `ErrorRaw`. Provides a convenient way
/// to handle raw error data.
pub struct Raw {
    /// The raw error data stored in this struct instance.
    pub data: ErrorRaw,
}

/// Handles error triggers, controlling whether an error should
/// cause a panic or just be displayed.

pub struct ErrorTrigger;

/// Represents raw error information, defining all necessary details to describe an error.
pub struct ErrorRaw {
    /// The type of the error (e.g., Error, Warning, Debug, etc.).
    pub error_type: ErrorsType,
    /// The main error message.
    pub message: String,
    /// A detailed description of the error (optional).
    pub description: Option<String>,
    /// An optional error code associated with this specific error.
    pub code: Option<u64>,
    /// The line in the file where the error occurred (if applicable).
    pub line: Option<u64>,
    /// The column in the file where the error occurred (if applicable).
    pub column: Option<u64>,
    /// The name of the file where the error occurred (optional).
    pub file: Option<String>,
    /// A hint or possible solution for the error (optional).
    pub hint: Option<String>,
    /// Whether the error should trigger a panic.
    pub should_panic: bool,
}

impl Raw {
    /// Creates a new instance of `Raw`, wrapping an instance of `ErrorRaw`.
    ///
    /// # Arguments
    /// * `data` - An instance of `ErrorRaw` containing error information.
    ///
    /// # Returns
    /// A new `Raw` struct containing the provided `ErrorRaw` data.
    ///
    pub fn new(data: ErrorRaw) -> Self {
        Self { data }
    }
}

impl ErrorTrigger {
    /// Processes an error and takes appropriate action based on its severity.
    /// If `should_panic` is `true`, the function will trigger a panic.
    /// Otherwise, the error details will simply be logged or displayed.
    ///
    /// # Arguments
    /// * `error` - An instance of `ErrorRaw` containing full information about the error.
    ///
    /// # Panics
    /// This function will panic if `error.should_panic == true`.
    pub fn throw_error(error: ErrorRaw) {
        let mut line_column_info = String::new();

        // Se `line` e `column` existirem, adiciona ao formato
        if let Some(line) = error.line {
            line_column_info.push_str(&format!("Line: {}", line));
        }
        if let Some(column) = error.column {
            if !line_column_info.is_empty() {
                line_column_info.push_str(", ");
            }
            line_column_info.push_str(&format!("Column: {}", column));
        }

        // Monta a mensagem
        let message = if let Some(hint) = &error.hint {
            format!(
                "{}! [{:?}]: {}.\n\n {}\n\n Hint: {}",
                get_error_type(error.error_type),
                error.code,
                error.message,
                line_column_info,
                hint,
            )
        } else {
            format!(
                "{}! [{:?}]: {}.\n\n {}",
                get_error_type(error.error_type),
                error.code,
                error.message,
                line_column_info,
            )
        };

        // Dependendo de should_panic, decide lançar panic ou apenas mostrar a mensagem
        if error.should_panic {
            panic!("{}", message);
        } else {
            println!("{}", message); // Ou log algo no lugar de println
        }
    }
}

/// Maps the error type to a string representation.
///
/// # Arguments
/// * `err` - The type of the error from `ErrorsType` enum.
///
/// # Returns
/// A string representing the error type.

fn get_error_type(err: ErrorsType) -> &'static str {
    match err {
        ErrorsType::Error => "Error",
        ErrorsType::Info => "Info",
        ErrorsType::Warn => "Warn",
        ErrorsType::Note => "Note",
        ErrorsType::Debug => "Debug",
    }
}

#[cfg(test)]
mod tests {
    use crate::errors::errors_type::ErrorsType;
    use crate::errors::raw::{ErrorRaw, ErrorTrigger, get_error_type};

    #[test]
    fn test_get_error_type() {
        assert_eq!(get_error_type(ErrorsType::Error), "Error");
        assert_eq!(get_error_type(ErrorsType::Warn), "Warn");
        assert_eq!(get_error_type(ErrorsType::Note), "Note");
        assert_eq!(get_error_type(ErrorsType::Debug), "Debug");
        assert_eq!(get_error_type(ErrorsType::Info), "Info");
    }

    #[test]
    fn test_throw_error_with_panic() {
        let error = ErrorRaw {
            error_type: ErrorsType::Error,
            message: "Critical Error!".to_string(),
            description: Some("A major issue occurred".to_string()),
            code: Some(500),
            line: Some(42),
            column: Some(24),
            file: None,
            hint: None,
            should_panic: true, // Este erro deve causar panic
        };

        // Usa catch_unwind para verificar se houve um panic
        let result = std::panic::catch_unwind(|| {
            ErrorTrigger::throw_error(error);
        });

        // Verifica se houve panic
        assert!(result.is_err(), "Expected error, but no panic.");
    }

    #[test]
    fn test_throw_error_without_panic() {
        let error = ErrorRaw {
            error_type: ErrorsType::Warn,
            message: "This is just a warning!".to_string(),
            description: None,
            code: None,
            line: Some(99),
            column: None,
            file: None,
            hint: Some("This can be ignored.".to_string()),
            should_panic: false, // Este erro não deve causar panic
        };

        // Captura a saída padrão (opcional: para verificar mensagens formatadas)
        let result = std::panic::catch_unwind(|| {
            ErrorTrigger::throw_error(error);
        });

        // Verifica se NÃO houve panic
        assert!(result.is_ok(), "No panic expected, but it happened.");
    }
}