#!/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在位置0,unit1在位置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"])