""" 测试事件系统和烟幕管理器 """ import pytest from kards_battle.core.battle_engine import BattleEngine from kards_battle.units.unit_loader import load_unit from kards_battle.core.enums import LineType from kards_battle.events.event_system import ( EventType, GameEvent, EventBus, EventSubscriber, publish_event, subscribe_to_events ) from kards_battle.events.managers.smokescreen_manager import SmokescreenManager class MockEventSubscriber(EventSubscriber): """测试用事件订阅者""" def __init__(self): self.received_events = [] def get_subscribed_events(self): return [EventType.UNIT_DEPLOYED, EventType.UNIT_MOVED, EventType.UNIT_ATTACKED] def handle_event(self, event): self.received_events.append(event) class TestEventSystem: """事件系统测试""" def test_event_bus_basic_functionality(self): """测试事件总线基本功能""" bus = EventBus() subscriber = MockEventSubscriber() # 订阅事件 bus.subscribe(subscriber) assert bus.get_subscriber_count(EventType.UNIT_DEPLOYED) == 1 # 发布事件 event = GameEvent(EventType.UNIT_DEPLOYED, data={"test": "data"}) bus.publish(event) # 检查是否收到事件 assert len(subscriber.received_events) == 1 assert subscriber.received_events[0].event_type == EventType.UNIT_DEPLOYED assert subscriber.received_events[0].data["test"] == "data" def test_event_cancellation(self): """测试事件取消功能""" bus = EventBus() class CancellingSubscriber(EventSubscriber): def get_subscribed_events(self): return [EventType.BEFORE_ATTACK_CHECK] def handle_event(self, event): if event.cancellable: event.cancel("Test cancellation") subscriber = CancellingSubscriber() bus.subscribe(subscriber) # 发布可取消事件 event = GameEvent( EventType.BEFORE_ATTACK_CHECK, cancellable=True ) bus.publish(event) # 检查事件是否被取消 assert event.cancelled assert event.cancel_reason == "Test cancellation" class TestSmokescreenManager: """烟幕管理器测试""" def setup_method(self): """每个测试前的设置""" self.engine = BattleEngine('Germany', 'USA', debug_mode=True) def test_smokescreen_deployment_and_activation(self): """测试烟幕部署和激活""" unit = load_unit('ger_infantry_grenadier') unit.add_keyword('SMOKESCREEN') # 部署到支援线应该激活烟幕 self.engine.deploy_unit_to_support(unit, 0) assert unit.has_keyword('SMOKESCREEN') assert unit.position[0] == LineType.PLAYER1_SUPPORT def test_smokescreen_removed_on_move(self): """测试移动时移除烟幕""" unit = load_unit('ger_infantry_grenadier') unit.add_keyword('SMOKESCREEN') self.engine.deploy_unit_to_support(unit, 0) assert unit.has_keyword('SMOKESCREEN') # 模拟下一回合允许移动 unit.start_new_turn() self.engine.debug_set_kredits(0, kredits=5) # 移动到前线应该移除烟幕 result = self.engine.move_unit(unit.id, (LineType.FRONT, 0), 0) assert result['success'] assert not unit.has_keyword('SMOKESCREEN') def test_smokescreen_removed_on_attack(self): """测试攻击时移除烟幕""" attacker = load_unit('ger_infantry_grenadier') attacker.add_keyword('SMOKESCREEN') target = load_unit('usa_infantry_gi') # 部署单位 self.engine.deploy_unit_to_support(attacker, 0) self.engine.end_turn() self.engine.deploy_unit_to_support(target, 1) # 移动攻击者到前线 attacker.start_new_turn() self.engine.debug_set_kredits(0, kredits=5) self.engine.move_unit(attacker.id, (LineType.FRONT, 0), 0) # 重新添加烟幕(因为移动时被移除了) attacker.add_keyword('SMOKESCREEN') assert attacker.has_keyword('SMOKESCREEN') # 切换回德军回合并攻击 self.engine.end_turn() attacker.start_new_turn() result = self.engine.attack_target(attacker.id, target.id, 0) if result['success']: # 如果攻击成功,烟幕应该被移除 assert not attacker.has_keyword('SMOKESCREEN') def test_smokescreen_blocks_attacks(self): """测试烟幕阻止攻击""" defender = load_unit('ger_infantry_grenadier') defender.add_keyword('SMOKESCREEN') attacker = load_unit('usa_infantry_gi') # 部署单位 self.engine.deploy_unit_to_support(defender, 0) self.engine.end_turn() self.engine.deploy_unit_to_support(attacker, 1) # 移动攻击者到前线 attacker.start_new_turn() self.engine.debug_set_kredits(1, kredits=5) self.engine.move_unit(attacker.id, (LineType.FRONT, 0), 1) # 尝试攻击有烟幕的单位 attacker.start_new_turn() result = self.engine.attack_target(attacker.id, defender.id, 1) assert not result['success'] assert "Protected by SMOKESCREEN" in result['reason'] assert defender.has_keyword('SMOKESCREEN') # 烟幕应该还在 def test_smokescreen_removed_on_front_line(self): """测试单位在前线时失去烟幕""" unit = load_unit('ger_infantry_grenadier') unit.add_keyword('SMOKESCREEN') self.engine.deploy_unit_to_support(unit, 0) assert unit.has_keyword('SMOKESCREEN') # 移动到前线 unit.start_new_turn() self.engine.debug_set_kredits(0, kredits=5) result = self.engine.move_unit(unit.id, (LineType.FRONT, 0), 0) assert result['success'] assert unit.position[0] == LineType.FRONT assert not unit.has_keyword('SMOKESCREEN') def test_smokescreen_removed_with_guard(self): """测试获得GUARD关键词时失去烟幕""" unit = load_unit('ger_infantry_grenadier') unit.add_keyword('SMOKESCREEN') self.engine.deploy_unit_to_support(unit, 0) assert unit.has_keyword('SMOKESCREEN') # 添加GUARD关键词应该移除烟幕 unit.add_keyword('GUARD') # 发布关键词添加事件来触发管理器 publish_event(GameEvent( event_type=EventType.KEYWORD_ADDED, target=unit, data={'keyword': 'GUARD'} )) # 烟幕应该被移除(可能需要等待事件处理) # 这个测试可能需要调整,取决于事件处理的具体实现 class TestIntegratedEventSystem: """集成事件系统测试""" def setup_method(self): """每个测试前的设置""" self.engine = BattleEngine('Germany', 'USA', debug_mode=True) def test_event_system_deployment_and_movement(self): """测试事件系统的部署和移动事件发布""" subscriber = MockEventSubscriber() subscribe_to_events(subscriber) # 创建和部署单位 ger_unit = load_unit('ger_infantry_grenadier') self.engine.deploy_unit_to_support(ger_unit, 0) # 检查部署事件 deployed_events = [e for e in subscriber.received_events if e.event_type == EventType.UNIT_DEPLOYED] assert len(deployed_events) == 1 assert deployed_events[0].source == ger_unit # 移动单位(在新回合) ger_unit.start_new_turn() self.engine.debug_set_kredits(0, kredits=5) result = self.engine.move_unit(ger_unit.id, (LineType.FRONT, 0), 0) # 检查移动是否成功 assert result['success'] # 检查移动事件 moved_events = [e for e in subscriber.received_events if e.event_type == EventType.UNIT_MOVED] assert len(moved_events) == 1 assert moved_events[0].source == ger_unit # 验证事件数据完整性 move_event = moved_events[0] assert 'old_position' in move_event.data assert 'new_position' in move_event.data assert 'player_id' in move_event.data