1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# -*- coding: utf-8 -*-
# Copyright (c) 2017-2022 Richard Hull and contributors
# See LICENSE.rst for details.
"""
Test helpers.
"""
import platform
from pathlib import Path
import pytest
from PIL import ImageChops, ImageFont
from unittest.mock import mock_open
rpi_gpio_missing = f'RPi.GPIO is not supported on this platform: {platform.system()}'
spidev_missing = f'spidev is not supported on this platform: {platform.system()}'
def get_reference_file(fname):
"""
Get absolute path for ``fname``.
:param fname: Filename.
:type fname: str or pathlib.Path
:rtype: str
"""
return str(Path(__file__).resolve().parent.joinpath('reference', fname))
def get_reference_image(fname):
"""
:param fname: Filename.
:type fname: str or pathlib.Path
"""
return get_reference_file(Path('images').joinpath(fname))
def get_reference_font(fname, fsize=12):
"""
:param fname: Filename of the font.
:type fname: str or pathlib.Path
"""
path = get_reference_file(Path('font').joinpath(fname))
return ImageFont.truetype(path, fsize)
def get_reference_pillow_font(fname):
"""
Load :py:class:`PIL.ImageFont` type font from provided fname
:param fname: The name of the file that contains the PIL.ImageFont
:type fname: str
:rtype: :py:class:`PIL.ImageFont`
"""
path = get_reference_file(Path('font').joinpath(fname))
return ImageFont.load(path)
# font used in (most) tests
#test_font = get_reference_pillow_font('courB08.pil')
def get_spidev():
try:
import spidev
return spidev
except ImportError:
pytest.skip(spidev_missing)
def assert_identical_image(reference, target, img_path):
"""
:param img_path: Location of image.
:type img_path: str
"""
bbox = ImageChops.difference(reference, target).getbbox()
#target.save(img_path)
assert bbox is None, f'{img_path} is not identical to generated image'
def i2c_error(path_name, err_no):
expected_error = OSError()
expected_error.errno = err_no
expected_error.filename = path_name
def fake_open(a, b):
raise expected_error
return fake_open
def fib(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# Attribution: https://gist.github.com/adammartinez271828/137ae25d0b817da2509c1a96ba37fc56
def multi_mock_open(*file_contents):
"""Create a mock "open" that will mock open multiple files in sequence
Args:
*file_contents ([str]): a list of file contents to be returned by open
Returns:
(MagicMock) a mock opener that will return the contents of the first
file when opened the first time, the second file when opened the
second time, etc.
"""
mock_files = [mock_open(read_data=content) for content in file_contents]
mock_opener = mock_files[-1]
mock_opener.side_effect = [mock_file.return_value for mock_file in mock_files]
return mock_opener
def skip_unsupported_platform(err):
pytest.skip(f'{type(err).__name__} ({str(err)})')
def _positional_args_list(mock):
return [call[0] for call in mock.call_args_list]
def assert_only_cleans_whats_setup(gpio):
setups = _positional_args_list(gpio.setup)
cleanups = _positional_args_list(gpio.cleanup)
for cleanup in cleanups:
assert len(cleanup) > 0, 'calling gpio.cleanup without specifying pins cleans all pins'
pins_set_up = {args[0] for args in setups}
pins_clean = {args[0] for args in setups}
assert pins_clean == pins_set_up, f"set pins {pins_set_up} but cleaned pins {pins_clean}"
|