Skip to content

Commit

Permalink
Level up tests, fix bugs and quirks
Browse files Browse the repository at this point in the history
  • Loading branch information
Gadgetoid committed Mar 10, 2020
1 parent 365bdd0 commit 1b648b3
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 42 deletions.
5 changes: 2 additions & 3 deletions library/inky/inky.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Inky e-Ink Display Driver."""
import sys
import time
import struct

Expand All @@ -8,7 +7,7 @@
try:
import numpy
except ImportError:
sys.exit('This library requires the numpy module\nInstall with: sudo apt install python-numpy')
raise ImportError('This library requires the numpy module\nInstall with: sudo apt install python-numpy')

WHITE = 0
BLACK = 1
Expand Down Expand Up @@ -204,7 +203,7 @@ def setup(self):
import RPi.GPIO as GPIO
self._gpio = GPIO
except ImportError:
sys.exit('This library requires the RPi.GPIO module\nInstall with: sudo apt install python-rpi.gpio')
raise ImportError('This library requires the RPi.GPIO module\nInstall with: sudo apt install python-rpi.gpio')
self._gpio.setmode(self._gpio.BCM)
self._gpio.setwarnings(False)
self._gpio.setup(self.dc_pin, self._gpio.OUT, initial=self._gpio.LOW, pull_up_down=self._gpio.PUD_OFF)
Expand Down
30 changes: 18 additions & 12 deletions library/inky/mock.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import sys
"""PIL/Tkinter based simulator for InkyWHAT and InkyWHAT."""
import numpy


from . import inky


class InkyMock(inky.Inky):
"""Base simulator class for Inky."""

def __init__(self, colour, h_flip=False, v_flip=False):
"""Initialise an Inky pHAT Display.
Expand All @@ -17,9 +18,13 @@ def __init__(self, colour, h_flip=False, v_flip=False):

try:
import tkinter
except ImportError:
raise ImportError('Simulation requires tkinter')

try:
from PIL import ImageTk, Image
except ImportError:
sys.exit('Simulation requires tkinter')
raise ImportError('Simulation requires PIL ImageTk and Image')

resolution = (self.WIDTH, self.HEIGHT)

Expand All @@ -30,6 +35,8 @@ def __init__(self, colour, h_flip=False, v_flip=False):
self.width, self.height = resolution
self.cols, self.rows, self.rotation = inky._RESOLUTION[resolution]

self.buf = numpy.zeros((self.height, self.width), dtype=numpy.uint8)

if colour not in ('red', 'black', 'yellow'):
raise ValueError('Colour {} is not supported!'.format(colour))

Expand All @@ -51,19 +58,20 @@ def __init__(self, colour, h_flip=False, v_flip=False):
# yellow color value: screen capture from
# https://www.thoughtsmakethings.com/Pimoroni-Inky-pHAT

self.c_palette = {"black": bw_inky_palette,
"red": red_inky_palette,
"yellow": ylw_inky_palette}
self.c_palette = {'black': bw_inky_palette,
'red': red_inky_palette,
'yellow': ylw_inky_palette}

self.tk_root = tkinter.Tk()
self.tk_root.title("Inky Preview")
self.tk_root.title('Inky Preview')
self.tk_root.geometry('{}x{}'.format(self.WIDTH, self.HEIGHT))
self.tk_root.aspect(self.WIDTH, self.HEIGHT, self.WIDTH, self.HEIGHT)
self.cv = None
self.cvh = self.HEIGHT
self.cvw = self.WIDTH

def resize(self, event):
"""Resize background image to window size."""
# adapted from:
# https://stackoverflow.com/questions/24061099/tkinter-resize-background-image-to-window-size
# https://stackoverflow.com/questions/19838972/how-to-update-an-image-on-a-canvas
Expand All @@ -82,7 +90,7 @@ def _simulate(self, region):
pass

def _display(self, region):
im = Image.fromarray(region, "P")
im = Image.fromarray(region, 'P')
im.putpalette(self.c_palette[self.colour])

