mirror of
				https://github.com/KevinMidboe/python-gpiozero.git
				synced 2025-10-29 17:50:37 +00:00 
			
		
		
		
	More work on the tests...
This commit is contained in:
		| @@ -19,6 +19,7 @@ from .exc import ( | |||||||
|     BadEventHandler, |     BadEventHandler, | ||||||
|     CompositeDeviceError, |     CompositeDeviceError, | ||||||
|     CompositeDeviceBadName, |     CompositeDeviceBadName, | ||||||
|  |     CompositeDeviceBadOrder, | ||||||
|     SPIError, |     SPIError, | ||||||
|     SPIBadArgs, |     SPIBadArgs, | ||||||
|     EnergenieSocketMissing, |     EnergenieSocketMissing, | ||||||
|   | |||||||
| @@ -49,5 +49,5 @@ def median(data): | |||||||
|         return data[n // 2] |         return data[n // 2] | ||||||
|     else: |     else: | ||||||
|         i = n // 2 |         i = n // 2 | ||||||
|         return (data[n - 1] + data[n]) / 2 |         return (data[i - 1] + data[i]) / 2 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,8 @@ from .mixins import ( | |||||||
|     ) |     ) | ||||||
| from .exc import ( | from .exc import ( | ||||||
|     DeviceClosed, |     DeviceClosed, | ||||||
|  |     CompositeDeviceBadName, | ||||||
|  |     CompositeDeviceBadOrder, | ||||||
|     GPIOPinMissing, |     GPIOPinMissing, | ||||||
|     GPIOPinInUse, |     GPIOPinInUse, | ||||||
|     GPIODeviceClosed, |     GPIODeviceClosed, | ||||||
| @@ -191,7 +193,7 @@ class GPIOBase(GPIOMeta(nstr('GPIOBase'), (), {})): | |||||||
|         method). Once a device is closed you can no longer use any other |         method). Once a device is closed you can no longer use any other | ||||||
|         methods or properties to control or query the device. |         methods or properties to control or query the device. | ||||||
|         """ |         """ | ||||||
|         return False |         raise NotImplementedError | ||||||
|  |  | ||||||
|     def _check_open(self): |     def _check_open(self): | ||||||
|         if self.closed: |         if self.closed: | ||||||
| @@ -223,7 +225,7 @@ class Device(ValuesMixin, GPIOBase): | |||||||
|         ranges (e.g. -1 to +1) and composite devices usually use tuples to |         ranges (e.g. -1 to +1) and composite devices usually use tuples to | ||||||
|         return the states of all their subordinate components. |         return the states of all their subordinate components. | ||||||
|         """ |         """ | ||||||
|         return 0 |         raise NotImplementedError | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def is_active(self): |     def is_active(self): | ||||||
| @@ -261,8 +263,8 @@ class CompositeDevice(Device): | |||||||
|         if self._order is None: |         if self._order is None: | ||||||
|             self._order = kwargs.keys() |             self._order = kwargs.keys() | ||||||
|         self._order = tuple(self._order) |         self._order = tuple(self._order) | ||||||
|         for missing_name in set(self._order) - set(kwargs.keys()): |         for missing_name in set(kwargs.keys()) - set(self._order): | ||||||
|             raise ValueError('%s missing from _order' % missing_name) |             raise CompositeDeviceBadOrder('%s missing from _order' % missing_name) | ||||||
|         super(CompositeDevice, self).__init__() |         super(CompositeDevice, self).__init__() | ||||||
|         for name in set(self._order) & set(dir(self)): |         for name in set(self._order) & set(dir(self)): | ||||||
|             raise CompositeDeviceBadName('%s is a reserved name' % name) |             raise CompositeDeviceBadName('%s is a reserved name' % name) | ||||||
| @@ -372,9 +374,6 @@ class GPIODevice(Device): | |||||||
|             self._check_open() |             self._check_open() | ||||||
|             raise |             raise | ||||||
|  |  | ||||||
|     def _fire_events(self): |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     def close(self): |     def close(self): | ||||||
|         super(GPIODevice, self).close() |         super(GPIODevice, self).close() | ||||||
|         with _PINS_LOCK: |         with _PINS_LOCK: | ||||||
|   | |||||||
| @@ -22,6 +22,9 @@ class CompositeDeviceError(GPIOZeroError): | |||||||
| class CompositeDeviceBadName(CompositeDeviceError, ValueError): | class CompositeDeviceBadName(CompositeDeviceError, ValueError): | ||||||
|     "Error raised when a composite device is constructed with a reserved name" |     "Error raised when a composite device is constructed with a reserved name" | ||||||
|  |  | ||||||
|  | class CompositeDeviceBadOrder(CompositeDeviceError, ValueError): | ||||||
|  |     "Error raised when a composite device is constructed with an incomplete order" | ||||||
|  |  | ||||||
| class EnergenieSocketMissing(CompositeDeviceError, ValueError): | class EnergenieSocketMissing(CompositeDeviceError, ValueError): | ||||||
|     "Error raised when socket number is not specified" |     "Error raised when socket number is not specified" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ import warnings | |||||||
| from time import sleep, time | from time import sleep, time | ||||||
| from threading import Event | from threading import Event | ||||||
|  |  | ||||||
| from .exc import InputDeviceError, GPIODeviceError, GPIODeviceClosed | from .exc import InputDeviceError, GPIODeviceError, DeviceClosed | ||||||
| from .devices import GPIODevice, CompositeDevice | from .devices import GPIODevice, CompositeDevice | ||||||
| from .mixins import GPIOQueue, EventsMixin | from .mixins import GPIOQueue, EventsMixin | ||||||
|  |  | ||||||
| @@ -161,7 +161,7 @@ class SmoothedInputDevice(EventsMixin, InputDevice): | |||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         try: |         try: | ||||||
|             self._check_open() |             self._check_open() | ||||||
|         except GPIODeviceClosed: |         except DeviceClosed: | ||||||
|             return super(SmoothedInputDevice, self).__repr__() |             return super(SmoothedInputDevice, self).__repr__() | ||||||
|         else: |         else: | ||||||
|             if self.partial or self._queue.full.wait(0): |             if self.partial or self._queue.full.wait(0): | ||||||
| @@ -649,7 +649,9 @@ class DistanceSensor(SmoothedInputDevice): | |||||||
|         return self.pin |         return self.pin | ||||||
|  |  | ||||||
|     def _read(self): |     def _read(self): | ||||||
|         # Make sure the echo event is clear |         # Make sure the echo pin is low then ensure the echo event is clear | ||||||
|  |         while self.pin.state: | ||||||
|  |             sleep(0.00001) | ||||||
|         self._echo.clear() |         self._echo.clear() | ||||||
|         # Fire the trigger |         # Fire the trigger | ||||||
|         self._trigger.pin.state = True |         self._trigger.pin.state = True | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ str = type('') | |||||||
|  |  | ||||||
|  |  | ||||||
| from collections import namedtuple | from collections import namedtuple | ||||||
| from time import time | from time import time, sleep | ||||||
| from threading import Thread, Event | from threading import Thread, Event | ||||||
| try: | try: | ||||||
|     from math import isclose |     from math import isclose | ||||||
| @@ -182,7 +182,7 @@ class MockChargingPin(MockPin): | |||||||
|     """ |     """ | ||||||
|     def __init__(self, number): |     def __init__(self, number): | ||||||
|         super(MockChargingPin, self).__init__() |         super(MockChargingPin, self).__init__() | ||||||
|         self.charge_time = 0.01 |         self.charge_time = 0.01 # dark charging time | ||||||
|         self._charge_stop = Event() |         self._charge_stop = Event() | ||||||
|         self._charge_thread = None |         self._charge_thread = None | ||||||
|  |  | ||||||
| @@ -193,16 +193,51 @@ class MockChargingPin(MockPin): | |||||||
|                 self._charge_stop.set() |                 self._charge_stop.set() | ||||||
|                 self._charge_thread.join() |                 self._charge_thread.join() | ||||||
|             self._charge_stop.clear() |             self._charge_stop.clear() | ||||||
|             self._charge_thread = Thread(target=lambda: self._charged) |             self._charge_thread = Thread(target=self._charge) | ||||||
|             self._charge_thread.start() |             self._charge_thread.start() | ||||||
|         elif value == 'output': |         elif value == 'output': | ||||||
|             if self.charge_thread: |             if self._charge_thread: | ||||||
|                 self._charge_stop.set() |                 self._charge_stop.set() | ||||||
|                 self._charge_thread.join() |                 self._charge_thread.join() | ||||||
|  |  | ||||||
|     def _charged(self): |     def _charge(self): | ||||||
|         if not self._charge_stop.wait(self.charge_time): |         if not self._charge_stop.wait(self.charge_time): | ||||||
|  |             try: | ||||||
|                 self.drive_high() |                 self.drive_high() | ||||||
|  |             except AssertionError: | ||||||
|  |                 # Charging pins are typically flipped between input and output | ||||||
|  |                 # repeatedly; if another thread has already flipped us to | ||||||
|  |                 # output ignore the assertion-error resulting from attempting | ||||||
|  |                 # to drive the pin high | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MockTriggerPin(MockPin): | ||||||
|  |     """ | ||||||
|  |     This derivative of :class:`MockPin` is intended to be used with another | ||||||
|  |     :class:`MockPin` to emulate a distance sensor. Set :attr:`echo_pin` to the | ||||||
|  |     corresponding pin instance. When this pin is driven high it will trigger | ||||||
|  |     the echo pin to drive high for the echo time. | ||||||
|  |     """ | ||||||
|  |     def __init__(self, number): | ||||||
|  |         super(MockTriggerPin, self).__init__() | ||||||
|  |         self.echo_pin = None | ||||||
|  |         self.echo_time = 0.04 # longest echo time | ||||||
|  |         self._echo_thread = None | ||||||
|  |  | ||||||
|  |     def _set_state(self, value): | ||||||
|  |         super(MockTriggerPin, self)._set_state(value) | ||||||
|  |         if value: | ||||||
|  |             if self._echo_thread: | ||||||
|  |                 self._echo_thread.join() | ||||||
|  |             self._echo_thread = Thread(target=self._echo) | ||||||
|  |             self._echo_thread.start() | ||||||
|  |  | ||||||
|  |     def _echo(self): | ||||||
|  |         sleep(0.001) | ||||||
|  |         self.echo_pin.drive_high() | ||||||
|  |         sleep(self.echo_time) | ||||||
|  |         self.echo_pin.drive_low() | ||||||
|  |  | ||||||
|  |  | ||||||
| class MockPWMPin(MockPin): | class MockPWMPin(MockPin): | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ try: | |||||||
| except ImportError: | except ImportError: | ||||||
|     pass |     pass | ||||||
| from itertools import count, cycle | from itertools import count, cycle | ||||||
| from math import sin, cos, floor | from math import sin, cos, floor, radians | ||||||
| try: | try: | ||||||
|     from statistics import mean |     from statistics import mean | ||||||
| except ImportError: | except ImportError: | ||||||
| @@ -270,7 +270,7 @@ def sin_values(): | |||||||
|     If you require a wider range than 0 to 1, see :func:`scaled`. |     If you require a wider range than 0 to 1, see :func:`scaled`. | ||||||
|     """ |     """ | ||||||
|     for d in cycle(range(360)): |     for d in cycle(range(360)): | ||||||
|         yield sin(d) |         yield sin(radians(d)) | ||||||
|  |  | ||||||
|  |  | ||||||
| def cos_values(): | def cos_values(): | ||||||
| @@ -292,5 +292,5 @@ def cos_values(): | |||||||
|     If you require a wider range than 0 to 1, see :func:`scaled`. |     If you require a wider range than 0 to 1, see :func:`scaled`. | ||||||
|     """ |     """ | ||||||
|     for d in cycle(range(360)): |     for d in cycle(range(360)): | ||||||
|         yield cos(d) |         yield cos(radians(d)) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,8 +23,8 @@ def _threads_shutdown(): | |||||||
|  |  | ||||||
| class GPIOThread(Thread): | class GPIOThread(Thread): | ||||||
|     def __init__(self, group=None, target=None, name=None, args=(), kwargs={}): |     def __init__(self, group=None, target=None, name=None, args=(), kwargs={}): | ||||||
|         super(GPIOThread, self).__init__(group, target, name, args, kwargs) |  | ||||||
|         self.stopping = Event() |         self.stopping = Event() | ||||||
|  |         super(GPIOThread, self).__init__(group, target, name, args, kwargs) | ||||||
|         self.daemon = True |         self.daemon = True | ||||||
|  |  | ||||||
|     def start(self): |     def start(self): | ||||||
|   | |||||||
							
								
								
									
										148
									
								
								tests/test_compat.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								tests/test_compat.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | |||||||
|  | from __future__ import ( | ||||||
|  |     unicode_literals, | ||||||
|  |     absolute_import, | ||||||
|  |     print_function, | ||||||
|  |     division, | ||||||
|  |     ) | ||||||
|  | str = type('') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import pytest | ||||||
|  | import random | ||||||
|  |  | ||||||
|  | from gpiozero.compat import * | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # ported from the official test cases; see | ||||||
|  | # https://github.com/python/cpython/blob/master/Lib/test/test_math.py for original | ||||||
|  |  | ||||||
|  | NAN = float('nan') | ||||||
|  | INF = float('inf') | ||||||
|  | NINF = float('-inf') | ||||||
|  |  | ||||||
|  | def test_isclose_negative_tolerances(): | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         isclose(1, 1, rel_tol=-1e-100) | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         isclose(1, 1, rel_tol=1e-100, abs_tol=-1e10) | ||||||
|  |  | ||||||
|  | def test_isclose_identical(): | ||||||
|  |     examples = [ | ||||||
|  |         (2.0, 2.0), | ||||||
|  |         (0.1e200, 0.1e200), | ||||||
|  |         (1.123e-300, 1.123e-300), | ||||||
|  |         (12345, 12345.0), | ||||||
|  |         (0.0, -0.0), | ||||||
|  |         (345678, 345678), | ||||||
|  |         ] | ||||||
|  |     for a, b in examples: | ||||||
|  |         assert isclose(a, b, rel_tol=0.0, abs_tol=0.0) | ||||||
|  |  | ||||||
|  | def test_isclose_eight_decimals(): | ||||||
|  |     examples = [ | ||||||
|  |         (1e8, 1e8 + 1), | ||||||
|  |         (-1e-8, -1.000000009e-8), | ||||||
|  |         (1.12345678, 1.12345679), | ||||||
|  |         ] | ||||||
|  |     for a, b in examples: | ||||||
|  |         assert isclose(a, b, rel_tol=1e-8) | ||||||
|  |         assert not isclose(a, b, rel_tol=1e-9) | ||||||
|  |  | ||||||
|  | def test_isclose_near_zero(): | ||||||
|  |     examples = [1e-9, -1e-9, -1e-150] | ||||||
|  |     for a in examples: | ||||||
|  |         assert not isclose(a, 0.0, rel_tol=0.9) | ||||||
|  |         assert isclose(a, 0.0, abs_tol=1e-8) | ||||||
|  |  | ||||||
|  | def test_isclose_inf(): | ||||||
|  |     assert isclose(INF, INF) | ||||||
|  |     assert isclose(INF, INF, abs_tol=0.0) | ||||||
|  |     assert isclose(NINF, NINF) | ||||||
|  |     assert isclose(NINF, NINF, abs_tol=0.0) | ||||||
|  |  | ||||||
|  | def test_isclose_inf_ninf_nan(): | ||||||
|  |     examples = [ | ||||||
|  |         (NAN, NAN), | ||||||
|  |         (NAN, 1e-100), | ||||||
|  |         (1e-100, NAN), | ||||||
|  |         (INF, NAN), | ||||||
|  |         (NAN, INF), | ||||||
|  |         (INF, NINF), | ||||||
|  |         (INF, 1.0), | ||||||
|  |         (1.0, INF), | ||||||
|  |         (INF, 1e308), | ||||||
|  |         (1e308, INF), | ||||||
|  |         ] | ||||||
|  |     for a, b in examples: | ||||||
|  |         assert not isclose(a, b, abs_tol=0.999999999999999) | ||||||
|  |  | ||||||
|  | def test_isclose_zero_tolerance(): | ||||||
|  |     examples = [ | ||||||
|  |         (1.0, 1.0), | ||||||
|  |         (-3.4, -3.4), | ||||||
|  |         (-1e-300, -1e-300), | ||||||
|  |         ] | ||||||
|  |     for a, b in examples: | ||||||
|  |         assert isclose(a, b, rel_tol=0.0) | ||||||
|  |     examples = [ | ||||||
|  |         (1.0, 1.000000000000001), | ||||||
|  |         (0.99999999999999, 1.0), | ||||||
|  |         (1.0e200, .999999999999999e200), | ||||||
|  |         ] | ||||||
|  |     for a, b in examples: | ||||||
|  |         assert not isclose(a, b, rel_tol=0.0) | ||||||
|  |  | ||||||
|  | def test_isclose_assymetry(): | ||||||
|  |     assert isclose(9, 10, rel_tol=0.1) | ||||||
|  |     assert isclose(10, 9, rel_tol=0.1) | ||||||
|  |  | ||||||
|  | def test_isclose_integers(): | ||||||
|  |     examples = [ | ||||||
|  |         (100000001, 100000000), | ||||||
|  |         (123456789, 123456788), | ||||||
|  |         ] | ||||||
|  |     for a, b in examples: | ||||||
|  |         assert isclose(a, b, rel_tol=1e-8) | ||||||
|  |         assert not isclose(a, b, rel_tol=1e-9) | ||||||
|  |  | ||||||
|  | # ported from the official test cases; see | ||||||
|  | # https://github.com/python/cpython/blob/master/Lib/test/test_statistics.py for | ||||||
|  | # original | ||||||
|  |  | ||||||
|  | def test_mean(): | ||||||
|  |     examples = [ | ||||||
|  |         (4.8125, (0, 1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 7, 7, 7, 8, 9)), | ||||||
|  |         (22.015625, (17.25, 19.75, 20.0, 21.5, 21.75, 23.25, 25.125, 27.5)), | ||||||
|  |         (INF, (1, 3, 5, 7, 9, INF)), | ||||||
|  |         (NINF, (1, 3, 5, 7, 9, NINF)), | ||||||
|  |         ] | ||||||
|  |     for result, values in examples: | ||||||
|  |         values = list(values) | ||||||
|  |         random.shuffle(values) | ||||||
|  |         assert mean(values) == result | ||||||
|  |  | ||||||
|  | def test_mean_big_data(): | ||||||
|  |     c = 1e9 | ||||||
|  |     data = [3.4, 4.5, 4.9, 6.7, 6.8, 7.2, 8.0, 8.1, 9.4] | ||||||
|  |     expected = mean(data) + c | ||||||
|  |     assert expected != c | ||||||
|  |     assert mean([x + c for x in data]) == expected | ||||||
|  |  | ||||||
|  | def test_mean_doubled_data(): | ||||||
|  |     data = [random.uniform(-3, 5) for _ in range(1000)] | ||||||
|  |     expected = mean(data) | ||||||
|  |     actual = mean(data * 2) | ||||||
|  |     assert isclose(expected, actual) | ||||||
|  |  | ||||||
|  | def test_mean_empty(): | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         mean(()) | ||||||
|  |  | ||||||
|  | def test_median(): | ||||||
|  |     assert median([1, 2, 3, 4, 5, 6]) == 3.5 | ||||||
|  |     assert median([1, 2, 3, 4, 5, 6, 9]) == 4 | ||||||
|  |  | ||||||
|  | def test_median_empty(): | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         median(()) | ||||||
|  |  | ||||||
| @@ -68,3 +68,60 @@ def test_device_repr_after_close(): | |||||||
|     device.close() |     device.close() | ||||||
|     assert repr(device) == '<gpiozero.GPIODevice object closed>' |     assert repr(device) == '<gpiozero.GPIODevice object closed>' | ||||||
|  |  | ||||||
|  | def test_device_unknown_attr(): | ||||||
|  |     pin = MockPin(2) | ||||||
|  |     device = GPIODevice(pin) | ||||||
|  |     with pytest.raises(AttributeError): | ||||||
|  |         device.foo = 1 | ||||||
|  |  | ||||||
|  | def test_device_context_manager(): | ||||||
|  |     pin = MockPin(2) | ||||||
|  |     with GPIODevice(pin) as device: | ||||||
|  |         assert not device.closed | ||||||
|  |     assert device.closed | ||||||
|  |  | ||||||
|  | def test_composite_device_sequence(): | ||||||
|  |     device = CompositeDevice( | ||||||
|  |         InputDevice(MockPin(2)), | ||||||
|  |         InputDevice(MockPin(3)) | ||||||
|  |         ) | ||||||
|  |     assert len(device) == 2 | ||||||
|  |     assert device[0].pin.number == 2 | ||||||
|  |     assert device[1].pin.number == 3 | ||||||
|  |     assert device.tuple._fields == ('_0', '_1') | ||||||
|  |  | ||||||
|  | def test_composite_device_values(): | ||||||
|  |     device = CompositeDevice( | ||||||
|  |         InputDevice(MockPin(2)), | ||||||
|  |         InputDevice(MockPin(3)) | ||||||
|  |         ) | ||||||
|  |     assert device.value == (0, 0) | ||||||
|  |     assert not device.is_active | ||||||
|  |     device[0].pin.drive_high() | ||||||
|  |     assert device.value == (1, 0) | ||||||
|  |     assert device.is_active | ||||||
|  |  | ||||||
|  | def test_composite_device_named(): | ||||||
|  |     device = CompositeDevice( | ||||||
|  |         foo=InputDevice(MockPin(2)), | ||||||
|  |         bar=InputDevice(MockPin(3)), | ||||||
|  |         _order=('foo', 'bar') | ||||||
|  |         ) | ||||||
|  |     assert device.tuple._fields == ('foo', 'bar') | ||||||
|  |     assert device.value == (0, 0) | ||||||
|  |     assert not device.is_active | ||||||
|  |  | ||||||
|  | def test_composite_device_bad_init(): | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         CompositeDevice(foo=1, bar=2, _order=('foo',)) | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         CompositeDevice(close=1) | ||||||
|  |  | ||||||
|  | def test_composite_device_read_only(): | ||||||
|  |     device = CompositeDevice( | ||||||
|  |         foo=InputDevice(MockPin(2)), | ||||||
|  |         bar=InputDevice(MockPin(3)) | ||||||
|  |         ) | ||||||
|  |     with pytest.raises(AttributeError): | ||||||
|  |         device.foo = 1 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,11 +7,16 @@ from __future__ import ( | |||||||
| str = type('') | str = type('') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import sys | ||||||
| import pytest | import pytest | ||||||
| import mock |  | ||||||
| from threading import Event | from threading import Event | ||||||
|  |  | ||||||
| from gpiozero.pins.mock import MockPin, MockPulledUpPin, MockChargingPin | from gpiozero.pins.mock import ( | ||||||
|  |     MockPin, | ||||||
|  |     MockPulledUpPin, | ||||||
|  |     MockChargingPin, | ||||||
|  |     MockTriggerPin, | ||||||
|  |     ) | ||||||
| from gpiozero import * | from gpiozero import * | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -136,12 +141,43 @@ def test_input_motion_sensor(): | |||||||
|     assert sensor.wait_for_no_motion(1) |     assert sensor.wait_for_no_motion(1) | ||||||
|     assert not sensor.motion_detected |     assert not sensor.motion_detected | ||||||
|  |  | ||||||
| @pytest.mark.skipif(True, reason='Freezes') | @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), | ||||||
|  |                     reason='timing is too random on pypy') | ||||||
| def test_input_light_sensor(): | def test_input_light_sensor(): | ||||||
|     pin = MockChargingPin(2) |     pin = MockChargingPin(2) | ||||||
|     sensor = LightSensor(pin) |     sensor = LightSensor(pin) | ||||||
|     pin.charge_time = 1 |     pin.charge_time = 0.1 | ||||||
|     assert not sensor.light_detected |     assert sensor.wait_for_dark(1) | ||||||
|     pin.charge_time = 0 |     pin.charge_time = 0.0 | ||||||
|     assert sensor.light_detected |     assert sensor.wait_for_light(1) | ||||||
|  |  | ||||||
|  | @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), | ||||||
|  |                     reason='timing is too random on pypy') | ||||||
|  | def test_input_distance_sensor(): | ||||||
|  |     echo_pin = MockPin(2) | ||||||
|  |     trig_pin = MockTriggerPin(3) | ||||||
|  |     trig_pin.echo_pin = echo_pin | ||||||
|  |     trig_pin.echo_time = 0.02 | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         DistanceSensor(echo_pin, trig_pin, max_distance=-1) | ||||||
|  |     # normal queue len is large (because the sensor is *really* jittery) but | ||||||
|  |     # we want quick tests and we've got precisely controlled pins :) | ||||||
|  |     sensor = DistanceSensor(echo_pin, trig_pin, queue_len=5, max_distance=1) | ||||||
|  |     assert sensor.max_distance == 1 | ||||||
|  |     assert sensor.trigger is trig_pin | ||||||
|  |     assert sensor.echo is echo_pin | ||||||
|  |     assert sensor.wait_for_out_of_range(1) | ||||||
|  |     assert not sensor.in_range | ||||||
|  |     assert sensor.distance == 1.0 # should be waay before max-distance so this should work | ||||||
|  |     trig_pin.echo_time = 0.0 | ||||||
|  |     assert sensor.wait_for_in_range(1) | ||||||
|  |     assert sensor.in_range | ||||||
|  |     assert sensor.distance < sensor.threshold_distance # depending on speed of machine, may not reach 0 here | ||||||
|  |     sensor.threshold_distance = 0.1 | ||||||
|  |     assert sensor.threshold_distance == 0.1 | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         sensor.max_distance = -1 | ||||||
|  |     sensor.max_distance = 20 | ||||||
|  |     assert sensor.max_distance == 20 | ||||||
|  |     assert sensor.threshold_distance == 0.1 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										88
									
								
								tests/test_source_tools.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								tests/test_source_tools.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | |||||||
