From 108a803b7b57e557c89f0d0c3e50dad526d80e5d Mon Sep 17 00:00:00 2001 From: "Dr.-Ing. Amilcar do Carmo Lucas" Date: Sat, 18 Jan 2025 02:26:06 +0100 Subject: [PATCH] FEATURE: Add more backend_filesystem tests --- tests/test_backend_filesystem.py | 210 +++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/tests/test_backend_filesystem.py b/tests/test_backend_filesystem.py index 9c90ee6..8d11c04 100755 --- a/tests/test_backend_filesystem.py +++ b/tests/test_backend_filesystem.py @@ -11,6 +11,7 @@ """ import unittest +from os import path as os_path from unittest.mock import MagicMock, patch from ardupilot_methodic_configurator.backend_filesystem import LocalFilesystem @@ -250,6 +251,215 @@ def test_get_upload_local_and_remote_filenames(self) -> None: assert result == ("vehicle_dir/source_local", "dest_on_fc") mock_join.assert_called_once_with("vehicle_dir", "source_local") + def test_copy_fc_values_to_file(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + test_params = {"PARAM1": 1.0, "PARAM2": 2.0} + test_file = "test.param" + + # Test with non-existent file + result = lfs.copy_fc_values_to_file(test_file, test_params) + assert result == 0 + + # Test with existing file and matching parameters + lfs.file_parameters = {test_file: {"PARAM1": MagicMock(value=0.0), "PARAM2": MagicMock(value=0.0)}} + result = lfs.copy_fc_values_to_file(test_file, test_params) + assert result == 2 + assert lfs.file_parameters[test_file]["PARAM1"].value == 1.0 + assert lfs.file_parameters[test_file]["PARAM2"].value == 2.0 + + def test_write_and_read_last_uploaded_filename(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + test_filename = "test.param" + + # Test writing + expected_path = os_path.join("vehicle_dir", "last_uploaded_filename.txt") + with patch("builtins.open", unittest.mock.mock_open()) as mock_file: + lfs.write_last_uploaded_filename(test_filename) + mock_file.assert_called_once_with(expected_path, "w", encoding="utf-8") + mock_file().write.assert_called_once_with(test_filename) + + # Test reading + with patch("builtins.open", unittest.mock.mock_open(read_data=test_filename)) as mock_file: + result = lfs._LocalFilesystem__read_last_uploaded_filename() + assert result == test_filename + mock_file.assert_called_once_with(expected_path, encoding="utf-8") + + def test_write_param_default_values(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + + # Test with new values + new_values = {"PARAM1": MagicMock(value=1.0)} + result = lfs.write_param_default_values(new_values) + assert result is True + assert lfs.param_default_dict == new_values + + # Test with same values (no change) + result = lfs.write_param_default_values(new_values) + assert result is False + + def test_get_start_file(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + lfs.file_parameters = {"01_file.param": {}, "02_file.param": {}, "03_file.param": {}} + + # Test with explicit index + result = lfs.get_start_file(1, True) # noqa: FBT003 + assert result == "02_file.param" + + # Test with out of range index + result = lfs.get_start_file(5, True) # noqa: FBT003 + assert result == "03_file.param" + + # Test with tcal available + result = lfs.get_start_file(-1, True) # noqa: FBT003 + assert result == "01_file.param" + + # Test with tcal not available + result = lfs.get_start_file(-1, False) # noqa: FBT003 + assert result == "03_file.param" + + def test_get_eval_variables(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + + # Test with empty components and doc_dict + result = lfs.get_eval_variables() + assert result == {} + + # Test with components and doc_dict + lfs.vehicle_components = {"Components": {"test": "value"}} + lfs.doc_dict = {"param": "doc"} + result = lfs.get_eval_variables() + assert "vehicle_components" in result + assert "doc_dict" in result + assert result["vehicle_components"] == {"test": "value"} + assert result["doc_dict"] == {"param": "doc"} + + def test_tolerance_check(self) -> None: + """Test numerical value comparison with tolerances.""" + LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + + # Test exact match + x, y = 1.0, 1.0 + assert abs(x - y) <= 1e-08 + (1e-03 * abs(y)) + + # Test within absolute tolerance + x, y = 1.0, 1.00000001 + assert abs(x - y) <= 1e-08 + (1e-03 * abs(y)) + + # Test within relative tolerance + x, y = 1.0, 1.001 + assert abs(x - y) <= 1e-08 + (1e-03 * abs(y)) + + # Test outside both tolerances + x, y = 1.0, 1.1 + assert not abs(x - y) <= 1e-08 + (1e-03 * abs(y)) + + # Test with custom tolerances + x, y = 1.0, 1.5 + assert abs(x - y) <= 1.0 + (1e-03 * abs(y)) # atol=1.0 + x, y = 1.0, 2.0 + assert abs(x - y) <= 1e-08 + (1.0 * abs(y)) # rtol=1.0 + + def test_categorize_parameters(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + lfs.param_default_dict = {"PARAM1": MagicMock(value=1.0)} + lfs.doc_dict = {"PARAM1": {"ReadOnly": True}, "PARAM2": {"Calibration": True}, "PARAM3": {}} + + test_params = {"PARAM1": MagicMock(value=2.0), "PARAM2": MagicMock(value=2.0), "PARAM3": MagicMock(value=2.0)} + + readonly, calibration, other = lfs.categorize_parameters(test_params) + + assert "PARAM1" in readonly + assert "PARAM2" in calibration + assert "PARAM3" in other + + def test_copy_fc_params_values_to_template_created_vehicle_files(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + fc_parameters = {"PARAM1": 1.0, "PARAM2": 2.0} + + # Test with empty file_parameters + result = lfs.copy_fc_params_values_to_template_created_vehicle_files(fc_parameters) + assert result == "" + + # Test with file_parameters and configuration_steps + param1_mock = MagicMock() + param1_mock.value = 0.0 + param2_mock = MagicMock() + param2_mock.value = 0.0 + + lfs.file_parameters = {"test.param": {"PARAM1": param1_mock, "PARAM2": param2_mock}} + lfs.configuration_steps = {"test.param": {"forced": {}, "derived": {}}} + + with ( + patch("ardupilot_methodic_configurator.backend_filesystem.Par.export_to_param") as mock_export, + patch("ardupilot_methodic_configurator.backend_filesystem.Par.format_params") as mock_format, + ): + mock_format.return_value = "formatted_params" + + result = lfs.copy_fc_params_values_to_template_created_vehicle_files(fc_parameters) + assert result == "" + assert param1_mock.value == 1.0 + assert param2_mock.value == 2.0 + mock_export.assert_called_once_with("formatted_params", os_path.join("vehicle_dir", "test.param")) + + def test_write_param_default_values_to_file(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + param_mock = MagicMock() + param_mock.value = 1.0 + param_default_values = {"PARAM1": param_mock} + + with ( + patch("ardupilot_methodic_configurator.backend_filesystem.Par.export_to_param") as mock_export, + patch("ardupilot_methodic_configurator.backend_filesystem.Par.format_params") as mock_format, + ): + mock_format.return_value = "formatted_params" + + # Test with new values + lfs.write_param_default_values_to_file(param_default_values) + assert lfs.param_default_dict == param_default_values + mock_format.assert_called_with(param_default_values) + mock_export.assert_called_with("formatted_params", os_path.join("vehicle_dir", "00_default.param")) + + # Test with same values (no change) + mock_export.reset_mock() + lfs.write_param_default_values_to_file(param_default_values) + mock_export.assert_not_called() + + def test_export_to_param(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + param_mock = MagicMock() + param_mock.value = 1.0 + test_params = {"PARAM1": param_mock} + + with ( + patch("ardupilot_methodic_configurator.backend_filesystem.Par.export_to_param") as mock_export, + patch("ardupilot_methodic_configurator.backend_filesystem.update_parameter_documentation") as mock_update, + patch("ardupilot_methodic_configurator.backend_filesystem.Par.format_params") as mock_format, + ): + mock_format.return_value = "formatted_params" + + # Test with documentation annotation + lfs.export_to_param(test_params, "test.param", True) # noqa: FBT003 + mock_format.assert_called_with(test_params) + mock_export.assert_called_with("formatted_params", os_path.join("vehicle_dir", "test.param")) + mock_update.assert_called_once() + + # Test without documentation annotation + mock_export.reset_mock() + mock_update.reset_mock() + lfs.export_to_param(test_params, "test.param", False) # noqa: FBT003 + mock_export.assert_called_once() + mock_update.assert_not_called() + + def test_all_intermediate_parameter_file_comments(self) -> None: + lfs = LocalFilesystem("vehicle_dir", "vehicle_type", None, allow_editing_template_files=False) + lfs.file_parameters = { + "file1.param": {"PARAM1": MagicMock(comment="Comment 1"), "PARAM2": MagicMock(comment="Comment 2")}, + "file2.param": {"PARAM2": MagicMock(comment="Override comment 2"), "PARAM3": MagicMock(comment="Comment 3")}, + } + + result = lfs._LocalFilesystem__all_intermediate_parameter_file_comments() + assert result == {"PARAM1": "Comment 1", "PARAM2": "Override comment 2", "PARAM3": "Comment 3"} + class TestCopyTemplateFilesToNewVehicleDir(unittest.TestCase): """Copy Template Files To New Vehicle Directory testclass."""