mirror of
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
synced 2026-10-24 00:48:53 +03:00
bindings: python: use unittest to implement a proper test-suite
Currently the only tests we have for python bindings are in a simple script that makes a lot of assumptions about the environment and doesn't even work anymore with recent kernels. Remove it and replace it with a proper test-suite implemented using libgpiod and the standard python unittest package. Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This commit is contained in:
9
TODO
9
TODO
@@ -25,15 +25,6 @@ and is partially functional.
|
||||
|
||||
----------
|
||||
|
||||
* use the python unit testing library for python bindings and reuse
|
||||
libgpiod-test
|
||||
|
||||
The best candidate for the testing framework is the standard unittest module
|
||||
available in cpython. We'd need however to wrap libgpiod-test in a C module
|
||||
for python just like we did for the bindings of the core C library.
|
||||
|
||||
----------
|
||||
|
||||
* implement a simple daemon for controlling GPIOs in C together with a client
|
||||
program
|
||||
|
||||
|
||||
@@ -16,3 +16,9 @@ gpiod_la_CFLAGS = -I$(top_srcdir)/include/
|
||||
gpiod_la_CFLAGS += -Wall -Wextra -g $(PYTHON_CPPFLAGS)
|
||||
gpiod_la_LDFLAGS = -module -avoid-version
|
||||
gpiod_la_LIBADD = $(top_builddir)/lib/libgpiod.la $(PYTHON_LIBS)
|
||||
|
||||
if WITH_TESTS
|
||||
|
||||
SUBDIRS += tests
|
||||
|
||||
endif
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
EXTRA_DIST = gpiod_tests.py \
|
||||
gpiodetect.py \
|
||||
EXTRA_DIST = gpiodetect.py \
|
||||
gpiofind.py \
|
||||
gpioget.py \
|
||||
gpioinfo.py \
|
||||
|
||||
@@ -1,437 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
'''Misc tests of libgpiod python bindings.
|
||||
|
||||
These tests assume that at least one dummy gpiochip is present in the
|
||||
system and that it's detected as gpiochip0.
|
||||
'''
|
||||
|
||||
import gpiod
|
||||
import select
|
||||
|
||||
test_cases = []
|
||||
|
||||
def add_test(name, func):
|
||||
global test_cases
|
||||
|
||||
test_cases.append((name, func))
|
||||
|
||||
def fire_line_event(chip, offset, rising):
|
||||
path = '/sys/kernel/debug/gpio-mockup-event/{}/{}'.format(chip, offset)
|
||||
with open(path, 'w') as fd:
|
||||
fd.write('{}'.format(1 if rising else 0))
|
||||
|
||||
def print_event(event):
|
||||
print('type: {}'.format('rising' if event.type == gpiod.LineEvent.RISING_EDGE else 'falling'))
|
||||
print('timestamp: {}.{}'.format(event.sec, event.nsec))
|
||||
print('source line offset: {}'.format(event.source.offset()))
|
||||
|
||||
def chip_open_default_lookup():
|
||||
by_name = gpiod.Chip('gpiochip0')
|
||||
by_path = gpiod.Chip('/dev/gpiochip0')
|
||||
by_label = gpiod.Chip('gpio-mockup-A')
|
||||
by_number = gpiod.Chip('0')
|
||||
print('All good')
|
||||
by_name.close()
|
||||
by_path.close()
|
||||
by_label.close()
|
||||
by_number.close()
|
||||
|
||||
add_test('Open a GPIO chip using different lookup modes', chip_open_default_lookup)
|
||||
|
||||
def chip_open_different_modes():
|
||||
chip = gpiod.Chip('/dev/gpiochip0', gpiod.Chip.OPEN_BY_PATH)
|
||||
chip.close()
|
||||
chip = gpiod.Chip('gpiochip0', gpiod.Chip.OPEN_BY_NAME)
|
||||
chip.close()
|
||||
chip = gpiod.Chip('gpio-mockup-A', gpiod.Chip.OPEN_BY_LABEL)
|
||||
chip.close()
|
||||
chip = gpiod.Chip('0', gpiod.Chip.OPEN_BY_NUMBER)
|
||||
chip.close()
|
||||
print('All good')
|
||||
|
||||
add_test('Open a GPIO chip using different modes', chip_open_different_modes)
|
||||
|
||||
def chip_open_nonexistent():
|
||||
try:
|
||||
chip = gpiod.Chip('/nonexistent_gpiochip')
|
||||
except OSError as ex:
|
||||
print('Exception raised as expected: {}'.format(ex))
|
||||
return
|
||||
|
||||
assert False, 'OSError expected'
|
||||
|
||||
add_test('Try to open a nonexistent GPIO chip', chip_open_nonexistent)
|
||||
|
||||
def chip_open_no_args():
|
||||
try:
|
||||
chip = gpiod.Chip()
|
||||
except TypeError:
|
||||
print('Error as expected')
|
||||
return
|
||||
|
||||
assert False, 'TypeError expected'
|
||||
|
||||
add_test('Open a GPIO chip without arguments', chip_open_no_args)
|
||||
|
||||
def chip_use_after_close():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
line = chip.get_line(2)
|
||||
chip.close()
|
||||
|
||||
try:
|
||||
chip.name()
|
||||
except ValueError as ex:
|
||||
print('Error as expected: {}'.format(ex))
|
||||
|
||||
try:
|
||||
line = chip.get_line(3)
|
||||
except ValueError as ex:
|
||||
print('Error as expected: {}'.format(ex))
|
||||
return
|
||||
|
||||
assert False, 'ValueError expected'
|
||||
|
||||
add_test('Use a GPIO chip after closing it', chip_use_after_close)
|
||||
|
||||
def chip_with_statement():
|
||||
with gpiod.Chip('gpiochip0') as chip:
|
||||
print('Chip name in controlled execution: {}'.format(chip.name()))
|
||||
line = chip.get_line(3)
|
||||
print('Got line from chip in controlled execution: {}'.format(line.name()))
|
||||
|
||||
add_test('Use a GPIO chip in controlled execution', chip_with_statement)
|
||||
|
||||
def chip_info():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
print('name: {}'.format(chip.name()))
|
||||
print('label: {}'.format(chip.label()))
|
||||
print('lines: {}'.format(chip.num_lines()))
|
||||
chip.close()
|
||||
|
||||
add_test('Print chip info', chip_info)
|
||||
|
||||
def print_chip():
|
||||
chip = gpiod.Chip('/dev/gpiochip0')
|
||||
print(chip)
|
||||
chip.close()
|
||||
|
||||
add_test('Print chip object', print_chip)
|
||||
|
||||
def create_chip_without_arguments():
|
||||
try:
|
||||
chip = gpiod.Chip()
|
||||
except TypeError as ex:
|
||||
print('Exception raised as expected: {}'.format(ex))
|
||||
return
|
||||
|
||||
assert False, 'TypeError expected'
|
||||
|
||||
add_test('Create chip object without arguments', create_chip_without_arguments)
|
||||
|
||||
def create_line_object():
|
||||
try:
|
||||
line = gpiod.Line()
|
||||
except NotImplementedError:
|
||||
print('Error as expected')
|
||||
return
|
||||
|
||||
assert False, 'NotImplementedError expected'
|
||||
|
||||
add_test('Create a line object - should fail', create_line_object)
|
||||
|
||||
def print_line():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
line = chip.get_line(3)
|
||||
print(line)
|
||||
chip.close()
|
||||
|
||||
add_test('Print line object', print_line)
|
||||
|
||||
def find_line():
|
||||
line = gpiod.find_line('gpio-mockup-A-4')
|
||||
print('found line - offset: {}'.format(line.offset()))
|
||||
line.owner().close()
|
||||
|
||||
add_test('Find line globally', find_line)
|
||||
|
||||
def create_empty_line_bulk():
|
||||
try:
|
||||
lines = gpiod.LineBulk()
|
||||
except TypeError:
|
||||
print('Error as expected')
|
||||
return
|
||||
|
||||
assert False, 'TypeError expected'
|
||||
|
||||
add_test('Create a line bulk object - should fail', create_empty_line_bulk)
|
||||
|
||||
def get_lines():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
|
||||
print('getting four lines from chip')
|
||||
lines = chip.get_lines([2, 4, 5, 7])
|
||||
|
||||
print('Retrieved lines:')
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Get lines from chip', get_lines)
|
||||
|
||||
def get_all_lines():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
|
||||
print('Retrieving all lines from chip')
|
||||
lines = chip.get_all_lines()
|
||||
|
||||
print('Retrieved lines:')
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Get all lines from chip', get_all_lines)
|
||||
|
||||
def find_lines():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
|
||||
print('looking up lines by names')
|
||||
lines = chip.find_lines(['gpio-mockup-A-3', 'gpio-mockup-A-4', 'gpio-mockup-A-7'])
|
||||
|
||||
print('Retrieved lines:')
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Find multiple lines by name', find_lines)
|
||||
|
||||
def find_lines_one_bad():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
|
||||
print('looking up lines by names')
|
||||
try:
|
||||
lines = chip.find_lines(['gpio-mockup-A-3', 'nonexistent', 'gpio-mockup-A-7'])
|
||||
except TypeError as ex:
|
||||
print('Error as expected')
|
||||
return
|
||||
|
||||
assert False, 'TypeError expected'
|
||||
|
||||
add_test('Find multiple lines but one line name is non-existent', find_lines_one_bad)
|
||||
|
||||
def create_line_bulk_from_lines():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
line1 = chip.get_line(2)
|
||||
line2 = chip.get_line(4)
|
||||
line3 = chip.get_line(6)
|
||||
lines = gpiod.LineBulk([line1, line2, line3])
|
||||
print('Created LineBulk:')
|
||||
print(lines)
|
||||
chip.close()
|
||||
|
||||
add_test('Create a LineBulk from a list of lines', create_line_bulk_from_lines)
|
||||
|
||||
def line_bulk_to_list():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
lines = chip.get_lines((1, 2, 3))
|
||||
print(lines.to_list())
|
||||
chip.close()
|
||||
|
||||
add_test('Convert a LineBulk to a list', line_bulk_to_list)
|
||||
|
||||
def line_flags():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
line = chip.get_line(3)
|
||||
|
||||
print('line is used: {}'.format(line.is_used()))
|
||||
print('line is requested: {}'.format(line.is_requested()))
|
||||
|
||||
print('requesting line')
|
||||
line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_OUT,
|
||||
flags=(gpiod.LINE_REQ_FLAG_OPEN_DRAIN | gpiod.LINE_REQ_FLAG_ACTIVE_LOW))
|
||||
|
||||
print('line is used: {}'.format(line.is_used()))
|
||||
print('line is open drain: {}'.format(line.is_open_drain()))
|
||||
print('line is open source: {}'.format(line.is_open_source()))
|
||||
print('line is requested: {}'.format(line.is_requested()))
|
||||
print('line is active-low: {}'.format(
|
||||
"True" if line.active_state() == gpiod.Line.ACTIVE_LOW else "False"))
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Check various line flags', line_flags)
|
||||
|
||||
def get_value_single_line():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
line = chip.get_line(2)
|
||||
line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_IN)
|
||||
print('line value: {}'.format(line.get_value()))
|
||||
chip.close()
|
||||
|
||||
add_test('Get value - single line', get_value_single_line)
|
||||
|
||||
def set_value_single_line():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_IN)
|
||||
|
||||
print('line value before: {}'.format(line.get_value()))
|
||||
line.release()
|
||||
line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_OUT)
|
||||
line.set_value(1)
|
||||
line.release()
|
||||
line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_IN)
|
||||
print('line value after: {}'.format(line.get_value()))
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Set value - single line', set_value_single_line)
|
||||
|
||||
def request_line_with_default_values():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
line = chip.get_line(3)
|
||||
|
||||
print('requesting a single line with a default value')
|
||||
line.request(consumer='gpiod_test.py', type=gpiod.LINE_REQ_DIR_OUT, default_vals=[ 1 ])
|
||||
|
||||
print('line value after request: {}'.format(line.get_value()))
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Request line with default value', request_line_with_default_values)
|
||||
|
||||
def request_multiple_lines_with_default_values():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
lines = chip.get_lines(( 1, 2, 3, 4, 5 ))
|
||||
|
||||
print('requesting lines with default values')
|
||||
lines.request(consumer='gpiod_test.py', type=gpiod.LINE_REQ_DIR_OUT, default_vals=( 1, 0, 1, 0, 1 ))
|
||||
|
||||
print('line values after request: {}'.format(lines.get_values()))
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Request multiple lines with default values', request_multiple_lines_with_default_values)
|
||||
|
||||
def request_line_incorrect_number_of_def_vals():
|
||||
with gpiod.Chip('gpiochip0') as chip:
|
||||
lines = chip.get_lines(( 1, 2, 3, 4, 5 ))
|
||||
|
||||
print('requesting lines with incorrect number of default values')
|
||||
try:
|
||||
lines.request(consumer='gpiod_test.py',
|
||||
type=gpiod.LINE_REQ_DIR_OUT,
|
||||
default_vals=( 1, 0, 1, 0 ))
|
||||
except TypeError:
|
||||
print('TypeError raised as expected')
|
||||
return
|
||||
|
||||
assert False, 'TypeError expected'
|
||||
|
||||
add_test('Request with incorrect number of default values', request_line_incorrect_number_of_def_vals)
|
||||
|
||||
def line_event_single_line():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
line = chip.get_line(1)
|
||||
|
||||
print('requesting line for events')
|
||||
line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
|
||||
print('generating a line event')
|
||||
fire_line_event('gpiochip0', 1, True)
|
||||
assert line.event_wait(sec=1), 'Expected a line event to occur'
|
||||
|
||||
print('event received')
|
||||
event = line.event_read()
|
||||
print_event(event)
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Monitor a single line for events', line_event_single_line)
|
||||
|
||||
def line_event_multiple_lines():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
lines = chip.get_lines((1, 2, 3, 4, 5))
|
||||
|
||||
print('requesting lines for events')
|
||||
lines.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
|
||||
print('generating two line events')
|
||||
fire_line_event('gpiochip0', 1, True)
|
||||
fire_line_event('gpiochip0', 2, True)
|
||||
|
||||
events = lines.event_wait(sec=1)
|
||||
assert events is not None and len(events) == 2, 'Expected to receive two line events'
|
||||
|
||||
print('events received:')
|
||||
for line in events:
|
||||
event = line.event_read()
|
||||
print_event(event)
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Monitor multiple lines for events', line_event_multiple_lines)
|
||||
|
||||
def line_event_poll_fd():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
lines = chip.get_lines((1, 2, 3, 4, 5, 6))
|
||||
print('requesting lines for events')
|
||||
lines.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
|
||||
print('generating three line events')
|
||||
fire_line_event('gpiochip0', 2, True)
|
||||
fire_line_event('gpiochip0', 3, False)
|
||||
fire_line_event('gpiochip0', 5, True)
|
||||
|
||||
print('retrieving the file descriptors')
|
||||
inputs = []
|
||||
fd_mapping = {}
|
||||
for line in lines:
|
||||
inputs.append(line.event_get_fd())
|
||||
fd_mapping[line.event_get_fd()] = line
|
||||
|
||||
readable, writable, exceptional = select.select(inputs, [], inputs, 1.0)
|
||||
assert len(readable) == 3, 'Expected to receive three line events'
|
||||
|
||||
print('events received:')
|
||||
for fd in readable:
|
||||
line = fd_mapping[fd]
|
||||
event = line.event_read()
|
||||
print_event(event)
|
||||
|
||||
chip.close()
|
||||
|
||||
add_test('Monitor multiple lines using their file descriptors', line_event_poll_fd)
|
||||
|
||||
def line_event_repr():
|
||||
with gpiod.Chip('gpiochip0') as chip:
|
||||
line = chip.get_line(1)
|
||||
|
||||
print('requesting line for events')
|
||||
line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
|
||||
print('generating a line event')
|
||||
fire_line_event('gpiochip0', 1, True)
|
||||
assert line.event_wait(sec=1), 'Expected a line event to occur'
|
||||
|
||||
print('event received: {}'.format(line.event_read()))
|
||||
|
||||
add_test('Line event string repr', line_event_repr)
|
||||
|
||||
print('API version is {}'.format(gpiod.version_string()))
|
||||
|
||||
for name, func in test_cases:
|
||||
print('==============================================')
|
||||
print('{}:'.format(name))
|
||||
print()
|
||||
func()
|
||||
18
bindings/python/tests/Makefile.am
Normal file
18
bindings/python/tests/Makefile.am
Normal file
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
#
|
||||
|
||||
bin_SCRIPTS = gpiod_py_test.py
|
||||
|
||||
pyexec_LTLIBRARIES = gpiomockup.la
|
||||
|
||||
gpiomockup_la_SOURCES = gpiomockupmodule.c
|
||||
gpiomockup_la_CFLAGS = -I$(top_srcdir)/tests/mockup/
|
||||
gpiomockup_la_CFLAGS += -Wall -Wextra -g $(PYTHON_CPPFLAGS)
|
||||
gpiomockup_la_LDFLAGS = -module -avoid-version
|
||||
gpiomockup_la_LIBADD = $(top_builddir)/tests/mockup/libgpiomockup.la
|
||||
gpiomockup_la_LIBADD += $(PYTHON_LIBS)
|
||||
650
bindings/python/tests/gpiod_py_test.py
Executable file
650
bindings/python/tests/gpiod_py_test.py
Executable file
@@ -0,0 +1,650 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
#
|
||||
|
||||
import errno
|
||||
import gpiod
|
||||
import gpiomockup
|
||||
import os
|
||||
import select
|
||||
import threading
|
||||
import unittest
|
||||
|
||||
from packaging import version
|
||||
|
||||
mockup = None
|
||||
default_consumer = 'gpiod-py-test'
|
||||
|
||||
class MockupTestCase(unittest.TestCase):
|
||||
|
||||
chip_sizes = None
|
||||
flags = 0
|
||||
|
||||
def setUp(self):
|
||||
mockup.probe(self.chip_sizes, flags=self.flags)
|
||||
|
||||
def tearDown(self):
|
||||
mockup.remove()
|
||||
|
||||
class EventThread(threading.Thread):
|
||||
|
||||
def __init__(self, chip_idx, line_offset, freq):
|
||||
threading.Thread.__init__(self)
|
||||
self.chip_idx = chip_idx
|
||||
self.line_offset = line_offset
|
||||
self.freq = freq
|
||||
self.lock = threading.Lock()
|
||||
self.cond = threading.Condition(self.lock)
|
||||
self.should_stop = False
|
||||
|
||||
def run(self):
|
||||
i = 0;
|
||||
while True:
|
||||
with self.lock:
|
||||
if self.should_stop:
|
||||
break;
|
||||
|
||||
if not self.cond.wait(float(self.freq) / 1000):
|
||||
mockup.chip_set_pull(self.chip_idx,
|
||||
self.line_offset, i % 2)
|
||||
i += 1
|
||||
|
||||
def stop(self):
|
||||
with self.lock:
|
||||
self.should_stop = True
|
||||
self.cond.notify_all()
|
||||
|
||||
def __enter__(self):
|
||||
self.start()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.stop()
|
||||
self.join()
|
||||
|
||||
def check_kernel(major, minor, release):
|
||||
current = os.uname().release
|
||||
required = '{}.{}.{}'.format(major, minor, release)
|
||||
if version.parse(current) < version.parse(required):
|
||||
raise NotImplementedError(
|
||||
'linux kernel version must be at least {} - got {}'.format(required, current))
|
||||
|
||||
#
|
||||
# Chip test cases
|
||||
#
|
||||
|
||||
class ChipOpen(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, 8, 8 )
|
||||
|
||||
def test_open_chip_by_name(self):
|
||||
with gpiod.Chip(mockup.chip_name(1), gpiod.Chip.OPEN_BY_NAME) as chip:
|
||||
self.assertEqual(chip.name(), mockup.chip_name(1))
|
||||
|
||||
def test_open_chip_by_path(self):
|
||||
with gpiod.Chip(mockup.chip_path(1), gpiod.Chip.OPEN_BY_PATH) as chip:
|
||||
self.assertEqual(chip.name(), mockup.chip_name(1))
|
||||
|
||||
def test_open_chip_by_num(self):
|
||||
with gpiod.Chip('{}'.format(mockup.chip_num(1)),
|
||||
gpiod.Chip.OPEN_BY_NUMBER) as chip:
|
||||
self.assertEqual(chip.name(), mockup.chip_name(1))
|
||||
|
||||
def test_open_chip_by_label(self):
|
||||
with gpiod.Chip('gpio-mockup-B', gpiod.Chip.OPEN_BY_LABEL) as chip:
|
||||
self.assertEqual(chip.name(), mockup.chip_name(1))
|
||||
|
||||
def test_lookup_chip_by_name(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
self.assertEqual(chip.name(), mockup.chip_name(1))
|
||||
|
||||
def test_lookup_chip_by_path(self):
|
||||
with gpiod.Chip(mockup.chip_path(1)) as chip:
|
||||
self.assertEqual(chip.name(), mockup.chip_name(1))
|
||||
|
||||
def test_lookup_chip_by_num(self):
|
||||
with gpiod.Chip('{}'.format(mockup.chip_num(1))) as chip:
|
||||
self.assertEqual(chip.name(), mockup.chip_name(1))
|
||||
|
||||
def test_lookup_chip_by_label(self):
|
||||
with gpiod.Chip('gpio-mockup-B') as chip:
|
||||
self.assertEqual(chip.name(), mockup.chip_name(1))
|
||||
|
||||
def test_nonexistent_chip(self):
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
chip = gpiod.Chip('nonexistent-chip')
|
||||
|
||||
def test_open_chip_no_arguments(self):
|
||||
with self.assertRaises(TypeError):
|
||||
chip = gpiod.Chip()
|
||||
|
||||
class ChipClose(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, )
|
||||
|
||||
def test_use_chip_after_close(self):
|
||||
chip = gpiod.Chip(mockup.chip_name(0))
|
||||
self.assertEqual(chip.name(), mockup.chip_name(0))
|
||||
chip.close()
|
||||
with self.assertRaises(ValueError):
|
||||
chip.name()
|
||||
|
||||
class ChipInfo(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 16, )
|
||||
|
||||
def test_chip_get_info(self):
|
||||
chip = gpiod.Chip(mockup.chip_name(0))
|
||||
self.assertEqual(chip.name(), mockup.chip_name(0))
|
||||
self.assertEqual(chip.label(), 'gpio-mockup-A')
|
||||
self.assertEqual(chip.num_lines(), 16)
|
||||
|
||||
class ChipGetLines(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, 8, 4 )
|
||||
flags = gpiomockup.Mockup.FLAG_NAMED_LINES
|
||||
|
||||
def test_get_single_line_by_offset(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
line = chip.get_line(4)
|
||||
self.assertEqual(line.name(), 'gpio-mockup-B-4')
|
||||
|
||||
def test_find_single_line_by_name(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
line = chip.find_line('gpio-mockup-B-4')
|
||||
self.assertEqual(line.offset(), 4)
|
||||
|
||||
def test_get_single_line_invalid_offset(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
with self.assertRaises(OSError) as err_ctx:
|
||||
line = chip.get_line(11)
|
||||
|
||||
self.assertEqual(err_ctx.exception.errno, errno.EINVAL)
|
||||
|
||||
def test_find_single_line_nonexistent(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
line = chip.find_line('nonexistent-line')
|
||||
self.assertEqual(line, None)
|
||||
|
||||
def test_get_multiple_lines_by_offsets_in_tuple(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
lines = chip.get_lines(( 1, 3, 6, 7 )).to_list()
|
||||
self.assertEqual(len(lines), 4)
|
||||
self.assertEqual(lines[0].name(), 'gpio-mockup-B-1')
|
||||
self.assertEqual(lines[1].name(), 'gpio-mockup-B-3')
|
||||
self.assertEqual(lines[2].name(), 'gpio-mockup-B-6')
|
||||
self.assertEqual(lines[3].name(), 'gpio-mockup-B-7')
|
||||
|
||||
def test_get_multiple_lines_by_offsets_in_list(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
lines = chip.get_lines([ 1, 3, 6, 7 ]).to_list()
|
||||
self.assertEqual(len(lines), 4)
|
||||
self.assertEqual(lines[0].name(), 'gpio-mockup-B-1')
|
||||
self.assertEqual(lines[1].name(), 'gpio-mockup-B-3')
|
||||
self.assertEqual(lines[2].name(), 'gpio-mockup-B-6')
|
||||
self.assertEqual(lines[3].name(), 'gpio-mockup-B-7')
|
||||
|
||||
def test_find_multiple_lines_by_names_in_tuple(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
lines = chip.find_lines(( 'gpio-mockup-B-0',
|
||||
'gpio-mockup-B-3',
|
||||
'gpio-mockup-B-4',
|
||||
'gpio-mockup-B-6' )).to_list()
|
||||
self.assertEqual(len(lines), 4)
|
||||
self.assertEqual(lines[0].offset(), 0)
|
||||
self.assertEqual(lines[1].offset(), 3)
|
||||
self.assertEqual(lines[2].offset(), 4)
|
||||
self.assertEqual(lines[3].offset(), 6)
|
||||
|
||||
def test_find_multiple_lines_by_names_in_list(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
lines = chip.find_lines([ 'gpio-mockup-B-0',
|
||||
'gpio-mockup-B-3',
|
||||
'gpio-mockup-B-4',
|
||||
'gpio-mockup-B-6' ]).to_list()
|
||||
self.assertEqual(len(lines), 4)
|
||||
self.assertEqual(lines[0].offset(), 0)
|
||||
self.assertEqual(lines[1].offset(), 3)
|
||||
self.assertEqual(lines[2].offset(), 4)
|
||||
self.assertEqual(lines[3].offset(), 6)
|
||||
|
||||
def test_get_multiple_lines_invalid_offset(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
with self.assertRaises(OSError) as err_ctx:
|
||||
line = chip.get_lines(( 1, 3, 11, 7 ))
|
||||
|
||||
self.assertEqual(err_ctx.exception.errno, errno.EINVAL)
|
||||
|
||||
def test_find_multiple_lines_nonexistent(self):
|
||||
with gpiod.Chip(mockup.chip_name(1)) as chip:
|
||||
with self.assertRaises(TypeError):
|
||||
lines = chip.find_lines(( 'gpio-mockup-B-0',
|
||||
'nonexistent-line',
|
||||
'gpio-mockup-B-4',
|
||||
'gpio-mockup-B-6' )).to_list()
|
||||
|
||||
def test_get_all_lines(self):
|
||||
with gpiod.Chip(mockup.chip_name(2)) as chip:
|
||||
lines = chip.get_all_lines().to_list()
|
||||
self.assertEqual(len(lines), 4)
|
||||
self.assertEqual(lines[0].name(), 'gpio-mockup-C-0')
|
||||
self.assertEqual(lines[1].name(), 'gpio-mockup-C-1')
|
||||
self.assertEqual(lines[2].name(), 'gpio-mockup-C-2')
|
||||
self.assertEqual(lines[3].name(), 'gpio-mockup-C-3')
|
||||
|
||||
#
|
||||
# Line test cases
|
||||
#
|
||||
|
||||
class LineGlobalFindLine(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 4, 8, 16 )
|
||||
flags = gpiomockup.Mockup.FLAG_NAMED_LINES
|
||||
|
||||
def test_global_find_line_function(self):
|
||||
line = gpiod.find_line('gpio-mockup-B-4')
|
||||
self.assertNotEqual(line, None)
|
||||
try:
|
||||
self.assertEqual(line.owner().label(), 'gpio-mockup-B')
|
||||
self.assertEqual(line.offset(), 4)
|
||||
finally:
|
||||
line.owner().close()
|
||||
|
||||
def test_global_find_line_function_nonexistent(self):
|
||||
line = gpiod.find_line('nonexistent-line')
|
||||
self.assertEqual(line, None)
|
||||
|
||||
class LineInfo(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, )
|
||||
flags = gpiomockup.Mockup.FLAG_NAMED_LINES
|
||||
|
||||
def test_unexported_line(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(4)
|
||||
self.assertEqual(line.offset(), 4)
|
||||
self.assertEqual(line.name(), 'gpio-mockup-A-4')
|
||||
self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
|
||||
self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
|
||||
self.assertEqual(line.consumer(), None)
|
||||
self.assertFalse(line.is_used())
|
||||
self.assertFalse(line.is_requested())
|
||||
|
||||
def test_exported_line(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(4)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_OUT,
|
||||
flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
|
||||
self.assertEqual(line.offset(), 4)
|
||||
self.assertEqual(line.name(), 'gpio-mockup-A-4')
|
||||
self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
|
||||
self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_LOW)
|
||||
self.assertEqual(line.consumer(), default_consumer)
|
||||
self.assertTrue(line.is_used())
|
||||
self.assertTrue(line.is_requested())
|
||||
|
||||
def test_exported_line_with_flags(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(4)
|
||||
flags = (gpiod.LINE_REQ_FLAG_ACTIVE_LOW |
|
||||
gpiod.LINE_REQ_FLAG_OPEN_DRAIN)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_OUT,
|
||||
flags=flags)
|
||||
self.assertEqual(line.offset(), 4)
|
||||
self.assertEqual(line.name(), 'gpio-mockup-A-4')
|
||||
# FIXME Uncomment the line below once this issue is fixed in the kernel.
|
||||
#self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
|
||||
self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_LOW)
|
||||
self.assertEqual(line.consumer(), default_consumer)
|
||||
self.assertTrue(line.is_used())
|
||||
self.assertTrue(line.is_requested())
|
||||
self.assertTrue(line.is_open_drain())
|
||||
self.assertFalse(line.is_open_source())
|
||||
|
||||
class LineValues(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, )
|
||||
|
||||
def test_get_value_single_line(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_IN)
|
||||
self.assertEqual(line.get_value(), 0)
|
||||
mockup.chip_set_pull(0, 3, 1)
|
||||
self.assertEqual(line.get_value(), 1)
|
||||
|
||||
def test_set_value_single_line(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_OUT)
|
||||
line.set_value(1)
|
||||
self.assertEqual(mockup.chip_get_value(0, 3), 1)
|
||||
line.set_value(0)
|
||||
self.assertEqual(mockup.chip_get_value(0, 3), 0)
|
||||
|
||||
def test_set_value_with_default_value_argument(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_OUT,
|
||||
default_val=1)
|
||||
self.assertEqual(mockup.chip_get_value(0, 3), 1)
|
||||
|
||||
def test_get_value_multiple_lines(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
lines = chip.get_lines(( 0, 3, 4, 6 ))
|
||||
lines.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_IN)
|
||||
self.assertEqual(lines.get_values(), [ 0, 0, 0, 0 ])
|
||||
mockup.chip_set_pull(0, 0, 1)
|
||||
mockup.chip_set_pull(0, 4, 1)
|
||||
mockup.chip_set_pull(0, 6, 1)
|
||||
self.assertEqual(lines.get_values(), [ 1, 0, 1, 1 ])
|
||||
|
||||
def test_set_value_multiple_lines(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
lines = chip.get_lines(( 0, 3, 4, 6 ))
|
||||
lines.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_OUT)
|
||||
lines.set_values(( 1, 0, 1, 1 ))
|
||||
self.assertEqual(mockup.chip_get_value(0, 0), 1)
|
||||
self.assertEqual(mockup.chip_get_value(0, 3), 0)
|
||||
self.assertEqual(mockup.chip_get_value(0, 4), 1)
|
||||
self.assertEqual(mockup.chip_get_value(0, 6), 1)
|
||||
lines.set_values(( 0, 0, 1, 0 ))
|
||||
self.assertEqual(mockup.chip_get_value(0, 0), 0)
|
||||
self.assertEqual(mockup.chip_get_value(0, 3), 0)
|
||||
self.assertEqual(mockup.chip_get_value(0, 4), 1)
|
||||
self.assertEqual(mockup.chip_get_value(0, 6), 0)
|
||||
|
||||
def test_set_multiple_values_with_default_vals_argument(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
lines = chip.get_lines(( 0, 3, 4, 6 ))
|
||||
lines.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_OUT,
|
||||
default_vals=( 1, 0, 1, 1 ))
|
||||
self.assertEqual(mockup.chip_get_value(0, 0), 1)
|
||||
self.assertEqual(mockup.chip_get_value(0, 3), 0)
|
||||
self.assertEqual(mockup.chip_get_value(0, 4), 1)
|
||||
self.assertEqual(mockup.chip_get_value(0, 6), 1)
|
||||
|
||||
def test_get_value_active_low(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_IN,
|
||||
flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
|
||||
self.assertEqual(line.get_value(), 1)
|
||||
mockup.chip_set_pull(0, 3, 1)
|
||||
self.assertEqual(line.get_value(), 0)
|
||||
|
||||
def test_set_value_active_low(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_OUT,
|
||||
flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
|
||||
line.set_value(1)
|
||||
self.assertEqual(mockup.chip_get_value(0, 3), 0)
|
||||
line.set_value(0)
|
||||
self.assertEqual(mockup.chip_get_value(0, 3), 1)
|
||||
|
||||
class LineRequestBehavior(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, )
|
||||
|
||||
def test_line_export_release(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_IN)
|
||||
self.assertTrue(line.is_requested())
|
||||
self.assertEqual(line.get_value(), 0)
|
||||
line.release()
|
||||
self.assertFalse(line.is_requested())
|
||||
|
||||
def test_line_request_twice_two_calls(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_IN)
|
||||
with self.assertRaises(OSError):
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_IN)
|
||||
|
||||
def test_line_request_twice_in_bulk(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
lines = chip.get_lines(( 2, 3, 6, 6 ))
|
||||
with self.assertRaises(OSError):
|
||||
lines.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_IN)
|
||||
|
||||
def test_use_value_unrequested(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
with self.assertRaises(OSError):
|
||||
line.get_value()
|
||||
|
||||
#
|
||||
# Iterator test cases
|
||||
#
|
||||
|
||||
class ChipIterator(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 4, 8, 16 )
|
||||
|
||||
def test_iterate_over_chips(self):
|
||||
gotA = False
|
||||
gotB = False
|
||||
gotC = False
|
||||
|
||||
for chip in gpiod.ChipIter():
|
||||
if chip.label() == 'gpio-mockup-A':
|
||||
gotA = True
|
||||
elif chip.label() == 'gpio-mockup-B':
|
||||
gotB = True
|
||||
elif chip.label() == 'gpio-mockup-C':
|
||||
gotC = True
|
||||
|
||||
self.assertTrue(gotA)
|
||||
self.assertTrue(gotB)
|
||||
self.assertTrue(gotC)
|
||||
|
||||
class LineIterator(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 4, )
|
||||
|
||||
def test_iterate_over_lines(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
count = 0
|
||||
|
||||
for line in gpiod.LineIter(chip):
|
||||
self.assertEqual(line.offset(), count)
|
||||
count += 1
|
||||
|
||||
self.assertEqual(count, chip.num_lines())
|
||||
|
||||
class LineBulkIter(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 4, )
|
||||
|
||||
def test_line_bulk_iterator(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
lines = chip.get_all_lines()
|
||||
count = 0
|
||||
|
||||
for line in lines:
|
||||
self.assertEqual(line.offset(), count)
|
||||
count += 1
|
||||
|
||||
self.assertEqual(count, chip.num_lines())
|
||||
|
||||
#
|
||||
# Event test cases
|
||||
#
|
||||
|
||||
class EventSingleLine(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, )
|
||||
|
||||
def test_single_line_rising_edge_event(self):
|
||||
with EventThread(0, 4, 200):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(4)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_RISING_EDGE)
|
||||
self.assertTrue(line.event_wait(sec=1))
|
||||
event = line.event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 4)
|
||||
|
||||
def test_single_line_falling_edge_event(self):
|
||||
with EventThread(0, 4, 200):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(4)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_FALLING_EDGE)
|
||||
self.assertTrue(line.event_wait(sec=1))
|
||||
event = line.event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 4)
|
||||
|
||||
def test_single_line_both_edges_events(self):
|
||||
with EventThread(0, 4, 200):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(4)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
self.assertTrue(line.event_wait(sec=1))
|
||||
event = line.event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 4)
|
||||
self.assertTrue(line.event_wait(sec=1))
|
||||
event = line.event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 4)
|
||||
|
||||
def test_single_line_both_edges_events_active_low(self):
|
||||
with EventThread(0, 4, 200):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(4)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_BOTH_EDGES,
|
||||
flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
|
||||
self.assertTrue(line.event_wait(sec=1))
|
||||
event = line.event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 4)
|
||||
self.assertTrue(line.event_wait(sec=1))
|
||||
event = line.event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 4)
|
||||
|
||||
class EventBulk(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, )
|
||||
|
||||
def test_watch_multiple_lines_for_events(self):
|
||||
with EventThread(0, 2, 200):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
lines = chip.get_lines(( 0, 1, 2, 3, 4 ))
|
||||
lines.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
event_lines = lines.event_wait(sec=1)
|
||||
self.assertEqual(len(event_lines), 1)
|
||||
line = event_lines[0]
|
||||
event = line.event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 2)
|
||||
event_lines = lines.event_wait(sec=1)
|
||||
self.assertEqual(len(event_lines), 1)
|
||||
line = event_lines[0]
|
||||
event = line.event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 2)
|
||||
|
||||
class EventValues(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, )
|
||||
|
||||
def test_request_for_events_get_value(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
self.assertEqual(line.get_value(), 0)
|
||||
mockup.chip_set_pull(0, 3, 1)
|
||||
self.assertEqual(line.get_value(), 1)
|
||||
|
||||
def test_request_for_events_get_value_active_low(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_BOTH_EDGES,
|
||||
flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
|
||||
self.assertEqual(line.get_value(), 1)
|
||||
mockup.chip_set_pull(0, 3, 1)
|
||||
self.assertEqual(line.get_value(), 0)
|
||||
|
||||
class EventFileDescriptor(MockupTestCase):
|
||||
|
||||
chip_sizes = ( 8, )
|
||||
|
||||
def test_event_get_fd(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
fd = line.event_get_fd();
|
||||
self.assertGreaterEqual(fd, 0)
|
||||
|
||||
def test_event_get_fd_not_requested(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
with self.assertRaises(OSError):
|
||||
fd = line.event_get_fd();
|
||||
|
||||
def test_event_get_fd_requested_for_values(self):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_DIR_IN)
|
||||
with self.assertRaises(OSError):
|
||||
fd = line.event_get_fd();
|
||||
|
||||
def test_event_fd_polling(self):
|
||||
with EventThread(0, 2, 200):
|
||||
with gpiod.Chip(mockup.chip_name(0)) as chip:
|
||||
lines = chip.get_lines(( 0, 1, 2, 3, 4, 5, 6 ))
|
||||
lines.request(consumer=default_consumer,
|
||||
type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
|
||||
inputs = []
|
||||
for line in lines:
|
||||
inputs.append(line.event_get_fd())
|
||||
|
||||
readable, writable, exceptional = select.select(inputs, [],
|
||||
inputs, 1.0)
|
||||
|
||||
self.assertEqual(len(readable), 1)
|
||||
event = lines.to_list()[2].event_read()
|
||||
self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
|
||||
self.assertEqual(event.source.offset(), 2)
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
|
||||
if __name__ == '__main__':
|
||||
check_kernel(5, 2, 7)
|
||||
mockup = gpiomockup.Mockup()
|
||||
unittest.main()
|
||||
313
bindings/python/tests/gpiomockupmodule.c
Normal file
313
bindings/python/tests/gpiomockupmodule.c
Normal file
@@ -0,0 +1,313 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <gpio-mockup.h>
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
struct gpio_mockup *mockup;
|
||||
} gpiomockup_MockupObject;
|
||||
|
||||
enum {
|
||||
gpiomockup_FLAG_NAMED_LINES = 1,
|
||||
};
|
||||
|
||||
static int gpiomockup_Mockup_init(gpiomockup_MockupObject *self,
|
||||
PyObject *Py_UNUSED(ignored0),
|
||||
PyObject *Py_UNUSED(ignored1))
|
||||
{
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
self->mockup = gpio_mockup_new();
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (!self->mockup) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiomockup_Mockup_dealloc(gpiomockup_MockupObject *self)
|
||||
{
|
||||
if (self->mockup) {
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
gpio_mockup_unref(self->mockup);
|
||||
Py_END_ALLOW_THREADS;
|
||||
}
|
||||
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
static PyObject *gpiomockup_Mockup_probe(gpiomockup_MockupObject *self,
|
||||
PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *kwlist[] = { "chip_sizes",
|
||||
"flags",
|
||||
NULL };
|
||||
|
||||
PyObject *chip_sizes_obj, *iter, *next;
|
||||
unsigned int *chip_sizes;
|
||||
int ret, flags = 0, i;
|
||||
Py_ssize_t num_chips;
|
||||
|
||||
ret = PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist,
|
||||
&chip_sizes_obj, &flags);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
num_chips = PyObject_Size(chip_sizes_obj);
|
||||
if (num_chips < 0) {
|
||||
return NULL;
|
||||
} else if (num_chips == 0) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Number of chips must be greater thatn 0");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chip_sizes = PyMem_RawCalloc(num_chips, sizeof(unsigned int));
|
||||
if (!chip_sizes)
|
||||
return NULL;
|
||||
|
||||
iter = PyObject_GetIter(chip_sizes_obj);
|
||||
if (!iter) {
|
||||
PyMem_RawFree(chip_sizes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0;; i++) {
|
||||
next = PyIter_Next(iter);
|
||||
if (!next) {
|
||||
Py_DECREF(iter);
|
||||
break;
|
||||
}
|
||||
|
||||
chip_sizes[i] = PyLong_AsUnsignedLong(next);
|
||||
Py_DECREF(next);
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(iter);
|
||||
PyMem_RawFree(chip_sizes);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & gpiomockup_FLAG_NAMED_LINES)
|
||||
flags |= GPIO_MOCKUP_FLAG_NAMED_LINES;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
ret = gpio_mockup_probe(self->mockup, num_chips, chip_sizes, flags);
|
||||
Py_END_ALLOW_THREADS;
|
||||
PyMem_RawFree(chip_sizes);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *gpiomockup_Mockup_remove(gpiomockup_MockupObject *self,
|
||||
PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
int ret;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
ret = gpio_mockup_remove(self->mockup);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (ret) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *gpiomockup_Mockup_chip_name(gpiomockup_MockupObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
unsigned int idx;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
ret = PyArg_ParseTuple(args, "I", &idx);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
name = gpio_mockup_chip_name(self->mockup, idx);
|
||||
if (!name) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyUnicode_FromString(name);
|
||||
}
|
||||
|
||||
static PyObject *gpiomockup_Mockup_chip_path(gpiomockup_MockupObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
unsigned int idx;
|
||||
const char *path;
|
||||
int ret;
|
||||
|
||||
ret = PyArg_ParseTuple(args, "I", &idx);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
path = gpio_mockup_chip_path(self->mockup, idx);
|
||||
if (!path) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyUnicode_FromString(path);
|
||||
}
|
||||
|
||||
static PyObject *gpiomockup_Mockup_chip_num(gpiomockup_MockupObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
unsigned int idx;
|
||||
int ret, num;
|
||||
|
||||
ret = PyArg_ParseTuple(args, "I", &idx);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
num = gpio_mockup_chip_num(self->mockup, idx);
|
||||
if (num < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyLong_FromLong(num);
|
||||
}
|
||||
|
||||
static PyObject *gpiomockup_Mockup_chip_get_value(gpiomockup_MockupObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
unsigned int chip_idx, line_offset;
|
||||
int ret, val;
|
||||
|
||||
ret = PyArg_ParseTuple(args, "II", &chip_idx, &line_offset);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
val = gpio_mockup_get_value(self->mockup, chip_idx, line_offset);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (val < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyLong_FromUnsignedLong(val);
|
||||
}
|
||||
|
||||
static PyObject *gpiomockup_Mockup_chip_set_pull(gpiomockup_MockupObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
unsigned int chip_idx, line_offset;
|
||||
int ret, pull;
|
||||
|
||||
ret = PyArg_ParseTuple(args, "IIi", &chip_idx, &line_offset, &pull);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
ret = gpio_mockup_set_pull(self->mockup, chip_idx, line_offset, pull);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (ret) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef gpiomockup_Mockup_methods[] = {
|
||||
{
|
||||
.ml_name = "probe",
|
||||
.ml_meth = (PyCFunction)(void (*)(void))gpiomockup_Mockup_probe,
|
||||
.ml_flags = METH_VARARGS | METH_KEYWORDS,
|
||||
},
|
||||
{
|
||||
.ml_name = "remove",
|
||||
.ml_meth = (PyCFunction)gpiomockup_Mockup_remove,
|
||||
.ml_flags = METH_NOARGS,
|
||||
},
|
||||
{
|
||||
.ml_name = "chip_name",
|
||||
.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_name,
|
||||
.ml_flags = METH_VARARGS,
|
||||
},
|
||||
{
|
||||
.ml_name = "chip_path",
|
||||
.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_path,
|
||||
.ml_flags = METH_VARARGS,
|
||||
},
|
||||
{
|
||||
.ml_name = "chip_num",
|
||||
.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_num,
|
||||
.ml_flags = METH_VARARGS,
|
||||
},
|
||||
{
|
||||
.ml_name = "chip_get_value",
|
||||
.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_get_value,
|
||||
.ml_flags = METH_VARARGS,
|
||||
},
|
||||
{
|
||||
.ml_name = "chip_set_pull",
|
||||
.ml_meth = (PyCFunction)gpiomockup_Mockup_chip_set_pull,
|
||||
.ml_flags = METH_VARARGS,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static PyTypeObject gpiomockup_MockupType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "gpiomockup.Mockup",
|
||||
.tp_basicsize = sizeof(gpiomockup_MockupObject),
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_new = PyType_GenericNew,
|
||||
.tp_init = (initproc)gpiomockup_Mockup_init,
|
||||
.tp_dealloc = (destructor)gpiomockup_Mockup_dealloc,
|
||||
.tp_methods = gpiomockup_Mockup_methods,
|
||||
};
|
||||
|
||||
static PyModuleDef gpiomockup_Module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_name = "gpiomockup",
|
||||
.m_size = -1,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_gpiomockup(void)
|
||||
{
|
||||
PyObject *module, *val;
|
||||
int ret;
|
||||
|
||||
module = PyModule_Create(&gpiomockup_Module);
|
||||
if (!module)
|
||||
return NULL;
|
||||
|
||||
ret = PyType_Ready(&gpiomockup_MockupType);
|
||||
if (ret)
|
||||
return NULL;
|
||||
Py_INCREF(&gpiomockup_MockupType);
|
||||
|
||||
ret = PyModule_AddObject(module, "Mockup",
|
||||
(PyObject *)&gpiomockup_MockupType);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
val = PyLong_FromLong(gpiomockup_FLAG_NAMED_LINES);
|
||||
if (!val)
|
||||
return NULL;
|
||||
|
||||
ret = PyDict_SetItemString(gpiomockup_MockupType.tp_dict,
|
||||
"FLAG_NAMED_LINES", val);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
return module;
|
||||
}
|
||||
@@ -220,6 +220,7 @@ AC_CONFIG_FILES([libgpiod.pc
|
||||
bindings/cxx/tests/Makefile
|
||||
bindings/python/Makefile
|
||||
bindings/python/examples/Makefile
|
||||
bindings/python/tests/Makefile
|
||||
man/Makefile])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
Reference in New Issue
Block a user