Fix real pin tests ... and some other bits

The real pin tests were broken by the new factory stuff. This commit
fixes them up, and fixes up a few other bits besides (like why the
pigpio PWM tests were failing, why RPi.GPIO sometimes segfaulted on PWM
tests, etc.)

It also causes the real pin tests to run against MockPin (thanks to
@lurch for the suggestion!). This required some tweaks to MockPin to
make it emulate physically pulled up pins itself (which in turn
necessitated changing quite a few pin numbers in the main test suite
because we were using 2 and 3 everywhere), and to allow one MockPin to
drive another. Anyway, everything's working now including all the tests
on a Pi (haven't tried RPIO yet, but only because I'm on a Pi3 -
everything else works with overall coverage of 88% :).
This commit is contained in:
Dave Jones
2016-10-22 22:28:33 +01:00
parent 4049ef5094
commit 2495939603
9 changed files with 265 additions and 159 deletions

View File

@@ -18,7 +18,13 @@ except ImportError:
import pkg_resources
from ..exc import PinPWMUnsupported, PinSetInput, PinFixedPull
from ..exc import (
PinPWMUnsupported,
PinSetInput,
PinFixedPull,
PinInvalidFunction,
PinInvalidPull,
)
from ..devices import Device
from .pi import PiPin
from .local import LocalPiFactory
@@ -34,8 +40,8 @@ class MockPin(PiPin):
def __init__(self, factory, number):
super(MockPin, self).__init__(factory, number)
self._function = 'input'
self._state = False
self._pull = 'floating'
self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating'
self._state = self._pull == 'up'
self._bounce = None
self._edges = 'both'
self._when_changed = None
@@ -49,7 +55,8 @@ class MockPin(PiPin):
return self._function
def _set_function(self, value):
assert value in ('input', 'output')
if value not in ('input', 'output'):
raise PinInvalidFunction('function must be input or output')
self._function = value
if value == 'input':
# Drive the input to the pull
@@ -85,8 +92,12 @@ class MockPin(PiPin):
return self._pull
def _set_pull(self, value):
assert self._function == 'input'
assert value in ('floating', 'up', 'down')
if self.function != 'input':
raise PinFixedPull('cannot set pull on non-input pin %r' % self)
if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]):
raise PinFixedPull('%r has a physical pull-up resistor' % self)
if value not in ('floating', 'up', 'down'):
raise PinInvalidPull('pull must be floating, up, or down')
self._pull = value
if value == 'up':
self.drive_high()
@@ -132,7 +143,12 @@ class MockPin(PiPin):
def assert_states(self, expected_states):
# Tests that the pin went through the expected states (a list of values)
for actual, expected in zip(self.states, expected_states):
assert actual.state == expected
try:
assert actual.state == expected
except AssertionError:
print('Actual states', self.states)
print('Expected states', expected_states)
raise
def assert_states_and_times(self, expected_states):
# Tests that the pin went through the expected states at the expected
@@ -140,8 +156,32 @@ class MockPin(PiPin):
# that's about all we can reasonably expect in a non-realtime
# environment on a Pi 1)
for actual, expected in zip(self.states, expected_states):
assert isclose(actual.timestamp, expected[0], rel_tol=0.05, abs_tol=0.05)
assert isclose(actual.state, expected[1])
try:
assert isclose(actual.timestamp, expected[0], rel_tol=0.05, abs_tol=0.05)
assert isclose(actual.state, expected[1])
except AssertionError:
print('Actual states', self.states)
print('Expected states', expected_states)
raise
class MockConnectedPin(MockPin):
"""
This derivative of :class:`MockPin` emulates a pin connected to another
mock pin. This is used in the "real pins" portion of the test suite to
check that one pin can influence another.
"""
def __init__(self, factory, number):
super(MockConnectedPin, self).__init__(factory, number)
self.input_pin = None
def _change_state(self, value):
if self.input_pin:
if value:
self.input_pin.drive_high()
else:
self.input_pin.drive_low()
return super(MockConnectedPin, self)._change_state(value)
class MockPulledUpPin(MockPin):

View File

@@ -236,6 +236,12 @@ class PiGPIOPin(PiPin):
def _set_frequency(self, value):
if not self._pwm and value is not None:
if self.function != 'output':
raise PinPWMFixedValue('cannot start PWM on pin %r' % self)
# NOTE: the pin's state *must* be set to zero; if it's currently
# high, starting PWM and setting a 0 duty-cycle *doesn't* bring
# the pin low; it stays high!
self.factory.connection.write(self.number, 0)
self.factory.connection.set_PWM_frequency(self.number, value)
self.factory.connection.set_PWM_range(self.number, 10000)
self.factory.connection.set_PWM_dutycycle(self.number, 0)