Module meshtastic.tests.test_main

Meshtastic unit tests for main.py

Expand source code
"""Meshtastic unit tests for __main__.py"""
# pylint: disable=C0302

import sys
import os
import re
import logging
import platform

from unittest.mock import patch, MagicMock
import pytest

from meshtastic.__main__ import initParser, main, Globals, onReceive, onConnection, export_config, getPref, setPref, onNode, tunnelMain
#from ..radioconfig_pb2 import UserPreferences
#import meshtastic.config_pb2
from ..serial_interface import SerialInterface
from ..tcp_interface import TCPInterface
#from ..ble_interface import BLEInterface
from ..node import Node
from ..channel_pb2 import Channel
#from ..remote_hardware import onGPIOreceive
#from ..config_pb2 import Config


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_init_parser_no_args(capsys):
    """Test no arguments"""
    sys.argv = ['']
    Globals.getInstance().set_args(sys.argv)
    initParser()
    out, err = capsys.readouterr()
    assert out == ''
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_init_parser_version(capsys):
    """Test --version"""
    sys.argv = ['', '--version']
    Globals.getInstance().set_args(sys.argv)

    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]+[\.a][0-9]', out)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_main_version(capsys):
    """Test --version"""
    sys.argv = ['', '--version']
    Globals.getInstance().set_args(sys.argv)

    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]+[\.a][0-9]', out)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_main_no_args(capsys):
    """Test with no args"""
    sys.argv = ['']
    Globals.getInstance().set_args(sys.argv)

    with pytest.raises(SystemExit) as pytest_wrapped_e:
        main()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 1
    _, err = capsys.readouterr()
    assert re.search(r'usage:', err, re.MULTILINE)


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_support(capsys):
    """Test --support"""
    sys.argv = ['', '--support']
    Globals.getInstance().set_args(sys.argv)

    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
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=[])
def test_main_ch_index_no_devices(patched_find_ports, capsys):
    """Test --ch-index 1"""
    sys.argv = ['', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    with pytest.raises(SystemExit) as pytest_wrapped_e:
        main()
    assert Globals.getInstance().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 == ''
    patched_find_ports.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=[])