self.disp_img_copy = im.copy() # can be changed due to window resizing, so copy
Expand All @@ -101,7 +109,7 @@ def show(self, busy_wait=True):
:param busy_wait: Ignored. Updates are simulated and instant.
"""
print(">> Simulating {} {}x{}...".format(self.colour, self.WIDTH, self.HEIGHT))
print('>> Simulating {} {}x{}...'.format(self.colour, self.WIDTH, self.HEIGHT))

region = self.buf

Expand All @@ -118,8 +126,7 @@ def show(self, busy_wait=True):


class InkyMockPHAT(InkyMock):

"""Inky wHAT e-Ink Display Driver."""
"""Inky wHAT e-Ink Display Simulator."""

WIDTH = 212
HEIGHT = 104
Expand All @@ -137,8 +144,7 @@ def _simulate(self, region):


class InkyMockWHAT(InkyMock):

"""Inky wHAT e-Ink Display Driver."""
"""Inky wHAT e-Ink Display Simulator."""

WIDTH = 400
HEIGHT = 300
Expand Down
60 changes: 60 additions & 0 deletions library/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""Test configuration.
These allow the mocking of various Python modules
that might otherwise have runtime side-effects.
"""
import sys
import mock
import pytest

from tools import MockSMBus


@pytest.fixture(scope='function', autouse=False)
def GPIO():
"""Mock RPi.GPIO module."""
GPIO = mock.MagicMock()
# Fudge for Python < 37 (possibly earlier)
sys.modules['RPi'] = mock.MagicMock()
sys.modules['RPi'].GPIO = GPIO
sys.modules['RPi.GPIO'] = GPIO
yield GPIO
del sys.modules['RPi']
del sys.modules['RPi.GPIO']


@pytest.fixture(scope='function', autouse=False)
def smbus2():
"""Mock smbus2 module."""
sys.modules['smbus2'] = mock.Mock()
sys.modules['smbus2'].SMBus = MockSMBus
yield MockSMBus
del sys.modules['smbus2']


@pytest.fixture(scope='function', autouse=False)
def spidev():
"""Mock spidev module."""
spidev = mock.MagicMock()
sys.modules['spidev'] = spidev
yield spidev
del sys.modules['spidev']


@pytest.fixture(scope='function', autouse=False)
def tkinter():
"""Mock tkinter module."""
tkinter = mock.MagicMock()
sys.modules['tkinter'] = tkinter
yield tkinter
del sys.modules['tkinter']


@pytest.fixture(scope='function', autouse=False)
def PIL():
"""Mock PIL module."""
PIL = mock.MagicMock()
sys.modules['PIL'] = PIL
yield PIL
del sys.modules['PIL']
44 changes: 18 additions & 26 deletions library/tests/test_init.py
Original file line number Diff line number Diff line change
@@ -1,67 +1,59 @@
"""Initialization tests for Inky."""
import sys
import mock
from tools import MockSMBus


def mockery():
"""Mock requires modules."""
sys.modules['RPi'] = mock.Mock()
sys.modules['RPi.GPIO'] = mock.Mock()
sys.modules['spidev'] = mock.Mock()
sys.modules['smbus2'] = mock.Mock()
sys.modules['smbus2'].SMBus = MockSMBus
def test_init_mock_phat_black(tkinter, PIL):
"""Test initialisation of InkyMockPHAT with 'black' colour choice."""
from inky import InkyMockPHAT

InkyMockPHAT('black')

def test_init_phat_black():
"""Test initialisation of InkyPHAT with 'black' colour choice."""
mockery()

def test_init_mock_what_black(tkinter, PIL):
"""Test initialisation of InkyMockWHAT with 'black' colour choice."""
from inky import InkyMockWHAT

InkyMockWHAT('black')


def test_init_phat_black(spidev, smbus2):
"""Test initialisation of InkyPHAT with 'black' colour choice."""
from inky import InkyPHAT

InkyPHAT('black')


