diff --git a/TASKS.md b/TASKS.md index 8bd2f63..ef88309 100644 --- a/TASKS.md +++ b/TASKS.md @@ -19,6 +19,6 @@ ## 5. Расширение тестов фракций - [x] Дописать интеграционные тесты для `get_recent_events`, `get_location` и работы с активами. -- [ ] Расширить тесты логики ходов фракций в `test_wwn_mechanics.py`. +- [x] Расширить тесты логики ходов фракций в `test_wwn_mechanics.py`. - [x] Добавлены setup-тесты для перезаписи тестовых файлов фракций (frontmatter и контент) для детерминированности среды. - [x] Убедиться, что текущий набор pytest проходит без ошибок (`pytest -v`). diff --git a/faction_turns/tests/test_wwn_mechanics.py b/faction_turns/tests/test_wwn_mechanics.py index 6387e0a..324eb7f 100644 --- a/faction_turns/tests/test_wwn_mechanics.py +++ b/faction_turns/tests/test_wwn_mechanics.py @@ -5,7 +5,12 @@ from pathlib import Path # Добавляем родительскую директорию в sys.path для импорта модулей sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) -from wwn_mechanics import calc_hp_max, calc_income, calc_xp_cost_to_raise +from wwn_mechanics import ( + calc_hp_max, calc_income, calc_xp_cost_to_raise, + calc_asset_upkeep, calc_repair_heal, calc_faction_repair_heal, + get_available_upgrades, get_attack_extra_die_flags, + has_antimagical_penalty, check_massive_auto_win +) # ----------------------------------------------- HP Tests ------------------------------------------------------------ @@ -32,3 +37,108 @@ def test_calc_xp_cost_to_raise(): assert calc_xp_cost_to_raise(4) == 9 assert calc_xp_cost_to_raise(7) == 20 assert calc_xp_cost_to_raise(8) is None + + +# ----------------------------------------------- Upkeep Tests ------------------------------------------------------------ + +def test_calc_asset_upkeep(): + """Проверяет расчет апкипа фракции за превышение лимитов активов.""" + faction_fm = { + "force": 1, "wealth": 1, "cunning": 1, + "assets": [ + {"name": "Infantry", "attribute": "Force", "is_base_of_influence": False}, + {"name": "Thugs", "attribute": "Force", "is_base_of_influence": False}, # Excess + {"name": "Free Company", "attribute": "Wealth", "is_base_of_influence": False}, # special upkeep + {"name": "Farmers", "attribute": "Wealth", "is_base_of_influence": False}, # Excess + {"name": "BoI", "attribute": "Wealth", "is_base_of_influence": True} # Not counted + ] + } + upkeep = calc_asset_upkeep(faction_fm) + assert upkeep["excess_force"] == 1 + assert upkeep["excess_wealth"] == 1 + assert upkeep["free_company_count"] == 1 + assert upkeep["total_upkeep"] == 3 # 1 (Force) + 1 (Wealth) + 1 (Free Company) + assert "Thugs" in upkeep["excess_assets"] + +# ----------------------------------------------- Repair Tests ------------------------------------------------------------ + +def test_calc_repair_heal(): + """Проверяет расчет стоимости и объема лечения актива.""" + fm = {"force": 5, "wealth": 2, "cunning": 4} + res1 = calc_repair_heal(fm, "Force", 1) + assert res1["cost"] == 1 + assert res1["heal"] == 3 # ceil(5/2) + + res2 = calc_repair_heal(fm, "Cunning", 3) + assert res2["cost"] == 3 + assert res2["heal"] == 2 # ceil(4/2) + +def test_calc_faction_repair_heal(): + """Проверяет расчет лечения самой фракции.""" + fm = {"force": 8, "wealth": 2, "cunning": 4} + res = calc_faction_repair_heal(fm) + assert res["cost"] == 1 + assert res["heal"] == 5 # ceil((8+2)/2) + assert res["highest_attr"] == "force" + assert res["lowest_attr"] == "wealth" + +# ----------------------------------------------- Faction Tags Tests ------------------------------------------------------------ + +def test_get_attack_extra_die_flags(): + """Проверяет флаги бонусных кубиков при атаке.""" + atk_fm = {"faction_tags": ["Martial", "Machiavellian"]} + def_fm = {"faction_tags": ["Rich"]} + + # Martial дает бонус на Force + a_extra, d_extra = get_attack_extra_die_flags(atk_fm, def_fm, "Force") + assert a_extra is True + assert d_extra is False + + # Rich дает бонус на Wealth + a_extra, d_extra = get_attack_extra_die_flags(atk_fm, def_fm, "Wealth") + assert a_extra is False + assert d_extra is True + +def test_has_antimagical_penalty(): + """Проверяет применение штрафа Antimagical.""" + def_fm = {"faction_tags": ["Antimagical"]} + assert has_antimagical_penalty(def_fm, "High") is True + assert has_antimagical_penalty(def_fm, "Medium") is True + assert has_antimagical_penalty(def_fm, "Low") is False + +def test_check_massive_auto_win(): + """Проверяет автопобеду тега Massive.""" + atk_fm = {"faction_tags": ["Massive"], "force": 7} + def_fm = {"force": 3} + + # Атакующий > 2 * защитника + assert check_massive_auto_win(atk_fm, def_fm, "Force") is True + + def_fm["force"] = 4 + # Не более чем в 2 раза + assert check_massive_auto_win(atk_fm, def_fm, "Force") is None + + # Защитник Massive + atk_fm2 = {"force": 2} + def_fm2 = {"faction_tags": ["Massive"], "force": 5} + assert check_massive_auto_win(atk_fm2, def_fm2, "Force") is False + +# ----------------------------------------------- Upgrades Tests ------------------------------------------------------------ + +def test_get_available_upgrades(): + """Проверяет получение доступных для повышения атрибутов.""" + fm = {"force": 2, "wealth": 7, "cunning": 8, "xp": 15} + upgrades = get_available_upgrades(fm) + + # Cunning 8 не должно быть в списке + assert len(upgrades) == 2 + + force_upg = next(u for u in upgrades if u["attribute"] == "force") + assert force_upg["current_value"] == 2 + assert force_upg["next_value"] == 3 + assert force_upg["xp_cost"] == 4 + assert force_upg["can_afford"] is True + + wealth_upg = next(u for u in upgrades if u["attribute"] == "wealth") + assert wealth_upg["xp_cost"] == 20 + assert wealth_upg["can_afford"] is False \ No newline at end of file