Files
HeurAMS/tests/test_electron.py
2026-04-25 01:36:52 +08:00

151 lines
4.7 KiB
Python

"""Tests for heurams.kernel.particles.electron.Electron"""
from copy import deepcopy
import pytest
from heurams.kernel.algorithms import algorithms
from heurams.kernel.particles.electron import Electron
from heurams.services import timer
class TestElectronInit:
def test_default_algo_is_sm2(self, timer_context):
e = Electron("test-id", {})
assert e.algoname == "SM-2"
assert e.ident == "test-id"
def test_specific_algo(self, timer_context):
e = Electron("test-id", {}, algo_name="NSP-0")
assert e.algoname == "NSP-0"
def test_integrity_check_fills_defaults(self, timer_context):
e = Electron("test-id", {})
assert "SM-2" in e.algodata
assert e.algodata["SM-2"]["efactor"] == 2.5
def test_existing_data_preserved(self, timer_context):
data = {"SM-2": {"efactor": 1.5, "rept": 3, "real_rept": 5, "interval": 10,
"last_date": 100, "next_date": 200, "is_activated": 1,
"last_modify": 1e9}}
e = Electron("test-id", data)
assert e.algodata["SM-2"]["efactor"] == 1.5
assert e.algodata["SM-2"]["rept"] == 3
class TestElectronActivation:
def test_activate_sets_flag(self, timer_context):
e = Electron("test-id", {})
assert e.is_activated() == 0
e.activate()
assert e.is_activated() == 1
def test_is_due_requires_activation(self, timer_context):
e = Electron("test-id", {})
e.algodata["SM-2"]["next_date"] = 0 # past
assert e.is_due() == 0 # not activated
e.activate()
assert e.is_due() == 1
def test_is_due_returns_false_when_not_due(self, timer_context):
e = Electron("test-id", {})
e.activate()
e.algodata["SM-2"]["next_date"] = 999999
assert e.is_due() is False
class TestElectronModify:
def test_modify_valid_key(self, timer_context):
e = Electron("test-id", {})
e.modify("efactor", 3.0)
assert e.algodata["SM-2"]["efactor"] == 3.0
def test_modify_invalid_key_raises(self, timer_context):
e = Electron("test-id", {})
with pytest.raises(AttributeError):
e.modify("nonexistent", 42)
class TestElectronRevisor:
def test_revisor_delegates_to_algo(self, timer_context):
e = Electron("test-id", {})
e.activate()
e.algodata["SM-2"]["next_date"] = 0
assert e.is_due() == 1
e.revisor(quality=5)
# After good review, interval > 0
assert e.algodata["SM-2"]["interval"] >= 1
def test_revisor_nsp0(self, timer_context):
e = Electron("test-id", {}, algo_name="NSP-0")
e.activate()
e.algodata["NSP-0"]["next_date"] = 0
assert e.is_due() == 1
e.revisor(quality=3) # bad feedback
assert e.algodata["NSP-0"]["interval"] == 1
class TestElectronProperties:
def test_rept(self, timer_context):
e = Electron("test-id", {})
assert e.rept() == 0
def test_rept_real(self, timer_context):
e = Electron("test-id", {})
assert e.rept(real_rept=True) == 0
def test_get_rating(self, timer_context):
e = Electron("test-id", {})
rating = e.get_rating()
assert isinstance(rating, str)
def test_nextdate_returns_int(self, timer_context):
e = Electron("test-id", {})
nd = e.nextdate()
assert isinstance(nd, int)
def test_hash(self, timer_context):
e = Electron("test-id", {})
assert hash(e) == hash("test-id")
def test_len(self, timer_context):
e = Electron("test-id", {})
assert len(e) == len(algorithms["SM-2"].defaults)
class TestElectronGetSetItem:
def test_getitem_ident(self, timer_context):
e = Electron("test-id", {})
assert e["ident"] == "test-id"
def test_getitem_algo_key(self, timer_context):
e = Electron("test-id", {})
assert e["efactor"] == 2.5
def test_getitem_missing_key_raises(self, timer_context):
e = Electron("test-id", {})
with pytest.raises(KeyError):
_ = e["nonexistent"]
def test_setitem_valid_key(self, timer_context):
e = Electron("test-id", {})
e["efactor"] = 3.5
assert e["efactor"] == 3.5
def test_setitem_ident_raises(self, timer_context):
e = Electron("test-id", {})
with pytest.raises(AttributeError):
e["ident"] = "new-id"
class TestElectronFromData:
def test_from_data_creates_electron(self, timer_context):
data = {"SM-2": {}}
e = Electron.from_data(("my-ident", data), algo_name="SM-2")
assert e.ident == "my-ident"
assert e.algoname == "SM-2"
assert "SM-2" in e.algodata