Skip to content

Commit

Permalink
IMPROVEMENT: Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
amilcarlucas committed Jan 16, 2025
1 parent c8f71aa commit 5dbedad
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 36 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,13 @@ jobs:
run: |
cd tests
python -m coverage run -m unittest test_annotate_params.py
python -m coverage run -m unittest test_ardupilot_methodic_configurator.py
python -m coverage run -m unittest test_argparse_check_range.py
python -m coverage run -m unittest test_backend_filesystem.py
python -m coverage run -m unittest test_battery_cell_voltages.py
python -m coverage run -m unittest test_common_arguments.py
python -m coverage run -m unittest test_extract_param_defaults.py
python -m coverage run -m unittest test_internationalization.py
python -m coverage run -m unittest test_middleware_template_overview.py
python -m coverage run -m unittest test_param_pid_adjustment_update.py
python -m coverage run -m unittest version_test.py
python -m coverage html
67 changes: 67 additions & 0 deletions tests/test__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env python3

"""
Tests for the __main__.py file.
This file is part of Ardupilot methodic configurator. https://github.com/ArduPilot/MethodicConfigurator
SPDX-FileCopyrightText: 2024 Amilcar do Carmo Lucas <[email protected]>
SPDX-License-Identifier: GPL-3.0-or-later
"""

import argparse
import unittest
from unittest.mock import MagicMock, patch

from ardupilot_methodic_configurator.__main__ import argument_parser, component_editor, connect_to_fc_and_read_parameters


class TestArgumentParser(unittest.TestCase): # pylint: disable=missing-class-docstring
@patch(
"argparse.ArgumentParser.parse_args", return_value=argparse.Namespace(conn="tcp:127.0.0.1:5760", params="params_dir")
)
def test_argument_parser(self, mock_args) -> None:
args = argument_parser()
assert args.conn == "tcp:127.0.0.1:5760"
assert args.params == "params_dir"


class TestMainFunctions(unittest.TestCase):
@patch("ardupilot_methodic_configurator.__main__.FlightController")
def test_connect_to_fc_and_read_parameters(self, mock_flight_controller) -> None:
mock_fc = mock_flight_controller.return_value
mock_fc.connect.return_value = ""
mock_fc.info.vehicle_type = "quad"
mock_fc.info.flight_sw_version_and_type = "v1.0"
mock_fc.info.vendor = "vendor"
mock_fc.info.firmware_type = "type"

args = argparse.Namespace(device="test_device", vehicle_type="", reboot_time=5)
flight_controller, vehicle_type = connect_to_fc_and_read_parameters(args)
assert flight_controller == mock_fc
assert vehicle_type == "quad"

@patch("ardupilot_methodic_configurator.__main__.ComponentEditorWindow")
@patch("ardupilot_methodic_configurator.__main__.LocalFilesystem")
@patch("ardupilot_methodic_configurator.__main__.ProgramSettings")
def test_component_editor(self, mock_program_settings, mock_local_filesystem, mock_component_editor_window) -> None:
mock_program_settings = mock_program_settings.return_value
mock_program_settings.get_setting.return_value = True

mock_local_filesystem = mock_local_filesystem.return_value
mock_local_filesystem.doc_dict = {}

mock_fc = MagicMock()
mock_fc.fc_parameters = {"param1": "value1"}
mock_fc.info.flight_sw_version_and_type = "v1.0"
mock_fc.info.vendor = "vendor"
mock_fc.info.firmware_type = "type"

args = argparse.Namespace(skip_component_editor=False)
component_editor(args, mock_fc, "quad", mock_local_filesystem, None)
mock_component_editor_window.assert_called_once()


if __name__ == "__main__":
unittest.main()
35 changes: 0 additions & 35 deletions tests/test_ardupilot_methodic_configurator.py

This file was deleted.

71 changes: 71 additions & 0 deletions tests/test_argparse_check_range.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/python3

"""
Tests for the argparse_check_range.py file.
This file is part of Ardupilot methodic configurator. https://github.com/ArduPilot/MethodicConfigurator
SPDX-FileCopyrightText: 2024-2025 Amilcar do Carmo Lucas <[email protected]>
SPDX-License-Identifier: GPL-3.0-or-later
"""

import unittest
from argparse import ArgumentParser

import pytest

from ardupilot_methodic_configurator.argparse_check_range import CheckRange


class TestCheckRange(unittest.TestCase):
def setUp(self) -> None:
self.parser = ArgumentParser()

