ggen-domain 5.1.3

Domain logic layer for ggen - pure business logic without CLI dependencies
Documentation
//! Validate ontology structure and content
//!
//! This module handles:
//! - Validating ontology pack structure
//! - Checking SPARQL endpoint connectivity
//! - Validating RDF/OWL syntax
//! - Ensuring template structure
//! - Verifying generated code quality

use ggen_utils::error::Result;
use std::path::PathBuf;

/// Input for ontology validation
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ValidateInput {
    /// Path to ontology pack
    pub pack_path: PathBuf,

    /// Strict mode (fail on warnings)
    pub strict: bool,
}

/// Output from validation
#[derive(Debug, Clone, serde::Serialize)]
pub struct ValidateOutput {
    /// Whether validation passed
    pub valid: bool,

    /// Validation score (0-100)
    pub score: u8,

    /// Errors found
    #[serde(default)]
    pub errors: Vec<String>,

    /// Warnings found
    #[serde(default)]
    pub warnings: Vec<String>,

    /// Validation statistics
    pub stats: ValidationStats,
}

/// Validation statistics
#[derive(Debug, Clone, serde::Serialize)]
pub struct ValidationStats {
    /// Number of ontology files checked
    pub ontologies_checked: usize,

    /// Number of templates checked
    pub templates_checked: usize,

    /// Number of issues found
    pub issues_found: usize,

    /// Validation time in milliseconds
    pub validation_time_ms: u64,
}

/// Execute ontology validation
pub async fn execute_validate(input: &ValidateInput) -> Result<ValidateOutput> {
    let start_time = std::time::Instant::now();

    // 1. Check pack directory exists
    if !input.pack_path.exists() {
        return Err(ggen_utils::error::Error::new(&format!(
            "Pack directory not found: {}",
            input.pack_path.display()
        )));
    }

    // 2. Check gpack.toml exists
    let gpack_path = input.pack_path.join("gpack.toml");
    if !gpack_path.exists() {
        return Err(ggen_utils::error::Error::new(
            "gpack.toml not found in pack",
        ));
    }

    // 3. Validate structure (placeholder)
    let errors = Vec::new();
    let warnings = Vec::new();

    let elapsed = start_time.elapsed();
    let stats = ValidationStats {
        ontologies_checked: 0,
        templates_checked: 0,
        issues_found: errors.len() + warnings.len(),
        validation_time_ms: elapsed.as_millis() as u64,
    };

    let valid = (!input.strict || warnings.is_empty()) && errors.is_empty();
    let score = if valid { 100 } else { 50 };

    Ok(ValidateOutput {
        valid,
        score,
        errors,
        warnings,
        stats,
    })
}

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

    #[tokio::test]
    async fn test_validate_missing_pack() {
        let input = ValidateInput {
            pack_path: PathBuf::from("/nonexistent/pack"),
            strict: false,
        };

        let result = execute_validate(&input).await;
        assert!(result.is_err());
    }
}