Files
cultivation-world-simulator/tests/test_single_choice.py
Zihao Xu aaa636a08e fix: use str() instead of .value for realm i18n display (#98)
* fix: use str() instead of .value for realm i18n display

Fix bug where user-facing messages displayed raw enum values like
"FOUNDATION_ESTABLISHMENT" instead of translated names like "筑基".

The Realm and Stage classes already have __str__ methods that return
i18n translated text, but several places were incorrectly using
.value which returns the raw enum string.

Changed files:
- src/classes/single_choice.py: item exchange messages
- src/classes/kill_and_grab.py: loot messages
- src/classes/fortune.py: fortune discovery messages
- src/classes/avatar/inventory_mixin.py: purchase error messages

Also added unit tests and integration tests to prevent regression.

* test: add integration tests for all modified files

Add tests covering:
- kill_and_grab.py: context string realm display
- fortune.py: weapon/auxiliary intro realm display
- inventory_mixin.py: can_buy_item error message realm display
2026-01-25 18:44:13 +08:00

126 lines
4.4 KiB
Python
Raw Permalink 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.
import pytest
from unittest.mock import AsyncMock, Mock, patch
from src.classes.single_choice import handle_item_exchange
# Mocks for types
class MockAvatar:
def __init__(self):
self.name = "TestAvatar"
self.weapon = None
self.auxiliary = None
self.technique = None
self.world = Mock()
self.world.static_info = {}
self.change_weapon = Mock()
self.sell_weapon = Mock(return_value=100)
self.consume_elixir = Mock()
self.sell_elixir = Mock(return_value=50)
def get_info(self, detailed=False):
return {"name": self.name}
class MockItem:
def __init__(self, name, item_type="weapon"):
self.name = name
self.item_type = item_type
# Weapon/Auxiliary/Elixir usually have realm or grade.
self.realm = Mock()
self.realm.value = "TestRealm"
self.realm.__str__ = Mock(return_value="TestRealm")
def get_info(self, detailed=False):
return f"Info({self.name})"
@pytest.mark.asyncio
async def test_weapon_auto_equip_no_sell_new():
"""测试:自动装备兵器(无旧兵器,不可卖新)"""
avatar = MockAvatar()
new_weapon = MockItem("NewSword", "weapon")
# 模拟无旧兵器
avatar.weapon = None
swapped, msg = await handle_item_exchange(
avatar, new_weapon, "weapon", "Context", can_sell_new=False
)
assert swapped is True
assert "获得了TestRealm兵器『NewSword』并装备" in msg
avatar.change_weapon.assert_called_once_with(new_weapon)
@pytest.mark.asyncio
async def test_weapon_swap_choice_A():
"""测试:替换兵器,选择 A装备新卖旧"""
avatar = MockAvatar()
old_weapon = MockItem("OldSword", "weapon")
new_weapon = MockItem("NewSword", "weapon")
avatar.weapon = old_weapon
# Mock decision to return 'A'
with patch("src.classes.single_choice.make_decision", new_callable=AsyncMock) as mock_decision:
mock_decision.return_value = "A"
swapped, msg = await handle_item_exchange(
avatar, new_weapon, "weapon", "Context", can_sell_new=True
)
# 验证文案包含动词
# call_args[0][1] is context string, check options description
call_args = mock_decision.call_args
options = call_args[0][2] # options list
opt_a_desc = options[0]["desc"]
# 验证选项文案使用了 "装备" 和 "卖掉"
assert "装备新兵器『NewSword』" in opt_a_desc
assert "卖掉旧兵器『OldSword』" in opt_a_desc
assert swapped is True
assert "换上了TestRealm兵器『NewSword』" in msg
avatar.sell_weapon.assert_called_once_with(old_weapon)
avatar.change_weapon.assert_called_once_with(new_weapon)
@pytest.mark.asyncio
async def test_elixir_consume_choice_A():
"""测试:获得丹药,选择 A服用"""
avatar = MockAvatar()
new_elixir = MockItem("PowerPill", "elixir")
# Mock decision to return 'A'
with patch("src.classes.single_choice.make_decision", new_callable=AsyncMock) as mock_decision:
mock_decision.return_value = "A"
swapped, msg = await handle_item_exchange(
avatar, new_elixir, "elixir", "Context", can_sell_new=True
)
# 验证选项文案
options = mock_decision.call_args[0][2]
opt_a_desc = options[0]["desc"]
# 验证使用了 "服用"
assert "服用新丹药『PowerPill』" in opt_a_desc
assert swapped is True
# 验证结果使用了 "服用了"
assert "服用了TestRealm丹药『PowerPill』" in msg
avatar.consume_elixir.assert_called_once_with(new_elixir)
@pytest.mark.asyncio
async def test_elixir_sell_choice_B():
"""测试:获得丹药,选择 B卖出"""
avatar = MockAvatar()
new_elixir = MockItem("PowerPill", "elixir")
# Mock decision to return 'B'
with patch("src.classes.single_choice.make_decision", new_callable=AsyncMock) as mock_decision:
mock_decision.return_value = "B"
swapped, msg = await handle_item_exchange(
avatar, new_elixir, "elixir", "Context", can_sell_new=True
)
assert swapped is False
assert "卖掉了新获得的PowerPill" in msg
avatar.sell_elixir.assert_called_once_with(new_elixir)
avatar.consume_elixir.assert_not_called()