kards-env/tests/test_comprehensive_movement...

276 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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"])