import json from pathlib import Path from typing import Any from pytest import LogCaptureFixture import pydase import pydase.units as u from pydase.data_service.state_manager import StateManager class Service(pydase.DataService): def __init__(self, **kwargs: Any) -> None: self.some_unit: u.Quantity = 1.2 * u.units.A self.some_float = 1.0 self._name = "Service" super().__init__(**kwargs) @property def name(self) -> str: return self._name CURRENT_STATE = { "name": { "type": "str", "value": "Service", "readonly": True, "doc": None, }, "some_float": { "type": "float", "value": 1.0, "readonly": False, "doc": None, }, "some_unit": { "type": "Quantity", "value": {"magnitude": 1.2, "unit": "A"}, "readonly": False, "doc": None, }, } LOAD_STATE = { "name": { "type": "str", "value": "Service", "readonly": True, "doc": None, }, "some_float": { "type": "int", "value": 1, "readonly": False, "doc": None, }, "some_unit": { "type": "Quantity", "value": {"magnitude": 12.0, "unit": "A"}, "readonly": False, "doc": None, }, } def test_save_state(tmp_path: Path): # Create a StateManager instance with a temporary file file = tmp_path / "test_state.json" manager = StateManager(service=Service(), filename=str(file)) # Trigger the saving action manager.save_state() # Now check that the file was written correctly assert file.read_text() == json.dumps(CURRENT_STATE, indent=4) def test_load_state(tmp_path: Path): # Create a StateManager instance with a temporary file file = tmp_path / "test_state.json" # Write a temporary JSON file to read back with open(file, "w") as f: json.dump(LOAD_STATE, f, indent=4) service = Service() manager = StateManager(service=service, filename=str(file)) manager.load_state() assert service.some_unit == u.Quantity(12, "A") def test_filename_warning(tmp_path: Path, caplog: LogCaptureFixture): file = tmp_path / "test_state.json" service = Service(filename=str(file)) StateManager(service=service, filename=str(file)) assert f"Overwriting filename {str(file)!r} with {str(file)!r}." in caplog.text def test_filename_error(caplog: LogCaptureFixture): service = Service() manager = StateManager(service=service) manager.save_state() assert ( "State manager was not initialised with a filename. Skipping 'save_state'..." in caplog.text ) def test_readonly_attribute(tmp_path: Path, caplog: LogCaptureFixture): # Create a StateManager instance with a temporary file file = tmp_path / "test_state.json" # Write a temporary JSON file to read back with open(file, "w") as f: json.dump(LOAD_STATE, f, indent=4) service = Service() manager = StateManager(service=service, filename=str(file)) manager.load_state() assert ( "Attribute 'name' is read-only. Ignoring value from JSON file..." in caplog.text ) def test_changed_type(tmp_path: Path, caplog: LogCaptureFixture): # Create a StateManager instance with a temporary file file = tmp_path / "test_state.json" # Write a temporary JSON file to read back with open(file, "w") as f: json.dump(LOAD_STATE, f, indent=4) service = Service() manager = StateManager(service=service, filename=str(file)) manager.load_state() assert ( "Attribute type of 'some_float' changed from 'int' to " "'float'. Ignoring value from JSON file..." ) in caplog.text