#![allow(dead_code, unused_imports, unused_variables, deprecated, clippy::all)]
#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::needless_raw_string_hashes,
clippy::duration_suboptimal_units,
clippy::branches_sharing_code,
clippy::used_underscore_binding,
clippy::single_char_pattern,
clippy::ignore_without_reason,
clippy::cloned_ref_to_slice_refs,
clippy::doc_overindented_list_items,
clippy::match_wildcard_for_single_variants,
clippy::ignored_unit_patterns,
clippy::needless_collect,
clippy::unnecessary_map_or,
clippy::manual_flatten,
clippy::manual_strip,
clippy::future_not_send,
clippy::unnested_or_patterns,
clippy::no_effect_underscore_binding,
clippy::literal_string_with_formatting_args
)]
use std::collections::BTreeMap;
use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;
use ggen_core::ontology::{
Cardinality, OntClass, OntProperty, OntRelationship, OntologySchema, OwlRestriction,
PropertyRange, RelationshipType,
};
#[cfg(test)]
mod command_integration_tests {
use super::*;
#[test]
fn test_init_command_creates_files() {
let temp_dir = TempDir::new().unwrap();
let project_name = "test-project";
let original_dir = std::env::current_dir().unwrap();
std::env::set_current_dir(temp_dir.path()).unwrap();
let ontologies_dir = temp_dir.path().join("ontologies");
fs::create_dir_all(&ontologies_dir).unwrap();
let ontology_file = ontologies_dir.join(format!("{}.ttl", project_name));
let ttl_content = format!(
r#"@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix {0}: <http://example.org/{0}#> .
<{0}Ontology> a owl:Ontology ;
rdfs:label "{0} Ontology" ;
rdfs:comment "Auto-generated ontology for {0}" .
{0}:Thing a owl:Class ;
rdfs:label "Thing" ;
rdfs:comment "Base class for all entities" .
{0}:name a owl:DatatypeProperty ;
rdfs:label "name" ;
rdfs:domain {0}:Thing ;
rdfs:range xsd:string .
"#,
project_name
);
fs::write(&ontology_file, ttl_content).unwrap();
let config_file = temp_dir.path().join("ggen.config.json");
let config_content = format!(
r#"{{
"project_name": "{}",
"ontology_file": "ontologies/{}.ttl",
"version": "1.0.0"
}}
"#,
project_name, project_name
);
fs::write(&config_file, config_content).unwrap();
assert!(ontology_file.exists());
assert!(config_file.exists());
let ontology_content = fs::read_to_string(&ontology_file).unwrap();
assert!(ontology_content.contains("@prefix"));
assert!(ontology_content.contains("owl:Ontology"));
assert!(ontology_content.contains(&project_name));
let config_content = fs::read_to_string(&config_file).unwrap();
assert!(config_content.contains(&project_name));
assert!(config_content.contains("ontology_file"));
std::env::set_current_dir(original_dir).unwrap();
}
#[test]
fn test_validate_command_valid_turtle() {
use ggen_core::ontology_core::validators;
let temp_dir = TempDir::new().unwrap();
let ttl_file = temp_dir.path().join("valid.ttl");
let ttl_content = r#"
@prefix ex: <http://example.com/> .
ex:subject ex:predicate ex:object .
"#;
fs::write(&ttl_file, ttl_content).unwrap();
let report = validators::validate_turtle(&ttl_file).unwrap();
assert!(report.is_valid);
assert!(report.errors.is_empty());
}
#[test]
fn test_validate_command_invalid_turtle() {
use ggen_core::ontology_core::validators;
let temp_dir = TempDir::new().unwrap();
let ttl_file = temp_dir.path().join("invalid.ttl");
fs::write(&ttl_file, "this is not valid turtle !!!").unwrap();
let report = validators::validate_turtle(&ttl_file).unwrap();
assert!(!report.is_valid);
assert!(!report.errors.is_empty());
}
#[test]
fn test_generate_command_typescript() {
use ggen_core::codegen::TypeScriptGenerator;
use ggen_core::ontology::OntologySchema;
let schema = OntologySchema {
classes: vec![OntClass {
uri: "http://example.org#Product".to_string(),
name: "Product".to_string(),
label: "Product".to_string(),
description: Some("A product for sale".to_string()),
parent_classes: vec![],
properties: vec!["http://example.org#name".to_string()],
is_abstract: false,
restrictions: vec![],
}],
properties: vec![OntProperty {
uri: "http://example.org#name".to_string(),
name: "name".to_string(),
label: "Name".to_string(),
description: None,
domain: vec!["http://example.org#Product".to_string()],
range: PropertyRange::String,
cardinality: Cardinality::One,
required: true,
is_functional: true,
is_inverse_functional: false,
inverse_of: None,
}],
relationships: vec![],
namespace: "http://example.org#".to_string(),
version: "1.0".to_string(),
label: "Test Ontology".to_string(),
description: None,
metadata: BTreeMap::new(),
};
let ts_code = TypeScriptGenerator::generate_interfaces(&schema).unwrap();
assert!(ts_code.contains("export interface Product"));
assert!(ts_code.contains("name: string"));
assert!(ts_code.contains("Auto-generated TypeScript types"));
}
#[test]
fn test_namespaces_command_integration() {
use ggen_cli_lib::cmds::ontology::namespaces;
let result = namespaces().unwrap();
assert_eq!(result.count, 8);
assert_eq!(result.namespaces.len(), 8);
let prefixes: std::collections::HashSet<&str> = result
.namespaces
.iter()
.map(|ns| ns.prefix.as_str())
.collect();
assert!(prefixes.contains("rdf"));
assert!(prefixes.contains("rdfs"));
assert!(prefixes.contains("owl"));
assert!(prefixes.contains("schema"));
assert!(prefixes.contains("foaf"));
assert!(prefixes.contains("dc"));
assert!(prefixes.contains("skos"));
assert!(prefixes.contains("bigfive"));
for ns in &result.namespaces {
if ns.prefix == "rdf" || ns.prefix == "rdfs" || ns.prefix == "owl" {
assert_eq!(ns.source, "bundled-standard");
}
}
}
}
#[cfg(test)]
mod ontology_schema_tests {
use super::*;
#[test]
fn test_ontology_schema_minimal() {
let schema = OntologySchema {
classes: vec![],
properties: vec![],
relationships: vec![],
namespace: "http://example.org#".to_string(),
version: "1.0".to_string(),
label: "Test Ontology".to_string(),
description: None,
metadata: BTreeMap::new(),
};
assert_eq!(schema.namespace, "http://example.org#");
assert_eq!(schema.classes.len(), 0);
assert_eq!(schema.properties.len(), 0);
assert_eq!(schema.version, "1.0");
assert_eq!(schema.label, "Test Ontology");
}
#[test]
fn test_ontology_schema_full() {
let mut metadata = BTreeMap::new();
metadata.insert("author".to_string(), "Test Author".to_string());
metadata.insert("created".to_string(), "2025-01-01".to_string());
let schema = OntologySchema {
classes: vec![],
properties: vec![],
relationships: vec![],
namespace: "http://example.org#".to_string(),
version: "2.0".to_string(),
label: "Full Ontology".to_string(),
description: Some("A complete ontology example".to_string()),
metadata,
};
assert_eq!(
schema.description,
Some("A complete ontology example".to_string())
);
assert_eq!(schema.metadata.len(), 2);
assert_eq!(schema.metadata["author"], "Test Author");
}
#[test]
fn test_ontology_schema_with_classes() {
let schema = OntologySchema {
classes: vec![OntClass {
uri: "http://example.org#Product".to_string(),
name: "Product".to_string(),
label: "Product".to_string(),
description: Some("A product".to_string()),
parent_classes: vec![],
properties: vec![],
is_abstract: false,
restrictions: vec![],
}],
properties: vec![],
relationships: vec![],
namespace: "http://example.org#".to_string(),
version: "1.0".to_string(),
label: "Product Ontology".to_string(),
description: None,
metadata: BTreeMap::new(),
};
assert_eq!(schema.classes.len(), 1);
assert_eq!(schema.classes[0].name, "Product");
}
}
#[cfg(test)]
mod ont_class_tests {
use super::*;
#[test]
fn test_ont_class_full() {
let class = OntClass {
uri: "http://example.org#Person".to_string(),
name: "Person".to_string(),
label: "Person".to_string(),
description: Some("A human being".to_string()),
parent_classes: vec!["http://example.org#Agent".to_string()],
properties: vec!["name".to_string(), "age".to_string()],
is_abstract: false,
restrictions: vec![],
};
assert_eq!(class.uri, "http://example.org#Person");
assert_eq!(class.name, "Person");
assert_eq!(class.label, "Person");
assert_eq!(class.description, Some("A human being".to_string()));
assert_eq!(class.parent_classes.len(), 1);
assert_eq!(class.properties.len(), 2);
assert!(!class.is_abstract);
}
#[test]
fn test_ont_class_minimal() {
let class = OntClass {
uri: "http://example.org#Thing".to_string(),
name: "Thing".to_string(),
label: "Thing".to_string(),
description: None,
parent_classes: vec![],
properties: vec![],
is_abstract: true,
restrictions: vec![],
};
assert!(class.description.is_none());
assert!(class.is_abstract);
}
#[test]
fn test_ont_class_with_restrictions() {
let class = OntClass {
uri: "http://example.org#Adult".to_string(),
name: "Adult".to_string(),
label: "Adult".to_string(),
description: None,
parent_classes: vec![],
properties: vec![],
is_abstract: false,
restrictions: vec![OwlRestriction::MinCardinality(18)],
};
assert_eq!(class.restrictions.len(), 1);
}
}
#[cfg(test)]
mod ont_property_tests {
use super::*;
#[test]
fn test_ont_property_string_range() {
let property = OntProperty {
uri: "http://example.org#name".to_string(),
name: "name".to_string(),
label: "Name".to_string(),
description: Some("The name of something".to_string()),
domain: vec!["http://example.org#Person".to_string()],
range: PropertyRange::String,
cardinality: Cardinality::One,
required: true,
is_functional: true,
is_inverse_functional: false,
inverse_of: None,
};
assert_eq!(property.name, "name");
assert!(matches!(property.range, PropertyRange::String));
assert!(matches!(property.cardinality, Cardinality::One));
assert!(property.required);
assert!(property.is_functional);
}
#[test]
fn test_ont_property_reference_range() {
let property = OntProperty {
uri: "http://example.org#knows".to_string(),
name: "knows".to_string(),
label: "Knows".to_string(),
description: None,
domain: vec!["http://example.org#Person".to_string()],
range: PropertyRange::Reference("http://example.org#Person".to_string()),
cardinality: Cardinality::Many,
required: false,
is_functional: false,
is_inverse_functional: false,
inverse_of: None,
};
assert!(matches!(property.range, PropertyRange::Reference(_)));
assert!(matches!(property.cardinality, Cardinality::Many));
assert!(!property.required);
}
#[test]
fn test_ont_property_cardinalities() {
let cardinalities = vec![
(Cardinality::One, 1, Some(1)),
(Cardinality::ZeroOrOne, 0, Some(1)),
(Cardinality::Many, 0, None),
(Cardinality::OneOrMore, 1, None),
(
Cardinality::Range {
min: 2,
max: Some(5),
},
2,
Some(5),
),
];
for (cardinality, expected_min, expected_max) in cardinalities {
assert_eq!(cardinality.min(), expected_min);
assert_eq!(cardinality.max(), expected_max);
}
}
#[test]
fn test_ont_property_multiple_domains() {
let property = OntProperty {
uri: "http://example.org#identifier".to_string(),
name: "identifier".to_string(),
label: "Identifier".to_string(),
description: None,
domain: vec![
"http://example.org#Person".to_string(),
"http://example.org#Organization".to_string(),
],
range: PropertyRange::String,
cardinality: Cardinality::One,
required: true,
is_functional: true,
is_inverse_functional: false,
inverse_of: None,
};
assert_eq!(property.domain.len(), 2);
}
}
#[cfg(test)]
mod property_range_tests {
use super::*;
#[test]
fn test_property_range_variants() {
let ranges = vec![
PropertyRange::String,
PropertyRange::Integer,
PropertyRange::Float,
PropertyRange::Boolean,
PropertyRange::DateTime,
PropertyRange::Date,
PropertyRange::Time,
PropertyRange::Reference("http://example.org#Class".to_string()),
PropertyRange::Literal("custom".to_string()),
PropertyRange::Enum(vec!["A".to_string(), "B".to_string()]),
];
assert_eq!(ranges.len(), 10);
}
#[test]
fn test_property_range_reference() {
let range = PropertyRange::Reference("http://example.org#Person".to_string());
assert!(matches!(range, PropertyRange::Reference(_)));
}
#[test]
fn test_property_range_enum() {
let range = PropertyRange::Enum(vec![
"Red".to_string(),
"Green".to_string(),
"Blue".to_string(),
]);
if let PropertyRange::Enum(values) = range {
assert_eq!(values.len(), 3);
assert!(values.contains(&"Red".to_string()));
} else {
panic!("Expected Enum variant");
}
}
}
#[cfg(test)]
mod ont_relationship_tests {
use super::*;
#[test]
fn test_ont_relationship_basic() {
let relationship = OntRelationship {
from_class: "http://example.org#Person".to_string(),
to_class: "http://example.org#Organization".to_string(),
property: "http://example.org#worksFor".to_string(),
relationship_type: RelationshipType::ManyToOne,
bidirectional: false,
label: "works for".to_string(),
};
assert_eq!(relationship.from_class, "http://example.org#Person");
assert_eq!(relationship.to_class, "http://example.org#Organization");
assert!(matches!(
relationship.relationship_type,
RelationshipType::ManyToOne
));
assert!(!relationship.bidirectional);
}
#[test]
fn test_relationship_type_variants() {
let types = vec![
RelationshipType::OneToOne,
RelationshipType::OneToMany,
RelationshipType::ManyToOne,
RelationshipType::ManyToMany,
RelationshipType::Inheritance,
RelationshipType::Composition,
RelationshipType::Aggregation,
];
assert_eq!(types.len(), 7);
}
#[test]
fn test_ont_relationship_bidirectional() {
let relationship = OntRelationship {
from_class: "http://example.org#Person".to_string(),
to_class: "http://example.org#Person".to_string(),
property: "http://example.org#knows".to_string(),
relationship_type: RelationshipType::ManyToMany,
bidirectional: true,
label: "knows".to_string(),
};
assert!(relationship.bidirectional);
assert!(matches!(
relationship.relationship_type,
RelationshipType::ManyToMany
));
}
}
#[cfg(test)]
mod owl_restriction_tests {
use super::*;
#[test]
fn test_owl_restriction_variants() {
let restrictions = vec![
OwlRestriction::SomeValuesFrom("http://example.org#Class".to_string()),
OwlRestriction::AllValuesFrom("http://example.org#Class".to_string()),
OwlRestriction::HasValue("specific-value".to_string()),
OwlRestriction::MinCardinality(1),
OwlRestriction::MaxCardinality(10),
OwlRestriction::Cardinality(5),
];
assert_eq!(restrictions.len(), 6);
}
#[test]
fn test_owl_restriction_some_values_from() {
let restriction = OwlRestriction::SomeValuesFrom("http://example.org#Person".to_string());
assert!(matches!(restriction, OwlRestriction::SomeValuesFrom(_)));
}
#[test]
fn test_owl_restriction_cardinalities() {
let min_card = OwlRestriction::MinCardinality(1);
let max_card = OwlRestriction::MaxCardinality(5);
let card = OwlRestriction::Cardinality(3);
assert!(matches!(min_card, OwlRestriction::MinCardinality(1)));
assert!(matches!(max_card, OwlRestriction::MaxCardinality(5)));
assert!(matches!(card, OwlRestriction::Cardinality(3)));
}
}
#[cfg(test)]
mod cli_output_tests {
use super::*;
use serde_json;
#[test]
fn test_cli_generate_output_serialization() {
#[derive(serde::Serialize)]
struct GenerateOutput {
language: String,
files_generated: usize,
output_directory: String,
primary_file: String,
}
let output = GenerateOutput {
language: "typescript".to_string(),
files_generated: 3,
output_directory: ".".to_string(),
primary_file: "types.ts".to_string(),
};
let json = serde_json::to_string(&output).unwrap();
assert!(json.contains("typescript"));
assert!(json.contains("types.ts"));
}
#[test]
fn test_cli_validate_output_serialization() {
#[derive(serde::Serialize)]
struct ValidateOutput {
is_valid: bool,
classes_count: usize,
properties_count: usize,
warnings: Vec<String>,
errors: Vec<String>,
}
let output = ValidateOutput {
is_valid: true,
classes_count: 5,
properties_count: 12,
warnings: vec!["Class 'Thing' has no properties".to_string()],
errors: vec![],
};
let json = serde_json::to_string(&output).unwrap();
assert!(json.contains("true"));
assert!(json.contains("5"));
}
#[test]
fn test_cli_init_output_serialization() {
#[derive(serde::Serialize)]
struct InitOutput {
project_name: String,
ontology_file: String,
config_file: String,
generated_files: Vec<String>,
}
let output = InitOutput {
project_name: "my-ontology".to_string(),
ontology_file: "ontologies/example.ttl".to_string(),
config_file: "ggen.config.json".to_string(),
generated_files: vec!["package.json".to_string(), "README.md".to_string()],
};
let json = serde_json::to_string(&output).unwrap();
assert!(json.contains("my-ontology"));
}
}
#[cfg(test)]
mod integration_tests {
use super::*;
#[test]
fn test_integration_complete_schema() {
let schema = OntologySchema {
classes: vec![
OntClass {
uri: "http://example.org#Product".to_string(),
name: "Product".to_string(),
label: "Product".to_string(),
description: Some("A product for sale".to_string()),
parent_classes: vec![],
properties: vec!["name".to_string(), "price".to_string()],
is_abstract: false,
restrictions: vec![],
},
OntClass {
uri: "http://example.org#Order".to_string(),
name: "Order".to_string(),
label: "Order".to_string(),
description: Some("A customer order".to_string()),
parent_classes: vec![],
properties: vec!["product".to_string(), "quantity".to_string()],
is_abstract: false,
restrictions: vec![],
},
],
properties: vec![
OntProperty {
uri: "http://example.org#name".to_string(),
name: "name".to_string(),
label: "Name".to_string(),
description: None,
domain: vec!["http://example.org#Product".to_string()],
range: PropertyRange::String,
cardinality: Cardinality::One,
required: true,
is_functional: true,
is_inverse_functional: false,
inverse_of: None,
},
OntProperty {
uri: "http://example.org#price".to_string(),
name: "price".to_string(),
label: "Price".to_string(),
description: None,
domain: vec!["http://example.org#Product".to_string()],
range: PropertyRange::Float,
cardinality: Cardinality::One,
required: true,
is_functional: true,
is_inverse_functional: false,
inverse_of: None,
},
],
relationships: vec![OntRelationship {
from_class: "http://example.org#Order".to_string(),
to_class: "http://example.org#Product".to_string(),
property: "http://example.org#product".to_string(),
relationship_type: RelationshipType::ManyToOne,
bidirectional: false,
label: "contains".to_string(),
}],
namespace: "http://example.org#".to_string(),
version: "1.0".to_string(),
label: "E-commerce Ontology".to_string(),
description: Some("Product and Order ontology".to_string()),
metadata: BTreeMap::new(),
};
assert_eq!(schema.classes.len(), 2);
assert_eq!(schema.properties.len(), 2);
assert_eq!(schema.relationships.len(), 1);
let product_class = &schema.classes[0];
assert_eq!(product_class.properties.len(), 2);
}
#[test]
fn test_integration_schema_org_structure() {
let schema = OntologySchema {
classes: vec![OntClass {
uri: "https://schema.org/Product".to_string(),
name: "Product".to_string(),
label: "Product".to_string(),
description: Some("Any offered product or service".to_string()),
parent_classes: vec![],
properties: vec!["name".to_string()],
is_abstract: false,
restrictions: vec![],
}],
properties: vec![OntProperty {
uri: "https://schema.org/name".to_string(),
name: "name".to_string(),
label: "Name".to_string(),
description: None,
domain: vec!["https://schema.org/Product".to_string()],
range: PropertyRange::String,
cardinality: Cardinality::One,
required: true,
is_functional: true,
is_inverse_functional: false,
inverse_of: None,
}],
relationships: vec![],
namespace: "https://schema.org/".to_string(),
version: "1.0".to_string(),
label: "Schema.org".to_string(),
description: None,
metadata: BTreeMap::new(),
};
assert_eq!(schema.namespace, "https://schema.org/");
assert!(schema.classes.iter().any(|c| c.name == "Product"));
}
#[test]
fn test_integration_cardinality_methods() {
let test_cases = vec![
(Cardinality::One, false), (Cardinality::ZeroOrOne, false), (Cardinality::Many, true), (Cardinality::OneOrMore, true), (
Cardinality::Range {
min: 2,
max: Some(5),
},
true,
), (
Cardinality::Range {
min: 0,
max: Some(1),
},
false,
), ];
for (cardinality, expected) in test_cases {
assert_eq!(cardinality.is_multi_valued(), expected);
}
}
#[test]
fn test_integration_language_options() {
let languages = vec!["typescript", "graphql", "sql"];
for language in languages {
let output_dir = PathBuf::from(".");
let zod = true;
let utilities = true;
let _: &str = language;
let _: &PathBuf = &output_dir;
let _: bool = zod;
let _: bool = utilities;
}
}
#[test]
fn test_integration_template_options() {
let templates: Vec<Option<&str>> =
vec![Some("schema.org"), Some("foaf"), Some("dublincore"), None];
for template in templates {
let project_name = "test-project";
let _: &str = project_name;
let _: Option<&str> = template;
}
}
}