From 6ef5d3ef24f035211200a9724bd83dbede0998e1 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sun, 15 Dec 2024 02:59:25 -0300 Subject: [PATCH] TST: adds more unit tests to the codebase --- tests/fixtures/surfaces/surface_fixtures.py | 23 +++++- tests/unit/test_aero_surfaces.py | 64 ++++++++++++++++ tests/unit/test_flight_time_nodes.py | 10 +++ tests/unit/test_tank.py | 8 ++ tests/unit/test_tools.py | 28 +++++++ tests/unit/test_units.py | 82 +++++++++++++++++++++ tests/unit/test_utilities.py | 31 ++++++++ 7 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 tests/unit/test_units.py diff --git a/tests/fixtures/surfaces/surface_fixtures.py b/tests/fixtures/surfaces/surface_fixtures.py index 396206bd7..bf6e384c4 100644 --- a/tests/fixtures/surfaces/surface_fixtures.py +++ b/tests/fixtures/surfaces/surface_fixtures.py @@ -1,7 +1,13 @@ import pytest -from rocketpy import NoseCone, RailButtons, Tail, TrapezoidalFins -from rocketpy.rocket.aero_surface.fins.free_form_fins import FreeFormFins +from rocketpy.rocket.aero_surface import ( + EllipticalFins, + FreeFormFins, + NoseCone, + RailButtons, + Tail, + TrapezoidalFins, +) @pytest.fixture @@ -94,3 +100,16 @@ def calisto_rail_buttons(): angular_position=45, name="Rail Buttons", ) + + +@pytest.fixture +def elliptical_fin_set(): + return EllipticalFins( + n=4, + span=0.100, + root_chord=0.120, + rocket_radius=0.0635, + cant_angle=0, + airfoil=None, + name="Test Elliptical Fins", + ) diff --git a/tests/unit/test_aero_surfaces.py b/tests/unit/test_aero_surfaces.py index 5258814db..146dc593e 100644 --- a/tests/unit/test_aero_surfaces.py +++ b/tests/unit/test_aero_surfaces.py @@ -1,3 +1,5 @@ +from unittest.mock import patch + import pytest from rocketpy import NoseCone @@ -71,3 +73,65 @@ def test_powerseries_nosecones_setters(power, invalid_power, new_power): expected_k = (2 * new_power) / ((2 * new_power) + 1) assert pytest.approx(test_nosecone.k) == expected_k + + +@patch("matplotlib.pyplot.show") +def test_elliptical_fins_draw(mock_show, elliptical_fin_set): + assert elliptical_fin_set.plots.draw(filename=None) is None + + +def test_nose_cone_info(calisto_nose_cone): + assert calisto_nose_cone.info() is None + + +@patch("matplotlib.pyplot.show") +def test_nose_cone_draw(mock_show, calisto_nose_cone): + assert calisto_nose_cone.draw(filename=None) is None + + +def test_trapezoidal_fins_info(calisto_trapezoidal_fins): + assert calisto_trapezoidal_fins.info() is None + + +def test_trapezoidal_fins_tip_chord_setter(calisto_trapezoidal_fins): + calisto_trapezoidal_fins.tip_chord = 0.1 + assert calisto_trapezoidal_fins.tip_chord == 0.1 + + +def test_trapezoidal_fins_root_chord_setter(calisto_trapezoidal_fins): + calisto_trapezoidal_fins.root_chord = 0.1 + assert calisto_trapezoidal_fins.root_chord == 0.1 + + +def test_trapezoidal_fins_sweep_angle_setter(calisto_trapezoidal_fins): + calisto_trapezoidal_fins.sweep_angle = 0.1 + assert calisto_trapezoidal_fins.sweep_angle == 0.1 + + +def test_trapezoidal_fins_sweep_length_setter(calisto_trapezoidal_fins): + calisto_trapezoidal_fins.sweep_length = 0.1 + assert calisto_trapezoidal_fins.sweep_length == 0.1 + + +def test_tail_info(calisto_tail): + assert calisto_tail.info() is None + + +def test_tail_length_setter(calisto_tail): + calisto_tail.length = 0.1 + assert calisto_tail.length == 0.1 + + +def test_tail_rocket_radius_setter(calisto_tail): + calisto_tail.rocket_radius = 0.1 + assert calisto_tail.rocket_radius == 0.1 + + +def test_tail_bottom_radius_setter(calisto_tail): + calisto_tail.bottom_radius = 0.1 + assert calisto_tail.bottom_radius == 0.1 + + +def test_tail_top_radius_setter(calisto_tail): + calisto_tail.top_radius = 0.1 + assert calisto_tail.top_radius == 0.1 diff --git a/tests/unit/test_flight_time_nodes.py b/tests/unit/test_flight_time_nodes.py index dcdc11eff..20769b1f8 100644 --- a/tests/unit/test_flight_time_nodes.py +++ b/tests/unit/test_flight_time_nodes.py @@ -99,3 +99,13 @@ def test_time_node_lt(flight_calisto): node2 = flight_calisto.TimeNodes.TimeNode(2.0, [], [], []) assert node1 < node2 assert not node2 < node1 + + +def test_time_node_repr(flight_calisto): + node = flight_calisto.TimeNodes.TimeNode(1.0, [], [], []) + assert isinstance(repr(node), str) + + +def test_time_nodes_repr(flight_calisto): + time_nodes = flight_calisto.TimeNodes() + assert isinstance(repr(time_nodes), str) diff --git a/tests/unit/test_tank.py b/tests/unit/test_tank.py index a313caf20..b077cd2a3 100644 --- a/tests/unit/test_tank.py +++ b/tests/unit/test_tank.py @@ -1,10 +1,13 @@ from math import isclose from pathlib import Path +from unittest.mock import patch import numpy as np import pytest import scipy.integrate as spi +from rocketpy.motors import TankGeometry + BASE_PATH = Path("./data/rockets/berkeley/") @@ -355,3 +358,8 @@ def expected_gas_inertia(t): atol=1e-3, rtol=1e-2, ) + + +@patch("matplotlib.pyplot.show") +def test_tank_geometry_plots_info(mock_show): + assert TankGeometry({(0, 5): 1}).plots.all() is None diff --git a/tests/unit/test_tools.py b/tests/unit/test_tools.py index 9b321ea0e..fcf67ad37 100644 --- a/tests/unit/test_tools.py +++ b/tests/unit/test_tools.py @@ -6,6 +6,7 @@ euler313_to_quaternions, find_roots_cubic_function, haversine, + tuple_handler, ) @@ -72,3 +73,30 @@ def test_cardanos_root_finding(): def test_haversine(lat0, lon0, lat1, lon1, expected_distance): distance = haversine(lat0, lon0, lat1, lon1) assert np.isclose(distance, expected_distance, rtol=1e-2) + + +@pytest.mark.parametrize( + "input_value, expected_output", + [ + (5, (0, 5)), + (3.5, (0, 3.5)), + ([7], (0, 7)), + ((8,), (0, 8)), + ([2, 4], (2, 4)), + ((1, 3), (1, 3)), + ], +) +def test_tuple_handler(input_value, expected_output): + assert tuple_handler(input_value) == expected_output + + +@pytest.mark.parametrize( + "input_value, expected_exception", + [ + ([1, 2, 3], ValueError), + ((4, 5, 6), ValueError), + ], +) +def test_tuple_handler_exceptions(input_value, expected_exception): + with pytest.raises(expected_exception): + tuple_handler(input_value) diff --git a/tests/unit/test_units.py b/tests/unit/test_units.py new file mode 100644 index 000000000..e3a80c457 --- /dev/null +++ b/tests/unit/test_units.py @@ -0,0 +1,82 @@ +import pytest + +from rocketpy.units import ( + conversion_factor, + convert_temperature, + convert_units, +) + + +class TestConvertTemperature: + def test_convert_temperature_same_unit(self): + assert convert_temperature(300, "K", "K") == 300 + assert convert_temperature(27, "degC", "degC") == 27 + assert convert_temperature(80, "degF", "degF") == 80 + + def test_convert_temperature_K_to_degC(self): + assert convert_temperature(300, "K", "degC") == pytest.approx(26.85, rel=1e-2) + + def test_convert_temperature_K_to_degF(self): + assert convert_temperature(300, "K", "degF") == pytest.approx(80.33, rel=1e-2) + + def test_convert_temperature_degC_to_K(self): + assert convert_temperature(27, "degC", "K") == pytest.approx(300.15, rel=1e-2) + + def test_convert_temperature_degC_to_degF(self): + assert convert_temperature(27, "degC", "degF") == pytest.approx(80.6, rel=1e-2) + + def test_convert_temperature_degF_to_K(self): + assert convert_temperature(80, "degF", "K") == pytest.approx(299.817, rel=1e-2) + + def test_convert_temperature_degF_to_degC(self): + assert convert_temperature(80, "degF", "degC") == pytest.approx(26.67, rel=1e-2) + + def test_convert_temperature_invalid_conversion(self): + with pytest.raises(ValueError): + convert_temperature(300, "K", "invalid_unit") + with pytest.raises(ValueError): + convert_temperature(300, "invalid_unit", "K") + + +class TestConversionFactor: + def test_conversion_factor_same_unit(self): + assert conversion_factor("m", "m") == 1 + assert conversion_factor("ft", "ft") == 1 + assert conversion_factor("s", "s") == 1 + + def test_conversion_factor_m_to_ft(self): + assert conversion_factor("m", "ft") == pytest.approx(3.28084, rel=1e-2) + + def test_conversion_factor_ft_to_m(self): + assert conversion_factor("ft", "m") == pytest.approx(0.3048, rel=1e-2) + + def test_conversion_factor_s_to_min(self): + assert conversion_factor("s", "min") == pytest.approx(1 / 60, rel=1e-2) + + def test_conversion_factor_min_to_s(self): + assert conversion_factor("min", "s") == pytest.approx(60, rel=1e-2) + + def test_conversion_factor_invalid_conversion(self): + with pytest.raises(ValueError): + conversion_factor("m", "invalid_unit") + with pytest.raises(ValueError): + conversion_factor("invalid_unit", "m") + + +class TestConvertUnits: + def test_convert_units_same_unit(self): + assert convert_units(300, "K", "K") == 300 + assert convert_units(27, "degC", "degC") == 27 + assert convert_units(80, "degF", "degF") == 80 + + def test_convert_units_K_to_degC(self): + assert convert_units(300, "K", "degC") == pytest.approx(26.85, rel=1e-2) + + def test_convert_units_K_to_degF(self): + assert convert_units(300, "K", "degF") == pytest.approx(80.33, rel=1e-2) + + def test_convert_units_kilogram_to_pound(self): + assert convert_units(1, "kg", "lb") == pytest.approx(2.20462, rel=1e-2) + + def test_convert_units_kilometer_to_mile(self): + assert convert_units(1, "km", "mi") == pytest.approx(0.621371, rel=1e-2) diff --git a/tests/unit/test_utilities.py b/tests/unit/test_utilities.py index a6d1972a7..67cff10e3 100644 --- a/tests/unit/test_utilities.py +++ b/tests/unit/test_utilities.py @@ -178,3 +178,34 @@ def test_get_instance_attributes(flight_calisto_robust): assert np.allclose(attr, value) else: assert attr == value + + +@pytest.mark.parametrize( + "f, eps, expected", + [ + ([1.0, 1.0, 1.0, 2.0, 3.0], 1e-6, 0), + ([1.0, 1.0, 1.0, 2.0, 3.0], 1e-1, 0), + ([1.0, 1.1, 1.2, 2.0, 3.0], 1e-1, None), + ([1.0, 1.0, 1.0, 1.0, 1.0], 1e-6, 0), + ([1.0, 1.0, 1.0, 1.0, 1.0], 1e-1, 0), + ([1.0, 1.0, 1.0], 1e-6, 0), + ([1.0, 1.0], 1e-6, None), + ([1.0], 1e-6, None), + ([], 1e-6, None), + ], +) +def test_check_constant(f, eps, expected): + """Test if the function `check_constant` returns the correct index or None + for different scenarios. + + Parameters + ---------- + f : list or array + A list or array of numerical values. + eps : float + The tolerance level for comparing the elements. + expected : int or None + The expected result of the function. + """ + result = utilities.check_constant(f, eps) + assert result == expected