test: add 36 tests for health_manager, death_manager, ui.meters, config, inventory.belt, game_controller, game_recovery, item.pickit, char
This commit is contained in:
39
test/test_char.py
Normal file
39
test/test_char.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Tests for char module — IChar base class and CharacterCapabilities.
|
||||
|
||||
Covers: character construction, capability dataclass, active skill tracking.
|
||||
"""
|
||||
import pytest
|
||||
from logger import Logger
|
||||
|
||||
|
||||
class TestCharacterCapabilities:
|
||||
def test_capabilities_dataclass(self):
|
||||
from char.capabilities import CharacterCapabilities
|
||||
caps = CharacterCapabilities(can_teleport_natively=True, can_teleport_with_charges=False)
|
||||
assert caps.can_teleport_natively is True
|
||||
assert caps.can_teleport_with_charges is False
|
||||
|
||||
|
||||
class TestIChar:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
|
||||
def test_ichar_initializes_skill_hotkeys(self):
|
||||
from char.i_char import IChar
|
||||
char = IChar({"left_attack": "1", "right_attack": "2"})
|
||||
assert char._skill_hotkeys["left_attack"] == "1"
|
||||
assert char._skill_hotkeys["right_attack"] == "2"
|
||||
|
||||
def test_ichar_active_skill_defaults_empty(self):
|
||||
from char.i_char import IChar
|
||||
char = IChar({"left_attack": "1", "right_attack": "2"})
|
||||
assert char._active_skill["left"] == ""
|
||||
assert char._active_skill["right"] == ""
|
||||
|
||||
def test_ichar_set_active_skill(self):
|
||||
from char.i_char import IChar
|
||||
char = IChar({"left_attack": "1", "right_attack": "2"})
|
||||
char._set_active_skill("left", "hammer")
|
||||
assert char._active_skill["left"] == "hammer"
|
||||
51
test/test_config.py
Normal file
51
test/test_config.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
Tests for config.Config singleton and edge cases.
|
||||
|
||||
Covers: singleton behavior, config file merging, missing file handling.
|
||||
"""
|
||||
import os
|
||||
import pytest
|
||||
from logger import Logger
|
||||
|
||||
|
||||
class TestConfig:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
# Reset singleton so each test gets a fresh config
|
||||
import config
|
||||
if hasattr(config, '_instance'):
|
||||
config._instance = None
|
||||
|
||||
def test_config_is_singleton(self):
|
||||
from config import Config
|
||||
c1 = Config()
|
||||
c2 = Config()
|
||||
assert c1 is c2
|
||||
|
||||
def test_config_loads_difficulty(self):
|
||||
from config import Config
|
||||
c = Config()
|
||||
assert "difficulty" in c.general
|
||||
|
||||
def test_config_loads_char_type(self):
|
||||
from config import Config
|
||||
c = Config()
|
||||
assert "type" in c.char
|
||||
|
||||
def test_config_loads_routes(self):
|
||||
from config import Config
|
||||
c = Config()
|
||||
assert hasattr(c, 'routes')
|
||||
|
||||
def test_config_general_has_max_game_length(self):
|
||||
from config import Config
|
||||
c = Config()
|
||||
assert "max_game_length_s" in c.general
|
||||
|
||||
def test_config_char_has_keybinds(self):
|
||||
from config import Config
|
||||
c = Config()
|
||||
# hammerdin config should have stand_still and show_items
|
||||
assert "stand_still" in c.char
|
||||
assert "show_items" in c.char
|
||||
38
test/test_death_manager.py
Normal file
38
test/test_death_manager.py
Normal file
@@ -0,0 +1,38 @@
|
||||
"""
|
||||
Tests for death_manager state management logic.
|
||||
|
||||
Covers: death flag, callback wiring, monitor state, reset.
|
||||
All testable without a real D2R client.
|
||||
"""
|
||||
import pytest
|
||||
from logger import Logger
|
||||
|
||||
|
||||
class TestDeathManager:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
from death_manager import DeathManager
|
||||
self.dm = DeathManager()
|
||||
|
||||
def test_died_defaults_false(self):
|
||||
assert self.dm.died() is False
|
||||
|
||||
def test_loop_delay(self):
|
||||
assert self.dm.get_loop_delay() == 0.5
|
||||
|
||||
def test_callback_set_and_stored(self):
|
||||
cb_called = []
|
||||
self.dm.set_callback(lambda: cb_called.append(1))
|
||||
assert self.dm._callback is not None
|
||||
self.dm._callback()
|
||||
assert cb_called == [1]
|
||||
|
||||
def test_stop_monitor(self):
|
||||
self.dm.stop_monitor()
|
||||
assert self.dm._do_monitor is False
|
||||
|
||||
def test_reset_death_flag(self):
|
||||
self.dm._died = True
|
||||
self.dm.reset_death_flag()
|
||||
assert self.dm.died() is False
|
||||
44
test/test_game_controller.py
Normal file
44
test/test_game_controller.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""
|
||||
Tests for game_controller initialization and state.
|
||||
|
||||
Covers: GameController creates Bot, DeathManager, HealthManager, GameRecovery.
|
||||
Tests the wiring between components without needing a real D2R client.
|
||||
"""
|
||||
import pytest
|
||||
from logger import Logger
|
||||
|
||||
|
||||
class TestGameController:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
# Reset singletons
|
||||
import config
|
||||
if hasattr(config, '_instance'):
|
||||
config._instance = None
|
||||
from health_manager import HealthManager
|
||||
HealthManager._instance = None
|
||||
|
||||
def test_gamecontroller_creates_components(self):
|
||||
from game_controller import GameController
|
||||
gc = GameController()
|
||||
assert gc.game_stats is not None
|
||||
assert gc.is_running is False
|
||||
|
||||
def test_gamecontroller_creates_death_manager(self):
|
||||
from game_controller import GameController
|
||||
gc = GameController()
|
||||
gc.start()
|
||||
assert gc.death_manager is not None
|
||||
|
||||
def test_gamecontroller_creates_health_manager(self):
|
||||
from game_controller import GameController
|
||||
gc = GameController()
|
||||
gc.start()
|
||||
assert gc.health_manager is not None
|
||||
|
||||
def test_gamecontroller_creates_game_recovery(self):
|
||||
from game_controller import GameController
|
||||
gc = GameController()
|
||||
gc.start()
|
||||
assert gc.game_recovery is not None
|
||||
20
test/test_game_recovery.py
Normal file
20
test/test_game_recovery.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
Tests for game_recovery.
|
||||
|
||||
Covers: GameRecovery constructor and death_manager reference.
|
||||
"""
|
||||
import pytest
|
||||
from logger import Logger
|
||||
|
||||
|
||||
class TestGameRecovery:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
|
||||
def test_recovery_holds_death_manager_ref(self):
|
||||
from death_manager import DeathManager
|
||||
from game_recovery import GameRecovery
|
||||
dm = DeathManager()
|
||||
gr = GameRecovery(dm)
|
||||
assert gr._death_manager is dm
|
||||
55
test/test_health_manager.py
Normal file
55
test/test_health_manager.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Tests for health_manager state management logic.
|
||||
|
||||
Covers: pause state, panel check paused, chicken flag, callback wiring.
|
||||
These are all testable without a real D2R client — they're just state machines.
|
||||
"""
|
||||
import pytest
|
||||
from logger import Logger
|
||||
|
||||
|
||||
class TestHealthManager:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
from health_manager import HealthManager
|
||||
self.HM = HealthManager
|
||||
self.hm = HealthManager()
|
||||
|
||||
def test_pause_state_defaults_to_true(self):
|
||||
assert self.hm.get_pause_state() is True
|
||||
|
||||
def test_set_pause_state_changes(self):
|
||||
self.hm.set_pause_state(False)
|
||||
assert self.hm.get_pause_state() is False
|
||||
self.hm.set_pause_state(True)
|
||||
assert self.hm.get_pause_state() is True
|
||||
|
||||
def test_panel_check_paused_defaults_to_false(self):
|
||||
assert self.hm.get_panel_check_paused() is False
|
||||
|
||||
def test_set_panel_check_paused_changes(self):
|
||||
self.hm.set_panel_check_paused(True)
|
||||
assert self.hm.get_panel_check_paused() is True
|
||||
self.hm.set_panel_check_paused(False)
|
||||
assert self.hm.get_panel_check_paused() is False
|
||||
|
||||
def test_chicken_flag_defaults_false(self):
|
||||
assert self.hm.did_chicken() is False
|
||||
|
||||
def test_callback_set_and_stored(self):
|
||||
cb_called = []
|
||||
self.hm.set_callback(lambda: cb_called.append(1))
|
||||
assert self.hm._callback is not None
|
||||
self.hm._callback()
|
||||
assert cb_called == [1]
|
||||
|
||||
def test_stop_monitor_sets_flag(self):
|
||||
self.hm.stop_monitor()
|
||||
assert self.hm._do_monitor is False
|
||||
|
||||
def test_reset_chicken_flag(self):
|
||||
self.hm._did_chicken = True
|
||||
self.hm.reset_chicken_flag()
|
||||
assert self.hm.did_chicken() is False
|
||||
assert self.hm.get_pause_state() is True
|
||||
26
test/test_inventory_belt.py
Normal file
26
test/test_inventory_belt.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""
|
||||
Tests for inventory.belt logic.
|
||||
|
||||
Covers: potion type detection, belt toggle keys.
|
||||
"""
|
||||
import pytest
|
||||
import numpy as np
|
||||
from logger import Logger
|
||||
|
||||
|
||||
class TestInventoryBelt:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
|
||||
def test_belt_toggle_keys_returns_list(self):
|
||||
from inventory.belt import _belt_toggle_keys
|
||||
keys = _belt_toggle_keys()
|
||||
assert isinstance(keys, list)
|
||||
assert len(keys) > 0
|
||||
|
||||
def test_cut_potion_img_returns_array(self):
|
||||
from inventory.belt import _cut_potion_img
|
||||
img = np.full((100, 100, 3), 255, dtype=np.uint8)
|
||||
result = _cut_potion_img(img, 0, 0)
|
||||
assert isinstance(result, np.ndarray)
|
||||
24
test/test_item_pickit.py
Normal file
24
test/test_item_pickit.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Tests for item.pickit PickedUpResult enum and basic logic.
|
||||
|
||||
Covers: the result enum values and the pickit import chain.
|
||||
"""
|
||||
import pytest
|
||||
from logger import Logger
|
||||
|
||||
|
||||
class TestPickit:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
|
||||
def test_pickedupresult_enum_values(self):
|
||||
from item.pickit import PickedUpResult
|
||||
assert PickedUpResult.TeleportedTo.value == 0
|
||||
assert PickedUpResult.PickedUp.value == 1
|
||||
assert PickedUpResult.PickedUpFailed.value == 2
|
||||
|
||||
def test_pickit_imports_without_error(self):
|
||||
# This verifies the full import chain: pickit -> bnip -> d2r_image -> config
|
||||
from item.pickit import PickedUpResult
|
||||
assert PickedUpResult is not None
|
||||
41
test/test_ui_meters.py
Normal file
41
test/test_ui_meters.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""
|
||||
Tests for ui.meters — health/mana/merc health reading.
|
||||
|
||||
These test the math: given a known image, the percentage should be deterministic.
|
||||
"""
|
||||
import pytest
|
||||
import numpy as np
|
||||
import cv2
|
||||
from logger import Logger
|
||||
from config import Config
|
||||
|
||||
|
||||
class TestMeters:
|
||||
def setup_method(self):
|
||||
Logger.init()
|
||||
Logger.remove_file_logger()
|
||||
|
||||
def test_get_health_returns_value_between_0_and_1(self):
|
||||
from ui.meters import get_health
|
||||
# All-white image — no red/green pixels, so health = 0
|
||||
img = np.full((720, 1280, 3), 255, dtype=np.uint8)
|
||||
result = get_health(img)
|
||||
assert 0.0 <= result <= 1.0
|
||||
|
||||
def test_get_mana_returns_value_between_0_and_1(self):
|
||||
from ui.meters import get_mana
|
||||
img = np.full((720, 1280, 3), 255, dtype=np.uint8)
|
||||
result = get_mana(img)
|
||||
assert 0.0 <= result <= 1.0
|
||||
|
||||
def test_get_merc_health_returns_value_between_0_and_1(self):
|
||||
from ui.meters import get_merc_health
|
||||
img = np.full((720, 1280, 3), 255, dtype=np.uint8)
|
||||
result = get_merc_health(img)
|
||||
assert 0.0 <= result <= 1.0
|
||||
|
||||
def test_get_merc_health_black_image_is_zero(self):
|
||||
from ui.meters import get_merc_health
|
||||
img = np.zeros((720, 1280, 3), dtype=np.uint8)
|
||||
result = get_merc_health(img)
|
||||
assert result == 0.0
|
||||
Reference in New Issue
Block a user