Skip to content

Commit 7672a3d

Browse files
committed
IMPROVEMENT: Add more annotate_params tests
1 parent bcdbda3 commit 7672a3d

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed

tests/test_annotate_params.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
from ardupilot_methodic_configurator.annotate_params import (
2626
BASE_URL,
2727
PARAM_DEFINITION_XML_FILE,
28+
Par,
2829
arg_parser,
2930
create_doc_dict,
31+
extract_parameter_name_and_validate,
3032
format_columns,
3133
get_xml_data,
3234
get_xml_url,
@@ -568,6 +570,165 @@ def test_empty_parameter_file(self) -> None:
568570
# Check if the file is still empty
569571
assert updated_content == ""
570572

573+
def test_get_xml_url_valid_vehicles(self) -> None:
574+
"""Test get_xml_url with all valid vehicle types."""
575+
vehicle_types = ["ArduCopter", "ArduPlane", "Rover", "ArduSub", "AntennaTracker", "AP_Periph", "Blimp", "Heli", "SITL"]
576+
for vehicle in vehicle_types:
577+
url = get_xml_url(vehicle, "4.3")
578+
assert url.startswith(BASE_URL)
579+
assert "stable-4.3" in url
580+
assert url.endswith("/")
581+
582+
def test_get_xml_url_invalid_vehicle(self) -> None:
583+
"""Test get_xml_url with invalid vehicle type."""
584+
with pytest.raises(ValueError, match="Vehicle type 'InvalidVehicle' is not supported."):
585+
get_xml_url("InvalidVehicle", "4.3")
586+
587+
def test_split_into_lines_edge_cases(self) -> None:
588+
"""Test split_into_lines with edge cases."""
589+
# Test with various line lengths
590+
# Function will return largest possible chunks based on max length
591+
assert split_into_lines("a b c", 2) == ["a", "b", "c"]
592+
assert split_into_lines("", 10) == []
593+
594+
def test_format_columns_edge_cases(self) -> None:
595+
"""Test format_columns with edge cases."""
596+
# Empty dictionary
597+
assert format_columns({}) == []
598+
599+
# Single item
600+
assert format_columns({"Key": "Value"}) == ["Key: Value"]
601+
602+
# Test with different max widths
603+
values = {"K1": "V1", "K2": "V2"}
604+
assert len(format_columns(values, max_width=20)[0]) <= 20
605+
606+
# Test with many columns
607+
many_values = {f"Key{i}": f"Value{i}" for i in range(20)}
608+
result = format_columns(many_values, max_width=200, max_columns=5)
609+
assert all(len(line) <= 200 for line in result)
610+
611+
def test_create_doc_dict_edge_cases(self) -> None:
612+
"""Test create_doc_dict with edge cases."""
613+
# Test with empty XML
614+
empty_root = ET.Element("root")
615+
assert create_doc_dict(empty_root, "ArduCopter") == {}
616+
617+
# Test with missing attributes
618+
param = ET.SubElement(empty_root, "param")
619+
assert create_doc_dict(empty_root, "ArduCopter") == {}
620+
621+
# Test with minimal valid param
622+
param.set("name", "TEST_PARAM")
623+
param.set("humanName", "Test Parameter")
624+
param.set("documentation", "Test documentation")
625+
doc_dict = create_doc_dict(empty_root, "ArduCopter")
626+
assert "TEST_PARAM" in doc_dict
627+
assert doc_dict["TEST_PARAM"]["humanName"] == "Test Parameter"
628+
629+
@patch("os.path.isfile")
630+
def test_update_parameter_documentation_sorting(self, mock_isfile) -> None:
631+
"""Test parameter sorting in update_parameter_documentation."""
632+
# Mock file existence check
633+
mock_isfile.return_value = True
634+
635+
test_content = "PARAM_Z 100\nPARAM_A 200\nPARAM_M 300\n"
636+
637+
# Create a real temporary file for testing
638+
with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_file:
639+
temp_file.write(test_content)
640+
temp_file_name = temp_file.name
641+
642+
doc = {
643+
"PARAM_Z": {"humanName": "Z", "documentation": ["Z doc"], "fields": {}, "values": {}},
644+
"PARAM_A": {"humanName": "A", "documentation": ["A doc"], "fields": {}, "values": {}},
645+
"PARAM_M": {"humanName": "M", "documentation": ["M doc"], "fields": {}, "values": {}},
646+
}
647+
648+
try:
649+
# Test MissionPlanner sorting
650+
update_parameter_documentation(doc, temp_file_name, "missionplanner")
651+
652+
with open(temp_file_name, encoding="utf-8") as f:
653+
content = f.read()
654+
655+
# Verify content and order
656+
assert "PARAM_A" in content
657+
assert "PARAM_M" in content
658+
assert "PARAM_Z" in content
659+
assert content.index("PARAM_A") < content.index("PARAM_M") < content.index("PARAM_Z")
660+
661+
# Test MAVProxy sorting
662+
# Reset file content
663+
with open(temp_file_name, "w", encoding="utf-8") as f:
664+
f.write(test_content)
665+
666+
update_parameter_documentation(doc, temp_file_name, "mavproxy")
667+
668+
with open(temp_file_name, encoding="utf-8") as f:
669+
content = f.read()
670+
671+
# Verify content for MAVProxy format
672+
assert "PARAM_A" in content
673+
assert "PARAM_M" in content
674+
assert "PARAM_Z" in content
675+
676+
finally:
677+
# Clean up
678+
os.unlink(temp_file_name)
679+
680+
def test_extract_parameter_name_and_validate_invalid_cases(self) -> None:
681+
"""Test parameter name validation with invalid cases."""
682+
# Test invalid parameter name pattern
683+
with pytest.raises(SystemExit):
684+
extract_parameter_name_and_validate("invalid_param 100", "test.param", 1)
685+
686+
# Test too long parameter name
687+
with pytest.raises(SystemExit):
688+
extract_parameter_name_and_validate("VERY_LONG_PARAMETER_NAME_THAT_EXCEEDS_LIMIT 100", "test.param", 1)
689+
690+
# Test invalid separator
691+
with pytest.raises(SystemExit):
692+
extract_parameter_name_and_validate("PARAM:100", "test.param", 1)
693+
694+
def test_par_class_methods(self) -> None:
695+
"""Test Par class methods."""
696+
# Test equality
697+
par1 = Par(100.0, "comment1")
698+
par2 = Par(100.0, "comment1")
699+
par3 = Par(200.0, "comment2")
700+
701+
assert par1 == par2
702+
assert par1 != par3
703+
assert par1 != "not a Par object"
704+
705+
# Test load_param_file with invalid values
706+
with tempfile.NamedTemporaryFile(mode="w", delete=False) as tf:
707+
tf.write("PARAM1 invalid_value\n")
708+
tf.flush()
709+
710+
with pytest.raises(SystemExit):
711+
Par.load_param_file_into_dict(tf.name)
712+
713+
def test_format_params_methods(self) -> None:
714+
"""Test Par.format_params method."""
715+
param_dict = {"PARAM1": Par(100.0, "comment1"), "PARAM2": Par(200.0), "PARAM3": 300.0}
716+
717+
# Test MissionPlanner format
718+
mp_format = Par.format_params(param_dict, "missionplanner")
719+
assert any("PARAM1,100" in line for line in mp_format)
720+
assert any("# comment1" in line for line in mp_format)
721+
722+
# Test MAVProxy format
723+
mavproxy_format = Par.format_params(param_dict, "mavproxy")
724+
# Use correct spacing format - 16 chars for name, 8 for value
725+
assert any("PARAM1 100.000000" in line for line in mavproxy_format)
726+
assert any("# comment1" in line for line in mavproxy_format)
727+
728+
# Test invalid format
729+
with pytest.raises(SystemExit):
730+
Par.format_params(param_dict, "invalid_format")
731+
571732

572733
class AnnotateParamsTest(unittest.TestCase):
573734
"""Test annotate parameters."""

0 commit comments

Comments
 (0)