def test_init_phat_red():
def test_init_phat_red(spidev, smbus2):
"""Test initialisation of InkyPHAT with 'red' colour choice."""
mockery()

from inky import InkyPHAT

InkyPHAT('red')


def test_init_phat_yellow():
def test_init_phat_yellow(spidev, smbus2):
"""Test initialisation of InkyPHAT with 'yellow' colour choice."""
mockery()

from inky import InkyPHAT

InkyPHAT('red')


def test_init_what_black():
def test_init_what_black(spidev, smbus2):
"""Test initialisation of InkyWHAT with 'black' colour choice."""
mockery()

from inky import InkyWHAT

InkyWHAT('black')


def test_init_what_red():
def test_init_what_red(spidev, smbus2):
"""Test initialisation of InkyWHAT with 'red' colour choice."""
mockery()

from inky import InkyWHAT

InkyWHAT('red')


def test_init_what_yellow():
def test_init_what_yellow(spidev, smbus2):
"""Test initialisation of InkyWHAT with 'yellow' colour choice."""
mockery()

from inky import InkyWHAT

InkyWHAT('red')
42 changes: 42 additions & 0 deletions library/tests/test_install_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Install helper tests for Inky.
These validate that, in case of a missing package, an ImportError is raised.
They don't actually validate that our special message is produced!
"""
import sys
import mock
import pytest


def test_mock_phat_no_tkinter():
"""Test initialisation of InkyMockPHAT without tkinter."""
from inky import InkyMockPHAT

with pytest.raises(ImportError):
InkyMockPHAT('black')


def test_mock_what_no_tkinter():
"""Test initialisation of InkyMockWHAT without tkinter."""
from inky import InkyMockWHAT

with pytest.raises(ImportError):
InkyMockWHAT('black')


def test_mock_phat_no_pil(tkinter):
"""Test initialisation of InkyMockPHAT without PIL."""
from inky import InkyMockPHAT

with pytest.raises(ImportError):
InkyMockPHAT('black')


def test_mock_what_no_pil(tkinter):
"""Test initialisation of InkyMockWHAT without PIL."""
from inky import InkyMockWHAT

with pytest.raises(ImportError):
InkyMockWHAT('black')
56 changes: 56 additions & 0 deletions library/tests/test_simulator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Install helper tests for Inky.
These validate that, in case of a missing package, an ImportError is raised.
They don't actually validate that our special message is produced!
"""
import sys
import mock
import pytest
from inky.mock import InkyMock, InkyMockPHAT, InkyMockWHAT


class InkyMockFAIL(InkyMock):
"""Inky wHAT e-Ink Display Simulator."""

WIDTH = 999
HEIGHT = 999

WHITE = 0
BLACK = 1
RED = 2
YELLOW = 2

def _simulate(self, region):
pass


def test_mock_invalid_size(tkinter, PIL):
"""Test a class with an invalid size raises a ValueError."""
with pytest.raises(ValueError):
InkyMockFAIL('black')


def test_mock_invalid_colour(tkinter, PIL):
"""Test that instantiating with an invalid colour raises a ValueError."""
with pytest.raises(ValueError):
InkyMockPHAT('octarine')


def test_mock_show_phat(tkinter, PIL):
"""Test that show doesn't explode."""
inky = InkyMockPHAT('red')
inky.show()


def test_mock_show_what(tkinter, PIL):
"""Test that show doesn't explode."""
inky = InkyMockWHAT('red')
inky.show()


def test_mock_show_180(tkinter, PIL):
"""Test that show doesn't explode."""
inky = InkyMockPHAT('red', h_flip=True, v_flip=True)
inky.show()
2 changes: 1 addition & 1 deletion library/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ skip_missing_interpreters = True
commands =
python setup.py develop --no-deps
coverage run -m py.test -v -r wsx
coverage report
coverage report -m
deps =
mock
pytest>=3.1
Expand Down

0 comments on commit 1b648b3

Please sign in to comment.