kards-env/tests/test_comprehensive_movement...

276 lines
10 KiB
Plaintext
Raw Normal View History

2025-09-05 17:05:43 +08:00
#!/usr/bin/env python3
"""
全面移动系统测试 - 使用pytest
测试所有移动场景和边界条件
"""
import pytest
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from kards_battle.core.battle_engine import BattleEngine
from kards_battle.examples.sample_units import create_german_infantry, create_american_gi
from kards_battle.core.enums import LineType
class TestMovementScenarios:
"""测试移动场景"""
def setup_method(self):
"""每个测试前的设置"""
self.engine = BattleEngine("Germany", "USA", debug_mode=True)
def _deploy_and_wait(self, unit, player_id):
"""部署单位并等待一回合让其可以移动"""
deploy_result = self.engine.deploy_unit_to_support(unit, player_id)
assert deploy_result['success']
# 结束回合让单位可以移动
self.engine.end_turn()
self.engine.end_turn()
return deploy_result
def test_move_to_empty_frontline_occupies_control(self):
"""测试:移向空的前线占领前线"""
# 部署德军步兵到支援线
unit = create_german_infantry()
unit.stats.operation_cost = 1
self._deploy_and_wait(unit, 0)
# 设置足够的Kredits
self.engine.debug_set_kredits(0, kredits=5)
# 移动到空的前线
move_result = self.engine.move_unit(unit.id, (LineType.FRONT, 0), 0)
assert move_result['success']
assert move_result['action'] == 'move_to_front'
assert move_result['front_line_controller'] == 'Germany' # 德军控制前线
# 验证战场状态
front_units = self.engine.battlefield.front_line.get_all_units()
assert len(front_units) == 1
assert front_units[0].id == unit.id
def test_move_to_friendly_frontline_empty_position(self):
"""测试:移向有己方的前线,进入空格"""
# 部署两个德军单位
unit1 = create_german_infantry()
unit1.name = "Infantry1"
unit1.stats.operation_cost = 1
unit2 = create_german_infantry()
unit2.name = "Infantry2"
unit2.stats.operation_cost = 1
self.engine.deploy_unit_to_support(unit1, 0)
self.engine.deploy_unit_to_support(unit2, 0)
self.engine.debug_set_kredits(0, kredits=10)
# 先移动unit1到前线
self.engine.move_unit(unit1.id, (LineType.FRONT, 0), 0)
# 再移动unit2到前线空位
move_result = self.engine.move_unit(unit2.id, (LineType.FRONT, 1), 0)
assert move_result['success']
assert move_result['to_position'] == 1
# 验证前线有两个单位
front_units = self.engine.battlefield.front_line.get_all_units()
assert len(front_units) == 2
def test_move_to_friendly_frontline_squeeze_position(self):
"""测试:移向有己方的前线,挤占已有位置"""
# 部署两个德军单位
unit1 = create_german_infantry()
unit1.name = "Infantry1"
unit1.stats.operation_cost = 1
unit2 = create_german_infantry()
unit2.name = "Infantry2"
unit2.stats.operation_cost = 1
self.engine.deploy_unit_to_support(unit1, 0)
self.engine.deploy_unit_to_support(unit2, 0)
self.engine.debug_set_kredits(0, kredits=10)
# 先移动unit1到前线位置0
self.engine.move_unit(unit1.id, (LineType.FRONT, 0), 0)
# 再移动unit2到位置0应该挤入unit1后移
move_result = self.engine.move_unit(unit2.id, (LineType.FRONT, 0), 0)
assert move_result['success']
assert move_result['to_position'] == 0
# 验证unit2在位置0unit1在位置1
front_units = self.engine.battlefield.front_line.get_all_units()
assert len(front_units) == 2
assert front_units[0].name == "Infantry2" # unit2挤到前面
assert front_units[1].name == "Infantry1" # unit1被挤到后面
def test_move_from_frontline_to_enemy_support_fails(self):
"""测试:前线移向敌方阵线(应失败,局面不变)"""
# 部署并移动德军到前线
unit = create_german_infantry()
unit.stats.operation_cost = 1
self.engine.deploy_unit_to_support(unit, 0)
self.engine.debug_set_kredits(0, kredits=10)
self.engine.move_unit(unit.id, (LineType.FRONT, 0), 0)
# 尝试从前线移动到敌方支援线(不允许)
move_result = self.engine.move_unit(unit.id, (LineType.PLAYER2_SUPPORT, 0), 0)
assert not move_result['success']
assert "Can only move to front line" in move_result['reason']
# 验证单位仍在前线
front_units = self.engine.battlefield.front_line.get_all_units()
assert len(front_units) == 1
assert front_units[0].id == unit.id
def test_move_to_full_frontline_fails(self):
"""测试:前线已满时移向前线(应失败)"""
self.engine.debug_set_kredits(0, kredits=20)
# 部署并移动5个单位到前线填满前线
units = []
for i in range(5):
unit = create_german_infantry()
unit.name = f"Infantry{i+1}"
unit.stats.operation_cost = 1
units.append(unit)
self.engine.deploy_unit_to_support(unit, 0)
self.engine.move_unit(unit.id, (LineType.FRONT, i), 0)
# 验证前线已满
assert self.engine.battlefield.front_line.is_full()
# 尝试部署第6个单位并移动到前线
extra_unit = create_german_infantry()
extra_unit.name = "ExtraInfantry"
extra_unit.stats.operation_cost = 1
self.engine.deploy_unit_to_support(extra_unit, 0)
move_result = self.engine.move_unit(extra_unit.id, (LineType.FRONT, 2), 0)
assert not move_result['success']
assert "full" in move_result['reason'].lower()
# 验证前线仍然只有5个单位
front_units = self.engine.battlefield.front_line.get_all_units()
assert len(front_units) == 5
def test_move_to_enemy_controlled_frontline_fails(self):
"""测试:前线有敌人时移向前线空地(应失败)"""
# 先让美军占领前线
usa_unit = create_american_gi()
usa_unit.stats.operation_cost = 1
# 切换到美军回合
self.engine.end_turn() # 切换到美军
self.engine.deploy_unit_to_support(usa_unit, 1)
self.engine.debug_set_kredits(1, kredits=5)
usa_move = self.engine.move_unit(usa_unit.id, (LineType.FRONT, 0), 1)
assert usa_move['success']
assert usa_move['front_line_controller'] == 'USA'
# 切换回德军回合
self.engine.end_turn() # 切换回德军
# 德军尝试移动到被美军控制的前线
ger_unit = create_german_infantry()
ger_unit.stats.operation_cost = 1
self.engine.deploy_unit_to_support(ger_unit, 0)
self.engine.debug_set_kredits(0, kredits=5)
# 尝试移动到前线空位位置1
move_result = self.engine.move_unit(ger_unit.id, (LineType.FRONT, 1), 0)
assert not move_result['success']
assert "controlled by enemy" in move_result['reason'].lower()
# 验证前线仍然只有美军单位
front_units = self.engine.battlefield.front_line.get_all_units()
assert len(front_units) == 1
assert front_units[0].owner == 'USA'
def test_units_cannot_move_within_frontline(self):
"""测试:前线单位不能在前线内移动"""
# 部署并移动德军到前线
unit = create_german_infantry()
unit.stats.operation_cost = 1
self.engine.deploy_unit_to_support(unit, 0)
self.engine.debug_set_kredits(0, kredits=10)
self.engine.move_unit(unit.id, (LineType.FRONT, 0), 0)
# 尝试在前线内移动从位置0到位置1
move_result = self.engine.move_unit(unit.id, (LineType.FRONT, 1), 0)
assert not move_result['success']
assert "Units on front line cannot move" in move_result['reason']
# 验证单位仍在原位置
front_units = self.engine.battlefield.front_line.get_all_units()
assert len(front_units) == 1
assert front_units[0].position == (LineType.FRONT, 0)
def test_insufficient_kredits_move_fails(self):
"""测试Kredits不足时移动失败"""
unit = create_german_infantry()
unit.stats.operation_cost = 3 # 需要3点激活费用
self.engine.deploy_unit_to_support(unit, 0)
# 只给1点Kredits
self.engine.debug_set_kredits(0, kredits=1)
move_result = self.engine.move_unit(unit.id, (LineType.FRONT, 0), 0)
assert not move_result['success']
assert "Insufficient Kredits" in move_result['reason']
# 验证单位仍在支援线
support_units = self.engine.battlefield.player1_support.get_all_units()
assert len(support_units) == 1
def test_move_consumes_kredits(self):
"""测试移动消耗Kredits"""
unit = create_german_infantry()
unit.stats.operation_cost = 2
self.engine.deploy_unit_to_support(unit, 0)
self.engine.debug_set_kredits(0, kredits=5)
initial_kredits = self.engine.get_kredits(0)
move_result = self.engine.move_unit(unit.id, (LineType.FRONT, 0), 0)
final_kredits = self.engine.get_kredits(0)
assert move_result['success']
assert final_kredits == initial_kredits - 2
def test_not_your_turn_move_fails(self):
"""测试:不是自己回合时移动失败"""
unit = create_german_infantry()
unit.stats.operation_cost = 1
self.engine.deploy_unit_to_support(unit, 0)
# 切换到美军回合
self.engine.end_turn()
# 德军在美军回合尝试移动
move_result = self.engine.move_unit(unit.id, (LineType.FRONT, 0), 0)
assert not move_result['success']
assert "Not your turn" in move_result['reason']
if __name__ == "__main__":
pytest.main([__file__, "-v"])