diff --git a/dev_requirements.txt b/dev_requirements.txt index acb5d77..b00073a 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,5 +1,6 @@ -r requirements.txt +mock==3.0.5;python_version<"3.3" pytest==5.3.1;python_version>="3.5" pytest==4.6.6;python_version<"3.5" pytest-cov==2.8.1 diff --git a/tests/unit/test_route.py b/tests/unit/test_route.py new file mode 100644 index 0000000..8c052e8 --- /dev/null +++ b/tests/unit/test_route.py @@ -0,0 +1,36 @@ +import pytest + +from umodbus.route import DataRule + + +endpoint = lambda slave_id, function_code, address: 0 + + +def test_basic_route(): + rule = DataRule(endpoint, slave_ids=[1], function_codes=[1], addresses=[1]) + assert rule.match(slave_id=1, function_code=1, address=1) + assert not rule.match(slave_id=0, function_code=1, address=1) + assert not rule.match(slave_id=1, function_code=0, address=1) + assert not rule.match(slave_id=1, function_code=1, address=0) + + +def test_other_iterables(): + # Other iterable types should work, not just lists + rule = DataRule(endpoint, + slave_ids=set([1]), function_codes=[1], addresses=[1]) + assert rule.match(slave_id=1, function_code=1, address=1) + + +def test_wildcard_slave_id(): + rule = DataRule(endpoint, slave_ids=None, function_codes=[1], addresses=[1]) + assert rule.match(slave_id=1, function_code=1, address=1) + + +def test_wildcard_function_code(): + rule = DataRule(endpoint, slave_ids=[1], function_codes=None, addresses=[1]) + assert rule.match(slave_id=1, function_code=1, address=1) + + +def test_wildcard_address(): + rule = DataRule(endpoint, slave_ids=[1], function_codes=[1], addresses=None) + assert rule.match(slave_id=1, function_code=1, address=1) diff --git a/umodbus/route.py b/umodbus/route.py index b95e6f4..3765e87 100644 --- a/umodbus/route.py +++ b/umodbus/route.py @@ -20,9 +20,8 @@ def __init__(self, endpoint, slave_ids, function_codes, addresses): self.addresses = addresses def match(self, slave_id, function_code, address): - if slave_id in self.slave_ids and\ - function_code in self.function_codes and \ - address in self.addresses: - return True - - return False + # A constraint of None matches any value + matches = lambda values, v: values is None or v in values + return matches(self.slave_ids, slave_id) and \ + matches(self.function_codes, function_code) and \ + matches(self.addresses, address) diff --git a/umodbus/server/__init__.py b/umodbus/server/__init__.py index 03b598b..f9d4093 100644 --- a/umodbus/server/__init__.py +++ b/umodbus/server/__init__.py @@ -19,9 +19,11 @@ def route(self, slave_ids=None, function_codes=None, addresses=None): def read_single_bit_values(slave_id, address): return random.choise([0, 1]) - :param slave_ids: A list or set with slave id's. - :param function_codes: A list or set with function codes. - :param addresses: A list or set with addresses. + Any argument can be omitted to match any value. + + :param slave_ids: A list (or iterable) of slave ids. + :param function_codes: A list (or iterable) of function codes. + :param addresses: A list (or iterable) of addresses. """ def inner(f): self.route_map.add_rule(f, slave_ids, function_codes, addresses)