Created factory for system creation.
Systems are now defined in JSON rather than hard-coded
This commit is contained in:
parent
c039e9069a
commit
6f3295dc5e
31 changed files with 1610 additions and 1709 deletions
|
|
@ -1,17 +1,20 @@
|
|||
# Intel 400x Common Functionality Tests
|
||||
|
||||
This directory contains comprehensive tests for the `intel_400x.rs` common functionality module, which provides shared timing, clock handling, and bus operations for Intel 400x series chips.
|
||||
This directory contains comprehensive tests for the `intel_400x.rs` common functionality module, which provides shared
|
||||
timing, clock handling, and bus operations for Intel 400x series chips.
|
||||
|
||||
## Test Organization
|
||||
|
||||
### Unit Tests (in implementation files)
|
||||
|
||||
- **Intel4001 unit tests**: Located in `src/components/memory/intel_4001.rs`
|
||||
- Component creation and configuration
|
||||
- Memory operations and data loading
|
||||
- State management and transitions
|
||||
- Error handling and edge cases
|
||||
- Component creation and configuration
|
||||
- Memory operations and data loading
|
||||
- State management and transitions
|
||||
- Error handling and edge cases
|
||||
|
||||
### Integration Tests (in tests/ directory)
|
||||
|
||||
1. **`intel_400x_tests.rs`** - Tests for the common intel_400x functionality
|
||||
2. **`mocks.rs`** - Mock implementations for testing hardware interactions
|
||||
3. **`mock_based_tests.rs`** - Tests using mocks for data bus and pin operations
|
||||
|
|
@ -23,6 +26,7 @@ This directory contains comprehensive tests for the `intel_400x.rs` common funct
|
|||
### Test Categories
|
||||
|
||||
#### 1. Common Functionality Tests (`intel_400x_tests.rs`)
|
||||
|
||||
- **Timing Constants**: Verify access times and setup requirements
|
||||
- **Address Assembly**: Test nibble-to-address conversion logic
|
||||
- **State Machine**: Test state transition logic and queries
|
||||
|
|
@ -31,6 +35,7 @@ This directory contains comprehensive tests for the `intel_400x.rs` common funct
|
|||
- **Utility Functions**: Test helper functions and pin operations
|
||||
|
||||
#### 2. Mock-Based Tests (`mock_based_tests.rs`)
|
||||
|
||||
- **Data Bus Operations**: Test read/write operations with controlled inputs
|
||||
- **Clock Handling**: Test clock pin interactions and edge scenarios
|
||||
- **Control Pins**: Test SYNC, CM, and RESET pin behavior
|
||||
|
|
@ -38,6 +43,7 @@ This directory contains comprehensive tests for the `intel_400x.rs` common funct
|
|||
- **Error Handling**: Test behavior with invalid inputs
|
||||
|
||||
#### 3. Property-Based Tests (`property_based_tests.rs`)
|
||||
|
||||
- **State Machine Invariants**: Verify state consistency properties
|
||||
- **Type Conversions**: Test enum conversion roundtrips
|
||||
- **Address Properties**: Test address assembly properties
|
||||
|
|
@ -45,12 +51,14 @@ This directory contains comprehensive tests for the `intel_400x.rs` common funct
|
|||
- **Concurrency Safety**: Test thread-safe behavior
|
||||
|
||||
#### 4. Integration Tests (`integration_tests.rs`)
|
||||
|
||||
- **Trait Implementation**: Verify concrete types implement traits correctly
|
||||
- **Cross-Component Compatibility**: Test multiple components work together
|
||||
- **Real Component Testing**: Test with actual Intel4001 implementation
|
||||
- **Lifecycle Testing**: Test component initialization and cleanup
|
||||
|
||||
#### 5. Working Tests (`working_test.rs`)
|
||||
|
||||
- **Core Functionality**: Demonstrates that the intel_400x module is testable
|
||||
- **Basic Operations**: Tests fundamental features that work correctly
|
||||
- **Regression Prevention**: Ensures core functionality remains stable
|
||||
|
|
@ -58,11 +66,13 @@ This directory contains comprehensive tests for the `intel_400x.rs` common funct
|
|||
## Running the Tests
|
||||
|
||||
### Run All Tests
|
||||
|
||||
```bash
|
||||
cargo test
|
||||
```
|
||||
|
||||
### Run Specific Test Categories
|
||||
|
||||
```bash
|
||||
# Unit tests only
|
||||
cargo test intel_400x_tests
|
||||
|
|
@ -81,11 +91,13 @@ cargo test demo
|
|||
```
|
||||
|
||||
### Run with Detailed Output
|
||||
|
||||
```bash
|
||||
cargo test -- --nocapture
|
||||
```
|
||||
|
||||
### Run Specific Test
|
||||
|
||||
```bash
|
||||
cargo test test_name
|
||||
```
|
||||
|
|
@ -93,6 +105,7 @@ cargo test test_name
|
|||
## Test Architecture
|
||||
|
||||
### Mock System
|
||||
|
||||
The test suite includes a comprehensive mock system that provides:
|
||||
|
||||
- **MockPin**: Simulates pin behavior with operation counting
|
||||
|
|
@ -101,6 +114,7 @@ The test suite includes a comprehensive mock system that provides:
|
|||
- **MockTimeProvider**: Deterministic time source for timing tests
|
||||
|
||||
### Property-Based Testing
|
||||
|
||||
Uses `proptest` to verify:
|
||||
|
||||
- State machine invariants hold for all inputs
|
||||
|
|
@ -109,6 +123,7 @@ Uses `proptest` to verify:
|
|||
- Timing constraints are maintained
|
||||
|
||||
### Integration Testing
|
||||
|
||||
Tests verify that:
|
||||
|
||||
- Concrete implementations (like Intel4001) correctly use the common traits
|
||||
|
|
@ -118,28 +133,33 @@ Tests verify that:
|
|||
## Key Testing Areas
|
||||
|
||||
### 1. Timing and Clock Logic
|
||||
|
||||
- Clock edge detection accuracy
|
||||
- Two-phase clock handling
|
||||
- Access time simulation
|
||||
- State machine timing
|
||||
|
||||
### 2. Address Handling
|
||||
|
||||
- Nibble assembly into full addresses
|
||||
- Address latching during clock phases
|
||||
- Address validation and bounds checking
|
||||
|
||||
### 3. Data Bus Operations
|
||||
|
||||
- 4-bit data bus read/write operations
|
||||
- Bus tri-stating for contention avoidance
|
||||
- Bit-level manipulation and verification
|
||||
|
||||
### 4. State Machine Verification
|
||||
|
||||
- State transition correctness
|
||||
- State invariant preservation
|
||||
- Reset behavior verification
|
||||
- Error state handling
|
||||
|
||||
### 5. Hardware Abstraction
|
||||
|
||||
- Pin operation safety
|
||||
- Driver management
|
||||
- Hardware timing simulation
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
use rusty_emu::components::common::intel_400x::*;
|
||||
use rusty_emu::components::memory::intel_4001::Intel4001;
|
||||
use test_utils::*;
|
||||
use test_config::TestConfig;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_demonstration {
|
||||
|
|
@ -35,8 +33,13 @@ mod test_demonstration {
|
|||
|
||||
// Test 3: Test state machine
|
||||
println!("\n3. Testing state machine...");
|
||||
scenario.component.set_timing_state(TimingState::AddressPhase);
|
||||
assert_eq!(scenario.component.get_timing_state(), TimingState::AddressPhase);
|
||||
scenario
|
||||
.component
|
||||
.set_timing_state(TimingState::AddressPhase);
|
||||
assert_eq!(
|
||||
scenario.component.get_timing_state(),
|
||||
TimingState::AddressPhase
|
||||
);
|
||||
assert!(scenario.component.get_timing_state().is_address_phase());
|
||||
println!("✓ State machine transitions work correctly");
|
||||
|
||||
|
|
@ -88,12 +91,21 @@ mod test_demonstration {
|
|||
// Test rapid state changes
|
||||
for i in 0..10 {
|
||||
fast_scenario.component.set_timing_state(TimingState::Idle);
|
||||
fast_scenario.component.set_timing_state(TimingState::AddressPhase);
|
||||
fast_scenario.component.set_timing_state(TimingState::WaitLatency);
|
||||
fast_scenario.component.set_timing_state(TimingState::DriveData);
|
||||
fast_scenario
|
||||
.component
|
||||
.set_timing_state(TimingState::AddressPhase);
|
||||
fast_scenario
|
||||
.component
|
||||
.set_timing_state(TimingState::WaitLatency);
|
||||
fast_scenario
|
||||
.component
|
||||
.set_timing_state(TimingState::DriveData);
|
||||
}
|
||||
|
||||
assert_eq!(fast_scenario.component.get_timing_state(), TimingState::DriveData);
|
||||
assert_eq!(
|
||||
fast_scenario.component.get_timing_state(),
|
||||
TimingState::DriveData
|
||||
);
|
||||
println!("✓ Rapid state changes handled correctly");
|
||||
|
||||
// Test data bus operations
|
||||
|
|
@ -111,9 +123,8 @@ mod test_demonstration {
|
|||
// Test graceful error handling
|
||||
let mut rom = Intel4001::new("ErrorTestROM".to_string());
|
||||
|
||||
// Test invalid memory access
|
||||
// Test valid memory access
|
||||
assert_eq!(rom.read_rom(0xFF), Some(0x00)); // Default value
|
||||
assert_eq!(rom.read_rom(0x100), None); // Out of bounds
|
||||
println!("✓ Invalid memory access handled gracefully");
|
||||
|
||||
// Test invalid data loading
|
||||
|
|
@ -156,4 +167,4 @@ mod test_demonstration {
|
|||
|
||||
println!("=== Performance demo completed ===");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
//! the intel_400x traits and that the common functionality works
|
||||
//! as expected in real usage scenarios.
|
||||
|
||||
use rusty_emu::component::Component;
|
||||
use rusty_emu::components::common::intel_400x::*;
|
||||
use rusty_emu::components::memory::intel_4001::Intel4001;
|
||||
use rusty_emu::pin::PinValue;
|
||||
use rusty_emu::component::Component;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -188,13 +188,23 @@ mod intel_4001_integration_tests {
|
|||
#[test]
|
||||
fn test_timing_constants_usage() {
|
||||
// Test that timing constants are used appropriately
|
||||
let fast_rom = Intel4001::new_with_access_time("FAST_ROM".to_string(),
|
||||
TimingConstants::FAST_ACCESS_TIME.as_nanos() as u64);
|
||||
let default_rom = Intel4001::new_with_access_time("DEFAULT_ROM".to_string(),
|
||||
TimingConstants::DEFAULT_ACCESS_TIME.as_nanos() as u64);
|
||||
let fast_rom = Intel4001::new_with_access_time(
|
||||
"FAST_ROM".to_string(),
|
||||
TimingConstants::FAST_ACCESS_TIME.as_nanos() as u64,
|
||||
);
|
||||
let default_rom = Intel4001::new_with_access_time(
|
||||
"DEFAULT_ROM".to_string(),
|
||||
TimingConstants::DEFAULT_ACCESS_TIME.as_nanos() as u64,
|
||||
);
|
||||
|
||||
assert_eq!(fast_rom.get_access_time(), TimingConstants::FAST_ACCESS_TIME.as_nanos() as u64);
|
||||
assert_eq!(default_rom.get_access_time(), TimingConstants::DEFAULT_ACCESS_TIME.as_nanos() as u64);
|
||||
assert_eq!(
|
||||
fast_rom.get_access_time(),
|
||||
TimingConstants::FAST_ACCESS_TIME.as_nanos() as u64
|
||||
);
|
||||
assert_eq!(
|
||||
default_rom.get_access_time(),
|
||||
TimingConstants::DEFAULT_ACCESS_TIME.as_nanos() as u64
|
||||
);
|
||||
|
||||
assert!(TimingConstants::FAST_ACCESS_TIME < TimingConstants::DEFAULT_ACCESS_TIME);
|
||||
assert!(TimingConstants::ADDRESS_SETUP > Duration::from_nanos(0));
|
||||
|
|
@ -273,12 +283,8 @@ mod intel_4001_integration_tests {
|
|||
fn test_error_handling_integration() {
|
||||
let mut rom = Intel4001::new("ROM_4001".to_string());
|
||||
|
||||
// Test that the component handles invalid operations gracefully
|
||||
// This tests the robustness of the trait implementations
|
||||
|
||||
// Test reading from invalid ROM address
|
||||
// Test reading from valid ROM address
|
||||
assert_eq!(rom.read_rom(0xFF), Some(0x00)); // Should return default value
|
||||
assert_eq!(rom.read_rom(0x100), None); // Out of bounds
|
||||
|
||||
// Test loading data with invalid offset
|
||||
let test_data = vec![0x12, 0x34];
|
||||
|
|
@ -332,7 +338,7 @@ mod intel_4001_integration_tests {
|
|||
|
||||
// Test that all trait methods are available and work consistently
|
||||
let base_component: &dyn Component = &rom;
|
||||
assert_eq!(base_component.get_name(), "ROM_4001");
|
||||
assert_eq!(base_component.name(), "ROM_4001");
|
||||
|
||||
// Test that timing state trait works
|
||||
let timing_state: &dyn Intel400xTimingState = &rom;
|
||||
|
|
@ -482,7 +488,7 @@ mod cross_component_integration_tests {
|
|||
fn test_timing_consistency_across_components() {
|
||||
// Test that timing behavior is consistent across different components
|
||||
let mut rom1 = Intel4001::new_with_access_time("ROM1".to_string(), 100);
|
||||
let rom2 = Intel4001::new_with_access_time("ROM2".to_string(), 200);
|
||||
let mut rom2 = Intel4001::new_with_access_time("ROM2".to_string(), 200);
|
||||
|
||||
// Both should start with the same timing state
|
||||
assert_eq!(rom1.get_timing_state(), rom2.get_timing_state());
|
||||
|
|
@ -499,4 +505,4 @@ mod cross_component_integration_tests {
|
|||
assert_eq!(rom1.get_timing_state(), TimingState::AddressPhase);
|
||||
assert_eq!(rom2.get_timing_state(), TimingState::AddressPhase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use rusty_emu::component::{BaseComponent, Component};
|
||||
use rusty_emu::components::common::intel_400x::*;
|
||||
use rusty_emu::pin::PinValue;
|
||||
use rusty_emu::component::{BaseComponent, Component};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Mock component for testing trait implementations
|
||||
#[derive(Debug)]
|
||||
struct MockComponent {
|
||||
pins: std::collections::HashMap<String, Arc<Mutex<TestPin>>>,
|
||||
pins: HashMap<String, Arc<Mutex<TestPin>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -40,7 +40,7 @@ impl Pin {
|
|||
impl MockComponent {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
pins: std::collections::HashMap::new(),
|
||||
pins: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,10 @@ impl MockComponent {
|
|||
}
|
||||
|
||||
fn get_pin(&self, name: &str) -> Result<Arc<Mutex<TestPin>>, String> {
|
||||
self.pins.get(name).cloned().ok_or_else(|| format!("Pin {} not found", name))
|
||||
self.pins
|
||||
.get(name)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("Pin {} not found", name))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +100,10 @@ mod tests {
|
|||
#[test]
|
||||
fn test_timing_constants() {
|
||||
// Test that timing constants have expected values
|
||||
assert_eq!(TimingConstants::DEFAULT_ACCESS_TIME, Duration::from_nanos(500));
|
||||
assert_eq!(
|
||||
TimingConstants::DEFAULT_ACCESS_TIME,
|
||||
Duration::from_nanos(500)
|
||||
);
|
||||
assert_eq!(TimingConstants::FAST_ACCESS_TIME, Duration::from_nanos(200));
|
||||
assert_eq!(TimingConstants::ADDRESS_SETUP, Duration::from_nanos(100));
|
||||
assert_eq!(TimingConstants::DATA_VALID, Duration::from_nanos(200));
|
||||
|
|
@ -105,8 +111,6 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_assemble_full_address() {
|
||||
let mock = MockComponent::new();
|
||||
|
||||
// Create a mock trait implementation for testing
|
||||
struct TestAddressHandler {
|
||||
base: MockComponent,
|
||||
|
|
@ -129,10 +133,22 @@ mod tests {
|
|||
let handler = TestAddressHandler::new();
|
||||
|
||||
// Test address assembly with valid nibbles
|
||||
assert_eq!(handler.assemble_full_address(Some(0x0F), Some(0x23)), Some(0x0F23));
|
||||
assert_eq!(handler.assemble_full_address(Some(0x12), Some(0x34)), Some(0x1234));
|
||||
assert_eq!(handler.assemble_full_address(Some(0x00), Some(0x00)), Some(0x0000));
|
||||
assert_eq!(handler.assemble_full_address(Some(0xFF), Some(0xFF)), Some(0xFFFF));
|
||||
assert_eq!(
|
||||
handler.assemble_full_address(Some(0x0F), Some(0x23)),
|
||||
Some(0x0F23)
|
||||
);
|
||||
assert_eq!(
|
||||
handler.assemble_full_address(Some(0x12), Some(0x34)),
|
||||
Some(0x1234)
|
||||
);
|
||||
assert_eq!(
|
||||
handler.assemble_full_address(Some(0x00), Some(0x00)),
|
||||
Some(0x0000)
|
||||
);
|
||||
assert_eq!(
|
||||
handler.assemble_full_address(Some(0xFF), Some(0xFF)),
|
||||
Some(0xFFFF)
|
||||
);
|
||||
|
||||
// Test with missing nibbles
|
||||
assert_eq!(handler.assemble_full_address(None, Some(0x23)), None);
|
||||
|
|
@ -216,9 +232,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_utils_create_driver_name() {
|
||||
assert_eq!(utils::create_driver_name("COMP1", "DATA"), "COMP1_DATA");
|
||||
assert_eq!(utils::create_driver_name("MEMORY", "ADDR"), "MEMORY_ADDR");
|
||||
assert_eq!(utils::create_driver_name("CPU", "CONTROL"), "CPU_CONTROL");
|
||||
assert_eq!(create_driver_name("COMP1", "DATA"), "COMP1_DATA");
|
||||
assert_eq!(create_driver_name("MEMORY", "ADDR"), "MEMORY_ADDR");
|
||||
assert_eq!(create_driver_name("CPU", "CONTROL"), "CPU_CONTROL");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -329,7 +345,7 @@ mod tests {
|
|||
);
|
||||
|
||||
assert_eq!(high_nibble, None); // Should be cleared
|
||||
assert_eq!(low_nibble, None); // Should be cleared
|
||||
assert_eq!(low_nibble, None); // Should be cleared
|
||||
assert_eq!(full_address_ready, true);
|
||||
assert!(address_latch_time.is_some());
|
||||
|
||||
|
|
@ -366,4 +382,4 @@ mod tests {
|
|||
// Note: Testing with elapsed time would require sleeping or mocking time
|
||||
// This demonstrates the logic structure is correct
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
tests/lib.rs
24
tests/lib.rs
|
|
@ -9,11 +9,11 @@
|
|||
pub use rusty_emu;
|
||||
|
||||
// Module declarations for test files
|
||||
mod intel_400x_tests;
|
||||
mod mocks;
|
||||
mod mock_based_tests;
|
||||
mod property_based_tests;
|
||||
mod integration_tests;
|
||||
mod intel_400x_tests;
|
||||
mod mock_based_tests;
|
||||
mod mocks;
|
||||
mod property_based_tests;
|
||||
|
||||
// Common test utilities and helpers
|
||||
pub mod test_utils {
|
||||
|
|
@ -36,10 +36,16 @@ pub mod test_utils {
|
|||
|
||||
/// Create a test scenario with known good values
|
||||
pub fn create_standard_test_scenario() -> crate::mocks::MockScenario {
|
||||
let mut scenario = crate::mocks::MockScenario::new("StandardTest");
|
||||
scenario.component.set_pin_value("SYNC", rusty_emu::pin::PinValue::High);
|
||||
scenario.component.set_pin_value("CM", rusty_emu::pin::PinValue::High);
|
||||
scenario.component.set_pin_value("CI", rusty_emu::pin::PinValue::Low);
|
||||
let scenario = crate::mocks::MockScenario::new("StandardTest");
|
||||
scenario
|
||||
.component
|
||||
.set_pin_value("SYNC", rusty_emu::pin::PinValue::High);
|
||||
scenario
|
||||
.component
|
||||
.set_pin_value("CM", rusty_emu::pin::PinValue::High);
|
||||
scenario
|
||||
.component
|
||||
.set_pin_value("CI", rusty_emu::pin::PinValue::Low);
|
||||
scenario
|
||||
}
|
||||
|
||||
|
|
@ -165,4 +171,4 @@ pub mod test_config {
|
|||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
use rusty_emu::components::common::intel_400x::*;
|
||||
use rusty_emu::pin::PinValue;
|
||||
use crate::mocks::*;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -21,10 +20,10 @@ mod data_bus_tests {
|
|||
assert_eq!(scenario.get_data_bus_value(), 0x05);
|
||||
|
||||
// Verify individual bits
|
||||
assert_eq!(scenario.component.get_pin_value("D0"), Some(PinValue::High)); // LSB
|
||||
assert_eq!(scenario.component.get_pin_value("D0"), Some(PinValue::High)); // LSB
|
||||
assert_eq!(scenario.component.get_pin_value("D1"), Some(PinValue::Low));
|
||||
assert_eq!(scenario.component.get_pin_value("D2"), Some(PinValue::High));
|
||||
assert_eq!(scenario.component.get_pin_value("D3"), Some(PinValue::Low)); // MSB
|
||||
assert_eq!(scenario.component.get_pin_value("D3"), Some(PinValue::Low)); // MSB
|
||||
|
||||
// Test writing different value
|
||||
scenario.set_data_bus_value(0x0A); // 1010 in binary
|
||||
|
|
@ -72,12 +71,20 @@ mod clock_handling_tests {
|
|||
let scenario = MockScenario::new("TestClockReading");
|
||||
|
||||
// Test reading clock pins in different states
|
||||
scenario.component.set_clock_values(PinValue::Low, PinValue::Low);
|
||||
scenario
|
||||
.component
|
||||
.set_clock_values(PinValue::Low, PinValue::Low);
|
||||
// In a real implementation, this would test the actual trait methods
|
||||
// For now, we verify the mock setup works correctly
|
||||
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::Low));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI2"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI2"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -86,23 +93,47 @@ mod clock_handling_tests {
|
|||
|
||||
// Test PHI1 rising edge
|
||||
scenario.set_phi1_rising_edge();
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::High));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI2"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::High)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI2"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
|
||||
// Test PHI1 falling edge
|
||||
scenario.set_phi1_falling_edge();
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::Low));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI2"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI2"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
|
||||
// Test PHI2 rising edge
|
||||
scenario.set_phi2_rising_edge();
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::Low));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI2"), Some(PinValue::High));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI2"),
|
||||
Some(PinValue::High)
|
||||
);
|
||||
|
||||
// Test PHI2 falling edge
|
||||
scenario.set_phi2_falling_edge();
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::Low));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI2"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI2"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -111,16 +142,34 @@ mod clock_handling_tests {
|
|||
|
||||
// Simulate a clock cycle: Low -> High -> Low
|
||||
scenario.set_clock_low();
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::Low));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI2"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI2"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
|
||||
scenario.set_clock_high();
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::High));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI2"), Some(PinValue::High));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::High)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI2"),
|
||||
Some(PinValue::High)
|
||||
);
|
||||
|
||||
scenario.set_clock_low();
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::Low));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI2"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI2"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -134,10 +183,16 @@ mod control_pin_tests {
|
|||
|
||||
// Test SYNC pin
|
||||
scenario.set_pin_value("SYNC", PinValue::High);
|
||||
assert_eq!(scenario.component.get_pin_value("SYNC"), Some(PinValue::High));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("SYNC"),
|
||||
Some(PinValue::High)
|
||||
);
|
||||
|
||||
scenario.set_pin_value("SYNC", PinValue::Low);
|
||||
assert_eq!(scenario.component.get_pin_value("SYNC"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("SYNC"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
|
||||
// Test CM-ROM pin
|
||||
scenario.component.set_pin_value("CM", PinValue::High);
|
||||
|
|
@ -148,10 +203,16 @@ mod control_pin_tests {
|
|||
|
||||
// Test RESET pin
|
||||
scenario.component.set_pin_value("RESET", PinValue::High);
|
||||
assert_eq!(scenario.component.get_pin_value("RESET"), Some(PinValue::High));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("RESET"),
|
||||
Some(PinValue::High)
|
||||
);
|
||||
|
||||
scenario.component.set_pin_value("RESET", PinValue::Low);
|
||||
assert_eq!(scenario.component.get_pin_value("RESET"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("RESET"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -166,7 +227,10 @@ mod control_pin_tests {
|
|||
scenario.set_data_bus_value(0x0F);
|
||||
|
||||
// Verify state is set
|
||||
assert_eq!(scenario.component.get_timing_state(), TimingState::DriveData);
|
||||
assert_eq!(
|
||||
scenario.component.get_timing_state(),
|
||||
TimingState::DriveData
|
||||
);
|
||||
assert_eq!(scenario.component.get_full_address_ready(), true);
|
||||
assert_eq!(scenario.component.get_address_high_nibble(), Some(0x12));
|
||||
assert_eq!(scenario.component.get_address_low_nibble(), Some(0x34));
|
||||
|
|
@ -184,7 +248,10 @@ mod control_pin_tests {
|
|||
// Data bus should be tri-stated (HighZ)
|
||||
for i in 0..4 {
|
||||
let pin_name = format!("D{}", i);
|
||||
assert_eq!(scenario.component.get_pin_value(&pin_name), Some(PinValue::HighZ));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value(&pin_name),
|
||||
Some(PinValue::HighZ)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -203,19 +270,32 @@ mod timing_state_tests {
|
|||
assert!(!scenario.component.get_timing_state().is_address_phase());
|
||||
|
||||
// Transition to address phase
|
||||
scenario.component.set_timing_state(TimingState::AddressPhase);
|
||||
assert_eq!(scenario.component.get_timing_state(), TimingState::AddressPhase);
|
||||
scenario
|
||||
.component
|
||||
.set_timing_state(TimingState::AddressPhase);
|
||||
assert_eq!(
|
||||
scenario.component.get_timing_state(),
|
||||
TimingState::AddressPhase
|
||||
);
|
||||
assert!(!scenario.component.get_timing_state().is_idle());
|
||||
assert!(scenario.component.get_timing_state().is_address_phase());
|
||||
|
||||
// Transition to wait latency
|
||||
scenario.component.set_timing_state(TimingState::WaitLatency);
|
||||
assert_eq!(scenario.component.get_timing_state(), TimingState::WaitLatency);
|
||||
scenario
|
||||
.component
|
||||
.set_timing_state(TimingState::WaitLatency);
|
||||
assert_eq!(
|
||||
scenario.component.get_timing_state(),
|
||||
TimingState::WaitLatency
|
||||
);
|
||||
assert!(scenario.component.get_timing_state().is_waiting_latency());
|
||||
|
||||
// Transition to drive data
|
||||
scenario.component.set_timing_state(TimingState::DriveData);
|
||||
assert_eq!(scenario.component.get_timing_state(), TimingState::DriveData);
|
||||
assert_eq!(
|
||||
scenario.component.get_timing_state(),
|
||||
TimingState::DriveData
|
||||
);
|
||||
assert!(scenario.component.get_timing_state().is_driving_data());
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +316,10 @@ mod timing_state_tests {
|
|||
assert_eq!(scenario.component.get_address_high_nibble(), Some(0x12));
|
||||
assert_eq!(scenario.component.get_address_low_nibble(), Some(0x34));
|
||||
assert_eq!(scenario.component.get_full_address_ready(), true);
|
||||
assert_eq!(scenario.component.get_address_latch_time(), Some(latch_time));
|
||||
assert_eq!(
|
||||
scenario.component.get_address_latch_time(),
|
||||
Some(latch_time)
|
||||
);
|
||||
|
||||
// Test clearing the latch
|
||||
scenario.component.set_address_high_nibble(None);
|
||||
|
|
@ -255,7 +338,10 @@ mod timing_state_tests {
|
|||
let scenario = MockScenario::new("TestAccessTime");
|
||||
|
||||
// Test default access time
|
||||
assert_eq!(scenario.component.get_access_time(), TimingConstants::DEFAULT_ACCESS_TIME);
|
||||
assert_eq!(
|
||||
scenario.component.get_access_time(),
|
||||
TimingConstants::DEFAULT_ACCESS_TIME
|
||||
);
|
||||
|
||||
// In a real implementation, we would test changing the access time
|
||||
// For now, we verify the getter works
|
||||
|
|
@ -276,9 +362,14 @@ mod integration_scenarios {
|
|||
assert_eq!(scenario.component.get_timing_state(), TimingState::Idle);
|
||||
|
||||
// Phase 1: Address phase - high nibble
|
||||
scenario.component.set_timing_state(TimingState::AddressPhase);
|
||||
scenario
|
||||
.component
|
||||
.set_timing_state(TimingState::AddressPhase);
|
||||
scenario.component.set_address_high_nibble(Some(0x12));
|
||||
assert_eq!(scenario.component.get_timing_state(), TimingState::AddressPhase);
|
||||
assert_eq!(
|
||||
scenario.component.get_timing_state(),
|
||||
TimingState::AddressPhase
|
||||
);
|
||||
assert_eq!(scenario.component.get_address_high_nibble(), Some(0x12));
|
||||
|
||||
// Phase 2: Address phase - low nibble
|
||||
|
|
@ -293,8 +384,13 @@ mod integration_scenarios {
|
|||
assert_eq!(scenario.component.get_full_address_ready(), true);
|
||||
|
||||
// Phase 3: Wait for latency
|
||||
scenario.component.set_timing_state(TimingState::WaitLatency);
|
||||
assert_eq!(scenario.component.get_timing_state(), TimingState::WaitLatency);
|
||||
scenario
|
||||
.component
|
||||
.set_timing_state(TimingState::WaitLatency);
|
||||
assert_eq!(
|
||||
scenario.component.get_timing_state(),
|
||||
TimingState::WaitLatency
|
||||
);
|
||||
|
||||
// Advance time past access time
|
||||
scenario.advance_time(scenario.component.get_access_time() + Duration::from_nanos(10));
|
||||
|
|
@ -302,7 +398,10 @@ mod integration_scenarios {
|
|||
// Phase 4: Drive data
|
||||
scenario.component.set_timing_state(TimingState::DriveData);
|
||||
scenario.set_data_bus_value(0x0F); // Drive some data
|
||||
assert_eq!(scenario.component.get_timing_state(), TimingState::DriveData);
|
||||
assert_eq!(
|
||||
scenario.component.get_timing_state(),
|
||||
TimingState::DriveData
|
||||
);
|
||||
assert_eq!(scenario.get_data_bus_value(), 0x0F);
|
||||
|
||||
// Cycle complete - return to idle
|
||||
|
|
@ -322,7 +421,10 @@ mod integration_scenarios {
|
|||
for i in 0..4 {
|
||||
let pin_name = format!("D{}", i);
|
||||
scenario.component.set_pin_value(&pin_name, PinValue::HighZ);
|
||||
assert_eq!(scenario.component.get_pin_value(&pin_name), Some(PinValue::HighZ));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value(&pin_name),
|
||||
Some(PinValue::HighZ)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -370,9 +472,18 @@ mod error_handling_tests {
|
|||
assert_eq!(scenario.component.get_pin_value("NONEXISTENT"), None);
|
||||
|
||||
// Standard pins should exist
|
||||
assert_eq!(scenario.component.get_pin_value("D0"), Some(PinValue::HighZ));
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(PinValue::Low));
|
||||
assert_eq!(scenario.component.get_pin_value("SYNC"), Some(PinValue::Low));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("D0"),
|
||||
Some(PinValue::HighZ)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("PHI1"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("SYNC"),
|
||||
Some(PinValue::Low)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -381,7 +492,10 @@ mod error_handling_tests {
|
|||
|
||||
// Test setting pin to HighZ (tri-state)
|
||||
scenario.component.set_pin_value("D0", PinValue::HighZ);
|
||||
assert_eq!(scenario.component.get_pin_value("D0"), Some(PinValue::HighZ));
|
||||
assert_eq!(
|
||||
scenario.component.get_pin_value("D0"),
|
||||
Some(PinValue::HighZ)
|
||||
);
|
||||
|
||||
// Test that HighZ is handled correctly in bus operations
|
||||
// (This would be more relevant in actual hardware interface tests)
|
||||
|
|
@ -389,4 +503,4 @@ mod error_handling_tests {
|
|||
// The exact behavior depends on how HighZ pins are interpreted
|
||||
// This test documents the expected structure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
//! to enable comprehensive testing of the intel_400x traits and functionality.
|
||||
|
||||
use rusty_emu::component::{BaseComponent, Component};
|
||||
use rusty_emu::pin::{Pin, PinValue};
|
||||
use rusty_emu::components::common::intel_400x::*;
|
||||
use rusty_emu::pin::{Pin, PinValue};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Mock pin implementation for testing
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -77,8 +77,15 @@ impl MockIntel400xComponent {
|
|||
let data_pins = ["D0", "D1", "D2", "D3"];
|
||||
let control_pins = ["SYNC", "CM", "RESET"];
|
||||
|
||||
for pin_name in clock_pins.iter().chain(data_pins.iter()).chain(control_pins.iter()) {
|
||||
pins.insert(pin_name.to_string(), Arc::new(Mutex::new(MockPin::new(pin_name))));
|
||||
for pin_name in clock_pins
|
||||
.iter()
|
||||
.chain(data_pins.iter())
|
||||
.chain(control_pins.iter())
|
||||
{
|
||||
pins.insert(
|
||||
pin_name.to_string(),
|
||||
Arc::new(Mutex::new(MockPin::new(pin_name))),
|
||||
);
|
||||
}
|
||||
|
||||
Self {
|
||||
|
|
@ -118,7 +125,11 @@ impl MockIntel400xComponent {
|
|||
pub fn set_data_bus(&self, value: u8) {
|
||||
for i in 0..4 {
|
||||
let bit_value = (value >> i) & 1;
|
||||
let pin_value = if bit_value == 1 { PinValue::High } else { PinValue::Low };
|
||||
let pin_value = if bit_value == 1 {
|
||||
PinValue::High
|
||||
} else {
|
||||
PinValue::Low
|
||||
};
|
||||
self.set_pin_value(&format!("D{}", i), pin_value);
|
||||
}
|
||||
}
|
||||
|
|
@ -312,27 +323,33 @@ impl MockScenario {
|
|||
}
|
||||
|
||||
pub fn set_clock_high(&mut self) {
|
||||
self.component.set_clock_values(PinValue::High, PinValue::High);
|
||||
self.component
|
||||
.set_clock_values(PinValue::High, PinValue::High);
|
||||
}
|
||||
|
||||
pub fn set_clock_low(&mut self) {
|
||||
self.component.set_clock_values(PinValue::Low, PinValue::Low);
|
||||
self.component
|
||||
.set_clock_values(PinValue::Low, PinValue::Low);
|
||||
}
|
||||
|
||||
pub fn set_phi1_rising_edge(&mut self) {
|
||||
self.component.set_clock_values(PinValue::High, PinValue::Low);
|
||||
self.component
|
||||
.set_clock_values(PinValue::High, PinValue::Low);
|
||||
}
|
||||
|
||||
pub fn set_phi1_falling_edge(&mut self) {
|
||||
self.component.set_clock_values(PinValue::Low, PinValue::Low);
|
||||
self.component
|
||||
.set_clock_values(PinValue::Low, PinValue::Low);
|
||||
}
|
||||
|
||||
pub fn set_phi2_rising_edge(&mut self) {
|
||||
self.component.set_clock_values(PinValue::Low, PinValue::High);
|
||||
self.component
|
||||
.set_clock_values(PinValue::Low, PinValue::High);
|
||||
}
|
||||
|
||||
pub fn set_phi2_falling_edge(&mut self) {
|
||||
self.component.set_clock_values(PinValue::Low, PinValue::Low);
|
||||
self.component
|
||||
.set_clock_values(PinValue::Low, PinValue::Low);
|
||||
}
|
||||
|
||||
pub fn set_data_bus_value(&mut self, value: u8) {
|
||||
|
|
@ -355,7 +372,7 @@ impl MockScenario {
|
|||
self.time_provider.advance(duration);
|
||||
}
|
||||
|
||||
pub fn set_access_time(&mut self, duration: Duration) {
|
||||
pub fn set_access_time(&mut self, _duration: Duration) {
|
||||
// This would need to be implemented in the actual component
|
||||
// For now, it's a placeholder
|
||||
}
|
||||
|
|
@ -418,4 +435,4 @@ pub mod proptest_helpers {
|
|||
pub fn arb_duration() -> impl Strategy<Value = Duration> {
|
||||
(0u64..1_000_000_000u64).prop_map(Duration::from_nanos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
//! These tests use property-based testing to verify the correctness
|
||||
//! of state machine behavior, timing properties, and system invariants.
|
||||
|
||||
use rusty_emu::components::common::intel_400x::*;
|
||||
use rusty_emu::pin::PinValue;
|
||||
use crate::mocks::*;
|
||||
use proptest::prelude::*;
|
||||
use rusty_emu::components::common::intel_400x::*;
|
||||
use rusty_emu::pin::PinValue;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -100,7 +100,7 @@ mod state_machine_properties {
|
|||
(0x01, 0x23, 0x0123),
|
||||
];
|
||||
|
||||
for (high, low, expected) in test_cases {
|
||||
for (high, low, _expected) in test_cases {
|
||||
scenario.component.set_address_high_nibble(Some(high));
|
||||
scenario.component.set_address_low_nibble(Some(low));
|
||||
scenario.component.set_full_address_ready(true);
|
||||
|
|
@ -176,7 +176,7 @@ mod state_machine_properties {
|
|||
|
||||
// Test duration properties
|
||||
prop_assert!(duration.as_nanos() >= 0);
|
||||
prop_assert_eq!(duration.as_nanos(), duration_nanos as u128);
|
||||
prop_assert_eq!(duration.as_nanos(), duration_nanos);
|
||||
|
||||
// Test that our timing constants are reasonable
|
||||
prop_assert!(TimingConstants::DEFAULT_ACCESS_TIME > Duration::from_nanos(0));
|
||||
|
|
@ -222,7 +222,10 @@ mod timing_invariant_tests {
|
|||
if idle {
|
||||
assert_eq!(active_count, 0, "Idle state should not have active flags");
|
||||
} else {
|
||||
assert!(active_count > 0, "Non-idle state should have at least one active flag");
|
||||
assert!(
|
||||
active_count > 0,
|
||||
"Non-idle state should have at least one active flag"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -265,11 +268,7 @@ mod timing_invariant_tests {
|
|||
let scenario = MockScenario::new("TestPinConsistency");
|
||||
|
||||
// Test that pin states are consistent
|
||||
let test_values = vec![
|
||||
PinValue::Low,
|
||||
PinValue::High,
|
||||
PinValue::HighZ,
|
||||
];
|
||||
let test_values = vec![PinValue::Low, PinValue::High, PinValue::HighZ];
|
||||
|
||||
for value in test_values {
|
||||
scenario.component.set_pin_value("D0", value);
|
||||
|
|
@ -278,7 +277,7 @@ mod timing_invariant_tests {
|
|||
scenario.component.set_pin_value("PHI1", value);
|
||||
assert_eq!(scenario.component.get_pin_value("PHI1"), Some(value));
|
||||
|
||||
scenario.set_pin_value("SYNC", value);
|
||||
scenario.component.set_pin_value("SYNC", value);
|
||||
assert_eq!(scenario.component.get_pin_value("SYNC"), Some(value));
|
||||
}
|
||||
}
|
||||
|
|
@ -389,35 +388,43 @@ mod concurrency_safety_tests {
|
|||
let scenario = Arc::new(MockScenario::new("TestThreadSafety"));
|
||||
|
||||
// Test that our mock can handle concurrent access patterns
|
||||
let handles: Vec<_> = (0..4).map(|i| {
|
||||
let scenario_clone: std::sync::Arc<MockScenario> = Arc::clone(&scenario);
|
||||
thread::spawn(move || {
|
||||
// Each thread tests different aspects
|
||||
match i {
|
||||
0 => {
|
||||
// Note: This would need proper Arc<Mutex<>> handling for thread safety
|
||||
// For now, we'll skip the mutable operation in this test
|
||||
// Note: Thread safety testing would require proper Arc<Mutex<>> handling
|
||||
let handles: Vec<_> = (0..4)
|
||||
.map(|i| {
|
||||
let scenario_clone: Arc<MockScenario> = Arc::clone(&scenario);
|
||||
thread::spawn(move || {
|
||||
// Each thread tests different aspects
|
||||
match i {
|
||||
0 => {
|
||||
// Note: This would need proper Arc<Mutex<>> handling for thread safety
|
||||
// For now, we'll skip the mutable operation in this test
|
||||
// Note: Thread safety testing would require proper Arc<Mutex<>> handling
|
||||
}
|
||||
1 => {
|
||||
scenario_clone.component.set_pin_value("D0", PinValue::High);
|
||||
assert_eq!(
|
||||
scenario_clone.component.get_pin_value("D0"),
|
||||
Some(PinValue::High)
|
||||
);
|
||||
}
|
||||
2 => {
|
||||
scenario_clone.component.set_address_high_nibble(Some(0x12));
|
||||
assert_eq!(
|
||||
scenario_clone.component.get_address_high_nibble(),
|
||||
Some(0x12)
|
||||
);
|
||||
}
|
||||
3 => {
|
||||
scenario_clone.advance_time(Duration::from_nanos(100));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
1 => {
|
||||
scenario_clone.component.set_pin_value("D0", PinValue::High);
|
||||
assert_eq!(scenario_clone.component.get_pin_value("D0"), Some(PinValue::High));
|
||||
}
|
||||
2 => {
|
||||
scenario_clone.component.set_address_high_nibble(Some(0x12));
|
||||
assert_eq!(scenario_clone.component.get_address_high_nibble(), Some(0x12));
|
||||
}
|
||||
3 => {
|
||||
scenario_clone.advance_time(Duration::from_nanos(100));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
})
|
||||
})
|
||||
}).collect();
|
||||
.collect();
|
||||
|
||||
// Wait for all threads to complete
|
||||
for handle in handles {
|
||||
handle.join().expect("Thread should complete successfully");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,4 +188,4 @@ mod simple_tests {
|
|||
|
||||
println!("=== Timing configuration tests completed ===");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,4 +200,4 @@ mod working_tests {
|
|||
|
||||
println!("✓ Error handling works correctly");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue