//! 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 = 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 = 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 = HashMap::new(); // Empty - no names let axiom_names: Vec = 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 = HashMap::new(); let axiom_names: Vec = 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 = HashMap::new(); let axiom_names: Vec = 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 = HashMap::new(); let axiom_names: Vec = 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); }