geolog-zeta-fork/tests/unit_debugger.rs
2026-03-20 11:30:19 +01:00

94 lines
3.6 KiB
Rust

//! Unit tests for the chase debugger
use std::collections::HashMap;
use geolog::debugger::InteractiveDebugger;
use geolog::id::{NumericId, Slid};
use geolog::query::chase::{Binding, ChaseControl, ChaseEvent, ChaseObserver};
/// Test that format_binding correctly displays bindings with element names
#[test]
fn test_format_binding_with_names() {
let mut slid_to_name: HashMap<Slid, String> = HashMap::new();
slid_to_name.insert(Slid::from_usize(0), "alice".to_string());
slid_to_name.insert(Slid::from_usize(1), "bob".to_string());
slid_to_name.insert(Slid::from_usize(2), "charlie".to_string());
let axiom_names: Vec<String> = vec!["ax/test".to_string()];
let debugger = InteractiveDebugger::new(&slid_to_name, &axiom_names);
let mut binding: Binding = HashMap::new();
binding.insert("x".to_string(), Slid::from_usize(0));
binding.insert("y".to_string(), Slid::from_usize(1));
let formatted = debugger.format_binding(&binding);
// Should contain both variable bindings with element names
assert!(formatted.contains("x=alice"), "Should contain x=alice, got: {}", formatted);
assert!(formatted.contains("y=bob"), "Should contain y=bob, got: {}", formatted);
}
/// Test that format_binding handles unknown elements gracefully
#[test]
fn test_format_binding_unknown_elements() {
let slid_to_name: HashMap<Slid, String> = HashMap::new(); // Empty - no names
let axiom_names: Vec<String> = vec![];
let debugger = InteractiveDebugger::new(&slid_to_name, &axiom_names);
let mut binding: Binding = HashMap::new();
binding.insert("x".to_string(), Slid::from_usize(42));
let formatted = debugger.format_binding(&binding);
// Should show "?" for unknown element
assert!(formatted.contains("x=?"), "Should contain x=? for unknown element, got: {}", formatted);
}
/// Test that format_binding handles empty bindings
#[test]
fn test_format_binding_empty() {
let slid_to_name: HashMap<Slid, String> = HashMap::new();
let axiom_names: Vec<String> = vec![];
let debugger = InteractiveDebugger::new(&slid_to_name, &axiom_names);
let binding: Binding = HashMap::new();
let formatted = debugger.format_binding(&binding);
assert_eq!(formatted, "(empty)");
}
/// Test that observer responds to iteration events
#[test]
fn test_debugger_iteration_events() {
let slid_to_name: HashMap<Slid, String> = HashMap::new();
let axiom_names: Vec<String> = vec!["ax/refl".to_string()];
let mut debugger = InteractiveDebugger::new(&slid_to_name, &axiom_names);
// Iteration start should continue
let result = debugger.on_event(ChaseEvent::IterationStart { iteration: 1 });
assert_eq!(result, ChaseControl::Continue);
// Iteration end should continue (in default step mode, but no prompt in test)
let result = debugger.on_event(ChaseEvent::IterationEnd { iteration: 1, changed: false });
assert_eq!(result, ChaseControl::Continue);
// Chase complete should continue
let result = debugger.on_event(ChaseEvent::ChaseComplete { iterations: 1 });
assert_eq!(result, ChaseControl::Continue);
}
/// Test that axiom fired events are handled
#[test]
fn test_debugger_axiom_fired_event() {
let slid_to_name: HashMap<Slid, String> = HashMap::new();
let axiom_names: Vec<String> = vec!["ax/refl".to_string()];
let mut debugger = InteractiveDebugger::new(&slid_to_name, &axiom_names);
// AxiomFired should always continue (it's informational)
let result = debugger.on_event(ChaseEvent::AxiomFired {
axiom_index: 0,
axiom_name: Some("ax/refl"),
changed: true,
});
assert_eq!(result, ChaseControl::Continue);
}