feat: 배치 엔티티 재사용 로직 개선 및 README 업데이트
- `place_entity` 함수에서 인벤토리 아이템 유무를 확인하기 전에 기존 엔티티를 탐색하여 재사용(`REUSED`) 처리하도록 로직 개선 - 요청 좌표 주변 `±1 타일` 및 반경 `3` 타일 내에서 기존 엔티티를 찾아 재사용할 수 있도록 확장 - `stone-furnace`의 재사용 시 자동 부트스트랩 기능이 정상 작동하도록 보장 - README.md에 변경 사항 및 새로운 동작 설명 추가 - `tests/test_place_entity_reuse.py`에 대한 단위 테스트 추가
This commit is contained in:
82
tests/test_place_entity_reuse.py
Normal file
82
tests/test_place_entity_reuse.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import unittest
|
||||
|
||||
from action_executor import ActionExecutor
|
||||
|
||||
|
||||
class _FakeRCON:
|
||||
def __init__(self, lua_return: str):
|
||||
self.lua_return = lua_return
|
||||
self.last_lua: str | None = None
|
||||
|
||||
def lua(self, code: str) -> str:
|
||||
self.last_lua = code
|
||||
return self.lua_return
|
||||
|
||||
|
||||
class TestPlaceEntityReuse(unittest.TestCase):
|
||||
def test_place_entity_treats_reused_as_success(self):
|
||||
"""
|
||||
place_entity가 REUSED:-91,-68 같은 값을 반환하면,
|
||||
executor는 이를 성공으로 처리해야 한다.
|
||||
"""
|
||||
rcon = _FakeRCON("REUSED:-91,-68")
|
||||
ex = ActionExecutor(rcon) # type: ignore[arg-type]
|
||||
|
||||
ok, msg = ex.place_entity("stone-furnace", x=-91, y=-68, direction="north")
|
||||
|
||||
self.assertTrue(ok, msg)
|
||||
self.assertIn("재사용", msg)
|
||||
|
||||
def test_place_entity_reuse_searches_a_wider_radius(self):
|
||||
"""
|
||||
REUSED 탐지를 ±1 타일(9칸)에서 끝내지 않고,
|
||||
요청 좌표 중심으로 더 넓은 반경 내 기존 엔티티도 찾아야 한다.
|
||||
"""
|
||||
rcon = _FakeRCON("BLOCKED")
|
||||
ex = ActionExecutor(rcon) # type: ignore[arg-type]
|
||||
|
||||
# 실제 성공/실패는 필요 없고, place_entity에 전달된 Lua 코드에
|
||||
# wider radius 탐색이 포함됐는지만 확인한다.
|
||||
ex.place_entity("stone-furnace", x=-92, y=-70, direction="north")
|
||||
|
||||
assert rcon.last_lua is not None
|
||||
self.assertIn("radius = 3", rcon.last_lua)
|
||||
|
||||
def test_execute_bootstraps_furnace_when_place_entity_reused_message_has_coords(self):
|
||||
ex = ActionExecutor(_FakeRCON("OK"))
|
||||
|
||||
def fake_place_entity(name: str, x: int, y: int, direction: str = "north"):
|
||||
return True, "stone-furnace 재사용 (-91, -68)"
|
||||
|
||||
ex.place_entity = fake_place_entity # type: ignore[assignment]
|
||||
|
||||
called: list[dict] = []
|
||||
|
||||
def fake_auto_bootstrap(*, furnace_name: str, x: int, y: int, reason: str = ""):
|
||||
called.append({
|
||||
"furnace_name": furnace_name,
|
||||
"x": x,
|
||||
"y": y,
|
||||
"reason": reason,
|
||||
})
|
||||
return True, "mock_bootstrap_ok"
|
||||
|
||||
ex._auto_bootstrap_furnace = fake_auto_bootstrap # type: ignore[attr-defined]
|
||||
|
||||
ok, msg = ex.execute({
|
||||
"action": "place_entity",
|
||||
"reason": "기존 제련소 재사용 후 가동",
|
||||
"params": {
|
||||
"name": "stone-furnace",
|
||||
"x": -91,
|
||||
"y": -68,
|
||||
"direction": "north",
|
||||
},
|
||||
})
|
||||
|
||||
self.assertTrue(ok, msg)
|
||||
self.assertEqual(len(called), 1)
|
||||
self.assertEqual(called[0]["furnace_name"], "stone-furnace")
|
||||
self.assertEqual(called[0]["x"], -91)
|
||||
self.assertEqual(called[0]["y"], -68)
|
||||
|
||||
Reference in New Issue
Block a user