Skip to content
This repository has been archived by the owner on Jan 25, 2024. It is now read-only.

Create a Button Component #57

Merged
merged 12 commits into from Feb 12, 2019
3 changes: 2 additions & 1 deletion j5/components/__init__.py
@@ -1,6 +1,7 @@
"""This module contains components, which are the smallest logical element of hardware."""

from .base import Component
from .button import Button, ButtonInterface
from .led import LED, LEDInterface

__all__ = ["Component", "LED", "LEDInterface"]
__all__ = ["Component", "Button", "ButtonInterface", "LED", "LEDInterface"]
43 changes: 43 additions & 0 deletions j5/components/button.py
@@ -0,0 +1,43 @@
"""Classes for Button."""

from abc import ABCMeta, abstractmethod

from j5.boards import Board
from j5.components import Component


class ButtonInterface(metaclass=ABCMeta):
"""An interface containing the methods required for a button."""

@abstractmethod
def get_button_state(self, board: Board, identifier: int) -> bool:
"""Set the state of a button."""
raise NotImplementedError # pragma: no cover

@abstractmethod
def wait_until_button_pressed(self, board: Board, identifier: int) -> bool:
"""Halt the program until this button is pushed."""
raise NotImplementedError # pragma: no cover


class Button(Component):
"""A button."""

def __init__(self, identifier: int, board: Board, backend: ButtonInterface) -> None:
self._board = board
self._backend = backend
self._identifier = identifier

@staticmethod
def interface_class():
"""Get the interface class that is required to use this component."""
return ButtonInterface

@property
def is_pressed(self) -> bool:
"""Get the current pushed state of the button."""
return self._backend.get_button_state(self._board, self._identifier)

def wait_until_button_pressed(self):
kierdavis marked this conversation as resolved.
Show resolved Hide resolved
"""Halt the program until this button is pushed."""
self._backend.wait_until_button_pressed(self._board, self._identifier)
81 changes: 81 additions & 0 deletions tests/components/test_button.py
@@ -0,0 +1,81 @@
"""Tests for the Button Classes."""
from time import sleep, time
from typing import List, Type

from j5.backends import Backend
from j5.boards import Board
from j5.components.button import Button, ButtonInterface


class MockButtonDriver(ButtonInterface):
"""A testing driver for the button component."""

def get_button_state(self, board: Board, identifier: int) -> bool:
"""Get the state of the button."""
return False # Never pushed.

def wait_until_button_pressed(self, board: Board, identifier: int) -> bool:
"""Wait until the button was pressed."""
sleep(0.2) # The mock driver always presses the button after 0.2s


class MockButtonBoard(Board):
"""A testing board for the button."""

@property
def name(self) -> str:
"""The name of this board."""
return "Testing Button Board"

@property
def serial(self) -> str:
"""The serial number of this board."""
return "SERIAL"

def make_safe(self):
"""Make this board safe."""
pass

@staticmethod
def supported_components() -> List[Type['Component']]:
trickeydan marked this conversation as resolved.
Show resolved Hide resolved
"""List the types of component that this Board supports."""
return [Button]

@staticmethod
def discover(backend: Backend) -> List['Board']:
"""Detect all of the boards on a given backend."""
return []


def test_button_interface_implementation():
"""Test that we can implement the button interface."""
MockButtonDriver()


def test_button_instantiation():
"""Test that we can instantiate a button."""
Button(0, MockButtonBoard(), MockButtonDriver())


def test_button_state():
"""Test that we can get the state of the button."""
button = Button(0, MockButtonBoard(), MockButtonDriver())

assert not button.is_pressed
trickeydan marked this conversation as resolved.
Show resolved Hide resolved


def test_button_wait_until_pressed():
"""Test that the button takes at 0.2 secs to be pressed."""
trickeydan marked this conversation as resolved.
Show resolved Hide resolved
button = Button(0, MockButtonBoard(), MockButtonDriver())
start_time = time()
button.wait_until_button_pressed()
end_time = time()
time_taken = end_time - start_time

assert time_taken > 0.2
assert time_taken < 2


def test_button_interface_class():
"""Test that the Button Interface class is a ButtonInterface."""
assert Button.interface_class() == ButtonInterface
trickeydan marked this conversation as resolved.
Show resolved Hide resolved