diff --git a/.coveragerc b/.coveragerc index 85bf3bb..055fbe5 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,2 +1,2 @@ [run] -omit = meshtastic/*_pb2.py,meshtastic/test.py,meshtastic/test/*.py +omit = meshtastic/*_pb2.py,meshtastic/tests/*.py diff --git a/README.md b/README.md index ac8f760..003c2be 100644 --- a/README.md +++ b/README.md @@ -231,11 +231,11 @@ pytest -m smokewifi * To run a specific test: ``` -pytest -msmoke1 meshtastic/test/test_smoke1.py::test_smoke1_info +pytest -msmoke1 meshtastic/tests/test_smoke1.py::test_smoke1_info # or to run a specific smoke2 test -pytest -m smoke2 meshtastic/test/test_smoke2.py::test_smoke2_info +pytest -m smoke2 meshtastic/tests/test_smoke2.py::test_smoke2_info # or to run a specific smoke_wifi test -pytest -m smokewifi meshtastic/test/test_smoke_wifi.py::test_smokewifi_info +pytest -m smokewifi meshtastic/tests/test_smoke_wifi.py::test_smokewifi_info ``` * To add another classification of tests such as "unit" or "smoke1", see [pytest.ini](pytest.ini). diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index f060465..fdf0de5 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -11,12 +11,14 @@ import yaml from pubsub import pub import pyqrcode import pkg_resources +import meshtastic.util +import meshtastic.test +from meshtastic.serial_interface import SerialInterface from .serial_interface import SerialInterface from .tcp_interface import TCPInterface from .ble_interface import BLEInterface -from . import test, remote_hardware +from . import remote_hardware from . import portnums_pb2, channel_pb2, mesh_pb2, radioconfig_pb2 -from .util import support_info, our_exit, genPSK256, fromPSK, fromStr from .globals import Globals """We only import the tunnel code if we are on a platform that can run it""" @@ -98,7 +100,7 @@ def setPref(attributes, name, valStr): print(f" {f.name}") return - val = fromStr(valStr) + val = meshtastic.util.fromStr(valStr) enumType = field.enum_type # pylint: disable=C0123 @@ -232,7 +234,7 @@ def onConnected(interface): getNode().setOwner(args.set_ham, is_licensed=True) # Must turn off crypt on primary channel ch = getNode().channels[0] - ch.settings.psk = fromPSK("none") + ch.settings.psk = meshtastic.util.fromPSK("none") print(f"Writing modified channels to device") getNode().writeChannel(0) @@ -349,7 +351,7 @@ def onConnected(interface): closeNow = True n = getNode() if len(args.ch_add) > 10: - our_exit("Warning: Channel name must be shorter. Channel not added.") + meshtastic.util.our_exit("Warning: Channel name must be shorter. Channel not added.") ch = n.getChannelByName(args.ch_add) if ch: logging.error( @@ -357,9 +359,9 @@ def onConnected(interface): else: ch = n.getDisabledChannel() if not ch: - our_exit("Warning: No free channels were found") + meshtastic.util.our_exit("Warning: No free channels were found") chs = channel_pb2.ChannelSettings() - chs.psk = genPSK256() + chs.psk = meshtastic.util.genPSK256() chs.name = args.ch_add ch.settings.CopyFrom(chs) ch.role = channel_pb2.Channel.Role.SECONDARY @@ -383,7 +385,7 @@ def onConnected(interface): if args.ch_longslow or args.ch_longfast or args.ch_mediumslow or args.ch_mediumfast or args.ch_shortslow or args.ch_shortfast: if channelIndex != 0: - our_exit("Warning: Standard channel settings can only be applied to the PRIMARY channel") + meshtastic.util.our_exit("Warning: Standard channel settings can only be applied to the PRIMARY channel") enable = True # force enable @@ -425,7 +427,7 @@ def onConnected(interface): # Handle the channel settings for pref in (args.ch_set or []): if pref[0] == "psk": - ch.settings.psk = fromPSK(pref[1]) + ch.settings.psk = meshtastic.util.fromPSK(pref[1]) else: setPref(ch.settings, pref[0], pref[1]) enable = True # If we set any pref, assume the user wants to enable the channel @@ -512,11 +514,11 @@ def common(): if len(sys.argv) == 1: parser.print_help(sys.stderr) - our_exit("", 1) + meshtastic.util.our_exit("", 1) else: if args.support: - support_info() - our_exit("", 0) + meshtastic.util.support_info() + meshtastic.util.our_exit("", 0) if args.ch_index is not None: channelIndex = int(args.ch_index) @@ -540,11 +542,13 @@ def common(): logging.error( 'This option has been deprecated, see help below for the correct replacement...') parser.print_help(sys.stderr) - our_exit('', 1) + meshtastic.util.our_exit('', 1) elif args.test: - result = test.testAll() + result = meshtastic.test.testAll() if not result: - our_exit("Warning: Test was not successful.") + meshtastic.util.our_exit("Warning: Test was not successful.") + else: + meshtastic.util.our_exit("Test was a success.", 0) else: if args.seriallog == "stdout": logfile = sys.stdout diff --git a/meshtastic/test.py b/meshtastic/test.py index 9930cae..0c70f73 100644 --- a/meshtastic/test.py +++ b/meshtastic/test.py @@ -7,11 +7,11 @@ import sys import traceback from dotmap import DotMap from pubsub import pub -from . import util +import meshtastic.util from .__init__ import BROADCAST_NUM from .serial_interface import SerialInterface from .tcp_interface import TCPInterface -from .util import our_exit + """The interfaces we are using for our tests""" interfaces = None @@ -146,9 +146,9 @@ def testAll(numTests=5): This is called from the cli with the "--test" option. """ - ports = util.findPorts() + ports = meshtastic.util.findPorts() if len(ports) < 2: - our_exit("Warning: Must have at least two devices connected to USB.") + meshtastic.util.our_exit("Warning: Must have at least two devices connected to USB.") pub.subscribe(onConnection, "meshtastic.connection") pub.subscribe(onReceive, "meshtastic.receive") diff --git a/meshtastic/test/test_main.py b/meshtastic/test/test_main.py deleted file mode 100644 index d9eaaaa..0000000 --- a/meshtastic/test/test_main.py +++ /dev/null @@ -1,122 +0,0 @@ -"""Meshtastic unit tests for __main__.py""" - -import sys -import argparse -import re - -import pytest - -from meshtastic.__main__ import initParser, main, Globals - - -@pytest.mark.unit -def test_main_init_parser_no_args(capsys): - """Test no arguments""" - sys.argv = [''] - args = sys.argv - our_globals = Globals.getInstance() - parser = argparse.ArgumentParser() - our_globals.set_parser(parser) - our_globals.set_args(args) - initParser() - out, err = capsys.readouterr() - assert out == '' - assert err == '' - - -@pytest.mark.unit -def test_main_init_parser_version(capsys): - """Test --version""" - sys.argv = ['', '--version'] - args = sys.argv - parser = None - parser = argparse.ArgumentParser() - our_globals = Globals.getInstance() - our_globals.set_parser(parser) - our_globals.set_args(args) - with pytest.raises(SystemExit) as pytest_wrapped_e: - initParser() - assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == 0 - out, err = capsys.readouterr() - assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out) - assert err == '' - - -@pytest.mark.unit -def test_main_main_version(capsys): - """Test --version""" - sys.argv = ['', '--version'] - args = sys.argv - parser = None - parser = argparse.ArgumentParser() - our_globals = Globals.getInstance() - our_globals.set_parser(parser) - our_globals.set_args(args) - with pytest.raises(SystemExit) as pytest_wrapped_e: - main() - assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == 0 - out, err = capsys.readouterr() - assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out) - assert err == '' - - -@pytest.mark.unit -def test_main_main_no_args(): - """Test with no args""" - sys.argv = [''] - args = sys.argv - parser = None - parser = argparse.ArgumentParser() - our_globals = Globals.getInstance() - our_globals.set_parser(parser) - our_globals.set_args(args) - with pytest.raises(SystemExit) as pytest_wrapped_e: - main() - assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == 1 - - -@pytest.mark.unit -def test_main_support(capsys): - """Test --support""" - sys.argv = ['', '--support'] - args = sys.argv - parser = None - parser = argparse.ArgumentParser() - our_globals = Globals.getInstance() - our_globals.set_parser(parser) - our_globals.set_args(args) - with pytest.raises(SystemExit) as pytest_wrapped_e: - main() - assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == 0 - out, err = capsys.readouterr() - assert re.search(r'System', out, re.MULTILINE) - assert re.search(r'Platform', out, re.MULTILINE) - assert re.search(r'Machine', out, re.MULTILINE) - assert re.search(r'Executable', out, re.MULTILINE) - assert err == '' - - -@pytest.mark.unit -def test_main_ch_index_no_devices(capsys): - """Test --ch-index 1""" - sys.argv = ['', '--ch-index', '1'] - args = sys.argv - parser = None - parser = argparse.ArgumentParser() - our_globals = Globals.getInstance() - our_globals.set_parser(parser) - our_globals.set_args(args) - assert our_globals.get_target_node() is None - assert our_globals.get_channel_index() == 0 - with pytest.raises(SystemExit) as pytest_wrapped_e: - main() - assert our_globals.get_channel_index() == 1 - assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == 1 - out, err = capsys.readouterr() - assert re.search(r'Warning: No Meshtastic devices detected', out, re.MULTILINE) - assert err == '' diff --git a/meshtastic/test/__init__.py b/meshtastic/tests/__init__.py similarity index 100% rename from meshtastic/test/__init__.py rename to meshtastic/tests/__init__.py diff --git a/meshtastic/test/test_globals.py b/meshtastic/tests/test_globals.py similarity index 100% rename from meshtastic/test/test_globals.py rename to meshtastic/tests/test_globals.py diff --git a/meshtastic/test/test_int.py b/meshtastic/tests/test_int.py similarity index 100% rename from meshtastic/test/test_int.py rename to meshtastic/tests/test_int.py diff --git a/meshtastic/tests/test_main.py b/meshtastic/tests/test_main.py new file mode 100644 index 0000000..dbfbe23 --- /dev/null +++ b/meshtastic/tests/test_main.py @@ -0,0 +1,230 @@ +"""Meshtastic unit tests for __main__.py""" + +import sys +import argparse +import re + +from unittest.mock import patch +import pytest + +from meshtastic.__main__ import initParser, main, Globals +#from meshtastic.serial_interface import SerialInterface + + +@pytest.mark.unit +def test_main_init_parser_no_args(capsys): + """Test no arguments""" + sys.argv = [''] + args = sys.argv + our_globals = Globals.getInstance() + parser = argparse.ArgumentParser() + our_globals.set_parser(parser) + our_globals.set_args(args) + initParser() + out, err = capsys.readouterr() + assert out == '' + assert err == '' + + +@pytest.mark.unit +def test_main_init_parser_version(capsys): + """Test --version""" + sys.argv = ['', '--version'] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + with pytest.raises(SystemExit) as pytest_wrapped_e: + initParser() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 0 + out, err = capsys.readouterr() + assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out) + assert err == '' + + +@pytest.mark.unit +def test_main_main_version(capsys): + """Test --version""" + sys.argv = ['', '--version'] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + with pytest.raises(SystemExit) as pytest_wrapped_e: + main() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 0 + out, err = capsys.readouterr() + assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out) + assert err == '' + + +@pytest.mark.unit +def test_main_main_no_args(): + """Test with no args""" + sys.argv = [''] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + with pytest.raises(SystemExit) as pytest_wrapped_e: + main() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + + +@pytest.mark.unit +def test_main_support(capsys): + """Test --support""" + sys.argv = ['', '--support'] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + with pytest.raises(SystemExit) as pytest_wrapped_e: + main() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 0 + out, err = capsys.readouterr() + assert re.search(r'System', out, re.MULTILINE) + assert re.search(r'Platform', out, re.MULTILINE) + assert re.search(r'Machine', out, re.MULTILINE) + assert re.search(r'Executable', out, re.MULTILINE) + assert err == '' + + +@pytest.mark.unit +def test_main_ch_index_no_devices(capsys): + """Test --ch-index 1""" + sys.argv = ['', '--ch-index', '1'] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + assert our_globals.get_target_node() is None + assert our_globals.get_channel_index() == 0 + with pytest.raises(SystemExit) as pytest_wrapped_e: + main() + assert our_globals.get_channel_index() == 1 + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + out, err = capsys.readouterr() + assert re.search(r'Warning: No Meshtastic devices detected', out, re.MULTILINE) + assert err == '' + + +@pytest.mark.unit +@patch('meshtastic.util.findPorts', return_value=[]) +def test_main_test_no_ports(patched_find_ports): + """Test --test with no hardware""" + sys.argv = ['', '--test'] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + assert our_globals.get_target_node() is None + with pytest.raises(SystemExit) as pytest_wrapped_e: + main() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + patched_find_ports.assert_called() + + +@pytest.mark.unit +@patch('meshtastic.util.findPorts', return_value=['/dev/ttyFake1']) +def test_main_test_one_port(patched_find_ports): + """Test --test with one fake port""" + sys.argv = ['', '--test'] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + assert our_globals.get_target_node() is None + with pytest.raises(SystemExit) as pytest_wrapped_e: + main() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + patched_find_ports.assert_called() + + +@pytest.mark.unit +@patch('meshtastic.test.testAll', return_value=True) +@patch('meshtastic.util.findPorts', return_value=['/dev/ttyFake1', '/dev/ttyFake2']) +def test_main_test_two_ports_success(patched_find_ports, patched_test_all): + """Test --test two fake ports and testAll() is a simulated success""" + sys.argv = ['', '--test'] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + with pytest.raises(SystemExit) as pytest_wrapped_e: + main() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 0 + # TODO: why does this fail? patched_find_ports.assert_called() + patched_test_all.assert_called() + + +@pytest.mark.unit +@patch('meshtastic.test.testAll', return_value=False) +@patch('meshtastic.util.findPorts', return_value=['/dev/ttyFake1', '/dev/ttyFake2']) +def test_main_test_two_ports_fails(patched_find_ports, patched_test_all): + """Test --test two fake ports and testAll() is a simulated failure""" + sys.argv = ['', '--test'] + args = sys.argv + parser = None + parser = argparse.ArgumentParser() + our_globals = Globals.getInstance() + our_globals.set_parser(parser) + our_globals.set_args(args) + with pytest.raises(SystemExit) as pytest_wrapped_e: + main() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + # TODO: why does this fail? patched_find_ports.assert_called() + patched_test_all.assert_called() +# +# +#@pytest.mark.unit +#@patch('meshtastic.stream_interface.StreamInterface.__init__') +#@patch('serial.Serial') +#@patch('meshtastic.serial_interface.SerialInterface') +#@patch('meshtastic.util.findPorts', return_value=['/dev/ttyFake1']) +#def test_main_info_one_port(patched_find_ports, patched_serial_interface, +# patched_serial_serial, patched_stream_interface_constructor): +# """Test --info one fake port""" +# iface = MagicMock() +# patched_serial_interface.return_value = iface +# astream = MagicMock() +# patched_serial_serial = astream +# siface = MagicMock() +# patched_stream_interface_constructor = siface +# sys.argv = ['', '--info'] +# args = sys.argv +# parser = None +# parser = argparse.ArgumentParser() +# our_globals = Globals.getInstance() +# our_globals.set_parser(parser) +# our_globals.set_args(args) +# main() +# patched_find_ports.assert_called() +# patched_serial_interface.assert_called() +# patched_serial_serial.assert_called() +# patched_stream_interface_constructor diff --git a/meshtastic/test/test_mesh_interface.py b/meshtastic/tests/test_mesh_interface.py similarity index 100% rename from meshtastic/test/test_mesh_interface.py rename to meshtastic/tests/test_mesh_interface.py diff --git a/meshtastic/test/test_serial_interface.py b/meshtastic/tests/test_serial_interface.py similarity index 100% rename from meshtastic/test/test_serial_interface.py rename to meshtastic/tests/test_serial_interface.py diff --git a/meshtastic/test/test_smoke1.py b/meshtastic/tests/test_smoke1.py similarity index 100% rename from meshtastic/test/test_smoke1.py rename to meshtastic/tests/test_smoke1.py diff --git a/meshtastic/test/test_smoke2.py b/meshtastic/tests/test_smoke2.py similarity index 100% rename from meshtastic/test/test_smoke2.py rename to meshtastic/tests/test_smoke2.py diff --git a/meshtastic/test/test_smoke_wifi.py b/meshtastic/tests/test_smoke_wifi.py similarity index 100% rename from meshtastic/test/test_smoke_wifi.py rename to meshtastic/tests/test_smoke_wifi.py diff --git a/meshtastic/test/test_stream_interface.py b/meshtastic/tests/test_stream_interface.py similarity index 100% rename from meshtastic/test/test_stream_interface.py rename to meshtastic/tests/test_stream_interface.py diff --git a/meshtastic/test/test_tcp_interface.py b/meshtastic/tests/test_tcp_interface.py similarity index 100% rename from meshtastic/test/test_tcp_interface.py rename to meshtastic/tests/test_tcp_interface.py diff --git a/meshtastic/test/test_util.py b/meshtastic/tests/test_util.py similarity index 100% rename from meshtastic/test/test_util.py rename to meshtastic/tests/test_util.py