import pytest import asyncio import threading import time from contextlib import contextmanager from io import StringIO import colorama from slic.utils.pv import PV # The custom PV class to test # -------- caproto imports for the test IOC -------- from caproto.server import pvproperty, PVGroup, run # Create a simple IOC with one PV (TEST:VAL) class TestIOC(PVGroup): val = pvproperty(value=0.0, units='units') def __init__(self, prefix, **kwargs): super().__init__(prefix=prefix, **kwargs) # Run the IOC in a background thread (shared across module) @pytest.fixture(scope="module", autouse=True) def run_test_ioc(): prefix = "TEST:" ioc = TestIOC(prefix=prefix) # Define async loop to serve IOC def start_ioc(): asyncio.run(run(ioc.pvdb, startup_hook=None)) thread = threading.Thread(target=start_ioc, daemon=True) thread.start() # Wait a moment to ensure IOC is ready before test starts time.sleep(1.5) # Nothing to yield; test can now run yield # Helper to capture stdout output @pytest.fixture def capture_stdout(monkeypatch): buf = StringIO() monkeypatch.setattr("sys.stdout", buf) return buf @pytest.mark.parametrize("value, expected_bar, expected_color", [ (25.0, "██▌ ", colorama.Fore.GREEN), (50.0, "█████ ", colorama.Fore.GREEN), (75.0, "███████▌ ", colorama.Fore.GREEN), (100.0, "██████████", colorama.Fore.GREEN), (150.0, ">>>>>>>>>>", colorama.Fore.RED), (-50.0, "<<<<<<<<<<", colorama.Fore.RED) ]) def test_put_with_progress_and_repr(capture_stdout, value, expected_bar, expected_color): # Connect to the test PV using the custom slic PV class pv = PV("TEST:VAL") pv.wait_for_connection(timeout=2.0) assert pv.connected # Set initial value to 0.0 pv.put(0.0, wait=True) for _ in range(20): # max 2 sec val = pv.get() if val is not None: break time.sleep(0.1) assert val is not None, "PV did not return a value" assert pv.get() == 0.0 # Call put() with progress enabled pv.put(value, show_progress=True) # Get printed output from RangeBar output = capture_stdout.getvalue() # Check progress bar content and color assert f"|{expected_bar}|" in output assert expected_color in output assert str(value) in output # Verify PV value was correctly updated assert pv.get() == pytest.approx(value) # Check repr expected_repr = f'PV "TEST:VAL" at {value} units' assert repr(pv) == expected_repr assert pv.orig_repr().startswith('