Files
python-gpiozero/tests/test_real_pins.py
Dave Jones ee3bd6b532 Fix #204 and start readying the release
Also re-numbers energenie sockets 1-4 (as noted by @bennuttall in
comments to #239), and adds several "real pins" tests and board tests.
The bad-PWM stuff is currently disabled as it causes segfaults when
running the tests and I can't seem to trace the cause at the moment.
Finally, I've tweaked the deb config to suggest gpiozero, removed spidev
as a mandatory dep (which'll fix installs on wheezy for py3), and
there's some more miscellaneous last-minute stuff here that I can't
recall...
2016-04-06 23:06:46 +01:00

178 lines
5.1 KiB
Python

from __future__ import (
unicode_literals,
absolute_import,
print_function,
division,
)
str = type('')
try:
range = xrange
except NameError:
pass
import io
import subprocess
import pytest
from gpiozero import PinFixedPull, PinInvalidPull, PinInvalidFunction
try:
from math import isclose
except ImportError:
from gpiozero.compat import isclose
# This module assumes you've wired the following GPIO pins together
TEST_PIN = 22
INPUT_PIN = 27
# Skip the entire module if we're not on a Pi
def is_a_pi():
with io.open('/proc/cpuinfo', 'r') as cpuinfo:
for line in cpuinfo:
if line.startswith('Hardware'):
hardware, colon, soc = line.strip().split(None, 2)
return soc in ('BCM2708', 'BCM2709', 'BCM2835', 'BCM2836')
else:
return False
pytestmark = pytest.mark.skipif(not is_a_pi(), reason='tests cannot run on non-Pi platforms')
del is_a_pi
# Try and import as many pin libraries as possible
PIN_CLASSES = []
try:
from gpiozero.pins.rpigpio import RPiGPIOPin
PIN_CLASSES.append(RPiGPIOPin)
except ImportError:
RPiGPIOPin = None
try:
from gpiozero.pins.rpio import RPIOPin
PIN_CLASSES.append(RPIOPin)
except ImportError:
RPIOPin = None
try:
from gpiozero.pins.pigpiod import PiGPIOPin
PIN_CLASSES.append(PiGPIOPin)
except ImportError:
PiGPIOPin = None
try:
from gpiozero.pins.native import NativePin
PIN_CLASSES.append(NativePin)
except ImportError:
NativePin = None
@pytest.fixture(scope='module', params=PIN_CLASSES)
def pin_class(request):
# pigpiod needs to be running for PiGPIOPin
if request.param.__name__ == 'PiGPIOPin':
subprocess.check_call(['sudo', 'pigpiod'])
# Unfortunately, pigpiod provides no option for running in the
# foreground, so we have to use the sledgehammer of killall to get shot
# of it
def kill_pigpiod():
subprocess.check_call(['sudo', 'killall', 'pigpiod'])
request.addfinalizer(kill_pigpiod)
return request.param
@pytest.fixture(scope='function')
def pins(request, pin_class):
# Why return both pins in a single fixture? If we defined one fixture for
# each pin then pytest will (correctly) test RPiGPIOPin(22) against
# NativePin(27) and so on. This isn't supported, so we don't test it
test_pin = pin_class(TEST_PIN)
input_pin = pin_class(INPUT_PIN)
input_pin.function = 'input'
input_pin.pull = 'down'
def fin():
test_pin.close()
input_pin.close()
request.addfinalizer(fin)
return test_pin, input_pin
def test_pin_numbers(pins):
test_pin, input_pin = pins
assert test_pin.number == TEST_PIN
assert input_pin.number == INPUT_PIN
def test_function_bad(pins):
test_pin, input_pin = pins
with pytest.raises(PinInvalidFunction):
test_pin.function = 'foo'
def test_output(pins):
test_pin, input_pin = pins
test_pin.function = 'output'
test_pin.state = 0
assert input_pin.state == 0
test_pin.state = 1
assert input_pin.state == 1
def test_output_with_state(pins):
test_pin, input_pin = pins
test_pin.output_with_state(0)
assert input_pin.state == 0
test_pin.output_with_state(1)
assert input_pin.state == 1
def test_pull(pins):
test_pin, input_pin = pins
test_pin.function = 'input'
test_pin.pull = 'up'
assert input_pin.state == 1
test_pin.pull = 'down'
test_pin, input_pin = pins
assert input_pin.state == 0
def test_pull_bad(pins):
test_pin, input_pin = pins
test_pin.function = 'input'
with pytest.raises(PinInvalidPull):
test_pin.pull = 'foo'
with pytest.raises(PinInvalidPull):
test_pin.input_with_pull('foo')
def test_pull_down_warning(pin_class):
# XXX This assumes we're on a vaguely modern Pi and not a compute module
# Might want to refine this with the pi-info database
pin = pin_class(2)
try:
with pytest.raises(PinFixedPull):
pin.pull = 'down'
with pytest.raises(PinFixedPull):
pin.input_with_pull('down')
finally:
pin.close()
def test_input_with_pull(pins):
test_pin, input_pin = pins
test_pin.input_with_pull('up')
assert input_pin.state == 1
test_pin.input_with_pull('down')
assert input_pin.state == 0
@pytest.mark.skipif(True, reason='causes segfaults')
def test_bad_duty_cycle(pins):
test_pin, input_pin = pins
if test_pin.__class__.__name__ == 'NativePin':
pytest.skip("native pin doesn't support PWM")
test_pin.function = 'output'
test_pin.frequency = 100
with pytest.raises(ValueError):
test_pin.state = 1.1
def test_duty_cycles(pins):
test_pin, input_pin = pins
if test_pin.__class__.__name__ == 'NativePin':
pytest.skip("native pin doesn't support PWM")
test_pin.function = 'output'
test_pin.frequency = 100
for duty_cycle in (0.0, 0.1, 0.5, 1.0):
test_pin.state = duty_cycle
assert test_pin.state == duty_cycle
total = sum(input_pin.state for i in range(20000))
assert isclose(total / 20000, duty_cycle, rel_tol=0.1, abs_tol=0.1)