use thiserror::Error;
#[derive(Error, Debug)]
pub enum OntologyError {
#[error("IO error: {0}")]
IoError(String),
#[error("Parse error in file {file} at line {line}: {message}")]
ParseError {
file: String,
line: u32,
message: String,
},
#[error("Validation error(s):\n{}", format_errors(.0))]
ValidationError(Vec<String>),
#[error("SPARQL query error: {0}")]
QueryError(String),
#[error("Mapping error for entity {entity}: {reason}")]
MapperError {
entity: String,
reason: String,
},
#[error("Triple store error: {0}")]
TripleStoreError(String),
#[error("Configuration error: {0}")]
ConfigError(String),
#[error("Internal error: {0}")]
InternalError(String),
}
fn format_errors(errors: &[String]) -> String {
errors
.iter()
.enumerate()
.map(|(i, e)| format!(" {}. {}", i + 1, e))
.collect::<Vec<_>>()
.join("\n")
}
impl OntologyError {
pub fn io<S: Into<String>>(message: S) -> Self {
Self::IoError(message.into())
}
pub fn parse<S: Into<String>>(file: S, line: u32, message: S) -> Self {
Self::ParseError {
file: file.into(),
line,
message: message.into(),
}
}
pub fn validation(errors: Vec<String>) -> Self {
Self::ValidationError(errors)
}
pub fn query<S: Into<String>>(message: S) -> Self {
Self::QueryError(message.into())
}
pub fn mapper<S: Into<String>>(entity: S, reason: S) -> Self {
Self::MapperError {
entity: entity.into(),
reason: reason.into(),
}
}
pub fn triple_store<S: Into<String>>(message: S) -> Self {
Self::TripleStoreError(message.into())
}
pub fn config<S: Into<String>>(message: S) -> Self {
Self::ConfigError(message.into())
}
pub fn internal<S: Into<String>>(message: S) -> Self {
Self::InternalError(message.into())
}
}
pub type Result<T> = std::result::Result<T, OntologyError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_io_error_creation() {
let err = OntologyError::io("file not found");
assert_eq!(err.to_string(), "IO error: file not found");
}
#[test]
fn test_parse_error_creation() {
let err = OntologyError::parse("ontology.ttl", 42, "invalid predicate");
let msg = err.to_string();
assert!(msg.contains("ontology.ttl"));
assert!(msg.contains("42"));
assert!(msg.contains("invalid predicate"));
}
#[test]
fn test_validation_error_formatting() {
let errors = vec![
"Missing required field".to_string(),
"Invalid reference".to_string(),
];
let err = OntologyError::validation(errors);
let msg = err.to_string();
assert!(msg.contains("1."));
assert!(msg.contains("2."));
assert!(msg.contains("Missing required field"));
}
#[test]
fn test_query_error_creation() {
let err = OntologyError::query("SPARQL syntax error");
assert_eq!(err.to_string(), "SPARQL query error: SPARQL syntax error");
}
#[test]
fn test_mapper_error_creation() {
let err = OntologyError::mapper("policy-001", "no matching ontology class");
let msg = err.to_string();
assert!(msg.contains("policy-001"));
assert!(msg.contains("no matching ontology class"));
}
}