Added debug output
Added GUI
This commit is contained in:
parent
3d4de8b268
commit
e17d6ad177
18 changed files with 3137 additions and 162 deletions
575
tests/gui_integration_tests.rs
Normal file
575
tests/gui_integration_tests.rs
Normal file
|
|
@ -0,0 +1,575 @@
|
|||
//! # GUI Integration Tests
|
||||
//!
|
||||
//! Comprehensive integration tests for GUI functionality including
|
||||
//! system integration, thread safety, state synchronization, and
|
||||
//! error handling scenarios.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use rusty_emu::gui::{run_gui, GuiApp};
|
||||
use rusty_emu::system_config::{ConfigurableSystem, SystemFactory};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Test utilities for GUI integration testing
|
||||
mod gui_integration_test_utils {
|
||||
use super::*;
|
||||
|
||||
/// Create a test system for integration testing
|
||||
pub fn create_test_system() -> Arc<Mutex<ConfigurableSystem>> {
|
||||
let factory = SystemFactory::new();
|
||||
Arc::new(Mutex::new(
|
||||
factory.create_from_json("configs/mcs4_basic.json").unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Create a mock system for testing error conditions
|
||||
pub fn create_mock_system() -> Arc<Mutex<ConfigurableSystem>> {
|
||||
// For now, return a basic system
|
||||
// In a real implementation, this might create a mock or stub
|
||||
create_test_system()
|
||||
}
|
||||
|
||||
/// Simulate GUI state updates over time
|
||||
pub fn simulate_gui_updates(system: &Arc<Mutex<ConfigurableSystem>>) {
|
||||
// Simulate the kind of updates that would happen in the GUI thread
|
||||
if let Ok(mut system_guard) = system.lock() {
|
||||
// Simulate some system activity
|
||||
let _ = system_guard.is_running(); // Access system state
|
||||
}
|
||||
}
|
||||
|
||||
/// Test helper to verify thread-safe access patterns
|
||||
pub fn test_thread_safe_access(system: &Arc<Mutex<ConfigurableSystem>>) -> bool {
|
||||
let system_clone = Arc::clone(system);
|
||||
|
||||
// Spawn a thread that accesses the system
|
||||
let handle = thread::spawn(move || {
|
||||
if let Ok(system_guard) = system_clone.lock() {
|
||||
system_guard.is_running()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
// Main thread also accesses the system
|
||||
let main_thread_result = if let Ok(system_guard) = system.lock() {
|
||||
system_guard.is_running()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Wait for spawned thread
|
||||
let spawned_thread_result = handle.join().unwrap_or(false);
|
||||
|
||||
// Both threads should be able to access without deadlock
|
||||
main_thread_result && spawned_thread_result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod gui_system_integration_tests {
|
||||
use super::*;
|
||||
use gui_integration_test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_gui_system_integration() {
|
||||
let system = create_test_system();
|
||||
let system_clone = Arc::clone(&system);
|
||||
|
||||
// Test that GUI can be created with a system
|
||||
let mut app = GuiApp::new(&eframe::CreationContext {
|
||||
egui_ctx: Default::default(),
|
||||
integration_info: Default::default(),
|
||||
storage: None,
|
||||
build_info: Default::default(),
|
||||
});
|
||||
|
||||
// Set the system
|
||||
app.set_system(system);
|
||||
|
||||
// Verify system is properly set
|
||||
assert!(app.system.is_some());
|
||||
assert!(app.gui_state.system_loaded);
|
||||
|
||||
// Test that system access works
|
||||
let retrieved_system = app.get_system();
|
||||
assert!(retrieved_system.is_some());
|
||||
|
||||
// Verify the retrieved system is the same as the original
|
||||
assert!(Arc::ptr_eq(&retrieved_system.unwrap(), &system_clone));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_state_synchronization() {
|
||||
let system = create_test_system();
|
||||
|
||||
let mut app = GuiApp::new(&eframe::CreationContext {
|
||||
egui_ctx: Default::default(),
|
||||
integration_info: Default::default(),
|
||||
storage: None,
|
||||
build_info: Default::default(),
|
||||
});
|
||||
|
||||
app.set_system(Arc::clone(&system));
|
||||
|
||||
// Test state update mechanism
|
||||
// In a real implementation, this would test the actual update_from_system method
|
||||
// For now, we verify the state structure is properly initialized
|
||||
|
||||
assert!(app.gui_state.system_loaded);
|
||||
assert!(!app.gui_state.system_running); // Should start as not running
|
||||
|
||||
// Test that GUI state has proper structure for synchronization
|
||||
assert_eq!(app.gui_state.memory_state.ram_contents.len(), 4);
|
||||
assert_eq!(app.gui_state.register_state.index_registers.len(), 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_thread_safety() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test that multiple threads can safely access the system
|
||||
let thread_safety_ok = test_thread_safe_access(&system);
|
||||
|
||||
assert!(thread_safety_ok, "System should support thread-safe access");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_concurrent_state_access() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test concurrent access patterns that would occur in GUI
|
||||
let handles: Vec<_> = (0..5)
|
||||
.map(|_| {
|
||||
let system_clone = Arc::clone(&system);
|
||||
thread::spawn(move || {
|
||||
// Simulate GUI update pattern
|
||||
for _ in 0..10 {
|
||||
if let Ok(mut system_guard) = system_clone.lock() {
|
||||
let _ = system_guard.is_running();
|
||||
// Simulate some processing time
|
||||
thread::sleep(Duration::from_micros(10));
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Wait for all threads to complete
|
||||
for handle in handles {
|
||||
handle.join().expect("Thread should complete successfully");
|
||||
}
|
||||
|
||||
// If we get here without deadlock, the test passes
|
||||
assert!(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_error_handling() {
|
||||
let mut state = rusty_emu::gui::state::GuiState::new();
|
||||
|
||||
// Test error state management
|
||||
let test_error = "Test error for GUI".to_string();
|
||||
state.set_error(test_error.clone());
|
||||
|
||||
assert_eq!(state.get_error(), Some(test_error.as_str()));
|
||||
|
||||
// Test error clearing
|
||||
state.clear_error();
|
||||
assert!(state.get_error().is_none());
|
||||
|
||||
// Test multiple error scenarios
|
||||
state.set_error("First error".to_string());
|
||||
state.set_error("Second error".to_string());
|
||||
|
||||
assert_eq!(state.get_error(), Some("Second error"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_system_state_polling() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test the polling mechanism that GUI would use
|
||||
for i in 0..10 {
|
||||
if let Ok(system_guard) = system.lock() {
|
||||
let is_running = system_guard.is_running();
|
||||
|
||||
// Simulate state updates that would happen in GUI
|
||||
// In a real implementation, this would update GUI state
|
||||
|
||||
if i == 5 {
|
||||
// Simulate state change at midpoint
|
||||
assert!(is_running || !is_running); // Just verify we can read state
|
||||
}
|
||||
}
|
||||
|
||||
// Small delay to simulate GUI update interval
|
||||
thread::sleep(Duration::from_micros(100));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_memory_state_integration() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test memory state structure for GUI integration
|
||||
// In a real implementation, this would test actual memory access
|
||||
|
||||
if let Ok(system_guard) = system.lock() {
|
||||
// Test that system provides memory information
|
||||
let _ = system_guard.get_system_info(); // Access system info
|
||||
|
||||
// Verify GUI state can hold memory data
|
||||
let gui_state = rusty_emu::gui::state::GuiState::new();
|
||||
assert_eq!(gui_state.memory_state.ram_contents.len(), 4);
|
||||
|
||||
for bank in &gui_state.memory_state.ram_contents {
|
||||
assert_eq!(bank.len(), 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_register_state_integration() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test register state structure for GUI integration
|
||||
if let Ok(_system_guard) = system.lock() {
|
||||
// In a real implementation, this would access actual CPU registers
|
||||
// For now, we test the GUI state structure
|
||||
|
||||
let gui_state = rusty_emu::gui::state::GuiState::new();
|
||||
|
||||
// Verify register state structure
|
||||
assert_eq!(gui_state.register_state.accumulator, 0);
|
||||
assert!(!gui_state.register_state.carry_flag);
|
||||
assert_eq!(gui_state.register_state.program_counter, 0);
|
||||
assert_eq!(gui_state.register_state.index_registers.len(), 16);
|
||||
assert_eq!(gui_state.register_state.stack_pointer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_component_state_integration() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test component state monitoring for GUI
|
||||
if let Ok(system_guard) = system.lock() {
|
||||
let components = system_guard.get_components();
|
||||
|
||||
// Test that components are accessible (GUI would monitor these)
|
||||
assert!(!components.is_empty());
|
||||
|
||||
// Test GUI state structure for component monitoring
|
||||
let gui_state = rusty_emu::gui::state::GuiState::new();
|
||||
|
||||
// Verify component state structure
|
||||
assert!(!gui_state.component_states.cpu_running);
|
||||
assert!(!gui_state.component_states.ram_running);
|
||||
assert!(!gui_state.component_states.rom_running);
|
||||
assert!(!gui_state.component_states.clock_running);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_system_compatibility() {
|
||||
// Test that GUI works with different system configurations
|
||||
let system = create_test_system();
|
||||
|
||||
// Test GUI creation and system integration
|
||||
let mut app = GuiApp::new(&eframe::CreationContext {
|
||||
egui_ctx: Default::default(),
|
||||
integration_info: Default::default(),
|
||||
storage: None,
|
||||
build_info: Default::default(),
|
||||
});
|
||||
|
||||
app.set_system(system);
|
||||
|
||||
// Verify compatibility
|
||||
assert!(app.gui_state.system_loaded);
|
||||
assert!(app.get_system().is_some());
|
||||
|
||||
// Test that GUI state is properly initialized for the system
|
||||
assert_eq!(app.gui_state.memory_state.ram_contents.len(), 4);
|
||||
assert_eq!(app.gui_state.register_state.index_registers.len(), 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_performance_characteristics() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test GUI update performance characteristics
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
for _ in 0..100 {
|
||||
if let Ok(_system_guard) = system.lock() {
|
||||
// Simulate GUI state update
|
||||
simulate_gui_updates(&system);
|
||||
}
|
||||
}
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
|
||||
// GUI updates should be reasonably fast (less than 1ms per update on average)
|
||||
assert!(
|
||||
elapsed.as_millis() < 100,
|
||||
"GUI updates should be performant"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_error_recovery() {
|
||||
let mut state = rusty_emu::gui::state::GuiState::new();
|
||||
|
||||
// Test error state and recovery
|
||||
state.set_error("Simulated error".to_string());
|
||||
assert_eq!(state.get_error(), Some("Simulated error"));
|
||||
|
||||
// Test recovery by clearing error
|
||||
state.clear_error();
|
||||
assert!(state.get_error().is_none());
|
||||
|
||||
// Test that system can continue after error recovery
|
||||
state.system_running = true;
|
||||
assert!(state.system_running);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_state_consistency() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test that GUI state remains consistent during updates
|
||||
let mut app = GuiApp::new(&eframe::CreationContext {
|
||||
egui_ctx: Default::default(),
|
||||
integration_info: Default::default(),
|
||||
storage: None,
|
||||
build_info: Default::default(),
|
||||
});
|
||||
|
||||
app.set_system(Arc::clone(&system));
|
||||
|
||||
// Simulate multiple state updates
|
||||
for i in 0..10 {
|
||||
if let Some(sys) = app.get_system() {
|
||||
// In a real implementation, this would call update_from_system
|
||||
// For now, we verify the state structure remains consistent
|
||||
|
||||
assert_eq!(app.gui_state.memory_state.ram_contents.len(), 4);
|
||||
assert_eq!(app.gui_state.register_state.index_registers.len(), 16);
|
||||
|
||||
// Simulate state change
|
||||
app.gui_state.cycle_count = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify final state is consistent
|
||||
assert_eq!(app.gui_state.cycle_count, 9);
|
||||
assert!(app.gui_state.system_loaded);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod gui_error_handling_tests {
|
||||
use super::*;
|
||||
use gui_integration_test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_gui_invalid_system_handling() {
|
||||
// Test GUI behavior with invalid or corrupted system state
|
||||
let system = create_mock_system();
|
||||
|
||||
let mut app = GuiApp::new(&eframe::CreationContext {
|
||||
egui_ctx: Default::default(),
|
||||
integration_info: Default::default(),
|
||||
storage: None,
|
||||
build_info: Default::default(),
|
||||
});
|
||||
|
||||
// Test setting system that might be invalid
|
||||
app.set_system(system);
|
||||
|
||||
// GUI should handle this gracefully
|
||||
assert!(app.gui_state.system_loaded);
|
||||
|
||||
// Test error state handling
|
||||
app.gui_state.set_error("System access error".to_string());
|
||||
assert_eq!(app.gui_state.get_error(), Some("System access error"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_concurrent_error_handling() {
|
||||
let mut state = rusty_emu::gui::state::GuiState::new();
|
||||
|
||||
// Test error handling under concurrent access
|
||||
let handles: Vec<_> = (0..3)
|
||||
.map(|i| {
|
||||
let mut state_clone = state.clone();
|
||||
thread::spawn(move || {
|
||||
state_clone.set_error(format!("Error from thread {}", i));
|
||||
thread::sleep(Duration::from_micros(10));
|
||||
state_clone.get_error()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Main thread also sets errors
|
||||
state.set_error("Main thread error".to_string());
|
||||
|
||||
// Wait for threads
|
||||
let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
|
||||
|
||||
// All threads should complete without panic
|
||||
assert_eq!(results.len(), 3);
|
||||
for result in results {
|
||||
assert!(result.is_some());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_system_lock_timeout() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test behavior when system lock might timeout or fail
|
||||
// This simulates scenarios where the GUI can't immediately access the system
|
||||
|
||||
// Hold the lock for a short time to simulate contention
|
||||
let system_clone = Arc::clone(&system);
|
||||
let lock_handle = thread::spawn(move || {
|
||||
if let Ok(_system_guard) = system_clone.lock() {
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
});
|
||||
|
||||
// Try to access from main thread (should not deadlock)
|
||||
let access_result = system.try_lock().is_ok();
|
||||
|
||||
lock_handle.join().unwrap();
|
||||
|
||||
// Should be able to access after the lock is released
|
||||
assert!(access_result || system.try_lock().is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_state_corruption_recovery() {
|
||||
let mut state = rusty_emu::gui::state::GuiState::new();
|
||||
|
||||
// Simulate state corruption and recovery
|
||||
state.memory_state.ram_contents[0][0] = 255; // Invalid value
|
||||
state.register_state.accumulator = 255; // Invalid value
|
||||
|
||||
// Test recovery by resetting state
|
||||
state.memory_state.ram_contents = vec![[0; 4]; 4];
|
||||
state.register_state.accumulator = 0;
|
||||
|
||||
// Verify recovery
|
||||
assert_eq!(state.memory_state.ram_contents[0][0], 0);
|
||||
assert_eq!(state.register_state.accumulator, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod gui_real_time_tests {
|
||||
use super::*;
|
||||
use gui_integration_test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_gui_real_time_state_updates() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test real-time state update patterns
|
||||
let mut update_count = 0;
|
||||
let mut last_cycle_count = 0;
|
||||
|
||||
for i in 0..20 {
|
||||
if let Ok(_system_guard) = system.lock() {
|
||||
// Simulate GUI state polling
|
||||
update_count += 1;
|
||||
|
||||
// Simulate cycle count updates (would come from system in real implementation)
|
||||
if i > 0 {
|
||||
// In real implementation, this would be: gui_state.cycle_count = system.get_cycle_count()
|
||||
last_cycle_count = i; // Simulate increasing cycle count
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_micros(50)); // Simulate GUI update interval
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(update_count, 20);
|
||||
assert_eq!(last_cycle_count, 19);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_state_update_frequency() {
|
||||
let system = create_test_system();
|
||||
|
||||
// Test that GUI can handle high-frequency state updates
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
for _ in 0..50 {
|
||||
if let Ok(_system_guard) = system.lock() {
|
||||
// Simulate rapid GUI updates
|
||||
simulate_gui_updates(&system);
|
||||
}
|
||||
}
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
|
||||
// Should complete reasonably quickly (indicating good performance)
|
||||
assert!(
|
||||
elapsed.as_millis() < 500,
|
||||
"High-frequency updates should be performant"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_memory_update_synchronization() {
|
||||
// Test memory state synchronization between system and GUI
|
||||
let system = create_test_system();
|
||||
|
||||
// In a real implementation, this would test actual memory synchronization
|
||||
// For now, we test the data structures are compatible
|
||||
|
||||
if let Ok(_system_guard) = system.lock() {
|
||||
// Test memory data structure compatibility
|
||||
let gui_state = rusty_emu::gui::state::GuiState::new();
|
||||
|
||||
// Verify memory layout matches expected Intel 4002 structure
|
||||
assert_eq!(gui_state.memory_state.ram_contents.len(), 4); // 4 banks
|
||||
|
||||
for bank in &gui_state.memory_state.ram_contents {
|
||||
assert_eq!(bank.len(), 4); // 4 bytes per bank
|
||||
}
|
||||
|
||||
// Test bank selection bounds
|
||||
gui_state.memory_state.selected_bank = 0;
|
||||
gui_state.memory_state.selected_bank = 3; // Should be valid
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_register_update_synchronization() {
|
||||
// Test register state synchronization between system and GUI
|
||||
let system = create_test_system();
|
||||
|
||||
if let Ok(_system_guard) = system.lock() {
|
||||
let gui_state = rusty_emu::gui::state::GuiState::new();
|
||||
|
||||
// Verify register layout matches Intel 4004 structure
|
||||
assert_eq!(gui_state.register_state.index_registers.len(), 16); // 16 index registers
|
||||
|
||||
// Test register value bounds
|
||||
gui_state.register_state.accumulator = 0x0F; // 4-bit value (0-15)
|
||||
gui_state.register_state.carry_flag = true;
|
||||
|
||||
// Test program counter bounds (12-bit address)
|
||||
gui_state.register_state.program_counter = 0xFFF; // Maximum 12-bit value
|
||||
|
||||
// Test stack pointer bounds (4-bit value)
|
||||
gui_state.register_state.stack_pointer = 0x0F; // Maximum 4-bit value
|
||||
}
|
||||
}
|
||||
}
|
||||
447
tests/gui_tests.rs
Normal file
447
tests/gui_tests.rs
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
//! # GUI Component Tests
|
||||
//!
|
||||
//! Comprehensive tests for all GUI components including initialization,
|
||||
//! state management, user interactions, and display functionality.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use eframe::egui;
|
||||
use rusty_emu::gui::components::*;
|
||||
use rusty_emu::gui::state::*;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// Test utilities for GUI testing
|
||||
mod gui_test_utils {
|
||||
use super::*;
|
||||
use eframe::egui::{Context, Ui};
|
||||
|
||||
/// Create a test GUI context for component testing
|
||||
pub fn create_test_context() -> Context {
|
||||
let ctx = Context::default();
|
||||
// Configure for testing
|
||||
ctx.set_pixels_per_point(1.0);
|
||||
ctx
|
||||
}
|
||||
|
||||
/// Create a test UI instance for component rendering
|
||||
pub fn create_test_ui(ctx: &Context) -> Ui {
|
||||
let mut ui = Ui::new(
|
||||
ctx.clone(),
|
||||
egui::LayerId::new(egui::Order::Middle, egui::Id::new("test")),
|
||||
egui::Id::new("test_ui"),
|
||||
egui::Rect::from_min_size(egui::Pos2::ZERO, egui::Vec2::new(800.0, 600.0)),
|
||||
egui::Rect::from_min_size(egui::Pos2::ZERO, egui::Vec2::new(800.0, 600.0)),
|
||||
);
|
||||
ui
|
||||
}
|
||||
|
||||
/// Create a test GUI state with known values for testing
|
||||
pub fn create_test_gui_state() -> GuiState {
|
||||
let mut state = GuiState::new();
|
||||
state.system_loaded = true;
|
||||
state.system_running = true;
|
||||
state.cycle_count = 12345;
|
||||
|
||||
// Set up test memory data
|
||||
state.memory_state.ram_contents = vec![
|
||||
[0x12, 0x34, 0x56, 0x78],
|
||||
[0x9A, 0xBC, 0xDE, 0xF0],
|
||||
[0x11, 0x22, 0x33, 0x44],
|
||||
[0x55, 0x66, 0x77, 0x88],
|
||||
];
|
||||
|
||||
// Set up test register data
|
||||
state.register_state.accumulator = 0x0F;
|
||||
state.register_state.carry_flag = true;
|
||||
state.register_state.program_counter = 0x123;
|
||||
state.register_state.index_registers[0] = 0x2A;
|
||||
state.register_state.stack_pointer = 0x08;
|
||||
|
||||
// Set up component states
|
||||
state.component_states.cpu_running = true;
|
||||
state.component_states.ram_running = true;
|
||||
state.component_states.rom_running = false;
|
||||
state.component_states.clock_running = true;
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
/// Create a test system info
|
||||
pub fn create_test_system_info() -> rusty_emu::system_config::SystemInfo {
|
||||
rusty_emu::system_config::SystemInfo {
|
||||
name: "Test System".to_string(),
|
||||
description: "Test system for GUI testing".to_string(),
|
||||
component_count: 4,
|
||||
cpu_speed: 750_000.0,
|
||||
rom_size: 4096,
|
||||
ram_size: 1024,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod gui_components_tests {
|
||||
use super::*;
|
||||
use gui_test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_gui_components_creation() {
|
||||
let components = GuiComponents::new();
|
||||
|
||||
// Test that all components are properly initialized
|
||||
// Since the struct is mostly private, we test through the public interface
|
||||
assert!(true); // Placeholder - in real implementation, test component state
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_control_panel_creation() {
|
||||
let control_panel = ControlPanel::new();
|
||||
|
||||
// Test initial state
|
||||
assert_eq!(control_panel.start_button_text, "Start System");
|
||||
assert!(!control_panel.stop_button_enabled);
|
||||
assert!(!control_panel.reset_button_enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_control_panel_start_system() {
|
||||
let mut control_panel = ControlPanel::new();
|
||||
let mut state = GuiState::new();
|
||||
|
||||
control_panel.start_system(&mut state);
|
||||
|
||||
assert!(state.system_running);
|
||||
assert_eq!(control_panel.start_button_text, "System Running...");
|
||||
assert!(control_panel.stop_button_enabled);
|
||||
assert!(control_panel.reset_button_enabled);
|
||||
assert!(state.last_error.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_control_panel_stop_system() {
|
||||
let mut control_panel = ControlPanel::new();
|
||||
let mut state = GuiState::new();
|
||||
|
||||
// First start the system
|
||||
control_panel.start_system(&mut state);
|
||||
|
||||
// Then stop it
|
||||
control_panel.stop_system(&mut state);
|
||||
|
||||
assert!(!state.system_running);
|
||||
assert_eq!(control_panel.start_button_text, "Start System");
|
||||
assert!(!control_panel.stop_button_enabled);
|
||||
assert!(state.last_error.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_control_panel_reset_system() {
|
||||
let mut control_panel = ControlPanel::new();
|
||||
let mut state = GuiState::new();
|
||||
|
||||
// First start the system
|
||||
control_panel.start_system(&mut state);
|
||||
state.cycle_count = 1000;
|
||||
|
||||
// Then reset it
|
||||
control_panel.reset_system(&mut state);
|
||||
|
||||
assert!(!state.system_running);
|
||||
assert_eq!(state.cycle_count, 0);
|
||||
assert_eq!(control_panel.start_button_text, "Start System");
|
||||
assert!(!control_panel.stop_button_enabled);
|
||||
assert!(!control_panel.reset_button_enabled);
|
||||
assert!(state.last_error.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_memory_viewer_creation() {
|
||||
let memory_viewer = MemoryViewer::new();
|
||||
|
||||
assert!(memory_viewer.show_hex);
|
||||
assert_eq!(memory_viewer.bytes_per_row, 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_memory_viewer_display_modes() {
|
||||
let memory_viewer = MemoryViewer::new();
|
||||
let state = create_test_gui_state();
|
||||
let ctx = create_test_context();
|
||||
|
||||
// Test hex display mode
|
||||
// Note: In a real implementation, we would test the actual rendering
|
||||
// For now, we verify the component can be created and holds state
|
||||
assert!(memory_viewer.show_hex);
|
||||
|
||||
// Test that memory data is accessible
|
||||
assert_eq!(state.memory_state.ram_contents.len(), 4);
|
||||
for bank in &state.memory_state.ram_contents {
|
||||
assert_eq!(bank.len(), 4);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_register_viewer_creation() {
|
||||
let register_viewer = RegisterViewer::new();
|
||||
|
||||
assert_eq!(register_viewer.selected_register, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_register_viewer_selection() {
|
||||
let mut register_viewer = RegisterViewer::new();
|
||||
let state = create_test_gui_state();
|
||||
|
||||
// Test register selection bounds
|
||||
register_viewer.selected_register = 15;
|
||||
assert_eq!(register_viewer.selected_register, 15);
|
||||
|
||||
// Test register data access
|
||||
assert_eq!(state.register_state.accumulator, 0x0F);
|
||||
assert!(state.register_state.carry_flag);
|
||||
assert_eq!(state.register_state.program_counter, 0x123);
|
||||
assert_eq!(state.register_state.index_registers[0], 0x2A);
|
||||
assert_eq!(state.register_state.stack_pointer, 0x08);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rom_loader_creation() {
|
||||
let rom_loader = RomLoader::new();
|
||||
|
||||
assert!(!rom_loader.show_file_dialog);
|
||||
assert!(rom_loader.selected_file.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rom_loader_file_dialog() {
|
||||
let mut rom_loader = RomLoader::new();
|
||||
|
||||
// Test opening file dialog
|
||||
rom_loader.show_file_dialog = true;
|
||||
assert!(rom_loader.show_file_dialog);
|
||||
|
||||
// Test canceling file dialog
|
||||
rom_loader.show_file_dialog = false;
|
||||
assert!(!rom_loader.show_file_dialog);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_bar_creation() {
|
||||
let status_bar = StatusBar::new();
|
||||
|
||||
// StatusBar is a zero-sized type, just verify it can be created
|
||||
assert!(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_bar_state_display() {
|
||||
let status_bar = StatusBar::new();
|
||||
let state = create_test_gui_state();
|
||||
|
||||
// Test that status information is accessible
|
||||
assert!(state.system_running);
|
||||
assert_eq!(state.cycle_count, 12345);
|
||||
assert!(state.component_states.cpu_running);
|
||||
assert!(state.component_states.ram_running);
|
||||
assert!(!state.component_states.rom_running);
|
||||
assert!(state.component_states.clock_running);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod gui_state_tests {
|
||||
use super::*;
|
||||
use gui_test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_gui_state_creation() {
|
||||
let state = GuiState::new();
|
||||
|
||||
assert!(!state.system_loaded);
|
||||
assert!(!state.system_running);
|
||||
assert_eq!(state.cycle_count, 0);
|
||||
assert!(state.system_info.is_none());
|
||||
assert!(state.last_error.is_none());
|
||||
|
||||
// Test component states
|
||||
assert!(!state.component_states.cpu_running);
|
||||
assert!(!state.component_states.ram_running);
|
||||
assert!(!state.component_states.rom_running);
|
||||
assert!(!state.component_states.clock_running);
|
||||
|
||||
// Test memory state
|
||||
assert_eq!(state.memory_state.ram_contents.len(), 4);
|
||||
assert_eq!(state.memory_state.selected_bank, 0);
|
||||
assert_eq!(state.memory_state.selected_address, 0);
|
||||
|
||||
// Test register state
|
||||
assert_eq!(state.register_state.accumulator, 0);
|
||||
assert!(!state.register_state.carry_flag);
|
||||
assert_eq!(state.register_state.program_counter, 0);
|
||||
assert_eq!(state.register_state.index_registers.iter().sum::<u8>(), 0);
|
||||
assert_eq!(state.register_state.stack_pointer, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_state_error_handling() {
|
||||
let mut state = GuiState::new();
|
||||
|
||||
// Test setting error
|
||||
let error_msg = "Test error message".to_string();
|
||||
state.set_error(error_msg.clone());
|
||||
|
||||
assert_eq!(state.get_error(), Some(error_msg.as_str()));
|
||||
|
||||
// Test clearing error
|
||||
state.clear_error();
|
||||
|
||||
assert!(state.get_error().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_state_system_integration() {
|
||||
let mut state = GuiState::new();
|
||||
let test_info = create_test_system_info();
|
||||
|
||||
// Test system info conversion
|
||||
let gui_info: super::SystemInfo = test_info.into();
|
||||
|
||||
assert_eq!(gui_info.name, "Test System");
|
||||
assert_eq!(gui_info.component_count, 4);
|
||||
assert_eq!(gui_info.cpu_speed, 750_000.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_memory_state_initialization() {
|
||||
let state = GuiState::new();
|
||||
|
||||
// Verify memory banks are properly initialized
|
||||
assert_eq!(state.memory_state.ram_contents.len(), 4);
|
||||
|
||||
for (bank_idx, bank) in state.memory_state.ram_contents.iter().enumerate() {
|
||||
assert_eq!(bank.len(), 4, "Bank {} should have 4 bytes", bank_idx);
|
||||
|
||||
// All bytes should be initialized to 0
|
||||
for (addr, &value) in bank.iter().enumerate() {
|
||||
assert_eq!(value, 0, "Bank {}, address {} should be 0", bank_idx, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_register_state_initialization() {
|
||||
let state = GuiState::new();
|
||||
|
||||
// Verify all registers are properly initialized
|
||||
assert_eq!(state.register_state.accumulator, 0);
|
||||
assert!(!state.register_state.carry_flag);
|
||||
assert_eq!(state.register_state.program_counter, 0);
|
||||
assert_eq!(state.register_state.stack_pointer, 0);
|
||||
|
||||
// All index registers should be 0
|
||||
assert_eq!(state.register_state.index_registers.iter().sum::<u8>(), 0);
|
||||
|
||||
for (i, ®) in state.register_state.index_registers.iter().enumerate() {
|
||||
assert_eq!(reg, 0, "Index register R{} should be 0", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod gui_integration_tests {
|
||||
use super::*;
|
||||
use gui_test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_gui_app_creation() {
|
||||
use rusty_emu::gui::GuiApp;
|
||||
|
||||
let app = GuiApp::new(&eframe::CreationContext {
|
||||
egui_ctx: Default::default(),
|
||||
integration_info: Default::default(),
|
||||
storage: None,
|
||||
build_info: Default::default(),
|
||||
});
|
||||
|
||||
// Test initial state
|
||||
assert!(app.system.is_none());
|
||||
assert!(!app.gui_state.system_loaded);
|
||||
assert!(!app.gui_state.system_running);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_app_system_integration() {
|
||||
use rusty_emu::gui::GuiApp;
|
||||
use rusty_emu::system_config::{ConfigurableSystem, SystemFactory};
|
||||
|
||||
// Create a test system
|
||||
let factory = SystemFactory::new();
|
||||
let system = Arc::new(Mutex::new(
|
||||
factory.create_from_json("configs/mcs4_basic.json").unwrap(),
|
||||
));
|
||||
|
||||
let mut app = GuiApp::new(&eframe::CreationContext {
|
||||
egui_ctx: Default::default(),
|
||||
integration_info: Default::default(),
|
||||
storage: None,
|
||||
build_info: Default::default(),
|
||||
});
|
||||
|
||||
// Set the system
|
||||
app.set_system(system);
|
||||
|
||||
// Verify system is set
|
||||
assert!(app.system.is_some());
|
||||
assert!(app.gui_state.system_loaded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_app_system_access() {
|
||||
use rusty_emu::gui::GuiApp;
|
||||
use rusty_emu::system_config::{ConfigurableSystem, SystemFactory};
|
||||
|
||||
let factory = SystemFactory::new();
|
||||
let system = Arc::new(Mutex::new(
|
||||
factory.create_from_json("configs/mcs4_basic.json").unwrap(),
|
||||
));
|
||||
|
||||
let mut app = GuiApp::new(&eframe::CreationContext {
|
||||
egui_ctx: Default::default(),
|
||||
integration_info: Default::default(),
|
||||
storage: None,
|
||||
build_info: Default::default(),
|
||||
});
|
||||
|
||||
app.set_system(system);
|
||||
|
||||
// Test system access
|
||||
let retrieved_system = app.get_system();
|
||||
assert!(retrieved_system.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gui_components_integration() {
|
||||
let mut components = GuiComponents::new();
|
||||
let mut state = create_test_gui_state();
|
||||
let ctx = create_test_context();
|
||||
|
||||
// Test that all components can be rendered together
|
||||
// In a real implementation, this would test the actual rendering
|
||||
// For now, we verify the components exist and have valid state
|
||||
|
||||
// Test control panel rendering (would panic if component is invalid)
|
||||
components.render_control_panel(&mut create_test_ui(&ctx), &mut state);
|
||||
|
||||
// Test memory viewer rendering
|
||||
components.render_memory_viewer(&mut create_test_ui(&ctx), &state);
|
||||
|
||||
// Test register viewer rendering
|
||||
components.render_register_viewer(&mut create_test_ui(&ctx), &state);
|
||||
|
||||
// Test status bar rendering
|
||||
components.render_status_bar(&mut create_test_ui(&ctx), &state);
|
||||
|
||||
// If we get here without panicking, the integration is working
|
||||
assert!(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@
|
|||
pub use rusty_emu;
|
||||
|
||||
// Module declarations for test files
|
||||
mod gui_integration_tests;
|
||||
mod gui_tests;
|
||||
mod integration_tests;
|
||||
mod intel_400x_tests;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue