openscenario-rs 0.3.1

Rust library for parsing and manipulating OpenSCENARIO files
Documentation
//! Builder-specific error extensions and utilities
//!
//! This module provides specialized error types for builder operations,
//! extending the existing error system with builder-specific context.

use thiserror::Error;

/// Builder-specific error types with detailed context
#[derive(Debug, Error)]
pub enum BuilderError {
    /// Validation failed during builder operation
    #[error("Validation error: {message}. Suggestion: {suggestion}")]
    ValidationError { message: String, suggestion: String },

    /// Required field was not set before building
    #[error("Missing required field: {field}. Call {suggestion} first")]
    MissingField { field: String, suggestion: String },

    /// Invalid entity reference in action or condition
    #[error("Invalid entity reference: '{entity}'. Available entities: {available}")]
    InvalidEntityRef { entity: String, available: String },

    /// Constraint violation (range, compatibility, etc.)
    #[error("Constraint violation: {constraint}. Details: {details}")]
    ConstraintViolation { constraint: String, details: String },

    /// Integration error with existing OpenSCENARIO systems
    #[error("OpenSCENARIO error: {0}")]
    OpenScenarioError(#[from] crate::error::Error),
}

impl BuilderError {
    /// Create a validation error with suggestion
    pub fn validation_error(message: &str) -> Self {
        Self::ValidationError {
            message: message.to_string(),
            suggestion: "Check the documentation for valid values".to_string(),
        }
    }

    /// Create a validation error with custom suggestion  
    pub fn validation_error_with_suggestion(message: &str, suggestion: &str) -> Self {
        Self::ValidationError {
            message: message.to_string(),
            suggestion: suggestion.to_string(),
        }
    }

    /// Create a missing field error
    pub fn missing_field(field: &str, suggestion: &str) -> Self {
        Self::MissingField {
            field: field.to_string(),
            suggestion: suggestion.to_string(),
        }
    }

    /// Create an invalid entity reference error
    pub fn invalid_entity_ref(entity: &str, available: &[String]) -> Self {
        Self::InvalidEntityRef {
            entity: entity.to_string(),
            available: available.join(", "),
        }
    }

    /// Create a constraint violation error
    pub fn constraint_violation(constraint: &str, details: &str) -> Self {
        Self::ConstraintViolation {
            constraint: constraint.to_string(),
            details: details.to_string(),
        }
    }
}

/// Result type for builder operations
pub type BuilderResult<T> = Result<T, BuilderError>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_validation_error_display_includes_suggestion() {
        let err = BuilderError::validation_error("bad value");
        let msg = err.to_string();
        assert!(msg.contains("bad value"));
        assert!(msg.contains("Suggestion"));
    }

    #[test]
    fn test_missing_field_display() {
        let err = BuilderError::missing_field("name", "with_name()");
        let msg = err.to_string();
        assert!(msg.contains("name"));
        assert!(msg.contains("with_name()"));
    }

    #[test]
    fn test_invalid_entity_ref_joins_available() {
        let err = BuilderError::invalid_entity_ref(
            "ghost",
            &["ego".to_string(), "lead".to_string()],
        );
        let msg = err.to_string();
        assert!(msg.contains("ghost"));
        assert!(msg.contains("ego, lead"));
    }

    #[test]
    fn test_constraint_violation_display() {
        let err = BuilderError::constraint_violation("speed > 0", "speed was -1");
        let msg = err.to_string();
        assert!(msg.contains("speed > 0"));
        assert!(msg.contains("speed was -1"));
    }

    #[test]
    fn test_validation_error_with_custom_suggestion() {
        let err = BuilderError::validation_error_with_suggestion("oops", "try X");
        let msg = err.to_string();
        assert!(msg.contains("oops"));
        assert!(msg.contains("try X"));
    }
}