geolog-zeta-fork/tests/unit_meta.rs

266 lines
8.4 KiB
Rust
Raw Normal View History

2026-02-26 11:50:51 +01:00
//! Unit tests for GeologMeta theory and structure conversion
use geolog::core::{Context, DerivedSort, ElaboratedTheory, Formula, Sequent, Signature, Term, Theory};
use geolog::meta::{geolog_meta, structure_to_theory, theory_to_structure};
use geolog::naming::NamingIndex;
use geolog::universe::Universe;
#[test]
fn test_theory_to_structure() {
// Create a simple theory
let mut sig = Signature::new();
sig.add_sort("P".to_string());
sig.add_sort("T".to_string());
sig.add_function(
"src".to_string(),
DerivedSort::Base(1), // T
DerivedSort::Base(0), // P
);
let theory = ElaboratedTheory {
params: vec![],
theory: Theory {
name: "PetriNet".to_string(),
signature: sig,
axioms: vec![],
axiom_names: vec![],
},
};
let mut universe = Universe::new();
let mut naming = NamingIndex::new();
let structure = theory_to_structure(&theory, &mut universe, &mut naming);
// Check basic structure properties
assert!(!structure.is_empty());
// Check we have elements in the structure
// Should have: 1 Theory, 2 Srt, 1 Func, plus DSort/BaseDS elements
assert!(
structure.len() > 5,
"Expected more than 5 elements, got {}",
structure.len()
);
// Verify names were registered in naming index
assert!(naming.lookup_unique("PetriNet").is_some());
assert!(naming.lookup_unique("P").is_some());
assert!(naming.lookup_unique("T").is_some());
assert!(naming.lookup_unique("src").is_some());
}
#[test]
fn test_geolog_meta_parses() {
// Just ensure GeologMeta itself can be loaded
let meta = geolog_meta();
assert_eq!(meta.theory.name, "GeologMeta");
// Should have lots of sorts and functions (no Name sort anymore)
assert!(
meta.theory.signature.sorts.len() >= 25,
"Expected many sorts, got {}",
meta.theory.signature.sorts.len()
);
assert!(
meta.theory.signature.functions.len() >= 40,
"Expected many functions, got {}",
meta.theory.signature.functions.len()
);
assert!(
meta.theory.signature.relations.len() >= 3,
"Expected some relations"
);
}
#[test]
fn test_theory_roundtrip() {
// Create a theory with sorts, functions, and a relation
let mut sig = Signature::new();
let p_id = sig.add_sort("P".to_string());
let t_id = sig.add_sort("T".to_string());
sig.add_function(
"src".to_string(),
DerivedSort::Base(t_id),
DerivedSort::Base(p_id),
);
sig.add_function(
"tgt".to_string(),
DerivedSort::Base(t_id),
DerivedSort::Base(p_id),
);
// Add a relation with record domain
sig.add_relation(
"enabled".to_string(),
DerivedSort::Product(vec![
("place".to_string(), DerivedSort::Base(p_id)),
("trans".to_string(), DerivedSort::Base(t_id)),
]),
);
let original = ElaboratedTheory {
params: vec![],
theory: Theory {
name: "PetriNet".to_string(),
signature: sig,
axioms: vec![],
axiom_names: vec![],
},
};
// Convert to structure
let mut universe = Universe::new();
let mut naming = NamingIndex::new();
let structure = theory_to_structure(&original, &mut universe, &mut naming);
// Convert back
let reconstructed =
structure_to_theory(&structure, &universe, &naming).expect("roundtrip should succeed");
// Verify basic properties match
assert_eq!(reconstructed.theory.name, "PetriNet");
assert_eq!(reconstructed.theory.signature.sorts.len(), 2);
assert_eq!(reconstructed.theory.signature.functions.len(), 2);
assert_eq!(reconstructed.theory.signature.relations.len(), 1);
// Verify sort names
assert!(reconstructed.theory.signature.lookup_sort("P").is_some());
assert!(reconstructed.theory.signature.lookup_sort("T").is_some());
// Verify function names
assert!(reconstructed.theory.signature.lookup_func("src").is_some());
assert!(reconstructed.theory.signature.lookup_func("tgt").is_some());
// Verify relation name
assert!(
reconstructed
.theory
.signature
.lookup_rel("enabled")
.is_some()
);
}
#[test]
fn test_theory_roundtrip_with_axioms() {
// Create a preorder theory with reflexivity and transitivity axioms
let mut sig = Signature::new();
let x_id = sig.add_sort("X".to_string());
let x_sort = DerivedSort::Base(x_id);
// Add a binary relation: leq : [x: X, y: X] -> Prop
let rel_domain = DerivedSort::Product(vec![
("x".to_string(), x_sort.clone()),
("y".to_string(), x_sort.clone()),
]);
let rel_id = sig.add_relation("leq".to_string(), rel_domain);
// Reflexivity axiom: forall x:X. |- leq(x, x)
// Context: [x: X]
// Premise: True
// Conclusion: leq({x: x, y: x})
let reflexivity = Sequent {
context: Context {
vars: vec![("x".to_string(), x_sort.clone())],
},
premise: Formula::True,
conclusion: Formula::Rel(
rel_id,
Term::Record(vec![
("x".to_string(), Term::Var("x".to_string(), x_sort.clone())),
("y".to_string(), Term::Var("x".to_string(), x_sort.clone())),
]),
),
};
// Transitivity axiom: forall x,y,z:X. leq(x,y), leq(y,z) |- leq(x,z)
// Context: [x: X, y: X, z: X]
// Premise: leq(x,y) ∧ leq(y,z)
// Conclusion: leq(x,z)
let transitivity = Sequent {
context: Context {
vars: vec![
("x".to_string(), x_sort.clone()),
("y".to_string(), x_sort.clone()),
("z".to_string(), x_sort.clone()),
],
},
premise: Formula::Conj(vec![
Formula::Rel(
rel_id,
Term::Record(vec![
("x".to_string(), Term::Var("x".to_string(), x_sort.clone())),
("y".to_string(), Term::Var("y".to_string(), x_sort.clone())),
]),
),
Formula::Rel(
rel_id,
Term::Record(vec![
("x".to_string(), Term::Var("y".to_string(), x_sort.clone())),
("y".to_string(), Term::Var("z".to_string(), x_sort.clone())),
]),
),
]),
conclusion: Formula::Rel(
rel_id,
Term::Record(vec![
("x".to_string(), Term::Var("x".to_string(), x_sort.clone())),
("y".to_string(), Term::Var("z".to_string(), x_sort.clone())),
]),
),
};
let original = ElaboratedTheory {
params: vec![],
theory: Theory {
name: "Preorder".to_string(),
signature: sig,
axioms: vec![reflexivity, transitivity],
axiom_names: vec!["ax/refl".to_string(), "ax/trans".to_string()],
},
};
// Convert to structure
let mut universe = Universe::new();
let mut naming = NamingIndex::new();
let structure = theory_to_structure(&original, &mut universe, &mut naming);
// Convert back
let reconstructed =
structure_to_theory(&structure, &universe, &naming).expect("roundtrip should succeed");
// Verify basic properties match
assert_eq!(reconstructed.theory.name, "Preorder");
assert_eq!(reconstructed.theory.signature.sorts.len(), 1);
assert_eq!(reconstructed.theory.signature.relations.len(), 1);
assert_eq!(
reconstructed.theory.axioms.len(),
2,
"Expected 2 axioms, got {}",
reconstructed.theory.axioms.len()
);
// Verify sort name
assert!(reconstructed.theory.signature.lookup_sort("X").is_some());
// Verify relation name
assert!(reconstructed.theory.signature.lookup_rel("leq").is_some());
// Verify axiom names round-trip correctly
assert_eq!(
reconstructed.theory.axiom_names.len(),
2,
"Expected 2 axiom names, got {}",
reconstructed.theory.axiom_names.len()
);
assert!(
reconstructed.theory.axiom_names.contains(&"ax/refl".to_string()),
"Expected axiom names to contain 'ax/refl', got {:?}",
reconstructed.theory.axiom_names
);
assert!(
reconstructed.theory.axiom_names.contains(&"ax/trans".to_string()),
"Expected axiom names to contain 'ax/trans', got {:?}",
reconstructed.theory.axiom_names
);
}