kards-env/tests/test_event_system.py

245 lines
8.5 KiB
Python

"""
测试事件系统和烟幕管理器
"""
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