From 21d4fcc0ecd511e76f52d5aa67ca7697812753b5 Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Wed, 7 Aug 2024 04:08:10 -0700 Subject: [PATCH] add I2CScan operation (#13) --- circuitpython_mocks/_mixins.py | 2 ++ circuitpython_mocks/busio/__init__.py | 16 +++++++++++++--- circuitpython_mocks/busio/operations.py | 18 ++++++++++++++++++ docs/busio.rst | 1 + tests/test_i2c_fixture.py | 6 +++++- 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/circuitpython_mocks/_mixins.py b/circuitpython_mocks/_mixins.py index 714ad13..7e819ab 100644 --- a/circuitpython_mocks/_mixins.py +++ b/circuitpython_mocks/_mixins.py @@ -6,6 +6,7 @@ I2CRead, I2CWrite, I2CTransfer, + I2CScan, SPIRead, SPIWrite, SPITransfer, @@ -72,6 +73,7 @@ def __init__(self, **kwargs) -> None: I2CRead, I2CWrite, I2CTransfer, + I2CScan, SPIRead, SPIWrite, SPITransfer, diff --git a/circuitpython_mocks/busio/__init__.py b/circuitpython_mocks/busio/__init__.py index 059ba36..aa2cc0f 100644 --- a/circuitpython_mocks/busio/__init__.py +++ b/circuitpython_mocks/busio/__init__.py @@ -30,6 +30,7 @@ I2CRead, I2CWrite, I2CTransfer, + I2CScan, SPIRead, SPIWrite, SPITransfer, @@ -82,9 +83,18 @@ def __init__( super().__init__() def scan(self) -> List[int]: - """Returns an empty list. - Use :py:meth:`pytest.MonkeyPatch.setattr()` to change this output.""" - return [] + """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of + those that respond. + + .. mock-expects:: + + This function will check against `I2CScan` + :py:attr:`~circuitpython_mocks._mixins.Expecting.expectations`. + """ + assert self.expectations, "no expectation found for I2C.scan()" + op = self.expectations.popleft() + assert isinstance(op, I2CScan), f"I2CScan operation expected, found {repr(op)}" + return op.expected def readfrom_into( self, diff --git a/circuitpython_mocks/busio/operations.py b/circuitpython_mocks/busio/operations.py index a4588bd..23538f1 100644 --- a/circuitpython_mocks/busio/operations.py +++ b/circuitpython_mocks/busio/operations.py @@ -1,3 +1,4 @@ +from typing import List import sys import circuitpython_typing as cir_py_types @@ -140,6 +141,23 @@ def __repr__(self) -> str: ) +class I2CScan: + """A class to identify a scan operation over a + :py:class:`~circuitpython_mocks.busio.I2C` bus. + + The given ``expected`` value will be the result of `I2C.scan()`. + """ + + def __init__(self, expected: List[int]) -> None: + for val in expected: + assert val <= 0x7F, f"scan result {val} is not a valid I2C address" + self.expected = expected + + def __repr__(self) -> str: + stringify = ", ".join(["%02X" % x for x in self.expected]) + return f"" + + class SPIRead(_Read): """A class to identify a read operation over a :py:class:`~circuitpython_mocks.busio.SPI` bus.""" diff --git a/docs/busio.rst b/docs/busio.rst index b7401da..c04ef58 100644 --- a/docs/busio.rst +++ b/docs/busio.rst @@ -30,6 +30,7 @@ .. autoclass:: circuitpython_mocks.busio.operations.I2CRead .. autoclass:: circuitpython_mocks.busio.operations.I2CWrite .. autoclass:: circuitpython_mocks.busio.operations.I2CTransfer + .. autoclass:: circuitpython_mocks.busio.operations.I2CScan SPI operations ************** diff --git a/tests/test_i2c_fixture.py b/tests/test_i2c_fixture.py index 0847ce4..2b6280c 100644 --- a/tests/test_i2c_fixture.py +++ b/tests/test_i2c_fixture.py @@ -2,6 +2,7 @@ I2CRead, I2CWrite, I2CTransfer, + I2CScan, ) pytest_plugins = ["circuitpython_mocks.fixtures"] @@ -15,7 +16,10 @@ def test_i2c(mock_blinka_imports): address = 0x42 # do setup with I2C(board.SCL, board.SDA) as i2c_bus: - assert i2c_bus.scan() == [] + i2c_bus.expectations.append(I2CScan([address])) + assert i2c_bus.try_lock() + assert address in i2c_bus.scan() + i2c_bus.unlock() # set expectation for probing performed by I2CDevice.__init__() i2c_bus.expectations.append(I2CWrite(address, b""))