def test_init_with_both_min_and_inf(self) -> None:
with pytest.raises(ValueError, match="either min or inf, but not both"):
self.parser.add_argument("--test", action=CheckRange, min=0, inf=0)

def test_init_with_both_max_and_sup(self) -> None:
with pytest.raises(ValueError, match="either max or sup, but not both"):
self.parser.add_argument("--test", action=CheckRange, max=10, sup=10)

def test_interval_with_min_and_max(self) -> None:
action = CheckRange(option_strings=["--test"], dest="test", min=0, max=10)
assert action.interval() == "valid range: [0, 10]"

def test_interval_with_inf_and_sup(self) -> None:
action = CheckRange(option_strings=["--test"], dest="test", inf=0, sup=10)
assert action.interval() == "valid range: (0, 10)"

def test_interval_with_no_bounds(self) -> None:
action = CheckRange(option_strings=["--test"], dest="test")
assert action.interval() == "valid range: (-infinity, +infinity)"

def test_call_with_non_number_value(self) -> None:
self.parser.add_argument("--test", action=CheckRange, min=0, max=10)
with pytest.raises(SystemExit) as excinfo:
self.parser.parse_args(["--test", "non-number"])
assert str(excinfo.value) == "2"

def test_call_with_value_out_of_range(self) -> None:
self.parser.add_argument("--test", action=CheckRange, min=0, max=10)
with pytest.raises(SystemExit) as excinfo:
self.parser.parse_args(["--test", "11"])
assert str(excinfo.value) == "2"

def test_call_with_value_equal_to_inf(self) -> None:
self.parser.add_argument("--test", action=CheckRange, inf=0, sup=10)
with pytest.raises(SystemExit) as excinfo:
self.parser.parse_args(["--test", "0"])
assert str(excinfo.value) == "2"

def test_call_with_value_equal_to_sup(self) -> None:
self.parser.add_argument("--test", action=CheckRange, inf=0, sup=10)
with pytest.raises(SystemExit) as excinfo:
self.parser.parse_args(["--test", "10"])
assert str(excinfo.value) == "2"


if __name__ == "__main__":
unittest.main()
74 changes: 74 additions & 0 deletions tests/test_internationalization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/python3

"""
Tests for the internationalization.py file.
This file is part of Ardupilot methodic configurator. https://github.com/ArduPilot/MethodicConfigurator
SPDX-FileCopyrightText: 2024-2025 Amilcar do Carmo Lucas <[email protected]>
SPDX-License-Identifier: GPL-3.0-or-later
"""

import argparse
import unittest

import pytest

from ardupilot_methodic_configurator.internationalization import LANGUAGE_CHOICES, identity_function, load_translation


class TestInternationalization(unittest.TestCase):
def test_default_language_is_english(self) -> None:
assert LANGUAGE_CHOICES[0] == "en"

def test_load_translation_default(self) -> None:
translation_function = load_translation()
assert translation_function == identity_function

def test_identity_function(self) -> None:
test_string = "test"
assert identity_function(test_string) == test_string

@pytest.mark.usefixtures("mock_args_de")
def test_load_translation_with_language(self) -> None:
translation_function = load_translation()
assert translation_function != identity_function

@pytest.mark.usefixtures("mock_args_invalid")
def test_load_translation_with_invalid_language(self) -> None:
translation_function = load_translation()
assert translation_function == identity_function

@pytest.mark.usefixtures("mock_gettext", "mock_args_zh_cn")
def test_load_translation_fallback(self) -> None:
translation_function = load_translation()
assert translation_function == identity_function

def test_language_choices(self) -> None:
expected_languages = ["en", "zh_CN", "pt", "de"]
assert expected_languages == LANGUAGE_CHOICES


@pytest.fixture
def mock_args_de(mocker) -> None:
mocker.patch("argparse.ArgumentParser.parse_known_args", return_value=(argparse.Namespace(language="de"), []))


@pytest.fixture
def mock_args_invalid(mocker) -> None:
mocker.patch("argparse.ArgumentParser.parse_known_args", return_value=(argparse.Namespace(language="invalid"), []))


@pytest.fixture
def mock_args_zh_cn(mocker) -> None:
mocker.patch("argparse.ArgumentParser.parse_known_args", return_value=(argparse.Namespace(language="zh_CN"), []))


@pytest.fixture
def mock_gettext(mocker) -> None:
mocker.patch("gettext.translation", side_effect=FileNotFoundError)


if __name__ == "__main__":
unittest.main()

0 comments on commit 5dbedad

Please sign in to comment.