"""Tests for headless simulation engine.""" import time from unittest.mock import Mock, patch from engines.headless_engine import HeadlessSimulationEngine, HeadlessConfig from config.simulation_config import SimulationConfig class TestHeadlessConfig: """Test headless configuration.""" def test_custom_values(self): """Test custom configuration values.""" sim_config = SimulationConfig(initial_cells=50, default_tps=120.0) config = HeadlessConfig( simulation=sim_config, max_ticks=10000, max_duration=300.0, output_dir="custom_output", enable_metrics=False, enable_entities=True, enable_evolution=False, metrics_interval=50, entities_interval=500, evolution_interval=2000, output_formats=['json', 'csv'], real_time=True ) assert config.simulation == sim_config assert config.max_ticks == 10000 assert config.max_duration == 300.0 assert config.output_dir == "custom_output" assert config.enable_metrics == False assert config.enable_entities == True assert config.enable_evolution == False assert config.metrics_interval == 50 assert config.entities_interval == 500 assert config.evolution_interval == 2000 assert config.output_formats == ['json', 'csv'] assert config.real_time == True class TestHeadlessSimulationEngine: """Test headless simulation engine.""" def test_initialization(self): """Test engine initialization.""" sim_config = SimulationConfig(initial_cells=5, initial_food=10) config = HeadlessConfig( simulation=sim_config, max_ticks=1000, output_formats=['json'] ) engine = HeadlessSimulationEngine(config) assert engine.config == config assert engine.event_bus is not None assert engine.simulation_core is not None assert engine.file_writer is not None assert engine.formatters is not None assert engine.collectors is not None assert engine.running == False assert engine.start_time is None def test_collectors_creation(self): """Test collectors are created based on configuration.""" sim_config = SimulationConfig() config = HeadlessConfig( simulation=sim_config, enable_metrics=True, enable_entities=True, enable_evolution=False, metrics_interval=50, entities_interval=200 ) engine = HeadlessSimulationEngine(config) assert 'metrics' in engine.collectors assert 'entities' in engine.collectors assert 'evolution' not in engine.collectors assert engine.collectors['metrics'].collection_interval == 50 assert engine.collectors['entities'].collection_interval == 200 def test_formatters_creation(self): """Test formatters are created based on configuration.""" sim_config = SimulationConfig() config = HeadlessConfig( simulation=sim_config, output_formats=['json', 'csv'] ) engine = HeadlessSimulationEngine(config) assert 'json' in engine.formatters assert 'csv' in engine.formatters def test_should_terminate_max_ticks(self): """Test termination condition for max ticks.""" sim_config = SimulationConfig() config = HeadlessConfig(simulation=sim_config, max_ticks=100) engine = HeadlessSimulationEngine(config) engine.running = True engine.start_time = time.time() # Mock the simulation core to report tick count engine.simulation_core.state.total_ticks = 99 assert engine._should_terminate() == False engine.simulation_core.state.total_ticks = 100 assert engine._should_terminate() == True def test_should_terminate_max_duration(self): """Test termination condition for max duration.""" sim_config = SimulationConfig() config = HeadlessConfig(simulation=sim_config, max_duration=1.0) engine = HeadlessSimulationEngine(config) engine.running = True engine.start_time = time.time() # Should not terminate immediately assert engine._should_terminate() == False # Mock time passage with patch('time.time', return_value=engine.start_time + 1.5): assert engine._should_terminate() == True def test_should_terminate_no_limits(self): """Test no termination conditions.""" sim_config = SimulationConfig() config = HeadlessConfig(simulation=sim_config) engine = HeadlessSimulationEngine(config) engine.running = True engine.start_time = time.time() # Should never terminate without limits assert engine._should_terminate() == False def test_collect_data(self): """Test data collection from collectors.""" sim_config = SimulationConfig() config = HeadlessConfig( simulation=sim_config, enable_metrics=True, enable_entities=False, enable_evolution=False ) engine = HeadlessSimulationEngine(config) # Mock simulation core's get_world_state method engine.simulation_core.get_world_state = Mock(return_value={ 'tick_count': 1000, 'actual_tps': 60.0, 'entity_counts': {'total': 25} }) # Mock collector mock_collector = Mock() mock_collector.update.return_value = [ {'tick_count': 1000, 'actual_tps': 60.0, 'collection_type': 'metrics'} ] engine.collectors['metrics'] = mock_collector engine._collect_data() # Verify collector was called mock_collector.update.assert_called_once() # Verify data was collected assert len(engine.batch_data['metrics']) == 1 assert engine.batch_data['metrics'][0]['tick_count'] == 1000 def test_get_real_time_status(self): """Test real-time status reporting.""" sim_config = SimulationConfig() config = HeadlessConfig(simulation=sim_config) engine = HeadlessSimulationEngine(config) engine.running = True engine.start_time = time.time() - 5.0 # Mock simulation state engine.simulation_core.state.total_ticks = 300 engine.simulation_core.state.actual_tps = 60.0 engine.simulation_core.get_world_state = Mock(return_value={ 'tick_count': 300, 'actual_tps': 60.0, 'entity_counts': {'total': 50} }) status = engine.get_real_time_status() assert status['running'] == True assert status['ticks'] == 300 assert status['tps'] == 60.0 assert status['duration'] > 4.0 # Approximately 5 seconds assert status['world_state']['tick_count'] == 300 def test_signal_handler(self): """Test signal handling for graceful shutdown.""" sim_config = SimulationConfig() config = HeadlessConfig(simulation=sim_config) engine = HeadlessSimulationEngine(config) engine.running = True # Simulate signal handler engine._signal_handler(2, None) # SIGINT assert engine.running == False