def test_environment_board_backend_mapping() -> None: """Test that the board_backend_mapping works.""" environment = Environment("MockEnv") environment.register_backend(MockBackend) assert type(environment.board_backend_mapping) == dict assert len(environment.supported_boards) == 1 assert environment.board_backend_mapping[MockBoard] == MockBackend
def test_environment_get_board_group() -> None: """Test that we can create a boardgroup from an environment.""" env = Environment("TestEnv") env.register_backend(MockBackend) bg = env.get_board_group(MockBoard) assert bg.backend_class is MockBackend
def test_get_boardgroup_from_environment() -> None: """Test that we can create a boardgroup from an environment.""" env = Environment("TestEnv") env.register_backend(OneBoardMockBackend) # See https://github.com/j5api/j5/issues/408 bg = MockBoard.get_board_group_from_environment(env) # type: ignore assert bg.backend_class is OneBoardMockBackend assert len(bg) == 1
def test_environment_merge_duplicate() -> None: """Test that the correct exception is thrown if duplicate entries exist.""" env1 = Environment("Env1") env2 = Environment("Env2") env1.register_backend(MockBackend) env2.register_backend(MockBackend) with pytest.raises(RuntimeError) as e: env1.merge(env2) assert e is not None assert str(e.value) == \ "Attempted to merge two Environments that both contain: MockBoard"
def test_environment_merge() -> None: """Test that we can merge environments.""" env1 = Environment("Env1") env2 = Environment("Env2") assert len(env1.supported_boards) == 0 assert len(env2.supported_boards) == 0 env1.merge(env2) assert len(env1.supported_boards) == 0 assert len(env2.supported_boards) == 0 env2.register_backend(MockBackend) assert len(env2.supported_boards) == 1 env1.merge(env2) assert len(env1.supported_boards) == 1 assert len(env2.supported_boards) == 1
def test_environment_check_multiple_backends_same_env() -> None: """Test that we can't define two backends for the same board/environment combo.""" test_environment = Environment("test_environment") class BackendOne(Backend): board = MockBoard @classmethod def discover(cls) -> Set[Board]: return set() @property def firmware_version(self) -> Optional[str]: return None class BackendTwo(Backend): board = MockBoard @classmethod def discover(cls) -> Set[Board]: return set() @property def firmware_version(self) -> Optional[str]: return None test_environment.register_backend(BackendOne) with pytest.raises(RuntimeError): test_environment.register_backend(BackendTwo)
def get_board_group_from_environment( cls: Type[T], environment: Environment, ) -> 'BoardGroup[T, U]': """ Get a board group from an environment. This method is on Board, rather than BoardGroup for typing purposes. """ backend = environment.get_backend(cls) # Cast is needed here as environment doesn't return a known type. return BoardGroup.get_board_group(cls, cast(Type[U], backend))
class OneBoardMockBackend(Backend): """This backend finds exactly one.""" environment = Environment("MockEnvironment") board = MockBoard def get_testing_boards(self): """Get the connected MockBoards.""" return [MockBoard("TESTSERIAL1")] def get_firmware_version(self, board: 'Board') -> Optional[str]: """Get the firmware version of the board.""" return None @classmethod def discover(cls) -> List[Board]: """Discover boards available on this backend.""" return []
class TwoBoardsMockBackend(Backend): """This backend finds exactly two.""" environment = Environment("MockEnvironment") board = MockBoard def get_testing_boards(self): """Get the connected MockBoards.""" # These serial numbers are deliberately in reverse lexiographic order, to ensure # that sorting the boards (as tested by # test_board_group_iteration_sorted_by_serial) actually has an effect. return [MockBoard("TESTSERIAL2"), MockBoard("TESTSERIAL1")] def get_firmware_version(self, board: 'Board') -> Optional[str]: """Get the firmware version of the board.""" return None @classmethod def discover(cls) -> List[Board]: """Discover boards available on this backend.""" return []
def test_environment_board_get_backend_unknown() -> None: """Test that we can't get the backend of an unknown board.""" environment = Environment("MockEnv") environment.register_backend(MockBackend) with pytest.raises(NotImplementedError): assert environment.get_backend(Mock2Board)
def test_environment_board_get_backend() -> None: """Test that we can get the backend of a board.""" environment = Environment("MockEnv") environment.register_backend(MockBackend) assert issubclass(environment.get_backend(MockBoard), MockBackend)
"""The hardware Environment.""" from j5.backends import Environment HardwareEnvironment = Environment("HardwareEnvironment")
def test_environment_supported_boards() -> None: """Test that we can get the supported boards for a environment.""" environment = Environment("MockEnv") environment.register_backend(MockBackend) assert type(environment.supported_boards) is set assert len(environment.supported_boards) == 1
"""Test the full stack.""" import socket import pytest from j5 import BaseRobot from j5.backends import Environment from j5.base_robot import UnableToObtainLock TestEnvironment = Environment("TestEnvironment") class Robot(BaseRobot): """A robot.""" def __init__(self): self._env = TestEnvironment def test_robot_lock(): """Test that we cannot have more than one Robot object.""" r1 = Robot() r1._obtain_lock() # Check we can re-obtain the lock on the same object. assert isinstance(r1._lock, socket.socket) assert r1._lock.getsockname()[1] == 10653 with pytest.raises(UnableToObtainLock): Robot()
SRV4MotorBoardConsoleBackend, SRV4PowerBoardConsoleBackend, ) from j5.backends.console.sr.v4.servo_board import SRV4ServoBoardConsoleBackend from j5.backends.hardware.sb.arduino import SBArduinoHardwareBackend from j5.backends.hardware.sr.v4 import ( SRV4MotorBoardHardwareBackend, SRV4PowerBoardHardwareBackend, SRV4ServoBoardHardwareBackend, ) __all__ = [ "HardwareEnvironment", ] HardwareEnvironment = Environment("Hardware Environment") HardwareEnvironment.register_backend( cast(Type[Backend], SRV4PowerBoardHardwareBackend)) HardwareEnvironment.register_backend( cast(Type[Backend], SRV4ServoBoardHardwareBackend)) HardwareEnvironment.register_backend( cast(Type[Backend], SRV4MotorBoardHardwareBackend)) HardwareEnvironment.register_backend( cast(Type[Backend], SBArduinoHardwareBackend)) ConsoleEnvironment = Environment("Console Environment") ConsoleEnvironment.register_backend( cast(Type[Backend], SRV4PowerBoardConsoleBackend)) ConsoleEnvironment.register_backend(
) from j5.backends.console.sr.v4.servo_board import SRV4ServoBoardConsoleBackend from j5.backends.hardware.sb.arduino import SBArduinoHardwareBackend from j5.backends.hardware.sr.v4 import ( SRV4MotorBoardHardwareBackend, SRV4PowerBoardHardwareBackend, SRV4ServoBoardHardwareBackend, ) from sbot.vision.backend import SBZolotoSingleHardwareBackend __all__ = [ "HardwareEnvironment", ] HardwareEnvironment = Environment("Hardware Environment") HardwareEnvironment.register_backend(SRV4PowerBoardHardwareBackend) HardwareEnvironment.register_backend(SRV4ServoBoardHardwareBackend) HardwareEnvironment.register_backend(SRV4MotorBoardHardwareBackend) HardwareEnvironment.register_backend(SBArduinoHardwareBackend) HardwareEnvironment.register_backend(SBZolotoSingleHardwareBackend) ConsoleEnvironment = Environment("Console Environment") ConsoleEnvironment.register_backend(SRV4PowerBoardConsoleBackend) ConsoleEnvironment.register_backend(SRV4ServoBoardConsoleBackend) ConsoleEnvironment.register_backend(SRV4MotorBoardConsoleBackend) ConsoleEnvironment.register_backend(SBArduinoConsoleBackend) CONSOLE_ENVIRONMENT_WITH_VISION = Environment(
from j5.boards.sr.v4 import PowerBoard, PowerOutputGroup, PowerOutputPosition from j5.components import ( LED, BatterySensor, BatterySensorInterface, Button, ButtonInterface, LEDInterface, Piezo, PiezoInterface, PowerOutput, PowerOutputInterface, ) from j5.components.piezo import Pitch MockEnvironment = Environment("MockEnvironment") class MockPowerBoardBackend( PowerOutputInterface, PiezoInterface, ButtonInterface, BatterySensorInterface, LEDInterface, Backend, ): """A mock power board backend implementation.""" environment = MockEnvironment board = PowerBoard
def firmware_version(self) -> Optional[str]: """Get the firmware version of this board.""" return self._backend.get_firmware_version(self) @staticmethod def supported_components(): """List the types of component supported by this Board.""" return [] @staticmethod def discover(backend: Backend): """Get all boards of this type.""" return [] MockEnvironment = Environment("TestBackendGroup") class MockBackend(Backend): """A test backend.""" environment = MockEnvironment board = MockBoard @classmethod def discover(cls) -> List[Board]: """Discover boards available on this backend.""" return [] def get_firmware_version(self, board: 'Board') -> Optional[str]: """Get the firmware version of the board."""