//! Test library for Intel 400x common functionality //! //! This module provides a centralized entry point for all tests //! and exports common testing utilities. #![cfg(test)] // Re-export the rusty_emu crate for use in tests pub use rusty_emu; // Module declarations for test files mod gui_integration_tests; mod gui_tests; mod integration_tests; mod intel_4001_state_machine_test; mod intel_400x_tests; // Common test utilities and helpers pub mod test_utils { use std::sync::Arc; use std::time::{Duration, Instant}; /// Create a deterministic time source for testing pub fn create_test_time() -> Instant { Instant::now() } /// Create a test duration for timing-sensitive tests pub fn create_test_duration(nanos: u64) -> Duration { Duration::from_nanos(nanos) } /// Helper to advance time in tests pub fn advance_test_time(duration: Duration) { std::thread::sleep(duration); } /// Create a VirtualClock in MaxSpeed mode for fast deterministic tests. /// /// The clock starts in stopped state. Call `clock.start()` after spawning /// the governor thread. /// /// # Parameters /// - `tick_size_ns`: Virtual time advance per tick (default: 333ns for 750 kHz) pub fn create_maxspeed_clock(tick_size_ns: u64) -> Arc { let clock = Arc::new(rusty_emu::virtual_clock::VirtualClock::new( Duration::from_nanos(tick_size_ns), )); clock.set_mode(rusty_emu::virtual_clock::SimulationMode::MaxSpeed); clock } /// Create a VirtualClock in SingleStep mode for precise state verification. /// /// Each call to `clock.trigger_step()` advances virtual time by one tick. pub fn create_singlestep_clock(tick_size_ns: u64) -> Arc { let clock = Arc::new(rusty_emu::virtual_clock::VirtualClock::new( Duration::from_nanos(tick_size_ns), )); clock.set_mode(rusty_emu::virtual_clock::SimulationMode::SingleStep); clock } /// Spawn a RealTimeGovernor thread for the given clock. /// /// Returns a JoinHandle that can be used to wait for the governor to exit. /// The governor will exit when `clock.stop()` is called. pub fn spawn_governor( clock: Arc, ) -> std::thread::JoinHandle<()> { std::thread::spawn(move || { let governor = rusty_emu::real_time_governor::RealTimeGovernor::with_defaults(clock); governor.run(); }) } /// Stop the virtual clock and wait for the governor thread to finish. /// /// This ensures clean shutdown of the governor thread before the test ends. pub fn stop_governor( clock: &Arc, handle: std::thread::JoinHandle<()>, ) { clock.stop(); // Give the governor thread a moment to exit cleanly let _ = handle.join(); } /// Verify that a component implements all required traits pub fn verify_intel400x_traits(component: &C) where C: rusty_emu::components::common::intel_400x::Intel400xClockHandling, C: rusty_emu::components::common::intel_400x::Intel400xDataBus, C: rusty_emu::components::common::intel_400x::Intel400xAddressHandling, C: rusty_emu::components::common::intel_400x::Intel400xControlPins, C: rusty_emu::components::common::intel_400x::Intel400xResetHandling, C: rusty_emu::components::common::intel_400x::Intel400xTimingState, { // Test Intel400xClockHandling let _: &dyn rusty_emu::components::common::intel_400x::Intel400xClockHandling = component; // Test Intel400xDataBus let _: &dyn rusty_emu::components::common::intel_400x::Intel400xDataBus = component; // Test Intel400xAddressHandling let _: &dyn rusty_emu::components::common::intel_400x::Intel400xAddressHandling = component; // Test Intel400xControlPins let _: &dyn rusty_emu::components::common::intel_400x::Intel400xControlPins = component; // Test Intel400xResetHandling let _: &dyn rusty_emu::components::common::intel_400x::Intel400xResetHandling = component; // Test Intel400xTimingState let _: &dyn rusty_emu::components::common::intel_400x::Intel400xTimingState = component; } /// Test that timing constants are reasonable #[allow(dead_code)] pub fn verify_timing_constants() { use rusty_emu::components::common::intel_400x::TimingConstants; // Fast access should be faster than default assert!(TimingConstants::FAST_ACCESS_TIME < TimingConstants::DEFAULT_ACCESS_TIME); } /// Test that state machine properties hold #[allow(dead_code)] pub fn verify_state_machine_properties() { use rusty_emu::components::common::intel_400x::TimingState; let states = vec![ TimingState::Idle, TimingState::AddressPhase, TimingState::WaitLatency, TimingState::DriveData, ]; for state in states { // Each state should have consistent query results match state { TimingState::Idle => { assert!(state.is_idle()); assert!(!state.is_address_phase()); assert!(!state.is_waiting_latency()); assert!(!state.is_driving_data()); } TimingState::AddressPhase => { assert!(!state.is_idle()); assert!(state.is_address_phase()); assert!(!state.is_waiting_latency()); assert!(!state.is_driving_data()); } TimingState::WaitLatency => { assert!(!state.is_idle()); assert!(!state.is_address_phase()); assert!(state.is_waiting_latency()); assert!(!state.is_driving_data()); } TimingState::DriveData => { assert!(!state.is_idle()); assert!(!state.is_address_phase()); assert!(!state.is_waiting_latency()); assert!(state.is_driving_data()); } } } } } // Test configuration and setup pub mod test_config { /// Test configuration for running the test suite pub struct TestConfig { pub enable_detailed_output: bool, pub enable_timing_tests: bool, pub enable_property_tests: bool, } impl Default for TestConfig { fn default() -> Self { Self { enable_detailed_output: false, enable_timing_tests: true, enable_property_tests: true, } } } impl TestConfig { pub fn with_detailed_output(mut self) -> Self { self.enable_detailed_output = true; self } pub fn without_timing_tests(mut self) -> Self { self.enable_timing_tests = false; self } pub fn without_property_tests(mut self) -> Self { self.enable_property_tests = false; self } } }