From eb7ec0039f4be1fd22655ad6c7c3bb2bec491926 Mon Sep 17 00:00:00 2001 From: Sebastian Straub Date: Mon, 23 Sep 2024 19:45:23 +0200 Subject: [PATCH] make hardware emulation reversible fixes an issue that can be caused by side effects of certain tests --- src/raspi_poe_mon/mock.py | 31 ++++++++++++++++++++++++++----- src/raspi_poe_mon/poe_hat.py | 6 ++++-- tests/test_cli.py | 5 +++++ tests/test_mock.py | 9 +++++++++ 4 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 tests/test_mock.py diff --git a/src/raspi_poe_mon/mock.py b/src/raspi_poe_mon/mock.py index 4612b53..43c50b3 100644 --- a/src/raspi_poe_mon/mock.py +++ b/src/raspi_poe_mon/mock.py @@ -10,11 +10,32 @@ logger = logging.getLogger('raspi_poe_mon') -def monkeypatch(): - """monkeypatch all real hardware so the mock version is used instead. restart to undo""" - serial.i2c = MockFan - device.ssd1306 = MockDisplay - render.canvas = MockCanvas +class HardwarePatcher: + """allows to monkeypatch all real hardware so the mock versions are used instead""" + + real_i2c = serial.i2c + real_ssd1306 = device.ssd1306 + real_canvas = render.canvas + + @classmethod + def patch(cls): + serial.i2c = MockFan + device.ssd1306 = MockDisplay + render.canvas = MockCanvas + + @classmethod + def restore(cls): + serial.i2c = cls.real_i2c + device.ssd1306 = cls.real_ssd1306 + render.canvas = cls.real_canvas + + @classmethod + def is_real(cls) -> bool: + return ( + serial.i2c == cls.real_i2c + and device.ssd1306 == cls.real_ssd1306 + and render.canvas == cls.real_canvas + ) class MockDisplay: diff --git a/src/raspi_poe_mon/poe_hat.py b/src/raspi_poe_mon/poe_hat.py index 19adbbf..487ec7d 100644 --- a/src/raspi_poe_mon/poe_hat.py +++ b/src/raspi_poe_mon/poe_hat.py @@ -6,7 +6,7 @@ from luma.oled import device from PIL.ImageDraw import ImageDraw -from raspi_poe_mon import mock +from raspi_poe_mon.mock import HardwarePatcher class PoeHat: @@ -25,7 +25,7 @@ def __init__(self, dry_run=False, brightness=100) -> None: self.display: Optional[device.ssd1306] = None self.fan_state = False if self.dry_run: - mock.monkeypatch() + HardwarePatcher.patch() def fan_connect(self, force=False): if force or self.i2c_fan is None: @@ -69,3 +69,5 @@ def draw(self) -> ImageDraw: def cleanup(self): self.fan_off() self.display_clear() + if self.dry_run: + HardwarePatcher.restore() diff --git a/tests/test_cli.py b/tests/test_cli.py index 7b3a755..8ded019 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,6 +4,7 @@ from raspi_poe_mon import main from raspi_poe_mon.main import app +from raspi_poe_mon.mock import HardwarePatcher from raspi_poe_mon.version import __version__ runner = CliRunner() @@ -43,9 +44,13 @@ def validate_help(result: Result, contains: str): @pytest.mark.timeout(2) def test_dry_run(): + assert HardwarePatcher.is_real() main.run(dry_run=True, verbose=True, frame_time=0.02, timeout=0.05) + assert HardwarePatcher.is_real() @pytest.mark.timeout(2) def test_profiling(): + assert HardwarePatcher.is_real() main.run(dry_run=True, profiling=True, frame_time=0.05, timeout=0.1) + assert HardwarePatcher.is_real() diff --git a/tests/test_mock.py b/tests/test_mock.py new file mode 100644 index 0000000..af38b8c --- /dev/null +++ b/tests/test_mock.py @@ -0,0 +1,9 @@ +from raspi_poe_mon.mock import HardwarePatcher + + +def test_hardware_patcher(): + assert HardwarePatcher.is_real() is True + HardwarePatcher.patch() + assert HardwarePatcher.is_real() is False + HardwarePatcher.restore() + assert HardwarePatcher.is_real() is True