Add tests/test_utils_pyepics.py
Run CI Tests / test (push) Successful in 1m2s

This commit is contained in:
2025-08-10 23:56:33 +02:00
parent 7d58072afa
commit 43804d37f4
+187
View File
@@ -0,0 +1,187 @@
import pytest
import time
import threading
from morbidissimo import MorIOC
from slic.utils.hastyepics import get_pv as PV
from your_module import EnumWrapper, MonitorAccumulator, Positioner, EpicsString
# ------------------------------------------------------------------------------
# Fixture IOC avec PVs pour tous les cas de test
# ------------------------------------------------------------------------------
@pytest.fixture(scope="module", autouse=True)
def run_test_ioc():
stop = threading.Event()
def ioc():
with MorIOC("TEST") as mor:
mor.serve(
# Pour EnumWrapper
TEST_ENUM_FULL=["OFF", "ON", "STANDBY", "FAULT"],
TEST_ENUM_EMPTY=[],
TEST_ENUM_INT=0,
# Pour MonitorAccumulator
TEST_ANALOG=0.0,
# Pour EpicsString
TEST_STRING="init",
TEST_STRING_BINARY=b"binary",
# Pour tests avancés
TEST_SPECIAL_CHARS="a.b c@d"
)
while not stop.is_set():
time.sleep(0.1)
t = threading.Thread(target=ioc)
t.start()
time.sleep(2)
yield
stop.set()
t.join()
# ------------------------------------------------------------------------------
# Tests EnumWrapper avec couverture 100% de .set()
# ------------------------------------------------------------------------------
def test_enum_wrapper_set_coverage(capsys):
"""Test exhaustif de EnumWrapper.set() avec sorties print"""
enum_full = EnumWrapper("TEST_ENUM_FULL")
enum_empty = EnumWrapper("TEST_ENUM_EMPTY")
enum_int = EnumWrapper("TEST_ENUM_INT")
# Cas 1: Set avec string valide
print("\n=== Test set(str) valide ===")
enum_full.set("ON")
assert enum_full.get_name() == "ON"
out, _ = capsys.readouterr()
assert "ON" in out # Vérifie l'affichage
# Cas 2: Set avec index valide
print("\n=== Test set(int) valide ===")
enum_full.set(2)
assert enum_full.get_name() == "STANDBY"
out, _ = capsys.readouterr()
assert "STANDBY" in out
# Cas 3: Set avec string invalide
print("\n=== Test set(str) invalide ===")
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):
enum_full.set(-1)
# Cas 6: Enum vide
print("\n=== Test enum vide ===")
with pytest.raises(AssertionError):
enum_empty.set("ANY")
# Cas 7: Type non supporté
print("\n=== Test type invalide ===")
with pytest.raises(AssertionError):
enum_full.set(3.14) # Float non accepté
# ------------------------------------------------------------------------------
# Tests MonitorAccumulator avec couverture 100%
# ------------------------------------------------------------------------------
def test_monitor_accumulator_full_coverage(capsys):
"""Test exhaustif de MonitorAccumulator"""
pv = PV("TEST_ANALOG")
monitor = MonitorAccumulator(pv, attr="value", keywords=["value", "timestamp"])
# Cas 1: Accumulation normale
print("\n=== Test accumulation simple ===")
monitor.accumulate()
pv.put(42.0)
time.sleep(0.5)
assert len(monitor.values) > 0
assert monitor.values[-1][0] == pytest.approx(42.0)
# Cas 2: Cycle avec réinitialisation
print("\n=== Test cycle() ===")
data = monitor.cycle()
assert len(data) > 0
assert monitor.values == []
# 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%
# ------------------------------------------------------------------------------
def test_positioner_full_coverage(capsys):
"""Test exhaustif de Positioner"""
# Cas 1: Noms simples
print("\n=== Test noms simples ===")
pos = Positioner([("START", lambda: print("Started")),
("STOP", lambda: print("Stopped"))])
pos.START()
out, _ = capsys.readouterr()
assert "Started" in out
# Cas 2: Noms spéciaux
print("\n=== Test noms spéciaux ===")
pos_special = Positioner([
("1.2", lambda: print("Version")),
("a b", lambda: print("Espace")),
("@test", lambda: print("At"))
])
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%
# ------------------------------------------------------------------------------
def test_epics_string_full_coverage(capsys):
"""Test exhaustif de EpicsString"""
# Cas 1: String normale
print("\n=== Test string ASCII ===")
estr = EpicsString("TEST_STRING")
estr.set("new_value")
assert estr.get() == "new_value"
estr("updated")
assert str(estr) == "updated"
# Cas 2: Binary data
print("\n=== Test binary data ===")
estr_bin = EpicsString("TEST_STRING_BINARY")
assert isinstance(estr_bin.get(), str)
# 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()
# ------------------------------------------------------------------------------
# Exécution
# ------------------------------------------------------------------------------
if __name__ == "__main__":
pytest.main(["-v", "-s", "--cov=your_module", "--cov-report=term-missing"])