use tensorlogic_ir::{TLExpr, Term};
use crate::{
AxisMetadata, DomainHierarchy, DomainInfo, DomainMask, PredicateConstraints, PredicateInfo,
PredicateProperty, SchemaValidator, SymbolTable, ValueRange,
};
#[test]
fn test_domain_info() {
let domain = DomainInfo::with_elements(
"Person",
vec!["Alice".into(), "Bob".into(), "Charlie".into()],
);
assert_eq!(domain.cardinality, 3);
assert!(domain.has_element("Alice"));
assert!(!domain.has_element("Dave"));
assert_eq!(domain.get_index("Bob"), Some(1));
}
#[test]
fn test_predicate_info() {
let pred = PredicateInfo::new("Parent", vec!["Person".into(), "Person".into()]);
assert_eq!(pred.arity, 2);
assert!(pred
.validate_args(&[Term::var("x"), Term::var("y")])
.is_ok());
assert!(pred.validate_args(&[Term::var("x")]).is_err());
}
#[test]
fn test_predicate_with_constraints() {
let constraints = PredicateConstraints::new()
.with_property(PredicateProperty::Symmetric)
.with_property(PredicateProperty::Transitive);
let pred = PredicateInfo::new("Friend", vec!["Person".into(), "Person".into()])
.with_constraints(constraints);
assert_eq!(pred.arity, 2);
assert!(pred.constraints.is_some());
let c = pred.constraints.expect("unwrap");
assert!(c.is_symmetric());
assert!(c.is_transitive());
}
#[test]
fn test_axis_metadata() {
let mut meta = AxisMetadata::new();
let axis_x = meta.assign("x", "Person");
let axis_y = meta.assign("y", "City");
assert_eq!(axis_x, 0);
assert_eq!(axis_y, 1);
assert_eq!(meta.get_domain(0), Some("Person"));
assert_eq!(meta.get_char(0), Some('a'));
assert_eq!(meta.get_char(1), Some('b'));
let spec = meta.build_spec(&["x".into(), "y".into()]);
assert_eq!(spec, "ab");
}
#[test]
fn test_symbol_table() {
let mut table = SymbolTable::new();
table
.add_domain(DomainInfo::new("Person", 10))
.expect("unwrap");
table
.add_domain(DomainInfo::new("City", 5))
.expect("unwrap");
table
.add_predicate(PredicateInfo::new(
"LivesIn",
vec!["Person".into(), "City".into()],
))
.expect("unwrap");
assert_eq!(table.domains.len(), 2);
assert_eq!(table.predicates.len(), 1);
table.bind_variable("x", "Person").expect("unwrap");
assert_eq!(table.get_variable_domain("x"), Some("Person"));
}
#[test]
fn test_domain_mask() {
let domain = DomainInfo::with_elements(
"Person",
vec![
"Alice".into(),
"Bob".into(),
"Charlie".into(),
"Dave".into(),
],
);
let mut mask = DomainMask::new("Person");
mask.include("Alice").include("Bob");
assert!(mask.is_allowed("Alice"));
assert!(mask.is_allowed("Bob"));
assert!(!mask.is_allowed("Charlie"));
let indices = mask.apply_to_indices(&domain);
assert_eq!(indices, vec![0, 1]);
}
#[test]
fn test_symbol_table_json() {
let mut table = SymbolTable::new();
table
.add_domain(DomainInfo::new("Person", 10))
.expect("unwrap");
let json = table.to_json().expect("unwrap");
let restored = SymbolTable::from_json(&json).expect("unwrap");
assert_eq!(restored.domains.len(), 1);
assert_eq!(
restored.domains.get("Person").expect("unwrap").cardinality,
10
);
}
#[test]
fn test_symbol_table_yaml() {
let mut table = SymbolTable::new();
table
.add_domain(DomainInfo::new("Person", 10))
.expect("unwrap");
table
.add_predicate(PredicateInfo::new(
"Parent",
vec!["Person".into(), "Person".into()],
))
.expect("unwrap");
let yaml = table.to_yaml().expect("unwrap");
let restored = SymbolTable::from_yaml(&yaml).expect("unwrap");
assert_eq!(restored.domains.len(), 1);
assert_eq!(restored.predicates.len(), 1);
assert_eq!(
restored.domains.get("Person").expect("unwrap").cardinality,
10
);
}
#[test]
fn test_infer_from_expr() {
let mut table = SymbolTable::new();
let pred = TLExpr::pred("Parent", vec![Term::var("x"), Term::var("y")]);
let expr = TLExpr::exists("x", "Person", pred);
table.infer_from_expr(&expr).expect("unwrap");
assert!(table.domains.contains_key("Person"));
assert!(table.predicates.contains_key("Parent"));
assert_eq!(table.get_variable_domain("x"), Some("Person"));
}
#[test]
fn test_domain_hierarchy() {
let mut hierarchy = DomainHierarchy::new();
hierarchy.add_subtype("Student", "Person");
hierarchy.add_subtype("Teacher", "Person");
hierarchy.add_subtype("Person", "Agent");
assert!(hierarchy.is_subtype("Student", "Person"));
assert!(hierarchy.is_subtype("Student", "Agent"));
assert!(hierarchy.is_subtype("Teacher", "Person"));
assert!(!hierarchy.is_subtype("Student", "Teacher"));
let ancestors = hierarchy.get_ancestors("Student");
assert_eq!(ancestors.len(), 2);
assert!(ancestors.contains(&"Person".to_string()));
assert!(ancestors.contains(&"Agent".to_string()));
}
#[test]
fn test_schema_validation_complete() {
let mut table = SymbolTable::new();
table
.add_domain(DomainInfo::new("Person", 10))
.expect("unwrap");
table
.add_predicate(PredicateInfo::new(
"Parent",
vec!["Person".into(), "Person".into()],
))
.expect("unwrap");
let validator = SchemaValidator::new(&table);
let report = validator.validate().expect("unwrap");
assert!(report.is_valid());
}
#[test]
fn test_schema_validation_with_hierarchy() {
let mut table = SymbolTable::new();
table
.add_domain(DomainInfo::new("Person", 10))
.expect("unwrap");
table
.add_domain(DomainInfo::new("Student", 5))
.expect("unwrap");
let mut hierarchy = DomainHierarchy::new();
hierarchy.add_subtype("Student", "Person");
let validator = SchemaValidator::new(&table).with_hierarchy(&hierarchy);
let report = validator.validate().expect("unwrap");
assert!(report.is_valid());
}
#[test]
fn test_value_range_constraints() {
let range = ValueRange::new().with_min(0.0, true).with_max(1.0, true);
assert!(range.contains(0.0));
assert!(range.contains(0.5));
assert!(range.contains(1.0));
assert!(!range.contains(-0.1));
assert!(!range.contains(1.1));
}
#[test]
fn test_predicate_properties() {
let constraints = PredicateConstraints::new()
.with_property(PredicateProperty::Symmetric)
.with_property(PredicateProperty::Reflexive);
assert!(constraints.has_property(&PredicateProperty::Symmetric));
assert!(constraints.has_property(&PredicateProperty::Reflexive));
assert!(!constraints.has_property(&PredicateProperty::Transitive));
}
#[test]
fn test_infer_arithmetic_expr() {
let mut table = SymbolTable::new();
let pred1 = TLExpr::pred("Score", vec![Term::var("x")]);
let pred2 = TLExpr::pred("Bonus", vec![Term::var("x")]);
let expr = TLExpr::add(pred1, pred2);
table.infer_from_expr(&expr).expect("unwrap");
assert!(table.predicates.contains_key("Score"));
assert!(table.predicates.contains_key("Bonus"));
}
#[test]
fn test_infer_comparison_expr() {
let mut table = SymbolTable::new();
let pred1 = TLExpr::pred("Age", vec![Term::var("x")]);
let pred2 = TLExpr::constant(18.0);
let expr = TLExpr::gte(pred1, pred2);
table.infer_from_expr(&expr).expect("unwrap");
assert!(table.predicates.contains_key("Age"));
}
#[test]
fn test_infer_conditional_expr() {
let mut table = SymbolTable::new();
let cond = TLExpr::pred("IsAdult", vec![Term::var("x")]);
let then_branch = TLExpr::pred("CanVote", vec![Term::var("x")]);
let else_branch = TLExpr::pred("CannotVote", vec![Term::var("x")]);
let expr = TLExpr::if_then_else(cond, then_branch, else_branch);
table.infer_from_expr(&expr).expect("unwrap");
assert!(table.predicates.contains_key("IsAdult"));
assert!(table.predicates.contains_key("CanVote"));
assert!(table.predicates.contains_key("CannotVote"));
}