|  | from __future__ import ( | ||||||
|  |     unicode_literals, | ||||||
|  |     absolute_import, | ||||||
|  |     print_function, | ||||||
|  |     division, | ||||||
|  |     ) | ||||||
|  | str = type('') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import pytest | ||||||
|  | from math import sin, cos, radians | ||||||
|  | from time import time | ||||||
|  |  | ||||||
|  | from gpiozero import * | ||||||
|  | try: | ||||||
|  |     from math import isclose | ||||||
|  | except ImportError: | ||||||
|  |     from gpiozero.compat import isclose | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_negated(): | ||||||
|  |     assert list(negated(())) == [] | ||||||
|  |     assert list(negated((True, True, False, False))) == [False, False, True, True] | ||||||
|  |  | ||||||
|  | def test_inverted(): | ||||||
|  |     assert list(inverted(())) == [] | ||||||
|  |     assert list(inverted((1, 0, 0.1, 0.5))) == [0, 1, 0.9, 0.5] | ||||||
|  |  | ||||||
|  | def test_scaled(): | ||||||
|  |     assert list(scaled((0, 1, 0.5, 0.1), 0, 1)) == [0, 1, 0.5, 0.1] | ||||||
|  |     assert list(scaled((0, 1, 0.5, 0.1), -1, 1)) == [-1, 1, 0.0, -0.8] | ||||||
|  |  | ||||||
|  | def test_clamped(): | ||||||
|  |     assert list(clamped((-1, 0, 1, 2))) == [0, 0, 1, 1] | ||||||
|  |  | ||||||
|  | def test_quantized(): | ||||||
|  |     assert list(quantized((0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1), 4)) == [ | ||||||
|  |             0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, 0.5, 0.75, 0.75, 1.0] | ||||||
|  |     assert list(quantized((0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1), 5)) == [ | ||||||
|  |             0.0, 0.0, 0.2, 0.2, 0.4, 0.4, 0.6, 0.6, 0.8, 0.8, 1.0] | ||||||
|  |  | ||||||
|  | def test_conjunction(): | ||||||
|  |     assert list(conjunction(())) == [] | ||||||
|  |     assert list(conjunction((False, True))) == [False, True] | ||||||
|  |     assert list(conjunction((0, 1, 0, 1), (0, 0, 0, 1))) == [0, 0, 0, 1] | ||||||
|  |  | ||||||
|  | def test_disjunction(): | ||||||
|  |     assert list(disjunction(())) == [] | ||||||
|  |     assert list(disjunction((False, True))) == [False, True] | ||||||
|  |     assert list(disjunction((0, 1, 0, 1), (0, 0, 0, 1))) == [0, 1, 0, 1] | ||||||
|  |  | ||||||
|  | def test_averaged(): | ||||||
|  |     assert list(averaged(())) == [] | ||||||
|  |     assert list(averaged((0, 0.5, 1), (1, 1, 1))) == [0.5, 0.75, 1] | ||||||
|  |  | ||||||
|  | def test_queued(): | ||||||
|  |     assert list(queued((1, 2, 3, 4, 5), 5)) == [1] | ||||||
|  |     assert list(queued((1, 2, 3, 4, 5, 6), 5)) == [1, 2] | ||||||
|  |  | ||||||
|  | def test_pre_delayed(): | ||||||
|  |     start = time() | ||||||
|  |     for v in pre_delayed((0, 0, 0), 0.01): | ||||||
|  |         assert v == 0 | ||||||
|  |         assert time() - start >= 0.01 | ||||||
|  |         start = time() | ||||||
|  |  | ||||||
|  | def test_post_delayed(): | ||||||
|  |     start = time() | ||||||
|  |     for v in post_delayed((1, 2, 2), 0.01): | ||||||
|  |         if v == 1: | ||||||
|  |             assert time() - start < 0.01 | ||||||
|  |         else: | ||||||
|  |             assert time() - start >= 0.01 | ||||||
|  |         start = time() | ||||||
|  |     assert time() - start >= 0.01 | ||||||
|  |  | ||||||
|  | def test_random_values(): | ||||||
|  |     for i, v in zip(range(1000), random_values()): | ||||||
|  |         assert 0 <= v <= 1 | ||||||
|  |  | ||||||
|  | def test_sin_values(): | ||||||
|  |     for i, v in zip(range(1000), sin_values()): | ||||||
|  |         assert isclose(v, sin(radians(i)), abs_tol=1e-9) | ||||||
|  |  | ||||||
|  | def test_cos_values(): | ||||||
|  |     for i, v in zip(range(1000), cos_values()): | ||||||
|  |         assert isclose(v, cos(radians(i)), abs_tol=1e-9) | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user