pub mod error_recovery;
pub mod incremental;
mod resolver;
mod streaming;
mod ttl_parser;
pub use error_recovery::{ErrorRecoveryStrategy, RecoveryAction, RecoveryContext};
pub use incremental::{IncrementalParser, ParseEvent, ParseState};
pub use resolver::ModelResolver;
pub use streaming::StreamingParser;
pub use ttl_parser::SammTurtleParser;
use crate::error::{Result, SammError};
use crate::metamodel::Aspect;
use std::path::Path;
pub async fn parse_aspect_model<P: AsRef<Path>>(path: P) -> Result<Aspect> {
let mut parser = SammTurtleParser::new();
parser.parse_file(path.as_ref()).await
}
pub async fn parse_aspect_from_string(content: &str, base_uri: &str) -> Result<Aspect> {
let mut parser = SammTurtleParser::new();
parser.parse_string(content, base_uri).await
}
#[cfg(test)]
mod tests {
use super::*;
use crate::metamodel::ModelElement;
#[tokio::test]
async fn test_parse_from_string_basic() {
let ttl_content = r#"
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
@prefix : <urn:samm:org.example:1.0.0#> .
:TestAspect a samm:Aspect ;
samm:preferredName "Test Aspect"@en ;
samm:description "A test aspect"@en ;
samm:properties ( :testProperty ) .
:testProperty a samm:Property ;
samm:preferredName "Test Property"@en ;
samm:characteristic :TestCharacteristic .
:TestCharacteristic a samm:Characteristic ;
samm:dataType <http://www.w3.org/2001/XMLSchema#string> .
"#;
let result = parse_aspect_from_string(ttl_content, "urn:samm:org.example:1.0.0#").await;
assert!(
result.is_ok(),
"Failed to parse basic Turtle: {:?}",
result.err()
);
let aspect = result.expect("result should be Ok");
assert_eq!(aspect.name(), "TestAspect");
assert_eq!(aspect.properties().len(), 1);
assert_eq!(aspect.properties()[0].name(), "testProperty");
}
#[tokio::test]
async fn test_parse_from_string_invalid_ttl() {
let invalid_ttl = r#"
@prefix samm: <invalid syntax here
"#;
let result = parse_aspect_from_string(invalid_ttl, "urn:samm:org.example:1.0.0#").await;
assert!(result.is_err(), "Expected error for invalid Turtle syntax");
}
#[tokio::test]
async fn test_parse_from_string_no_aspect() {
let ttl_content = r#"
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
@prefix : <urn:samm:org.example:1.0.0#> .
:TestProperty a samm:Property ;
samm:preferredName "Test Property"@en .
"#;
let result = parse_aspect_from_string(ttl_content, "urn:samm:org.example:1.0.0#").await;
assert!(result.is_err(), "Expected error when no Aspect is defined");
if let Err(err) = result {
let err_str = format!("{:?}", err);
assert!(
err_str.contains("No Aspect found"),
"Expected 'No Aspect found' error"
);
}
}
#[tokio::test]
async fn test_parse_aspect_with_multiple_properties() {
let ttl_content = r#"
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
@prefix : <urn:samm:org.example:1.0.0#> .
:MultiPropAspect a samm:Aspect ;
samm:preferredName "Multi Property Aspect"@en ;
samm:properties ( :prop1 :prop2 :prop3 ) .
:prop1 a samm:Property ;
samm:characteristic :StringChar .
:prop2 a samm:Property ;
samm:characteristic :IntChar .
:prop3 a samm:Property ;
samm:characteristic :BoolChar .
:StringChar a samm:Characteristic ;
samm:dataType <http://www.w3.org/2001/XMLSchema#string> .
:IntChar a samm:Characteristic ;
samm:dataType <http://www.w3.org/2001/XMLSchema#int> .
:BoolChar a samm:Characteristic ;
samm:dataType <http://www.w3.org/2001/XMLSchema#boolean> .
"#;
let result = parse_aspect_from_string(ttl_content, "urn:samm:org.example:1.0.0#").await;
assert!(
result.is_ok(),
"Failed to parse multi-property aspect: {:?}",
result.err()
);
let aspect = result.expect("result should be Ok");
assert_eq!(aspect.properties().len(), 3);
assert_eq!(aspect.properties()[0].name(), "prop1");
assert_eq!(aspect.properties()[1].name(), "prop2");
assert_eq!(aspect.properties()[2].name(), "prop3");
}
#[tokio::test]
async fn test_parse_aspect_with_operations() {
let ttl_content = r#"
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
@prefix : <urn:samm:org.example:1.0.0#> .
:OperationAspect a samm:Aspect ;
samm:preferredName "Operation Aspect"@en ;
samm:operations ( :testOperation ) .
:testOperation a samm:Operation ;
samm:preferredName "Test Operation"@en .
"#;
let result = parse_aspect_from_string(ttl_content, "urn:samm:org.example:1.0.0#").await;
assert!(
result.is_ok(),
"Failed to parse aspect with operations: {:?}",
result.err()
);
let aspect = result.expect("result should be Ok");
assert_eq!(aspect.operations().len(), 1);
assert_eq!(aspect.operations()[0].name(), "testOperation");
}
#[tokio::test]
async fn test_model_resolver_creation() {
let resolver = ModelResolver::new();
let stats = resolver.cache_stats();
assert_eq!(stats.content_cache_size, 0);
assert_eq!(stats.path_cache_size, 0);
}
#[tokio::test]
async fn test_model_resolver_add_models_root() {
let mut resolver = ModelResolver::new();
let test_path = std::env::temp_dir();
resolver.add_models_root(test_path.clone());
}
}