geolog-zeta-fork/tests/unit_relations.rs

184 lines
5.2 KiB
Rust
Raw Normal View History

2026-02-26 11:50:51 +01:00
//! Unit tests for relation storage
use geolog::core::{RelationStorage, Structure, VecRelation};
use geolog::id::{NumericId, Slid};
use geolog::universe::Universe;
use geolog::serialize::{load_structure, save_structure};
use tempfile::tempdir;
/// Helper to create Slid from integer
fn slid(n: usize) -> Slid {
Slid::from_usize(n)
}
#[test]
fn test_vec_relation_basic() {
let mut rel = VecRelation::new(2);
// Insert a tuple
assert!(rel.insert(vec![slid(0), slid(1)]));
assert_eq!(rel.len(), 1);
// Check containment
assert!(rel.contains(&[slid(0), slid(1)]));
assert!(!rel.contains(&[slid(1), slid(0)]));
assert!(!rel.contains(&[slid(0), slid(0)]));
// Insert another tuple
assert!(rel.insert(vec![slid(1), slid(0)]));
assert_eq!(rel.len(), 2);
// Duplicate insert returns false
assert!(!rel.insert(vec![slid(0), slid(1)]));
assert_eq!(rel.len(), 2);
}
#[test]
fn test_vec_relation_remove() {
let mut rel = VecRelation::new(2);
rel.insert(vec![slid(0), slid(1)]);
rel.insert(vec![slid(1), slid(2)]);
assert_eq!(rel.len(), 2);
// Remove existing tuple
assert!(rel.remove(&[slid(0), slid(1)]));
assert_eq!(rel.len(), 1);
assert!(!rel.contains(&[slid(0), slid(1)]));
assert!(rel.contains(&[slid(1), slid(2)]));
// Remove non-existent tuple
assert!(!rel.remove(&[slid(0), slid(1)]));
assert_eq!(rel.len(), 1);
// Re-insert removed tuple (should reuse tuple ID)
assert!(rel.insert(vec![slid(0), slid(1)]));
assert_eq!(rel.len(), 2);
assert!(rel.contains(&[slid(0), slid(1)]));
}
#[test]
fn test_vec_relation_iter() {
let mut rel = VecRelation::new(2);
rel.insert(vec![slid(0), slid(1)]);
rel.insert(vec![slid(1), slid(2)]);
rel.insert(vec![slid(2), slid(3)]);
let tuples: Vec<_> = rel.iter().collect();
assert_eq!(tuples.len(), 3);
// Remove middle tuple
rel.remove(&[slid(1), slid(2)]);
let tuples: Vec<_> = rel.iter().collect();
assert_eq!(tuples.len(), 2);
}
#[test]
fn test_structure_relations() {
let mut universe = Universe::new();
let mut structure = Structure::new(2);
// Add elements to two sorts
let (a, _) = structure.add_element(&mut universe, 0);
let (b, _) = structure.add_element(&mut universe, 0);
let (x, _) = structure.add_element(&mut universe, 1);
let (y, _) = structure.add_element(&mut universe, 1);
// Initialize a binary relation (arity 2)
structure.init_relations(&[2]);
// Assert some tuples
assert!(structure.assert_relation(0, vec![a, x]));
assert!(structure.assert_relation(0, vec![b, y]));
assert_eq!(structure.get_relation(0).len(), 2);
// Query
assert!(structure.query_relation(0, &[a, x]));
assert!(!structure.query_relation(0, &[a, y]));
// Retract
assert!(structure.retract_relation(0, &[a, x]));
assert!(!structure.query_relation(0, &[a, x]));
}
#[test]
fn test_relation_serialization_roundtrip() {
let mut universe = Universe::new();
let mut structure = Structure::new(2);
// Add elements
let (a, _) = structure.add_element(&mut universe, 0);
let (b, _) = structure.add_element(&mut universe, 0);
let (x, _) = structure.add_element(&mut universe, 1);
// Initialize relation and add tuples
structure.init_relations(&[2]);
structure.assert_relation(0, vec![a, x]);
structure.assert_relation(0, vec![b, x]);
// Serialize and deserialize via StructureData
let data = geolog::serialize::StructureData::from_structure(&structure);
let restored = data.to_structure();
// Check relation was preserved
assert_eq!(restored.num_relations(), 1);
assert_eq!(restored.get_relation(0).len(), 2);
assert!(restored.query_relation(0, &[a, x]));
assert!(restored.query_relation(0, &[b, x]));
assert!(!restored.query_relation(0, &[a, b]));
}
#[test]
fn test_relation_file_roundtrip() {
let mut universe = Universe::new();
let mut structure = Structure::new(2);
// Add elements
let (a, _) = structure.add_element(&mut universe, 0);
let (b, _) = structure.add_element(&mut universe, 1);
// Initialize relation and add tuples
structure.init_relations(&[2]);
structure.assert_relation(0, vec![a, b]);
// Save to file
let dir = tempdir().unwrap();
let path = dir.path().join("test.structure");
save_structure(&structure, &path).expect("save should succeed");
// Load from file
let loaded = load_structure(&path).expect("load should succeed");
// Check relation was preserved
assert_eq!(loaded.num_relations(), 1);
assert!(loaded.query_relation(0, &[a, b]));
}
#[test]
fn test_unary_relation() {
let mut rel = VecRelation::new(1);
rel.insert(vec![slid(42)]);
rel.insert(vec![slid(100)]);
assert!(rel.contains(&[slid(42)]));
assert!(rel.contains(&[slid(100)]));
assert!(!rel.contains(&[slid(0)]));
assert_eq!(rel.len(), 2);
}
#[test]
fn test_ternary_relation() {
let mut rel = VecRelation::new(3);
rel.insert(vec![slid(1), slid(2), slid(3)]);
rel.insert(vec![slid(4), slid(5), slid(6)]);
assert!(rel.contains(&[slid(1), slid(2), slid(3)]));
assert!(rel.contains(&[slid(4), slid(5), slid(6)]));
assert!(!rel.contains(&[slid(1), slid(2), slid(4)]));
assert_eq!(rel.len(), 2);
}