Update tests/test_utils_pyepics.py
Run CI Tests / test (push) Successful in 1m11s

This commit is contained in:
2025-08-11 00:24:29 +02:00
parent bcef1a804f
commit 7bb1fbd14c
+82 -121
View File
@@ -3,179 +3,140 @@ import time
import threading import threading
from morbidissimo import MorIOC from morbidissimo import MorIOC
from slic.utils.hastyepics import get_pv as PV from slic.utils.hastyepics import get_pv as PV
from slic.utils.pyepics import * from slic.utils.pyepics import *
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Fixture IOC avec PVs pour tous les cas de test # Fixture IOC
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@pytest.fixture(scope="module", autouse=True) @pytest.fixture(scope="module", autouse=True)
def run_test_ioc(): def epics_ioc():
stop = threading.Event() stop = threading.Event()
def ioc(): def ioc():
with MorIOC("TEST") as mor: with MorIOC("TEST") as mor:
mor.serve( mor.serve(
# Pour EnumWrapper TEST_ENUM=["OFF", "ON", "STANDBY"],
TEST_ENUM_FULL=["OFF", "ON", "STANDBY", "FAULT"],
TEST_ENUM_EMPTY=[],
TEST_ENUM_INT=0,
# Pour MonitorAccumulator
TEST_ANALOG=0.0, TEST_ANALOG=0.0,
TEST_STRING="default",
# Pour EpicsString TEST_SPECIAL="a.b c@d"
TEST_STRING="init",
TEST_STRING_BINARY=b"binary",
# Pour tests avancés
TEST_SPECIAL_CHARS="a.b c@d"
) )
while not stop.is_set(): while not stop.is_set():
time.sleep(0.1) time.sleep(0.1)
t = threading.Thread(target=ioc) t = threading.Thread(target=ioc)
t.start() t.start()
time.sleep(2) time.sleep(2) # Attente connexion
yield yield
stop.set() stop.set()
t.join() t.join()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Tests EnumWrapper avec couverture 100% de .set() # Tests EnumWrapper
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
def test_enum_wrapper_set_coverage(capsys): def test_enum_wrapper_initial_state():
"""Test exhaustif de EnumWrapper.set() avec sorties print""" enum = EnumWrapper("TEST_ENUM")
enum_full = EnumWrapper("TEST_ENUM_FULL") assert enum.get() == 0
enum_empty = EnumWrapper("TEST_ENUM_EMPTY") assert enum.get_name() == "OFF"
enum_int = EnumWrapper("TEST_ENUM_INT")
# Cas 1: Set avec string valide def test_enum_wrapper_set_valid_string():
print("\n=== Test set(str) valide ===") enum = EnumWrapper("TEST_ENUM")
enum_full.set("ON") enum.set("ON")
assert enum_full.get_name() == "ON" assert enum.get() == 1
out, _ = capsys.readouterr() assert enum.get_name() == "ON"
assert "ON" in out # Vérifie l'affichage
# Cas 2: Set avec index valide def test_enum_wrapper_set_valid_index():
print("\n=== Test set(int) valide ===") enum = EnumWrapper("TEST_ENUM")
enum_full.set(2) enum.set(2)
assert enum_full.get_name() == "STANDBY" assert enum.get_name() == "STANDBY"
out, _ = capsys.readouterr()
assert "STANDBY" in out
# Cas 3: Set avec string invalide def test_enum_wrapper_set_invalid_string_raises():
print("\n=== Test set(str) invalide ===") enum = EnumWrapper("TEST_ENUM")
with pytest.raises(AssertionError) as exc:
enum_full.set("INVALID")
assert "need to be one of" in str(exc.value)
out, _ = capsys.readouterr()
assert "INVALID" in out
# Cas 4: Set avec index invalide (trop grand)
print("\n=== Test set(int) hors limite ===")
with pytest.raises(AssertionError) as exc:
enum_full.set(10)
assert "positive" in str(exc.value)
# Cas 5: Set avec index négatif
print("\n=== Test set(int) négatif ===")
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
enum_full.set(-1) enum.set("INVALID")
# Cas 6: Enum vide def test_enum_wrapper_set_invalid_index_raises():
print("\n=== Test enum vide ===") enum = EnumWrapper("TEST_ENUM")
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
enum_empty.set("ANY") enum.set(10)
# Cas 7: Type non supporté def test_enum_wrapper_set_negative_index_raises():
print("\n=== Test type invalide ===") enum = EnumWrapper("TEST_ENUM")
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
enum_full.set(3.14) # Float non accepté enum.set(-1)
def test_enum_wrapper_setters_property():
enum = EnumWrapper("TEST_ENUM")
setters = enum.setters
setters.ON()
assert enum.get_name() == "ON"
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Tests MonitorAccumulator avec couverture 100% # Tests MonitorAccumulator
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
def test_monitor_accumulator_full_coverage(capsys): def test_monitor_accumulator_initial_state():
"""Test exhaustif de MonitorAccumulator"""
pv = PV("TEST_ANALOG") pv = PV("TEST_ANALOG")
monitor = MonitorAccumulator(pv, attr="value", keywords=["value", "timestamp"]) monitor = MonitorAccumulator(pv)
assert len(monitor.values) == 0
# Cas 1: Accumulation normale def test_monitor_accumulator_captures_values():
print("\n=== Test accumulation simple ===") pv = PV("TEST_ANALOG")
monitor = MonitorAccumulator(pv)
monitor.accumulate() monitor.accumulate()
pv.put(42.0) pv.put(42.0)
time.sleep(0.5) time.sleep(0.5)
assert len(monitor.values) > 0 assert len(monitor.values) > 0
assert monitor.values[-1][0] == pytest.approx(42.0) assert monitor.values[-1][0] == pytest.approx(42.0)
# Cas 2: Cycle avec réinitialisation def test_monitor_accumulator_cycle_clears_values():
print("\n=== Test cycle() ===") pv = PV("TEST_ANALOG")
monitor = MonitorAccumulator(pv)
monitor.accumulate()
pv.put(42.0)
time.sleep(0.5)
data = monitor.cycle() data = monitor.cycle()
assert len(data) > 0 assert len(data) > 0
assert monitor.values == [] assert len(monitor.values) == 0
# Cas 3: Callback avec attribut spécifique
print("\n=== Test callback avec attr ===")
monitor_attr = MonitorAccumulator(pv, attr="precision")
monitor_attr.accumulate()
pv.put(99.9)
time.sleep(0.5)
monitor_attr.stop()
# Cas 4: Mots-clés personnalisés
print("\n=== Test keywords custom ===")
monitor_custom = MonitorAccumulator(pv, keywords=["severity"])
monitor_custom.accumulate()
pv.put(123.4)
time.sleep(0.5)
assert "severity" in str(monitor_custom.values)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Tests Positioner avec couverture 100% # Tests Positioner
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
def test_positioner_full_coverage(capsys): def test_positioner_creates_methods():
"""Test exhaustif de Positioner""" def mock_action():
# Cas 1: Noms simples return "executed"
print("\n=== Test noms simples ===")
pos = Positioner([("START", lambda: print("Started")), pos = Positioner([("TEST", mock_action)])
("STOP", lambda: print("Stopped"))]) assert pos.TEST() == "executed"
pos.START()
out, _ = capsys.readouterr()
assert "Started" in out
# Cas 2: Noms spéciaux def test_positioner_handles_special_chars():
print("\n=== Test noms spéciaux ===") def mock_action():
pos_special = Positioner([ return "ok"
("1.2", lambda: print("Version")),
("a b", lambda: print("Espace")), pos = Positioner([("1.2", mock_action), ("a b", mock_action)])
("@test", lambda: print("At")) assert pos.v1p2() == "ok"
]) assert pos.a_b() == "ok"
pos_special.v1p2()
pos_special.a_b()
pos_special._test()
out, _ = capsys.readouterr()
assert "Version" in out and "Espace" in out
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Tests EpicsString avec couverture 100% # Tests EpicsString
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
def test_epics_string_full_coverage(capsys): def test_epics_string_initial_value():
"""Test exhaustif de EpicsString""" estr = EpicsString("TEST_STRING")
# Cas 1: String normale assert estr.get() == "default"
print("\n=== Test string ASCII ===")
def test_epics_string_set_value():
estr = EpicsString("TEST_STRING") estr = EpicsString("TEST_STRING")
estr.set("new_value") estr.set("new_value")
assert estr.get() == "new_value" assert estr.get() == "new_value"
def test_epics_string_call_syntax():
estr = EpicsString("TEST_STRING")
estr("updated") estr("updated")
assert str(estr) == "updated" assert estr.get() == "updated"
# Cas 2: Binary data def test_epics_string_special_chars():
print("\n=== Test binary data ===") estr = EpicsString("TEST_SPECIAL")
estr_bin = EpicsString("TEST_STRING_BINARY") estr.set("test@value")
assert isinstance(estr_bin.get(), str) assert estr.get() == "test@value"
# Cas 3: Caractères spéciaux
print("\n=== Test caractères spéciaux ===")
estr_special = EpicsString("TEST_SPECIAL_CHARS")
estr_special.set("a@b.c d")
assert "d" in estr_special.get()