def test_main_test_no_ports(patched_find_ports, capsys):
    """Test --test with no hardware"""
    sys.argv = ['', '--test']
    Globals.getInstance().set_args(sys.argv)

    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()
    out, err = capsys.readouterr()
    assert re.search(r'Warning: Must have at least two devices connected to USB', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyFake1'])
def test_main_test_one_port(patched_find_ports, capsys):
    """Test --test with one fake port"""
    sys.argv = ['', '--test']
    Globals.getInstance().set_args(sys.argv)

    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()
    out, err = capsys.readouterr()
    assert re.search(r'Warning: Must have at least two devices connected to USB', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.test.testAll', return_value=True)
def test_main_test_two_ports_success(patched_test_all, capsys):
    """Test --test two fake ports and testAll() is a simulated success"""
    sys.argv = ['', '--test']
    Globals.getInstance().set_args(sys.argv)

    with pytest.raises(SystemExit) as pytest_wrapped_e:
        main()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 0
    patched_test_all.assert_called()
    out, err = capsys.readouterr()
    assert re.search(r'Test was a success.', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.test.testAll', return_value=False)
def test_main_test_two_ports_fails(patched_test_all, capsys):
    """Test --test two fake ports and testAll() is a simulated failure"""
    sys.argv = ['', '--test']
    Globals.getInstance().set_args(sys.argv)

    with pytest.raises(SystemExit) as pytest_wrapped_e:
        main()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 1
    patched_test_all.assert_called()
    out, err = capsys.readouterr()
    assert re.search(r'Test was not successful.', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_info(capsys, caplog):
    """Test --info"""
    sys.argv = ['', '--info']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo
    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
            main()
            out, err = capsys.readouterr()
            assert re.search(r'Connected to radio', out, re.MULTILINE)
            assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
            assert err == ''
            mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('os.getlogin')
def test_main_info_with_permission_error(patched_getlogin, capsys, caplog):
    """Test --info"""
    sys.argv = ['', '--info']
    Globals.getInstance().set_args(sys.argv)

    patched_getlogin.return_value = 'me'

    iface = MagicMock(autospec=SerialInterface)
    with caplog.at_level(logging.DEBUG):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
                mo.side_effect = PermissionError('bla bla')
                main()
            assert pytest_wrapped_e.type == SystemExit
            assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        patched_getlogin.assert_called()
        assert re.search(r'Need to add yourself', out, re.MULTILINE)
        assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_info_with_tcp_interface(capsys):
    """Test --info"""
    sys.argv = ['', '--info', '--host', 'meshtastic.local']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=TCPInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo
    with patch('meshtastic.tcp_interface.TCPInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


# TODO: comment out ble (for now)
#@pytest.mark.unit
#def test_main_info_with_ble_interface(capsys):
#    """Test --info"""
#    sys.argv = ['', '--info', '--ble', 'foo']
#    Globals.getInstance().set_args(sys.argv)
#
#    iface = MagicMock(autospec=BLEInterface)
#    def mock_showInfo():
#        print('inside mocked showInfo')
#    iface.showInfo.side_effect = mock_showInfo
#    with patch('meshtastic.ble_interface.BLEInterface', return_value=iface) as mo:
#        main()
#        out, err = capsys.readouterr()
#        assert re.search(r'Connected to radio', out, re.MULTILINE)
#        assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
#        assert err == ''
#        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_no_proto(capsys):
    """Test --noproto (using --info for output)"""
    sys.argv = ['', '--info', '--noproto']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo

    # Override the time.sleep so there is no loop
    def my_sleep(amount):
        print(f'amount:{amount}')
        sys.exit(0)

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with patch('time.sleep', side_effect=my_sleep):
            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'Connected to radio', out, re.MULTILINE)
            assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
            assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_info_with_seriallog_stdout(capsys):
    """Test --info"""
    sys.argv = ['', '--info', '--seriallog', 'stdout']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_info_with_seriallog_output_txt(capsys):
    """Test --info"""
    sys.argv = ['', '--info', '--seriallog', 'output.txt']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
    # do some cleanup
    os.remove('output.txt')


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_qr(capsys):
    """Test --qr"""
    sys.argv = ['', '--qr']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    # TODO: could mock/check url
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Primary channel URL', out, re.MULTILINE)
        # if a qr code is generated it will have lots of these
        assert re.search(r'\[7m', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onConnected_exception(capsys):
    """Test the exception in onConnected"""
    sys.argv = ['', '--qr']
    Globals.getInstance().set_args(sys.argv)

    def throw_an_exception(junk):
        raise Exception("Fake exception.")

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with patch('pyqrcode.create', side_effect=throw_an_exception):
            with pytest.raises(Exception) as pytest_wrapped_e:
                main()
                out, err = capsys.readouterr()
                assert re.search('Aborting due to: Fake exception', out, re.MULTILINE)
                assert err == ''
                assert pytest_wrapped_e.type == Exception


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_nodes(capsys):
    """Test --nodes"""
    sys.argv = ['', '--nodes']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showNodes():
        print('inside mocked showNodes')
    iface.showNodes.side_effect = mock_showNodes
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked showNodes', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_owner_to_bob(capsys):
    """Test --set-owner bob"""
    sys.argv = ['', '--set-owner', 'bob']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting device owner to bob', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_owner_short_to_bob(capsys):
    """Test --set-owner-short bob"""
    sys.argv = ['', '--set-owner-short', 'bob']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting device owner short to bob', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_canned_messages(capsys):
    """Test --set-canned-message """
    sys.argv = ['', '--set-canned-message', 'foo']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting canned plugin message to foo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_get_canned_messages(capsys, caplog, iface_with_nodes):
    """Test --get-canned-message """
    sys.argv = ['', '--get-canned-message']
    Globals.getInstance().set_args(sys.argv)

    iface = iface_with_nodes
    iface.localNode.cannedPluginMessage = 'foo'

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
            main()
            out, err = capsys.readouterr()
            assert re.search(r'Connected to radio', out, re.MULTILINE)
            assert re.search(r'canned_plugin_message:foo', out, re.MULTILINE)
            assert err == ''
            mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_ham_to_KI123(capsys):
    """Test --set-ham KI123"""
    sys.argv = ['', '--set-ham', 'KI123']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_turnOffEncryptionOnPrimaryChannel():
        print('inside mocked turnOffEncryptionOnPrimaryChannel')
    def mock_setOwner(name, is_licensed):
        print(f'inside mocked setOwner name:{name} is_licensed:{is_licensed}')
    mocked_node.turnOffEncryptionOnPrimaryChannel.side_effect = mock_turnOffEncryptionOnPrimaryChannel
    mocked_node.setOwner.side_effect = mock_setOwner

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting Ham ID to KI123', out, re.MULTILINE)
        assert re.search(r'inside mocked setOwner', out, re.MULTILINE)
        assert re.search(r'inside mocked turnOffEncryptionOnPrimaryChannel', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_reboot(capsys):
    """Test --reboot"""
    sys.argv = ['', '--reboot']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_reboot():
        print('inside mocked reboot')
    mocked_node.reboot.side_effect = mock_reboot

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked reboot', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_shutdown(capsys):
    """Test --shutdown"""
    sys.argv = ['', '--shutdown']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_shutdown():
        print('inside mocked shutdown')
    mocked_node.shutdown.side_effect = mock_shutdown

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked shutdown', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext(capsys):
    """Test --sendtext"""
    sys.argv = ['', '--sendtext', 'hello']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendText(text, dest, wantAck, channelIndex):
        print('inside mocked sendText')
        print(f'{text} {dest} {wantAck} {channelIndex}')
    iface.sendText.side_effect = mock_sendText

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Sending text message', out, re.MULTILINE)
        assert re.search(r'inside mocked sendText', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext_with_channel(capsys):
    """Test --sendtext"""
    sys.argv = ['', '--sendtext', 'hello', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendText(text, dest, wantAck, channelIndex):
        print('inside mocked sendText')
        print(f'{text} {dest} {wantAck} {channelIndex}')
    iface.sendText.side_effect = mock_sendText

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Sending text message', out, re.MULTILINE)
        assert re.search(r'on channelIndex:1', out, re.MULTILINE)
        assert re.search(r'inside mocked sendText', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext_with_invalid_channel(caplog, capsys):
    """Test --sendtext"""
    sys.argv = ['', '--sendtext', 'hello', '--ch-index', '-1']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    iface.localNode.getChannelByChannelIndex.return_value = None

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
            with pytest.raises(SystemExit) as pytest_wrapped_e:
                main()
            assert pytest_wrapped_e.type == SystemExit
            assert pytest_wrapped_e.value.code == 1
            out, err = capsys.readouterr()
            assert re.search(r'is not a valid channel', out, re.MULTILINE)
            assert err == ''
            mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext_with_invalid_channel_nine(caplog, capsys):
    """Test --sendtext"""
    sys.argv = ['', '--sendtext', 'hello', '--ch-index', '9']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    iface.localNode.getChannelByChannelIndex.return_value = None

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
            with pytest.raises(SystemExit) as pytest_wrapped_e:
                main()
            assert pytest_wrapped_e.type == SystemExit
            assert pytest_wrapped_e.value.code == 1
            out, err = capsys.readouterr()
            assert re.search(r'is not a valid channel', out, re.MULTILINE)
            assert err == ''
            mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext_with_dest(capsys, caplog, iface_with_nodes):
    """Test --sendtext with --dest"""
    sys.argv = ['', '--sendtext', 'hello', '--dest', 'foo']
    Globals.getInstance().set_args(sys.argv)

    iface = iface_with_nodes
    iface.myInfo.my_node_num = 2475227164
    mocked_channel = MagicMock(autospec=Channel)
    iface.localNode.getChannelByChannelIndex = mocked_channel

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with caplog.at_level(logging.DEBUG):

            with pytest.raises(SystemExit) as pytest_wrapped_e:
                main()
            assert pytest_wrapped_e.type == SystemExit
            assert pytest_wrapped_e.value.code == 1
            out, err = capsys.readouterr()
            assert re.search(r'Connected to radio', out, re.MULTILINE)
            assert not re.search(r"Warning: 0 is not a valid channel", out, re.MULTILINE)
            assert not re.search(r"There is a SECONDARY channel named 'admin'", out, re.MULTILINE)
            assert re.search(r'Warning: NodeId foo not found in DB', out, re.MULTILINE)
            assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendping(capsys):
    """Test --sendping"""
    sys.argv = ['', '--sendping']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendData(payload, dest, portNum, wantAck, wantResponse):
        print('inside mocked sendData')
        print(f'{payload} {dest} {portNum} {wantAck} {wantResponse}')
    iface.sendData.side_effect = mock_sendData

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Sending ping message', out, re.MULTILINE)
        assert re.search(r'inside mocked sendData', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setlat(capsys):
    """Test --sendlat"""
    sys.argv = ['', '--setlat', '37.5']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_writeConfig():
        print('inside mocked writeConfig')
    mocked_node.writeConfig.side_effect = mock_writeConfig

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendPosition(lat, lon, alt):
        print('inside mocked sendPosition')
        print(f'{lat} {lon} {alt}')
    iface.sendPosition.side_effect = mock_sendPosition
    iface.localNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Fixing latitude', out, re.MULTILINE)
        assert re.search(r'Setting device position', out, re.MULTILINE)
        assert re.search(r'inside mocked sendPosition', out, re.MULTILINE)
        # TODO: Why does this not work? assert re.search(r'inside mocked writeConfig', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setlon(capsys):
    """Test --setlon"""
    sys.argv = ['', '--setlon', '-122.1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_writeConfig():
        print('inside mocked writeConfig')
    mocked_node.writeConfig.side_effect = mock_writeConfig

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendPosition(lat, lon, alt):
        print('inside mocked sendPosition')
        print(f'{lat} {lon} {alt}')
    iface.sendPosition.side_effect = mock_sendPosition
    iface.localNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Fixing longitude', out, re.MULTILINE)
        assert re.search(r'Setting device position', out, re.MULTILINE)
        assert re.search(r'inside mocked sendPosition', out, re.MULTILINE)
        # TODO: Why does this not work? assert re.search(r'inside mocked writeConfig', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setalt(capsys):
    """Test --setalt"""
    sys.argv = ['', '--setalt', '51']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_writeConfig():
        print('inside mocked writeConfig')
    mocked_node.writeConfig.side_effect = mock_writeConfig

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendPosition(lat, lon, alt):
        print('inside mocked sendPosition')
        print(f'{lat} {lon} {alt}')
    iface.sendPosition.side_effect = mock_sendPosition
    iface.localNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Fixing altitude', out, re.MULTILINE)
        assert re.search(r'Setting device position', out, re.MULTILINE)
        assert re.search(r'inside mocked sendPosition', out, re.MULTILINE)
        # TODO: Why does this not work? assert re.search(r'inside mocked writeConfig', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_seturl(capsys):
    """Test --seturl (url used below is what is generated after a factory_reset)"""
    sys.argv = ['', '--seturl', 'https://www.meshtastic.org/d/#CgUYAyIBAQ']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_valid(capsys):
    """Test --set with valid field"""
    sys.argv = ['', '--set', 'wifi_ssid', 'foo']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Set wifi_ssid to foo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_valid_wifi_passwd(capsys):
    """Test --set with valid field"""
    sys.argv = ['', '--set', 'wifi_password', '123456789']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Set wifi_password to 123456789', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_invalid_wifi_passwd(capsys):
    """Test --set with an invalid value (password must be 8 or more characters)"""
    sys.argv = ['', '--set', 'wifi_password', '1234567']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert not re.search(r'Set wifi_password to 1234567', out, re.MULTILINE)
        assert re.search(r'Warning: wifi_password must be 8 or more characters.', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_valid_camel_case(capsys):
    """Test --set with valid field"""
    sys.argv = ['', '--set', 'wifi_ssid', 'foo']
    Globals.getInstance().set_args(sys.argv)
    Globals.getInstance().set_camel_case()

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Set wifiSsid to foo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_with_invalid(capsys):
    """Test --set with invalid field"""
    sys.argv = ['', '--set', 'foo', 'foo']
    Globals.getInstance().set_args(sys.argv)

    mocked_user_prefs = MagicMock()
    mocked_user_prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    mocked_node = MagicMock(autospec=Node)
    mocked_node.radioConfig.preferences = ( mocked_user_prefs )

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


# TODO: write some negative --configure tests
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_configure_with_snake_case(capsys):
    """Test --configure with valid file"""
    sys.argv = ['', '--configure', 'example_config.yaml']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting device owner', out, re.MULTILINE)
        assert re.search(r'Setting device owner short', out, re.MULTILINE)
        assert re.search(r'Setting channel url', out, re.MULTILINE)
        assert re.search(r'Fixing altitude', out, re.MULTILINE)
        assert re.search(r'Fixing latitude', out, re.MULTILINE)
        assert re.search(r'Fixing longitude', out, re.MULTILINE)
        assert re.search(r'Set location_share to LocEnabled', out, re.MULTILINE)
        assert re.search(r'Writing modified preferences', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_configure_with_camel_case_keys(capsys):
    """Test --configure with valid file"""
    sys.argv = ['', '--configure', 'exampleConfig.yaml']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting device owner', out, re.MULTILINE)
        assert re.search(r'Setting device owner short', out, re.MULTILINE)
        assert re.search(r'Setting channel url', out, re.MULTILINE)
        assert re.search(r'Fixing altitude', out, re.MULTILINE)
        assert re.search(r'Fixing latitude', out, re.MULTILINE)
        assert re.search(r'Fixing longitude', out, re.MULTILINE)
        assert re.search(r'Writing modified preferences', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()

@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_add_valid(capsys):
    """Test --ch-add with valid channel name, and that channel name does not already exist"""
    sys.argv = ['', '--ch-add', 'testing']
    Globals.getInstance().set_args(sys.argv)

    mocked_channel = MagicMock(autospec=Channel)
    # TODO: figure out how to get it to print the channel name instead of MagicMock

    mocked_node = MagicMock(autospec=Node)
    # set it up so we do not already have a channel named this
    mocked_node.getChannelByName.return_value = False
    # set it up so we have free channels
    mocked_node.getDisabledChannel.return_value = mocked_channel

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Writing modified channels to device', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_add_invalid_name_too_long(capsys):
    """Test --ch-add with invalid channel name, name too long"""
    sys.argv = ['', '--ch-add', 'testingtestingtesting']
    Globals.getInstance().set_args(sys.argv)

    mocked_channel = MagicMock(autospec=Channel)
    # TODO: figure out how to get it to print the channel name instead of MagicMock

    mocked_node = MagicMock(autospec=Node)
    # set it up so we do not already have a channel named this
    mocked_node.getChannelByName.return_value = False
    # set it up so we have free channels
    mocked_node.getDisabledChannel.return_value = mocked_channel

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Channel name must be shorter', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_add_but_name_already_exists(capsys):
    """Test --ch-add with a channel name that already exists"""
    sys.argv = ['', '--ch-add', 'testing']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    # set it up so we do not already have a channel named this
    mocked_node.getChannelByName.return_value = True

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: This node already has', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_add_but_no_more_channels(capsys):
    """Test --ch-add with but there are no more channels"""
    sys.argv = ['', '--ch-add', 'testing']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    # set it up so we do not already have a channel named this
    mocked_node.getChannelByName.return_value = False
    # set it up so we have free channels
    mocked_node.getDisabledChannel.return_value = None

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: No free channels were found', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_del(capsys):
    """Test --ch-del with valid secondary channel to be deleted"""
    sys.argv = ['', '--ch-del', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Deleting channel', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_del_no_ch_index_specified(capsys):
    """Test --ch-del without a valid ch-index"""
    sys.argv = ['', '--ch-del']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Need to specify', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_del_primary_channel(capsys):
    """Test --ch-del on ch-index=0"""
    sys.argv = ['', '--ch-del', '--ch-index', '0']
    Globals.getInstance().set_args(sys.argv)
    Globals.getInstance().set_channel_index(1)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Cannot delete primary channel', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_enable_valid_secondary_channel(capsys):
    """Test --ch-enable with --ch-index"""
    sys.argv = ['', '--ch-enable', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Writing modified channels', out, re.MULTILINE)
        assert err == ''
        assert Globals.getInstance().get_channel_index() == 1
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_disable_valid_secondary_channel(capsys):
    """Test --ch-disable with --ch-index"""
    sys.argv = ['', '--ch-disable', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Writing modified channels', out, re.MULTILINE)
        assert err == ''
        assert Globals.getInstance().get_channel_index() == 1
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_enable_without_a_ch_index(capsys):
    """Test --ch-enable without --ch-index"""
    sys.argv = ['', '--ch-enable']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Need to specify', out, re.MULTILINE)
        assert err == ''
        assert Globals.getInstance().get_channel_index() is None
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_enable_primary_channel(capsys):
    """Test --ch-enable with --ch-index = 0"""
    sys.argv = ['', '--ch-enable', '--ch-index', '0']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Cannot enable/disable PRIMARY', out, re.MULTILINE)
        assert err == ''
        assert Globals.getInstance().get_channel_index() == 0
        mo.assert_called()


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_ch_range_options(capsys):
#    """Test changing the various range options."""
#    range_options = ['--ch-vlongslow', '--ch-longslow', '--ch-longfast', '--ch-midslow',
#                     '--ch-midfast', '--ch-shortslow', '--ch-shortfast']
#    for range_option in range_options:
#        sys.argv = ['', f"{range_option}" ]
#        Globals.getInstance().set_args(sys.argv)
#
#        mocked_node = MagicMock(autospec=Node)
#
#        iface = MagicMock(autospec=SerialInterface)
#        iface.getNode.return_value = mocked_node
#
#        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
#            main()
#            out, err = capsys.readouterr()
#            assert re.search(r'Connected to radio', out, re.MULTILINE)
#            assert re.search(r'Writing modified channels', out, re.MULTILINE)
#            assert err == ''
#            mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_longsfast_on_non_primary_channel(capsys):
    """Test --ch-longfast --ch-index 1"""
    sys.argv = ['', '--ch-longfast', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Standard channel settings', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


# PositionFlags:
# Misc info that might be helpful (this info will grow stale, just
# a snapshot of the values.) The radioconfig_pb2.PositionFlags.Name and bit values are:
# POS_UNDEFINED 0
# POS_ALTITUDE 1
# POS_ALT_MSL 2
# POS_GEO_SEP 4
# POS_DOP 8
# POS_HVDOP 16
# POS_BATTERY 32
# POS_SATINVIEW 64
# POS_SEQ_NOS 128
# POS_TIMESTAMP 256

# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_pos_fields_no_args(capsys):
#    """Test --pos-fields no args (which shows settings)"""
#    sys.argv = ['', '--pos-fields']
#    Globals.getInstance().set_args(sys.argv)
#
#    pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags)
#
#    with patch('meshtastic.serial_interface.SerialInterface') as mo:
#        mo().getNode().radioConfig.preferences.position_flags = 35
#        with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc:
#
#            mrc.values.return_value = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256]
#            # Note: When you use side_effect and a list, each call will use a value from the front of the list then
#            # remove that value from the list. If there are three values in the list, we expect it to be called
#            # three times.
#            mrc.Name.side_effect = ['POS_ALTITUDE', 'POS_ALT_MSL', 'POS_BATTERY']
#
#            main()
#
#            mrc.Name.assert_called()
#            mrc.values.assert_called()
#            mo.assert_called()
#
#            out, err = capsys.readouterr()
#            assert re.search(r'Connected to radio', out, re.MULTILINE)
#            assert re.search(r'POS_ALTITUDE POS_ALT_MSL POS_BATTERY', out, re.MULTILINE)
#            assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_pos_fields_arg_of_zero(capsys):
#    """Test --pos-fields an arg of 0 (which shows list)"""
#    sys.argv = ['', '--pos-fields', '0']
#    Globals.getInstance().set_args(sys.argv)
#
#    pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags)
#
#    with patch('meshtastic.serial_interface.SerialInterface') as mo:
#        with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc:
#
#            def throw_value_error_exception(exc):
#                raise ValueError()
#            mrc.Value.side_effect = throw_value_error_exception
#            mrc.keys.return_value = [ 'POS_UNDEFINED', 'POS_ALTITUDE', 'POS_ALT_MSL',
#                                      'POS_GEO_SEP', 'POS_DOP', 'POS_HVDOP', 'POS_BATTERY',
#                                      'POS_SATINVIEW', 'POS_SEQ_NOS', 'POS_TIMESTAMP']
#
#            main()
#
#            mrc.Value.assert_called()
#            mrc.keys.assert_called()
#            mo.assert_called()
#
#            out, err = capsys.readouterr()
#            assert re.search(r'Connected to radio', out, re.MULTILINE)
#            assert re.search(r'ERROR: supported position fields are:', out, re.MULTILINE)
#            assert re.search(r"['POS_UNDEFINED', 'POS_ALTITUDE', 'POS_ALT_MSL', 'POS_GEO_SEP',"\
#                              "'POS_DOP', 'POS_HVDOP', 'POS_BATTERY', 'POS_SATINVIEW', 'POS_SEQ_NOS',"\
#                              "'POS_TIMESTAMP']", out, re.MULTILINE)
#            assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_pos_fields_valid_values(capsys):
#    """Test --pos-fields with valid values"""
#    sys.argv = ['', '--pos-fields', 'POS_GEO_SEP', 'POS_ALT_MSL']
#    Globals.getInstance().set_args(sys.argv)
#
#    pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags)
#
#    with patch('meshtastic.serial_interface.SerialInterface') as mo:
#        with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc:
#
#            mrc.Value.side_effect = [ 4, 2 ]
#
#            main()
#
#            mrc.Value.assert_called()
#            mo.assert_called()
#
#            out, err = capsys.readouterr()
#            assert re.search(r'Connected to radio', out, re.MULTILINE)
#            assert re.search(r'Setting position fields to 6', out, re.MULTILINE)
#            assert re.search(r'Set position_flags to 6', out, re.MULTILINE)
#            assert re.search(r'Writing modified preferences to device', out, re.MULTILINE)
#            assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_get_with_valid_values(capsys):
#    """Test --get with valid values (with string, number, boolean)"""
#    sys.argv = ['', '--get', 'ls_secs', '--get', 'wifi_ssid', '--get', 'fixed_position']
#    Globals.getInstance().set_args(sys.argv)
#
#    with patch('meshtastic.serial_interface.SerialInterface') as mo:
#
#        mo().getNode().radioConfig.preferences.wifi_ssid = 'foo'
#        mo().getNode().radioConfig.preferences.ls_secs = 300
#        mo().getNode().radioConfig.preferences.fixed_position = False
#
#        main()
#
#        mo.assert_called()
#
#        out, err = capsys.readouterr()
#        assert re.search(r'Connected to radio', out, re.MULTILINE)
#        assert re.search(r'ls_secs: 300', out, re.MULTILINE)
#        assert re.search(r'wifi_ssid: foo', out, re.MULTILINE)
#        assert re.search(r'fixed_position: False', out, re.MULTILINE)
#        assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_get_with_valid_values_camel(capsys, caplog):
    """Test --get with valid values (with string, number, boolean)"""
    sys.argv = ['', '--get', 'lsSecs', '--get', 'wifiSsid', '--get', 'fixedPosition']
    Globals.getInstance().set_args(sys.argv)
    Globals.getInstance().set_camel_case()

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface') as mo:

            mo().getNode().radioConfig.preferences.wifi_ssid = 'foo'
            mo().getNode().radioConfig.preferences.ls_secs = 300
            mo().getNode().radioConfig.preferences.fixed_position = False

            main()

            mo.assert_called()

            out, err = capsys.readouterr()
            assert re.search(r'Connected to radio', out, re.MULTILINE)
            assert re.search(r'lsSecs: 300', out, re.MULTILINE)
            assert re.search(r'wifiSsid: foo', out, re.MULTILINE)
            assert re.search(r'fixedPosition: False', out, re.MULTILINE)
            assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_get_with_invalid(capsys):
    """Test --get with invalid field"""
    sys.argv = ['', '--get', 'foo']
    Globals.getInstance().set_args(sys.argv)

    mocked_user_prefs = MagicMock()
    mocked_user_prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    mocked_node = MagicMock(autospec=Node)
    mocked_node.radioConfig.preferences = ( mocked_user_prefs )

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
        assert re.search(r'Choices in sorted order are', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onReceive_empty(caplog, capsys):
    """Test onReceive"""
    args = MagicMock()
    Globals.getInstance().set_args(args)
    iface = MagicMock(autospec=SerialInterface)
    packet = {}
    with caplog.at_level(logging.DEBUG):
        onReceive(packet, iface)
    assert re.search(r'in onReceive', caplog.text, re.MULTILINE)
    out, err = capsys.readouterr()
    assert re.search(r"Warning: There is no field 'to' in the packet.", out, re.MULTILINE)
    assert err == ''


#    TODO: use this captured position app message (might want/need in the future)
#    packet = {
#            'to': 4294967295,
#            'decoded': {
#                'portnum': 'POSITION_APP',
#                'payload': "M69\306a"
#                },
#            'id': 334776976,
#            'hop_limit': 3
#            }

@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onReceive_with_sendtext(caplog, capsys):
    """Test onReceive with sendtext
       The entire point of this test is to make sure the interface.close() call
       is made in onReceive().
    """
    sys.argv = ['', '--sendtext', 'hello']
    Globals.getInstance().set_args(sys.argv)

    # Note: 'TEXT_MESSAGE_APP' value is 1
    packet = {
            'to': 4294967295,
            'decoded': {
                'portnum': 1,
                'payload': "hello"
                },
            'id': 334776977,
            'hop_limit': 3,
            'want_ack': True
            }

    iface = MagicMock(autospec=SerialInterface)
    iface.myInfo.my_node_num = 4294967295

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with caplog.at_level(logging.DEBUG):
            main()
            onReceive(packet, iface)
        assert re.search(r'in onReceive', caplog.text, re.MULTILINE)
        mo.assert_called()
        out, err = capsys.readouterr()
        assert re.search(r'Sending text message hello to', out, re.MULTILINE)
        assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onReceive_with_text(caplog, capsys):
    """Test onReceive with text
    """
    args = MagicMock()
    args.sendtext.return_value = 'foo'
    Globals.getInstance().set_args(args)

    # Note: 'TEXT_MESSAGE_APP' value is 1
    # Note: Some of this is faked below.
    packet = {
            'to': 4294967295,
            'decoded': {
                'portnum': 1,
                'payload': "hello",
                'text': "faked"
                },
            'id': 334776977,
            'hop_limit': 3,
            'want_ack': True,
            'rxSnr': 6.0,
            'hopLimit': 3,
            'raw': 'faked',
            'fromId': '!28b5465c',
            'toId': '^all'
            }

    iface = MagicMock(autospec=SerialInterface)
    iface.myInfo.my_node_num = 4294967295

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with caplog.at_level(logging.DEBUG):
            onReceive(packet, iface)
        assert re.search(r'in onReceive', caplog.text, re.MULTILINE)
        out, err = capsys.readouterr()
        assert re.search(r'Sending reply', out, re.MULTILINE)
        assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onConnection(capsys):
    """Test onConnection"""
    sys.argv = ['']
    Globals.getInstance().set_args(sys.argv)
    iface = MagicMock(autospec=SerialInterface)
    class TempTopic:
        """ temp class for topic """
        def getName(self):
            """ return the fake name of a topic"""
            return 'foo'
    mytopic = TempTopic()
    onConnection(iface, mytopic)
    out, err = capsys.readouterr()
    assert re.search(r'Connection changed: foo', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_export_config(capsys):
    """Test export_config() function directly"""
    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        mo.getLongName.return_value = 'foo'
        mo.getShortName.return_value = 'oof'
        mo.localNode.getURL.return_value = 'bar'
        mo.getMyNodeInfo().get.return_value = { 'latitudeI': 1100000000, 'longitudeI': 1200000000,
                                                'altitude': 100, 'batteryLevel': 34, 'latitude': 110.0,
                                                'longitude': 120.0}
        mo.localNode.radioConfig.preferences = """phone_timeout_secs: 900
ls_secs: 300
position_broadcast_smart: true
fixed_position: true
position_flags: 35"""
        export_config(mo)
    out, err = capsys.readouterr()

    # ensure we do not output this line
    assert not re.search(r'Connected to radio', out, re.MULTILINE)

    assert re.search(r'owner: foo', out, re.MULTILINE)
    assert re.search(r'owner_short: oof', out, re.MULTILINE)
    assert re.search(r'channel_url: bar', out, re.MULTILINE)
    assert re.search(r'location:', out, re.MULTILINE)
    assert re.search(r'lat: 110.0', out, re.MULTILINE)
    assert re.search(r'lon: 120.0', out, re.MULTILINE)
    assert re.search(r'alt: 100', out, re.MULTILINE)
    assert re.search(r'user_prefs:', out, re.MULTILINE)
    assert re.search(r'phone_timeout_secs: 900', out, re.MULTILINE)
    assert re.search(r'ls_secs: 300', out, re.MULTILINE)
    assert re.search(r"position_broadcast_smart: 'true'", out, re.MULTILINE)
    assert re.search(r"fixed_position: 'true'", out, re.MULTILINE)
    assert re.search(r"position_flags: 35", out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_export_config_use_camel(capsys):
    """Test export_config() function directly"""
    Globals.getInstance().set_camel_case()
    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        mo.getLongName.return_value = 'foo'
        mo.localNode.getURL.return_value = 'bar'
        mo.getMyNodeInfo().get.return_value = { 'latitudeI': 1100000000, 'longitudeI': 1200000000,
                                                'altitude': 100, 'batteryLevel': 34, 'latitude': 110.0,
                                                'longitude': 120.0}
        mo.localNode.radioConfig.preferences = """phone_timeout_secs: 900
ls_secs: 300
position_broadcast_smart: true
fixed_position: true
position_flags: 35"""
        export_config(mo)
    out, err = capsys.readouterr()

    # ensure we do not output this line
    assert not re.search(r'Connected to radio', out, re.MULTILINE)

    assert re.search(r'owner: foo', out, re.MULTILINE)
    assert re.search(r'channelUrl: bar', out, re.MULTILINE)
    assert re.search(r'location:', out, re.MULTILINE)
    assert re.search(r'lat: 110.0', out, re.MULTILINE)
    assert re.search(r'lon: 120.0', out, re.MULTILINE)
    assert re.search(r'alt: 100', out, re.MULTILINE)
    assert re.search(r'userPrefs:', out, re.MULTILINE)
    assert re.search(r'phoneTimeoutSecs: 900', out, re.MULTILINE)
    assert re.search(r'lsSecs: 300', out, re.MULTILINE)
    # TODO: should True be capitalized here?
    assert re.search(r"positionBroadcastSmart: 'True'", out, re.MULTILINE)
    assert re.search(r"fixedPosition: 'True'", out, re.MULTILINE)
    assert re.search(r"positionFlags: 35", out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_export_config_called_from_main(capsys):
    """Test --export-config"""
    sys.argv = ['', '--export-config']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert not re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'# start of Meshtastic configure yaml', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_gpio_rd_no_gpio_channel(capsys):
    """Test --gpio_rd with no named gpio channel"""
    sys.argv = ['', '--gpio-rd', '0x10', '--dest', '!foo']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    iface.localNode.getChannelByName.return_value = None
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Warning: No channel named', out)
        assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_gpio_rd_no_dest(capsys):
    """Test --gpio_rd with a named gpio channel but no dest was specified"""
    sys.argv = ['', '--gpio-rd', '0x2000']
    Globals.getInstance().set_args(sys.argv)

    channel = Channel(index=2, role=2)
    channel.settings.psk = b'\x8a\x94y\x0e\xc6\xc9\x1e5\x91\x12@\xa60\xa8\xb43\x87\x00\xf2K\x0e\xe7\x7fAz\xcd\xf5\xb0\x900\xa84'
    channel.settings.name = 'gpio'

    iface = MagicMock(autospec=SerialInterface)
    iface.localNode.getChannelByName.return_value = channel
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Warning: Must use a destination node ID', out)
        assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#@patch('time.sleep')
#def test_main_gpio_rd(caplog, capsys):
#    """Test --gpio_rd with a named gpio channel"""
#    # Note: On the Heltec v2.1, there is a GPIO pin GPIO 13 that does not have a
#    # red arrow (meaning ok to use for our purposes)
#    # See https://resource.heltec.cn/download/WiFi_LoRa_32/WIFI_LoRa_32_V2.pdf
#    # To find out the mask for GPIO 13, let us assign n as 13.
#    # 1. Find the 2^n or 2^13 (8192)
#    # 2. Convert 8192 decimal to hex (0x2000)
#    # You can use python:
#    # >>> print(hex(2**13))
#    # 0x2000
#    sys.argv = ['', '--gpio-rd', '0x1000', '--dest', '!1234']
#    Globals.getInstance().set_args(sys.argv)
#
#    channel = Channel(index=1, role=1)
#    channel.settings.modem_config = 3
#    channel.settings.psk = b'\x01'
#
#    packet = {
#
#            'from': 682968668,
#            'to': 682968612,
#            'channel': 1,
#            'decoded': {
#                'portnum': 'REMOTE_HARDWARE_APP',
#                'payload': b'\x08\x05\x18\x80 ',
#                'requestId': 1629980484,
#                'remotehw': {
#                    'typ': 'READ_GPIOS_REPLY',
#                    'gpioValue': '4096',
#                    'raw': 'faked',
#                    'id': 1693085229,
#                    'rxTime': 1640294262,
#                    'rxSnr': 4.75,
#                    'hopLimit': 3,
#                    'wantAck': True,
#                    }
#                }
#            }
#
#    iface = MagicMock(autospec=SerialInterface)
#    iface.localNode.getChannelByName.return_value = channel
#    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
#        with caplog.at_level(logging.DEBUG):
#            main()
#            onGPIOreceive(packet, mo)
#    out, err = capsys.readouterr()
#    assert re.search(r'Connected to radio', out, re.MULTILINE)
#    assert re.search(r'Reading GPIO mask 0x1000 ', out, re.MULTILINE)
#    assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=4096', out, re.MULTILINE)
#    assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#@patch('time.sleep')
#def test_main_gpio_rd_with_no_gpioMask(caplog, capsys):
#    """Test --gpio_rd with a named gpio channel"""
#    sys.argv = ['', '--gpio-rd', '0x1000', '--dest', '!1234']
#    Globals.getInstance().set_args(sys.argv)
#
#    channel = Channel(index=1, role=1)
#    channel.settings.modem_config = 3
#    channel.settings.psk = b'\x01'
#
#    # Note: Intentionally do not have gpioValue in response as that is the
#    # default value
#    packet = {
#            'from': 682968668,
#            'to': 682968612,
#            'channel': 1,
#            'decoded': {
#                'portnum': 'REMOTE_HARDWARE_APP',
#                'payload': b'\x08\x05\x18\x80 ',
#                'requestId': 1629980484,
#                'remotehw': {
#                    'typ': 'READ_GPIOS_REPLY',
#                    'raw': 'faked',
#                    'id': 1693085229,
#                    'rxTime': 1640294262,
#                    'rxSnr': 4.75,
#                    'hopLimit': 3,
#                    'wantAck': True,
#                    }
#                }
#            }
#
#    iface = MagicMock(autospec=SerialInterface)
#    iface.localNode.getChannelByName.return_value = channel
#    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
#        with caplog.at_level(logging.DEBUG):
#            main()
#            onGPIOreceive(packet, mo)
#    out, err = capsys.readouterr()
#    assert re.search(r'Connected to radio', out, re.MULTILINE)
#    assert re.search(r'Reading GPIO mask 0x1000 ', out, re.MULTILINE)
#    assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=0', out, re.MULTILINE)
#    assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_gpio_watch(caplog, capsys):
#    """Test --gpio_watch with a named gpio channel"""
#    sys.argv = ['', '--gpio-watch', '0x1000', '--dest', '!1234']
#    Globals.getInstance().set_args(sys.argv)
#
#    def my_sleep(amount):
#        print(f'{amount}')
#        sys.exit(3)
#
#    channel = Channel(index=1, role=1)
#    channel.settings.modem_config = 3
#    channel.settings.psk = b'\x01'
#
#    packet = {
#
#            'from': 682968668,
#            'to': 682968612,
#            'channel': 1,
#            'decoded': {
#                'portnum': 'REMOTE_HARDWARE_APP',
#                'payload': b'\x08\x05\x18\x80 ',
#                'requestId': 1629980484,
#                'remotehw': {
#                    'typ': 'READ_GPIOS_REPLY',
#                    'gpioValue': '4096',
#                    'raw': 'faked',
#                    'id': 1693085229,
#                    'rxTime': 1640294262,
#                    'rxSnr': 4.75,
#                    'hopLimit': 3,
#                    'wantAck': True,
#                    }
#                }
#            }
#
#    with patch('time.sleep', side_effect=my_sleep):
#        with pytest.raises(SystemExit) as pytest_wrapped_e:
#            iface = MagicMock(autospec=SerialInterface)
#            iface.localNode.getChannelByName.return_value = channel
#            with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
#                with caplog.at_level(logging.DEBUG):
#                    main()
#                    onGPIOreceive(packet, mo)
#        assert pytest_wrapped_e.type == SystemExit
#        assert pytest_wrapped_e.value.code == 3
#        out, err = capsys.readouterr()
#        assert re.search(r'Connected to radio', out, re.MULTILINE)
#        assert re.search(r'Watching GPIO mask 0x1000 ', out, re.MULTILINE)
#        assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_gpio_wrb(caplog, capsys):
#    """Test --gpio_wrb with a named gpio channel"""
#    sys.argv = ['', '--gpio-wrb', '4', '1', '--dest', '!1234']
#    Globals.getInstance().set_args(sys.argv)
#
#    channel = Channel(index=1, role=1)
#    channel.settings.modem_config = 3
#    channel.settings.psk = b'\x01'
#
#    packet = {
#
#            'from': 682968668,
#            'to': 682968612,
#            'channel': 1,
#            'decoded': {
#                'portnum': 'REMOTE_HARDWARE_APP',
#                'payload': b'\x08\x05\x18\x80 ',
#                'requestId': 1629980484,
#                'remotehw': {
#                    'typ': 'READ_GPIOS_REPLY',
#                    'gpioValue': '16',
#                    'raw': 'faked',
#                    'id': 1693085229,
#                    'rxTime': 1640294262,
#                    'rxSnr': 4.75,
#                    'hopLimit': 3,
#                    'wantAck': True,
#                    }
#                }
#            }
#
#
#    iface = MagicMock(autospec=SerialInterface)
#    iface.localNode.getChannelByName.return_value = channel
#    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
#        with caplog.at_level(logging.DEBUG):
#            main()
#            onGPIOreceive(packet, mo)
#    out, err = capsys.readouterr()
#    assert re.search(r'Connected to radio', out, re.MULTILINE)
#    assert re.search(r'Writing GPIO mask 0x10 with value 0x10 to !1234', out, re.MULTILINE)
#    assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=16 value=0', out, re.MULTILINE)
#    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field(capsys):
    """Test getPref() with a valid field"""
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'ls_secs'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'ls_secs')
    out, err = capsys.readouterr()
    assert re.search(r'ls_secs: 300', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_camel(capsys):
    """Test getPref() with a valid field"""
    Globals.getInstance().set_camel_case()
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'ls_secs'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'ls_secs')
    out, err = capsys.readouterr()
    assert re.search(r'lsSecs: 300', out, re.MULTILINE)
    assert err == ''

@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_string(capsys):
    """Test getPref() with a valid field and value as a string"""
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'wifi_ssid'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'wifi_ssid')
    out, err = capsys.readouterr()
    assert re.search(r'wifi_ssid: foo', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_string_camel(capsys):
    """Test getPref() with a valid field and value as a string"""
    Globals.getInstance().set_camel_case()
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'wifi_ssid'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'wifi_ssid')
    out, err = capsys.readouterr()
    assert re.search(r'wifiSsid: foo', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_bool(capsys):
    """Test getPref() with a valid field and value as a bool"""
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'fixed_position'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'fixed_position')
    out, err = capsys.readouterr()
    assert re.search(r'fixed_position: False', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_bool_camel(capsys):
    """Test getPref() with a valid field and value as a bool"""
    Globals.getInstance().set_camel_case()
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'fixed_position'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'fixed_position')
    out, err = capsys.readouterr()
    assert re.search(r'fixedPosition: False', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_invalid_field(capsys):
    """Test getPref() with an invalid field"""

    class Field:
        """Simple class for testing."""

        def __init__(self, name):
            """constructor"""
            self.name = name

    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    # Note: This is a subset of the real fields
    ls_secs_field = Field('ls_secs')
    is_router = Field('is_router')
    fixed_position = Field('fixed_position')

    fields = [ ls_secs_field, is_router, fixed_position ]
    prefs.DESCRIPTOR.fields = fields

    getPref(prefs, 'foo')

    out, err = capsys.readouterr()
    assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
    # ensure they are sorted
    assert re.search(r'fixed_position\s+is_router\s+ls_secs', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_invalid_field_camel(capsys):
    """Test getPref() with an invalid field"""
    Globals.getInstance().set_camel_case()

    class Field:
        """Simple class for testing."""

        def __init__(self, name):
            """constructor"""
            self.name = name

    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    # Note: This is a subset of the real fields
    ls_secs_field = Field('ls_secs')
    is_router = Field('is_router')
    fixed_position = Field('fixed_position')

    fields = [ ls_secs_field, is_router, fixed_position ]
    prefs.DESCRIPTOR.fields = fields

    getPref(prefs, 'foo')

    out, err = capsys.readouterr()
    assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
    # ensure they are sorted
    assert re.search(r'fixedPosition\s+isRouter\s+lsSecs', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_valid_field_int_as_string(capsys):
    """Test setPref() with a valid field"""

    class Field:
        """Simple class for testing."""

        def __init__(self, name, enum_type):
            """constructor"""
            self.name = name
            self.enum_type = enum_type

    ls_secs_field = Field('ls_secs', 'int')
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = ls_secs_field

    setPref(prefs, 'ls_secs', '300')
    out, err = capsys.readouterr()
    assert re.search(r'Set ls_secs to 300', out, re.MULTILINE)
    assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_setPref_valid_field_invalid_enum(capsys, caplog):
#    """Test setPref() with a valid field but invalid enum value"""
#
#    radioConfig = RadioConfig()
#    prefs = radioConfig.preferences
#
#    with caplog.at_level(logging.DEBUG):
#        setPref(prefs, 'charge_current', 'foo')
#        out, err = capsys.readouterr()
#        assert re.search(r'charge_current does not have an enum called foo', out, re.MULTILINE)
#        assert re.search(r'Choices in sorted order are', out, re.MULTILINE)
#        assert re.search(r'MA100', out, re.MULTILINE)
#        assert re.search(r'MA280', out, re.MULTILINE)
#        assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_setPref_valid_field_invalid_enum_where_enums_are_camel_cased_values(capsys, caplog):
#    """Test setPref() with a valid field but invalid enum value"""
#
#    radioConfig = RadioConfig()
#    prefs = radioConfig.preferences
#
#    with caplog.at_level(logging.DEBUG):
#        setPref(prefs, 'region', 'foo')
#        out, err = capsys.readouterr()
#        assert re.search(r'region does not have an enum called foo', out, re.MULTILINE)
#        assert re.search(r'Choices in sorted order are', out, re.MULTILINE)
#        assert re.search(r'ANZ', out, re.MULTILINE)
#        assert re.search(r'CN', out, re.MULTILINE)
#        assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_setPref_valid_field_invalid_enum_camel(capsys, caplog):
#    """Test setPref() with a valid field but invalid enum value"""
#    Globals.getInstance().set_camel_case()
#
#    radioConfig = RadioConfig()
#    prefs = radioConfig.preferences
#
#    with caplog.at_level(logging.DEBUG):
#        setPref(prefs, 'charge_current', 'foo')
#        out, err = capsys.readouterr()
#        assert re.search(r'chargeCurrent does not have an enum called foo', out, re.MULTILINE)
#        assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_setPref_valid_field_valid_enum(capsys, caplog):
#    """Test setPref() with a valid field and valid enum value"""
#
#    # charge_current
#    # some valid values:   MA100 MA1000 MA1080
#
#    radioConfig = RadioConfig()
#    prefs = radioConfig.preferences
#
#    with caplog.at_level(logging.DEBUG):
#        setPref(prefs, 'charge_current', 'MA100')
#        out, err = capsys.readouterr()
#        assert re.search(r'Set charge_current to MA100', out, re.MULTILINE)
#        assert err == ''


# TODO
#@pytest.mark.unit
#@pytest.mark.usefixtures("reset_globals")
#def test_main_setPref_valid_field_valid_enum_camel(capsys, caplog):
#    """Test setPref() with a valid field and valid enum value"""
#    Globals.getInstance().set_camel_case()
#
#    # charge_current
#    # some valid values:   MA100 MA1000 MA1080
#
#    radioConfig = RadioConfig()
#    prefs = radioConfig.preferences
#
#    with caplog.at_level(logging.DEBUG):
#        setPref(prefs, 'charge_current', 'MA100')
#        out, err = capsys.readouterr()
#        assert re.search(r'Set chargeCurrent to MA100', out, re.MULTILINE)
#        assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_invalid_field(capsys):
    """Test setPref() with a invalid field"""


    class Field:
        """Simple class for testing."""

        def __init__(self, name):
            """constructor"""
            self.name = name

    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    # Note: This is a subset of the real fields
    ls_secs_field = Field('ls_secs')
    is_router = Field('is_router')
    fixed_position = Field('fixed_position')

    fields = [ ls_secs_field, is_router, fixed_position ]
    prefs.DESCRIPTOR.fields = fields

    setPref(prefs, 'foo', '300')
    out, err = capsys.readouterr()
    assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
    # ensure they are sorted
    assert re.search(r'fixed_position\s+is_router\s+ls_secs', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_invalid_field_camel(capsys):
    """Test setPref() with a invalid field"""
    Globals.getInstance().set_camel_case()

    class Field:
        """Simple class for testing."""

        def __init__(self, name):
            """constructor"""
            self.name = name

    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    # Note: This is a subset of the real fields
    ls_secs_field = Field('ls_secs')
    is_router = Field('is_router')
    fixed_position = Field('fixed_position')

    fields = [ ls_secs_field, is_router, fixed_position ]
    prefs.DESCRIPTOR.fields = fields

    setPref(prefs, 'foo', '300')
    out, err = capsys.readouterr()
    assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
    # ensure they are sorted
    assert re.search(r'fixedPosition\s+isRouter\s+lsSecs', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_ignore_incoming_123(capsys):
    """Test setPref() with ignore_incoming"""

    class Field:
        """Simple class for testing."""

        def __init__(self, name, enum_type):
            """constructor"""
            self.name = name
            self.enum_type = enum_type

    ignore_incoming_field = Field('ignore_incoming', 'list')
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = ignore_incoming_field

    setPref(prefs, 'ignore_incoming', '123')
    out, err = capsys.readouterr()
    assert re.search(r"Adding '123' to the ignore_incoming list", out, re.MULTILINE)
    assert re.search(r'Set ignore_incoming to 123', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_ignore_incoming_0(capsys):
    """Test setPref() with ignore_incoming"""

    class Field:
        """Simple class for testing."""

        def __init__(self, name, enum_type):
            """constructor"""
            self.name = name
            self.enum_type = enum_type

    ignore_incoming_field = Field('ignore_incoming', 'list')
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = ignore_incoming_field

    setPref(prefs, 'ignore_incoming', '0')
    out, err = capsys.readouterr()
    assert re.search(r'Clearing ignore_incoming list', out, re.MULTILINE)
    assert re.search(r'Set ignore_incoming to 0', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_set_psk_no_ch_index(capsys):
    """Test --ch-set psk """
    sys.argv = ['', '--ch-set', 'psk', 'foo', '--host', 'meshtastic.local']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=TCPInterface)
    with patch('meshtastic.tcp_interface.TCPInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r"Warning: Need to specify '--ch-index'", out, re.MULTILINE)
        assert err == ''
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_set_psk_with_ch_index(capsys):
    """Test --ch-set psk """
    sys.argv = ['', '--ch-set', 'psk', 'foo', '--host', 'meshtastic.local', '--ch-index', '0']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=TCPInterface)
    with patch('meshtastic.tcp_interface.TCPInterface', return_value=iface) as mo:
        main()
    out, err = capsys.readouterr()
    assert re.search(r'Connected to radio', out, re.MULTILINE)
    assert re.search(r"Writing modified channels to device", out, re.MULTILINE)
    assert err == ''
    mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_set_name_with_ch_index(capsys):
    """Test --ch-set setting other than psk"""
    sys.argv = ['', '--ch-set', 'name', 'foo', '--host', 'meshtastic.local', '--ch-index', '0']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=TCPInterface)
    with patch('meshtastic.tcp_interface.TCPInterface', return_value=iface) as mo:
        main()
    out, err = capsys.readouterr()
    assert re.search(r'Connected to radio', out, re.MULTILINE)
    assert re.search(r'Set name to foo', out, re.MULTILINE)
    assert re.search(r"Writing modified channels to device", out, re.MULTILINE)
    assert err == ''
    mo.assert_called()


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_onNode(capsys):
    """Test onNode"""
    onNode('foo')
    out, err = capsys.readouterr()
    assert re.search(r'Node changed', out, re.MULTILINE)
    assert err == ''


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_tunnel_no_args(capsys):
    """Test tunnel no arguments"""
    sys.argv = ['']
    Globals.getInstance().set_args(sys.argv)
    with pytest.raises(SystemExit) as pytest_wrapped_e:
        tunnelMain()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 1
    _, err = capsys.readouterr()
    assert re.search(r'usage: ', err, re.MULTILINE)


@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=[])
@patch('platform.system')
def test_tunnel_tunnel_arg_with_no_devices(mock_platform_system, caplog, capsys):
    """Test tunnel with tunnel arg (act like we are on a linux system)"""
    a_mock = MagicMock()
    a_mock.return_value = 'Linux'
    mock_platform_system.side_effect = a_mock
    sys.argv = ['', '--tunnel']
    Globals.getInstance().set_args(sys.argv)
    print(f'platform.system():{platform.system()}')
    with caplog.at_level(logging.DEBUG):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            tunnelMain()
        mock_platform_system.assert_called()
        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
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=[])
@patch('platform.system')
def test_tunnel_subnet_arg_with_no_devices(mock_platform_system, caplog, capsys):
    """Test tunnel with subnet arg (act like we are on a linux system)"""
    a_mock = MagicMock()
    a_mock.return_value = 'Linux'
    mock_platform_system.side_effect = a_mock
    sys.argv = ['', '--subnet', 'foo']
    Globals.getInstance().set_args(sys.argv)
    print(f'platform.system():{platform.system()}')
    with caplog.at_level(logging.DEBUG):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            tunnelMain()
        mock_platform_system.assert_called()
        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
@pytest.mark.usefixtures("reset_globals")
@patch('platform.system')
def test_tunnel_tunnel_arg(mock_platform_system, caplog, iface_with_nodes, capsys):
    """Test tunnel with tunnel arg (act like we are on a linux system)"""
    # Override the time.sleep so there is no loop
    def my_sleep(amount):
        print(f'{amount}')
        sys.exit(3)

    a_mock = MagicMock()
    a_mock.return_value = 'Linux'
    mock_platform_system.side_effect = a_mock
    sys.argv = ['', '--tunnel']
    Globals.getInstance().set_args(sys.argv)

    iface = iface_with_nodes
    iface.myInfo.my_node_num = 2475227164

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
            with patch('time.sleep', side_effect=my_sleep):
                with pytest.raises(SystemExit) as pytest_wrapped_e:
                    tunnelMain()
                    mock_platform_system.assert_called()
                assert pytest_wrapped_e.type == SystemExit
                assert pytest_wrapped_e.value.code == 3
                assert re.search(r'Not starting Tunnel', caplog.text, re.MULTILINE)
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert err == ''

Functions

def test_main_ch_add_but_name_already_exists(capsys)

Test –ch-add with a channel name that already exists

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_add_but_name_already_exists(capsys):
    """Test --ch-add with a channel name that already exists"""
    sys.argv = ['', '--ch-add', 'testing']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    # set it up so we do not already have a channel named this
    mocked_node.getChannelByName.return_value = True

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: This node already has', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_ch_add_but_no_more_channels(capsys)

Test –ch-add with but there are no more channels

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_add_but_no_more_channels(capsys):
    """Test --ch-add with but there are no more channels"""
    sys.argv = ['', '--ch-add', 'testing']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    # set it up so we do not already have a channel named this
    mocked_node.getChannelByName.return_value = False
    # set it up so we have free channels
    mocked_node.getDisabledChannel.return_value = None

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: No free channels were found', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_ch_add_invalid_name_too_long(capsys)

Test –ch-add with invalid channel name, name too long

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_add_invalid_name_too_long(capsys):
    """Test --ch-add with invalid channel name, name too long"""
    sys.argv = ['', '--ch-add', 'testingtestingtesting']
    Globals.getInstance().set_args(sys.argv)

    mocked_channel = MagicMock(autospec=Channel)
    # TODO: figure out how to get it to print the channel name instead of MagicMock

    mocked_node = MagicMock(autospec=Node)
    # set it up so we do not already have a channel named this
    mocked_node.getChannelByName.return_value = False
    # set it up so we have free channels
    mocked_node.getDisabledChannel.return_value = mocked_channel

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Channel name must be shorter', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_ch_add_valid(capsys)

Test –ch-add with valid channel name, and that channel name does not already exist

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_add_valid(capsys):
    """Test --ch-add with valid channel name, and that channel name does not already exist"""
    sys.argv = ['', '--ch-add', 'testing']
    Globals.getInstance().set_args(sys.argv)

    mocked_channel = MagicMock(autospec=Channel)
    # TODO: figure out how to get it to print the channel name instead of MagicMock

    mocked_node = MagicMock(autospec=Node)
    # set it up so we do not already have a channel named this
    mocked_node.getChannelByName.return_value = False
    # set it up so we have free channels
    mocked_node.getDisabledChannel.return_value = mocked_channel

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Writing modified channels to device', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_ch_del(capsys)

Test –ch-del with valid secondary channel to be deleted

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_del(capsys):
    """Test --ch-del with valid secondary channel to be deleted"""
    sys.argv = ['', '--ch-del', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Deleting channel', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_ch_del_no_ch_index_specified(capsys)

Test –ch-del without a valid ch-index

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_del_no_ch_index_specified(capsys):
    """Test --ch-del without a valid ch-index"""
    sys.argv = ['', '--ch-del']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Need to specify', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_ch_del_primary_channel(capsys)

Test –ch-del on ch-index=0

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_del_primary_channel(capsys):
    """Test --ch-del on ch-index=0"""
    sys.argv = ['', '--ch-del', '--ch-index', '0']
    Globals.getInstance().set_args(sys.argv)
    Globals.getInstance().set_channel_index(1)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Cannot delete primary channel', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_ch_disable_valid_secondary_channel(capsys)

Test –ch-disable with –ch-index

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_disable_valid_secondary_channel(capsys):
    """Test --ch-disable with --ch-index"""
    sys.argv = ['', '--ch-disable', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Writing modified channels', out, re.MULTILINE)
        assert err == ''
        assert Globals.getInstance().get_channel_index() == 1
        mo.assert_called()
def test_main_ch_enable_primary_channel(capsys)

Test –ch-enable with –ch-index = 0

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_enable_primary_channel(capsys):
    """Test --ch-enable with --ch-index = 0"""
    sys.argv = ['', '--ch-enable', '--ch-index', '0']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Cannot enable/disable PRIMARY', out, re.MULTILINE)
        assert err == ''
        assert Globals.getInstance().get_channel_index() == 0
        mo.assert_called()
def test_main_ch_enable_valid_secondary_channel(capsys)

Test –ch-enable with –ch-index

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_enable_valid_secondary_channel(capsys):
    """Test --ch-enable with --ch-index"""
    sys.argv = ['', '--ch-enable', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Writing modified channels', out, re.MULTILINE)
        assert err == ''
        assert Globals.getInstance().get_channel_index() == 1
        mo.assert_called()
def test_main_ch_enable_without_a_ch_index(capsys)

Test –ch-enable without –ch-index

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_enable_without_a_ch_index(capsys):
    """Test --ch-enable without --ch-index"""
    sys.argv = ['', '--ch-enable']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Need to specify', out, re.MULTILINE)
        assert err == ''
        assert Globals.getInstance().get_channel_index() is None
        mo.assert_called()
def test_main_ch_index_no_devices(patched_find_ports, capsys)

Test –ch-index 1

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=[])
def test_main_ch_index_no_devices(patched_find_ports, capsys):
    """Test --ch-index 1"""
    sys.argv = ['', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    with pytest.raises(SystemExit) as pytest_wrapped_e:
        main()
    assert Globals.getInstance().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 == ''
    patched_find_ports.assert_called()
def test_main_ch_longsfast_on_non_primary_channel(capsys)

Test –ch-longfast –ch-index 1

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_longsfast_on_non_primary_channel(capsys):
    """Test --ch-longfast --ch-index 1"""
    sys.argv = ['', '--ch-longfast', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Warning: Standard channel settings', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_ch_set_name_with_ch_index(capsys)

Test –ch-set setting other than psk

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_set_name_with_ch_index(capsys):
    """Test --ch-set setting other than psk"""
    sys.argv = ['', '--ch-set', 'name', 'foo', '--host', 'meshtastic.local', '--ch-index', '0']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=TCPInterface)
    with patch('meshtastic.tcp_interface.TCPInterface', return_value=iface) as mo:
        main()
    out, err = capsys.readouterr()
    assert re.search(r'Connected to radio', out, re.MULTILINE)
    assert re.search(r'Set name to foo', out, re.MULTILINE)
    assert re.search(r"Writing modified channels to device", out, re.MULTILINE)
    assert err == ''
    mo.assert_called()
def test_main_ch_set_psk_no_ch_index(capsys)

Test –ch-set psk

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_set_psk_no_ch_index(capsys):
    """Test --ch-set psk """
    sys.argv = ['', '--ch-set', 'psk', 'foo', '--host', 'meshtastic.local']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=TCPInterface)
    with patch('meshtastic.tcp_interface.TCPInterface', return_value=iface) as mo:
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r"Warning: Need to specify '--ch-index'", out, re.MULTILINE)
        assert err == ''
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        mo.assert_called()
def test_main_ch_set_psk_with_ch_index(capsys)

Test –ch-set psk

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_set_psk_with_ch_index(capsys):
    """Test --ch-set psk """
    sys.argv = ['', '--ch-set', 'psk', 'foo', '--host', 'meshtastic.local', '--ch-index', '0']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=TCPInterface)
    with patch('meshtastic.tcp_interface.TCPInterface', return_value=iface) as mo:
        main()
    out, err = capsys.readouterr()
    assert re.search(r'Connected to radio', out, re.MULTILINE)
    assert re.search(r"Writing modified channels to device", out, re.MULTILINE)
    assert err == ''
    mo.assert_called()
def test_main_configure_with_camel_case_keys(capsys)

Test –configure with valid file

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_configure_with_camel_case_keys(capsys):
    """Test --configure with valid file"""
    sys.argv = ['', '--configure', 'exampleConfig.yaml']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting device owner', out, re.MULTILINE)
        assert re.search(r'Setting device owner short', out, re.MULTILINE)
        assert re.search(r'Setting channel url', out, re.MULTILINE)
        assert re.search(r'Fixing altitude', out, re.MULTILINE)
        assert re.search(r'Fixing latitude', out, re.MULTILINE)
        assert re.search(r'Fixing longitude', out, re.MULTILINE)
        assert re.search(r'Writing modified preferences', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_configure_with_snake_case(capsys)

Test –configure with valid file

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_configure_with_snake_case(capsys):
    """Test --configure with valid file"""
    sys.argv = ['', '--configure', 'example_config.yaml']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting device owner', out, re.MULTILINE)
        assert re.search(r'Setting device owner short', out, re.MULTILINE)
        assert re.search(r'Setting channel url', out, re.MULTILINE)
        assert re.search(r'Fixing altitude', out, re.MULTILINE)
        assert re.search(r'Fixing latitude', out, re.MULTILINE)
        assert re.search(r'Fixing longitude', out, re.MULTILINE)
        assert re.search(r'Set location_share to LocEnabled', out, re.MULTILINE)
        assert re.search(r'Writing modified preferences', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_export_config(capsys)

Test export_config() function directly

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_export_config(capsys):
    """Test export_config() function directly"""
    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        mo.getLongName.return_value = 'foo'
        mo.getShortName.return_value = 'oof'
        mo.localNode.getURL.return_value = 'bar'
        mo.getMyNodeInfo().get.return_value = { 'latitudeI': 1100000000, 'longitudeI': 1200000000,
                                                'altitude': 100, 'batteryLevel': 34, 'latitude': 110.0,
                                                'longitude': 120.0}
        mo.localNode.radioConfig.preferences = """phone_timeout_secs: 900
ls_secs: 300
position_broadcast_smart: true
fixed_position: true
position_flags: 35"""
        export_config(mo)
    out, err = capsys.readouterr()

    # ensure we do not output this line
    assert not re.search(r'Connected to radio', out, re.MULTILINE)

    assert re.search(r'owner: foo', out, re.MULTILINE)
    assert re.search(r'owner_short: oof', out, re.MULTILINE)
    assert re.search(r'channel_url: bar', out, re.MULTILINE)
    assert re.search(r'location:', out, re.MULTILINE)
    assert re.search(r'lat: 110.0', out, re.MULTILINE)
    assert re.search(r'lon: 120.0', out, re.MULTILINE)
    assert re.search(r'alt: 100', out, re.MULTILINE)
    assert re.search(r'user_prefs:', out, re.MULTILINE)
    assert re.search(r'phone_timeout_secs: 900', out, re.MULTILINE)
    assert re.search(r'ls_secs: 300', out, re.MULTILINE)
    assert re.search(r"position_broadcast_smart: 'true'", out, re.MULTILINE)
    assert re.search(r"fixed_position: 'true'", out, re.MULTILINE)
    assert re.search(r"position_flags: 35", out, re.MULTILINE)
    assert err == ''
def test_main_export_config_called_from_main(capsys)

Test –export-config

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_export_config_called_from_main(capsys):
    """Test --export-config"""
    sys.argv = ['', '--export-config']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert not re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'# start of Meshtastic configure yaml', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_export_config_use_camel(capsys)

Test export_config() function directly

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_export_config_use_camel(capsys):
    """Test export_config() function directly"""
    Globals.getInstance().set_camel_case()
    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        mo.getLongName.return_value = 'foo'
        mo.localNode.getURL.return_value = 'bar'
        mo.getMyNodeInfo().get.return_value = { 'latitudeI': 1100000000, 'longitudeI': 1200000000,
                                                'altitude': 100, 'batteryLevel': 34, 'latitude': 110.0,
                                                'longitude': 120.0}
        mo.localNode.radioConfig.preferences = """phone_timeout_secs: 900
ls_secs: 300
position_broadcast_smart: true
fixed_position: true
position_flags: 35"""
        export_config(mo)
    out, err = capsys.readouterr()

    # ensure we do not output this line
    assert not re.search(r'Connected to radio', out, re.MULTILINE)

    assert re.search(r'owner: foo', out, re.MULTILINE)
    assert re.search(r'channelUrl: bar', out, re.MULTILINE)
    assert re.search(r'location:', out, re.MULTILINE)
    assert re.search(r'lat: 110.0', out, re.MULTILINE)
    assert re.search(r'lon: 120.0', out, re.MULTILINE)
    assert re.search(r'alt: 100', out, re.MULTILINE)
    assert re.search(r'userPrefs:', out, re.MULTILINE)
    assert re.search(r'phoneTimeoutSecs: 900', out, re.MULTILINE)
    assert re.search(r'lsSecs: 300', out, re.MULTILINE)
    # TODO: should True be capitalized here?
    assert re.search(r"positionBroadcastSmart: 'True'", out, re.MULTILINE)
    assert re.search(r"fixedPosition: 'True'", out, re.MULTILINE)
    assert re.search(r"positionFlags: 35", out, re.MULTILINE)
    assert err == ''
def test_main_getPref_invalid_field(capsys)

Test getPref() with an invalid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_invalid_field(capsys):
    """Test getPref() with an invalid field"""

    class Field:
        """Simple class for testing."""

        def __init__(self, name):
            """constructor"""
            self.name = name

    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    # Note: This is a subset of the real fields
    ls_secs_field = Field('ls_secs')
    is_router = Field('is_router')
    fixed_position = Field('fixed_position')

    fields = [ ls_secs_field, is_router, fixed_position ]
    prefs.DESCRIPTOR.fields = fields

    getPref(prefs, 'foo')

    out, err = capsys.readouterr()
    assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
    # ensure they are sorted
    assert re.search(r'fixed_position\s+is_router\s+ls_secs', out, re.MULTILINE)
    assert err == ''
def test_main_getPref_invalid_field_camel(capsys)

Test getPref() with an invalid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_invalid_field_camel(capsys):
    """Test getPref() with an invalid field"""
    Globals.getInstance().set_camel_case()

    class Field:
        """Simple class for testing."""

        def __init__(self, name):
            """constructor"""
            self.name = name

    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    # Note: This is a subset of the real fields
    ls_secs_field = Field('ls_secs')
    is_router = Field('is_router')
    fixed_position = Field('fixed_position')

    fields = [ ls_secs_field, is_router, fixed_position ]
    prefs.DESCRIPTOR.fields = fields

    getPref(prefs, 'foo')

    out, err = capsys.readouterr()
    assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
    # ensure they are sorted
    assert re.search(r'fixedPosition\s+isRouter\s+lsSecs', out, re.MULTILINE)
    assert err == ''
def test_main_getPref_valid_field(capsys)

Test getPref() with a valid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field(capsys):
    """Test getPref() with a valid field"""
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'ls_secs'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'ls_secs')
    out, err = capsys.readouterr()
    assert re.search(r'ls_secs: 300', out, re.MULTILINE)
    assert err == ''
def test_main_getPref_valid_field_bool(capsys)

Test getPref() with a valid field and value as a bool

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_bool(capsys):
    """Test getPref() with a valid field and value as a bool"""
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'fixed_position'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'fixed_position')
    out, err = capsys.readouterr()
    assert re.search(r'fixed_position: False', out, re.MULTILINE)
    assert err == ''
def test_main_getPref_valid_field_bool_camel(capsys)

Test getPref() with a valid field and value as a bool

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_bool_camel(capsys):
    """Test getPref() with a valid field and value as a bool"""
    Globals.getInstance().set_camel_case()
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'fixed_position'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'fixed_position')
    out, err = capsys.readouterr()
    assert re.search(r'fixedPosition: False', out, re.MULTILINE)
    assert err == ''
def test_main_getPref_valid_field_camel(capsys)

Test getPref() with a valid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_camel(capsys):
    """Test getPref() with a valid field"""
    Globals.getInstance().set_camel_case()
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'ls_secs'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'ls_secs')
    out, err = capsys.readouterr()
    assert re.search(r'lsSecs: 300', out, re.MULTILINE)
    assert err == ''
def test_main_getPref_valid_field_string(capsys)

Test getPref() with a valid field and value as a string

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_string(capsys):
    """Test getPref() with a valid field and value as a string"""
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'wifi_ssid'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'wifi_ssid')
    out, err = capsys.readouterr()
    assert re.search(r'wifi_ssid: foo', out, re.MULTILINE)
    assert err == ''
def test_main_getPref_valid_field_string_camel(capsys)

Test getPref() with a valid field and value as a string

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_getPref_valid_field_string_camel(capsys):
    """Test getPref() with a valid field and value as a string"""
    Globals.getInstance().set_camel_case()
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = 'wifi_ssid'
    prefs.wifi_ssid = 'foo'
    prefs.ls_secs = 300
    prefs.fixed_position = False

    getPref(prefs, 'wifi_ssid')
    out, err = capsys.readouterr()
    assert re.search(r'wifiSsid: foo', out, re.MULTILINE)
    assert err == ''
def test_main_get_canned_messages(capsys, caplog, iface_with_nodes)

Test –get-canned-message

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_get_canned_messages(capsys, caplog, iface_with_nodes):
    """Test --get-canned-message """
    sys.argv = ['', '--get-canned-message']
    Globals.getInstance().set_args(sys.argv)

    iface = iface_with_nodes
    iface.localNode.cannedPluginMessage = 'foo'

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
            main()
            out, err = capsys.readouterr()
            assert re.search(r'Connected to radio', out, re.MULTILINE)
            assert re.search(r'canned_plugin_message:foo', out, re.MULTILINE)
            assert err == ''
            mo.assert_called()
def test_main_get_with_invalid(capsys)

Test –get with invalid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_get_with_invalid(capsys):
    """Test --get with invalid field"""
    sys.argv = ['', '--get', 'foo']
    Globals.getInstance().set_args(sys.argv)

    mocked_user_prefs = MagicMock()
    mocked_user_prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    mocked_node = MagicMock(autospec=Node)
    mocked_node.radioConfig.preferences = ( mocked_user_prefs )

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
        assert re.search(r'Choices in sorted order are', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_get_with_valid_values_camel(capsys, caplog)

Test –get with valid values (with string, number, boolean)

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_get_with_valid_values_camel(capsys, caplog):
    """Test --get with valid values (with string, number, boolean)"""
    sys.argv = ['', '--get', 'lsSecs', '--get', 'wifiSsid', '--get', 'fixedPosition']
    Globals.getInstance().set_args(sys.argv)
    Globals.getInstance().set_camel_case()

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface') as mo:

            mo().getNode().radioConfig.preferences.wifi_ssid = 'foo'
            mo().getNode().radioConfig.preferences.ls_secs = 300
            mo().getNode().radioConfig.preferences.fixed_position = False

            main()

            mo.assert_called()

            out, err = capsys.readouterr()
            assert re.search(r'Connected to radio', out, re.MULTILINE)
            assert re.search(r'lsSecs: 300', out, re.MULTILINE)
            assert re.search(r'wifiSsid: foo', out, re.MULTILINE)
            assert re.search(r'fixedPosition: False', out, re.MULTILINE)
            assert err == ''
def test_main_gpio_rd_no_dest(capsys)

Test –gpio_rd with a named gpio channel but no dest was specified

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_gpio_rd_no_dest(capsys):
    """Test --gpio_rd with a named gpio channel but no dest was specified"""
    sys.argv = ['', '--gpio-rd', '0x2000']
    Globals.getInstance().set_args(sys.argv)

    channel = Channel(index=2, role=2)
    channel.settings.psk = b'\x8a\x94y\x0e\xc6\xc9\x1e5\x91\x12@\xa60\xa8\xb43\x87\x00\xf2K\x0e\xe7\x7fAz\xcd\xf5\xb0\x900\xa84'
    channel.settings.name = 'gpio'

    iface = MagicMock(autospec=SerialInterface)
    iface.localNode.getChannelByName.return_value = channel
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Warning: Must use a destination node ID', out)
        assert err == ''
def test_main_gpio_rd_no_gpio_channel(capsys)

Test –gpio_rd with no named gpio channel

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_gpio_rd_no_gpio_channel(capsys):
    """Test --gpio_rd with no named gpio channel"""
    sys.argv = ['', '--gpio-rd', '0x10', '--dest', '!foo']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    iface.localNode.getChannelByName.return_value = None
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()
        assert pytest_wrapped_e.type == SystemExit
        assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        assert re.search(r'Warning: No channel named', out)
        assert err == ''
def test_main_info(capsys, caplog)

Test –info

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_info(capsys, caplog):
    """Test --info"""
    sys.argv = ['', '--info']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo
    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
            main()
            out, err = capsys.readouterr()
            assert re.search(r'Connected to radio', out, re.MULTILINE)
            assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
            assert err == ''
            mo.assert_called()
def test_main_info_with_permission_error(patched_getlogin, capsys, caplog)

Test –info

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('os.getlogin')
def test_main_info_with_permission_error(patched_getlogin, capsys, caplog):
    """Test --info"""
    sys.argv = ['', '--info']
    Globals.getInstance().set_args(sys.argv)

    patched_getlogin.return_value = 'me'

    iface = MagicMock(autospec=SerialInterface)
    with caplog.at_level(logging.DEBUG):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
                mo.side_effect = PermissionError('bla bla')
                main()
            assert pytest_wrapped_e.type == SystemExit
            assert pytest_wrapped_e.value.code == 1
        out, err = capsys.readouterr()
        patched_getlogin.assert_called()
        assert re.search(r'Need to add yourself', out, re.MULTILINE)
        assert err == ''
def test_main_info_with_seriallog_output_txt(capsys)

Test –info

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_info_with_seriallog_output_txt(capsys):
    """Test --info"""
    sys.argv = ['', '--info', '--seriallog', 'output.txt']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
    # do some cleanup
    os.remove('output.txt')
def test_main_info_with_seriallog_stdout(capsys)

Test –info

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_info_with_seriallog_stdout(capsys):
    """Test --info"""
    sys.argv = ['', '--info', '--seriallog', 'stdout']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_info_with_tcp_interface(capsys)

Test –info

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_info_with_tcp_interface(capsys):
    """Test --info"""
    sys.argv = ['', '--info', '--host', 'meshtastic.local']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=TCPInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo
    with patch('meshtastic.tcp_interface.TCPInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_init_parser_no_args(capsys)

Test no arguments

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_init_parser_no_args(capsys):
    """Test no arguments"""
    sys.argv = ['']
    Globals.getInstance().set_args(sys.argv)
    initParser()
    out, err = capsys.readouterr()
    assert out == ''
    assert err == ''
def test_main_init_parser_version(capsys)

Test –version

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_init_parser_version(capsys):
    """Test --version"""
    sys.argv = ['', '--version']
    Globals.getInstance().set_args(sys.argv)

    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]+[\.a][0-9]', out)
    assert err == ''
def test_main_main_no_args(capsys)

Test with no args

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_main_no_args(capsys):
    """Test with no args"""
    sys.argv = ['']
    Globals.getInstance().set_args(sys.argv)

    with pytest.raises(SystemExit) as pytest_wrapped_e:
        main()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 1
    _, err = capsys.readouterr()
    assert re.search(r'usage:', err, re.MULTILINE)
def test_main_main_version(capsys)

Test –version

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_main_version(capsys):
    """Test --version"""
    sys.argv = ['', '--version']
    Globals.getInstance().set_args(sys.argv)

    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]+[\.a][0-9]', out)
    assert err == ''
def test_main_no_proto(capsys)

Test –noproto (using –info for output)

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_no_proto(capsys):
    """Test --noproto (using --info for output)"""
    sys.argv = ['', '--info', '--noproto']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showInfo():
        print('inside mocked showInfo')
    iface.showInfo.side_effect = mock_showInfo

    # Override the time.sleep so there is no loop
    def my_sleep(amount):
        print(f'amount:{amount}')
        sys.exit(0)

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with patch('time.sleep', side_effect=my_sleep):
            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'Connected to radio', out, re.MULTILINE)
            assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
            assert err == ''
def test_main_nodes(capsys)

Test –nodes

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_nodes(capsys):
    """Test --nodes"""
    sys.argv = ['', '--nodes']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_showNodes():
        print('inside mocked showNodes')
    iface.showNodes.side_effect = mock_showNodes
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked showNodes', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_onConnected_exception(capsys)

Test the exception in onConnected

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onConnected_exception(capsys):
    """Test the exception in onConnected"""
    sys.argv = ['', '--qr']
    Globals.getInstance().set_args(sys.argv)

    def throw_an_exception(junk):
        raise Exception("Fake exception.")

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with patch('pyqrcode.create', side_effect=throw_an_exception):
            with pytest.raises(Exception) as pytest_wrapped_e:
                main()
                out, err = capsys.readouterr()
                assert re.search('Aborting due to: Fake exception', out, re.MULTILINE)
                assert err == ''
                assert pytest_wrapped_e.type == Exception
def test_main_onConnection(capsys)

Test onConnection

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onConnection(capsys):
    """Test onConnection"""
    sys.argv = ['']
    Globals.getInstance().set_args(sys.argv)
    iface = MagicMock(autospec=SerialInterface)
    class TempTopic:
        """ temp class for topic """
        def getName(self):
            """ return the fake name of a topic"""
            return 'foo'
    mytopic = TempTopic()
    onConnection(iface, mytopic)
    out, err = capsys.readouterr()
    assert re.search(r'Connection changed: foo', out, re.MULTILINE)
    assert err == ''
def test_main_onReceive_empty(caplog, capsys)

Test onReceive

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onReceive_empty(caplog, capsys):
    """Test onReceive"""
    args = MagicMock()
    Globals.getInstance().set_args(args)
    iface = MagicMock(autospec=SerialInterface)
    packet = {}
    with caplog.at_level(logging.DEBUG):
        onReceive(packet, iface)
    assert re.search(r'in onReceive', caplog.text, re.MULTILINE)
    out, err = capsys.readouterr()
    assert re.search(r"Warning: There is no field 'to' in the packet.", out, re.MULTILINE)
    assert err == ''
def test_main_onReceive_with_sendtext(caplog, capsys)

Test onReceive with sendtext The entire point of this test is to make sure the interface.close() call is made in onReceive().

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onReceive_with_sendtext(caplog, capsys):
    """Test onReceive with sendtext
       The entire point of this test is to make sure the interface.close() call
       is made in onReceive().
    """
    sys.argv = ['', '--sendtext', 'hello']
    Globals.getInstance().set_args(sys.argv)

    # Note: 'TEXT_MESSAGE_APP' value is 1
    packet = {
            'to': 4294967295,
            'decoded': {
                'portnum': 1,
                'payload': "hello"
                },
            'id': 334776977,
            'hop_limit': 3,
            'want_ack': True
            }

    iface = MagicMock(autospec=SerialInterface)
    iface.myInfo.my_node_num = 4294967295

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        with caplog.at_level(logging.DEBUG):
            main()
            onReceive(packet, iface)
        assert re.search(r'in onReceive', caplog.text, re.MULTILINE)
        mo.assert_called()
        out, err = capsys.readouterr()
        assert re.search(r'Sending text message hello to', out, re.MULTILINE)
        assert err == ''
def test_main_onReceive_with_text(caplog, capsys)

Test onReceive with text

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_onReceive_with_text(caplog, capsys):
    """Test onReceive with text
    """
    args = MagicMock()
    args.sendtext.return_value = 'foo'
    Globals.getInstance().set_args(args)

    # Note: 'TEXT_MESSAGE_APP' value is 1
    # Note: Some of this is faked below.
    packet = {
            'to': 4294967295,
            'decoded': {
                'portnum': 1,
                'payload': "hello",
                'text': "faked"
                },
            'id': 334776977,
            'hop_limit': 3,
            'want_ack': True,
            'rxSnr': 6.0,
            'hopLimit': 3,
            'raw': 'faked',
            'fromId': '!28b5465c',
            'toId': '^all'
            }

    iface = MagicMock(autospec=SerialInterface)
    iface.myInfo.my_node_num = 4294967295

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with caplog.at_level(logging.DEBUG):
            onReceive(packet, iface)
        assert re.search(r'in onReceive', caplog.text, re.MULTILINE)
        out, err = capsys.readouterr()
        assert re.search(r'Sending reply', out, re.MULTILINE)
        assert err == ''
def test_main_qr(capsys)

Test –qr

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_qr(capsys):
    """Test --qr"""
    sys.argv = ['', '--qr']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    # TODO: could mock/check url
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Primary channel URL', out, re.MULTILINE)
        # if a qr code is generated it will have lots of these
        assert re.search(r'\[7m', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_reboot(capsys)

Test –reboot

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_reboot(capsys):
    """Test --reboot"""
    sys.argv = ['', '--reboot']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_reboot():
        print('inside mocked reboot')
    mocked_node.reboot.side_effect = mock_reboot

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked reboot', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_sendping(capsys)

Test –sendping

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendping(capsys):
    """Test --sendping"""
    sys.argv = ['', '--sendping']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendData(payload, dest, portNum, wantAck, wantResponse):
        print('inside mocked sendData')
        print(f'{payload} {dest} {portNum} {wantAck} {wantResponse}')
    iface.sendData.side_effect = mock_sendData

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Sending ping message', out, re.MULTILINE)
        assert re.search(r'inside mocked sendData', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_sendtext(capsys)

Test –sendtext

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext(capsys):
    """Test --sendtext"""
    sys.argv = ['', '--sendtext', 'hello']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendText(text, dest, wantAck, channelIndex):
        print('inside mocked sendText')
        print(f'{text} {dest} {wantAck} {channelIndex}')
    iface.sendText.side_effect = mock_sendText

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Sending text message', out, re.MULTILINE)
        assert re.search(r'inside mocked sendText', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_sendtext_with_channel(capsys)

Test –sendtext

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext_with_channel(capsys):
    """Test --sendtext"""
    sys.argv = ['', '--sendtext', 'hello', '--ch-index', '1']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendText(text, dest, wantAck, channelIndex):
        print('inside mocked sendText')
        print(f'{text} {dest} {wantAck} {channelIndex}')
    iface.sendText.side_effect = mock_sendText

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Sending text message', out, re.MULTILINE)
        assert re.search(r'on channelIndex:1', out, re.MULTILINE)
        assert re.search(r'inside mocked sendText', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_sendtext_with_dest(capsys, caplog, iface_with_nodes)

Test –sendtext with –dest

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext_with_dest(capsys, caplog, iface_with_nodes):
    """Test --sendtext with --dest"""
    sys.argv = ['', '--sendtext', 'hello', '--dest', 'foo']
    Globals.getInstance().set_args(sys.argv)

    iface = iface_with_nodes
    iface.myInfo.my_node_num = 2475227164
    mocked_channel = MagicMock(autospec=Channel)
    iface.localNode.getChannelByChannelIndex = mocked_channel

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
        with caplog.at_level(logging.DEBUG):

            with pytest.raises(SystemExit) as pytest_wrapped_e:
                main()
            assert pytest_wrapped_e.type == SystemExit
            assert pytest_wrapped_e.value.code == 1
            out, err = capsys.readouterr()
            assert re.search(r'Connected to radio', out, re.MULTILINE)
            assert not re.search(r"Warning: 0 is not a valid channel", out, re.MULTILINE)
            assert not re.search(r"There is a SECONDARY channel named 'admin'", out, re.MULTILINE)
            assert re.search(r'Warning: NodeId foo not found in DB', out, re.MULTILINE)
            assert err == ''
def test_main_sendtext_with_invalid_channel(caplog, capsys)

Test –sendtext

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext_with_invalid_channel(caplog, capsys):
    """Test --sendtext"""
    sys.argv = ['', '--sendtext', 'hello', '--ch-index', '-1']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    iface.localNode.getChannelByChannelIndex.return_value = None

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
            with pytest.raises(SystemExit) as pytest_wrapped_e:
                main()
            assert pytest_wrapped_e.type == SystemExit
            assert pytest_wrapped_e.value.code == 1
            out, err = capsys.readouterr()
            assert re.search(r'is not a valid channel', out, re.MULTILINE)
            assert err == ''
            mo.assert_called()
def test_main_sendtext_with_invalid_channel_nine(caplog, capsys)

Test –sendtext

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext_with_invalid_channel_nine(caplog, capsys):
    """Test --sendtext"""
    sys.argv = ['', '--sendtext', 'hello', '--ch-index', '9']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    iface.localNode.getChannelByChannelIndex.return_value = None

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
            with pytest.raises(SystemExit) as pytest_wrapped_e:
                main()
            assert pytest_wrapped_e.type == SystemExit
            assert pytest_wrapped_e.value.code == 1
            out, err = capsys.readouterr()
            assert re.search(r'is not a valid channel', out, re.MULTILINE)
            assert err == ''
            mo.assert_called()
def test_main_setPref_ignore_incoming_0(capsys)

Test setPref() with ignore_incoming

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_ignore_incoming_0(capsys):
    """Test setPref() with ignore_incoming"""

    class Field:
        """Simple class for testing."""

        def __init__(self, name, enum_type):
            """constructor"""
            self.name = name
            self.enum_type = enum_type

    ignore_incoming_field = Field('ignore_incoming', 'list')
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = ignore_incoming_field

    setPref(prefs, 'ignore_incoming', '0')
    out, err = capsys.readouterr()
    assert re.search(r'Clearing ignore_incoming list', out, re.MULTILINE)
    assert re.search(r'Set ignore_incoming to 0', out, re.MULTILINE)
    assert err == ''
def test_main_setPref_ignore_incoming_123(capsys)

Test setPref() with ignore_incoming

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_ignore_incoming_123(capsys):
    """Test setPref() with ignore_incoming"""

    class Field:
        """Simple class for testing."""

        def __init__(self, name, enum_type):
            """constructor"""
            self.name = name
            self.enum_type = enum_type

    ignore_incoming_field = Field('ignore_incoming', 'list')
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = ignore_incoming_field

    setPref(prefs, 'ignore_incoming', '123')
    out, err = capsys.readouterr()
    assert re.search(r"Adding '123' to the ignore_incoming list", out, re.MULTILINE)
    assert re.search(r'Set ignore_incoming to 123', out, re.MULTILINE)
    assert err == ''
def test_main_setPref_invalid_field(capsys)

Test setPref() with a invalid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_invalid_field(capsys):
    """Test setPref() with a invalid field"""


    class Field:
        """Simple class for testing."""

        def __init__(self, name):
            """constructor"""
            self.name = name

    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    # Note: This is a subset of the real fields
    ls_secs_field = Field('ls_secs')
    is_router = Field('is_router')
    fixed_position = Field('fixed_position')

    fields = [ ls_secs_field, is_router, fixed_position ]
    prefs.DESCRIPTOR.fields = fields

    setPref(prefs, 'foo', '300')
    out, err = capsys.readouterr()
    assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
    # ensure they are sorted
    assert re.search(r'fixed_position\s+is_router\s+ls_secs', out, re.MULTILINE)
    assert err == ''
def test_main_setPref_invalid_field_camel(capsys)

Test setPref() with a invalid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_invalid_field_camel(capsys):
    """Test setPref() with a invalid field"""
    Globals.getInstance().set_camel_case()

    class Field:
        """Simple class for testing."""

        def __init__(self, name):
            """constructor"""
            self.name = name

    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    # Note: This is a subset of the real fields
    ls_secs_field = Field('ls_secs')
    is_router = Field('is_router')
    fixed_position = Field('fixed_position')

    fields = [ ls_secs_field, is_router, fixed_position ]
    prefs.DESCRIPTOR.fields = fields

    setPref(prefs, 'foo', '300')
    out, err = capsys.readouterr()
    assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
    # ensure they are sorted
    assert re.search(r'fixedPosition\s+isRouter\s+lsSecs', out, re.MULTILINE)
    assert err == ''
def test_main_setPref_valid_field_int_as_string(capsys)

Test setPref() with a valid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_valid_field_int_as_string(capsys):
    """Test setPref() with a valid field"""

    class Field:
        """Simple class for testing."""

        def __init__(self, name, enum_type):
            """constructor"""
            self.name = name
            self.enum_type = enum_type

    ls_secs_field = Field('ls_secs', 'int')
    prefs = MagicMock()
    prefs.DESCRIPTOR.fields_by_name.get.return_value = ls_secs_field

    setPref(prefs, 'ls_secs', '300')
    out, err = capsys.readouterr()
    assert re.search(r'Set ls_secs to 300', out, re.MULTILINE)
    assert err == ''
def test_main_set_canned_messages(capsys)

Test –set-canned-message

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_canned_messages(capsys):
    """Test --set-canned-message """
    sys.argv = ['', '--set-canned-message', 'foo']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting canned plugin message to foo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_set_ham_to_KI123(capsys)

Test –set-ham KI123

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_ham_to_KI123(capsys):
    """Test --set-ham KI123"""
    sys.argv = ['', '--set-ham', 'KI123']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_turnOffEncryptionOnPrimaryChannel():
        print('inside mocked turnOffEncryptionOnPrimaryChannel')
    def mock_setOwner(name, is_licensed):
        print(f'inside mocked setOwner name:{name} is_licensed:{is_licensed}')
    mocked_node.turnOffEncryptionOnPrimaryChannel.side_effect = mock_turnOffEncryptionOnPrimaryChannel
    mocked_node.setOwner.side_effect = mock_setOwner

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting Ham ID to KI123', out, re.MULTILINE)
        assert re.search(r'inside mocked setOwner', out, re.MULTILINE)
        assert re.search(r'inside mocked turnOffEncryptionOnPrimaryChannel', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_set_invalid_wifi_passwd(capsys)

Test –set with an invalid value (password must be 8 or more characters)

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_invalid_wifi_passwd(capsys):
    """Test --set with an invalid value (password must be 8 or more characters)"""
    sys.argv = ['', '--set', 'wifi_password', '1234567']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert not re.search(r'Set wifi_password to 1234567', out, re.MULTILINE)
        assert re.search(r'Warning: wifi_password must be 8 or more characters.', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_set_owner_short_to_bob(capsys)

Test –set-owner-short bob

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_owner_short_to_bob(capsys):
    """Test --set-owner-short bob"""
    sys.argv = ['', '--set-owner-short', 'bob']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting device owner short to bob', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_set_owner_to_bob(capsys)

Test –set-owner bob

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_owner_to_bob(capsys):
    """Test --set-owner bob"""
    sys.argv = ['', '--set-owner', 'bob']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Setting device owner to bob', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_set_valid(capsys)

Test –set with valid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_valid(capsys):
    """Test --set with valid field"""
    sys.argv = ['', '--set', 'wifi_ssid', 'foo']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Set wifi_ssid to foo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_set_valid_camel_case(capsys)

Test –set with valid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_valid_camel_case(capsys):
    """Test --set with valid field"""
    sys.argv = ['', '--set', 'wifi_ssid', 'foo']
    Globals.getInstance().set_args(sys.argv)
    Globals.getInstance().set_camel_case()

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Set wifiSsid to foo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_set_valid_wifi_passwd(capsys)

Test –set with valid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_valid_wifi_passwd(capsys):
    """Test --set with valid field"""
    sys.argv = ['', '--set', 'wifi_password', '123456789']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Set wifi_password to 123456789', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_set_with_invalid(capsys)

Test –set with invalid field

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_with_invalid(capsys):
    """Test --set with invalid field"""
    sys.argv = ['', '--set', 'foo', 'foo']
    Globals.getInstance().set_args(sys.argv)

    mocked_user_prefs = MagicMock()
    mocked_user_prefs.DESCRIPTOR.fields_by_name.get.return_value = None

    mocked_node = MagicMock(autospec=Node)
    mocked_node.radioConfig.preferences = ( mocked_user_prefs )

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'does not have an attribute called foo', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_setalt(capsys)

Test –setalt

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setalt(capsys):
    """Test --setalt"""
    sys.argv = ['', '--setalt', '51']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_writeConfig():
        print('inside mocked writeConfig')
    mocked_node.writeConfig.side_effect = mock_writeConfig

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendPosition(lat, lon, alt):
        print('inside mocked sendPosition')
        print(f'{lat} {lon} {alt}')
    iface.sendPosition.side_effect = mock_sendPosition
    iface.localNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Fixing altitude', out, re.MULTILINE)
        assert re.search(r'Setting device position', out, re.MULTILINE)
        assert re.search(r'inside mocked sendPosition', out, re.MULTILINE)
        # TODO: Why does this not work? assert re.search(r'inside mocked writeConfig', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_setlat(capsys)

Test –sendlat

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setlat(capsys):
    """Test --sendlat"""
    sys.argv = ['', '--setlat', '37.5']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_writeConfig():
        print('inside mocked writeConfig')
    mocked_node.writeConfig.side_effect = mock_writeConfig

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendPosition(lat, lon, alt):
        print('inside mocked sendPosition')
        print(f'{lat} {lon} {alt}')
    iface.sendPosition.side_effect = mock_sendPosition
    iface.localNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Fixing latitude', out, re.MULTILINE)
        assert re.search(r'Setting device position', out, re.MULTILINE)
        assert re.search(r'inside mocked sendPosition', out, re.MULTILINE)
        # TODO: Why does this not work? assert re.search(r'inside mocked writeConfig', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_setlon(capsys)

Test –setlon

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setlon(capsys):
    """Test --setlon"""
    sys.argv = ['', '--setlon', '-122.1']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_writeConfig():
        print('inside mocked writeConfig')
    mocked_node.writeConfig.side_effect = mock_writeConfig

    iface = MagicMock(autospec=SerialInterface)
    def mock_sendPosition(lat, lon, alt):
        print('inside mocked sendPosition')
        print(f'{lat} {lon} {alt}')
    iface.sendPosition.side_effect = mock_sendPosition
    iface.localNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'Fixing longitude', out, re.MULTILINE)
        assert re.search(r'Setting device position', out, re.MULTILINE)
        assert re.search(r'inside mocked sendPosition', out, re.MULTILINE)
        # TODO: Why does this not work? assert re.search(r'inside mocked writeConfig', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_seturl(capsys)

Test –seturl (url used below is what is generated after a factory_reset)

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_seturl(capsys):
    """Test --seturl (url used below is what is generated after a factory_reset)"""
    sys.argv = ['', '--seturl', 'https://www.meshtastic.org/d/#CgUYAyIBAQ']
    Globals.getInstance().set_args(sys.argv)

    iface = MagicMock(autospec=SerialInterface)
    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_shutdown(capsys)

Test –shutdown

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_shutdown(capsys):
    """Test --shutdown"""
    sys.argv = ['', '--shutdown']
    Globals.getInstance().set_args(sys.argv)

    mocked_node = MagicMock(autospec=Node)
    def mock_shutdown():
        print('inside mocked shutdown')
    mocked_node.shutdown.side_effect = mock_shutdown

    iface = MagicMock(autospec=SerialInterface)
    iface.getNode.return_value = mocked_node

    with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
        main()
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert re.search(r'inside mocked shutdown', out, re.MULTILINE)
        assert err == ''
        mo.assert_called()
def test_main_support(capsys)

Test –support

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_support(capsys):
    """Test --support"""
    sys.argv = ['', '--support']
    Globals.getInstance().set_args(sys.argv)

    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 == ''
def test_main_test_no_ports(patched_find_ports, capsys)

Test –test with no hardware

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=[])
def test_main_test_no_ports(patched_find_ports, capsys):
    """Test --test with no hardware"""
    sys.argv = ['', '--test']
    Globals.getInstance().set_args(sys.argv)

    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()
    out, err = capsys.readouterr()
    assert re.search(r'Warning: Must have at least two devices connected to USB', out, re.MULTILINE)
    assert err == ''
def test_main_test_one_port(patched_find_ports, capsys)

Test –test with one fake port

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyFake1'])
def test_main_test_one_port(patched_find_ports, capsys):
    """Test --test with one fake port"""
    sys.argv = ['', '--test']
    Globals.getInstance().set_args(sys.argv)

    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()
    out, err = capsys.readouterr()
    assert re.search(r'Warning: Must have at least two devices connected to USB', out, re.MULTILINE)
    assert err == ''
def test_main_test_two_ports_fails(patched_test_all, capsys)

Test –test two fake ports and testAll() is a simulated failure

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.test.testAll', return_value=False)
def test_main_test_two_ports_fails(patched_test_all, capsys):
    """Test --test two fake ports and testAll() is a simulated failure"""
    sys.argv = ['', '--test']
    Globals.getInstance().set_args(sys.argv)

    with pytest.raises(SystemExit) as pytest_wrapped_e:
        main()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 1
    patched_test_all.assert_called()
    out, err = capsys.readouterr()
    assert re.search(r'Test was not successful.', out, re.MULTILINE)
    assert err == ''
def test_main_test_two_ports_success(patched_test_all, capsys)

Test –test two fake ports and testAll() is a simulated success

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.test.testAll', return_value=True)
def test_main_test_two_ports_success(patched_test_all, capsys):
    """Test --test two fake ports and testAll() is a simulated success"""
    sys.argv = ['', '--test']
    Globals.getInstance().set_args(sys.argv)

    with pytest.raises(SystemExit) as pytest_wrapped_e:
        main()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 0
    patched_test_all.assert_called()
    out, err = capsys.readouterr()
    assert re.search(r'Test was a success.', out, re.MULTILINE)
    assert err == ''
def test_onNode(capsys)

Test onNode

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_onNode(capsys):
    """Test onNode"""
    onNode('foo')
    out, err = capsys.readouterr()
    assert re.search(r'Node changed', out, re.MULTILINE)
    assert err == ''
def test_tunnel_no_args(capsys)

Test tunnel no arguments

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_tunnel_no_args(capsys):
    """Test tunnel no arguments"""
    sys.argv = ['']
    Globals.getInstance().set_args(sys.argv)
    with pytest.raises(SystemExit) as pytest_wrapped_e:
        tunnelMain()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 1
    _, err = capsys.readouterr()
    assert re.search(r'usage: ', err, re.MULTILINE)
def test_tunnel_subnet_arg_with_no_devices(mock_platform_system, caplog, capsys)

Test tunnel with subnet arg (act like we are on a linux system)

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=[])
@patch('platform.system')
def test_tunnel_subnet_arg_with_no_devices(mock_platform_system, caplog, capsys):
    """Test tunnel with subnet arg (act like we are on a linux system)"""
    a_mock = MagicMock()
    a_mock.return_value = 'Linux'
    mock_platform_system.side_effect = a_mock
    sys.argv = ['', '--subnet', 'foo']
    Globals.getInstance().set_args(sys.argv)
    print(f'platform.system():{platform.system()}')
    with caplog.at_level(logging.DEBUG):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            tunnelMain()
        mock_platform_system.assert_called()
        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 == ''
def test_tunnel_tunnel_arg(mock_platform_system, caplog, iface_with_nodes, capsys)

Test tunnel with tunnel arg (act like we are on a linux system)

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('platform.system')
def test_tunnel_tunnel_arg(mock_platform_system, caplog, iface_with_nodes, capsys):
    """Test tunnel with tunnel arg (act like we are on a linux system)"""
    # Override the time.sleep so there is no loop
    def my_sleep(amount):
        print(f'{amount}')
        sys.exit(3)

    a_mock = MagicMock()
    a_mock.return_value = 'Linux'
    mock_platform_system.side_effect = a_mock
    sys.argv = ['', '--tunnel']
    Globals.getInstance().set_args(sys.argv)

    iface = iface_with_nodes
    iface.myInfo.my_node_num = 2475227164

    with caplog.at_level(logging.DEBUG):
        with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
            with patch('time.sleep', side_effect=my_sleep):
                with pytest.raises(SystemExit) as pytest_wrapped_e:
                    tunnelMain()
                    mock_platform_system.assert_called()
                assert pytest_wrapped_e.type == SystemExit
                assert pytest_wrapped_e.value.code == 3
                assert re.search(r'Not starting Tunnel', caplog.text, re.MULTILINE)
        out, err = capsys.readouterr()
        assert re.search(r'Connected to radio', out, re.MULTILINE)
        assert err == ''
def test_tunnel_tunnel_arg_with_no_devices(mock_platform_system, caplog, capsys)

Test tunnel with tunnel arg (act like we are on a linux system)

Expand source code
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
@patch('meshtastic.util.findPorts', return_value=[])
@patch('platform.system')
def test_tunnel_tunnel_arg_with_no_devices(mock_platform_system, caplog, capsys):
    """Test tunnel with tunnel arg (act like we are on a linux system)"""
    a_mock = MagicMock()
    a_mock.return_value = 'Linux'
    mock_platform_system.side_effect = a_mock
    sys.argv = ['', '--tunnel']
    Globals.getInstance().set_args(sys.argv)
    print(f'platform.system():{platform.system()}')
    with caplog.at_level(logging.DEBUG):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            tunnelMain()
        mock_platform_system.assert_called()
        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 == ''

Classes

class Channel (*args, **kwargs)

A ProtocolMessage

Ancestors

  • google._upb._message.Message
  • google.protobuf.message.Message

Class variables

var DESCRIPTOR