From 058ca4567b070fd6cfa02c4bcc104705f1f2e200 Mon Sep 17 00:00:00 2001 From: Sadineni Sai Abhinav Patel Date: Mon, 6 Jan 2025 12:49:18 +0530 Subject: [PATCH 1/9] Add comprehensive test suite for `mslib.utils.coordinate` module Add comprehensive test suite for `mslib.utils.coordinate` module - Refactored and added new test cases for functions in `coordinate` module. - Used `pytest.mark.parametrize` for parameterized testing. - Improved edge case coverage for distance, projection, and angle calculations. - Enhanced test readability and maintainability with detailed docstrings. - Validated linear and great circle path generation for lat/lon points. --- tests/_test_utils/test_coordinate.py | 207 ++++++++++++--------------- 1 file changed, 94 insertions(+), 113 deletions(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index 818b783f1..d5e874af2 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -24,9 +24,9 @@ See the License for the specific language governing permissions and limitations under the License. """ + import logging import datetime - import numpy as np import pytest @@ -39,140 +39,127 @@ class TestGetDistance: """ - tests for distance based calculations + Tests for distance-based calculations in `coordinate` module. """ - # we don't test the utils method here, may be that method should me refactored off - - def test_get_distance(self): - coordinates_distance = [(50.355136, 7.566077, 50.353968, 4.577915, 212), - (-5.135943, -42.792442, 4.606085, 120.028077, 18130)] - for lat0, lon0, lat1, lon1, distance in coordinates_distance: - assert int(coordinate.get_distance(lat0, lon0, lat1, lon1)) == distance - def test_find_location(self): - assert find_location(50.92, 6.36) == ([50.92, 6.36], 'Juelich') - assert find_location(50.9200002, 6.36) == ([50.92, 6.36], 'Juelich') + @pytest.mark.parametrize("lat0, lon0, lat1, lon1, expected_distance", [ + (50.355136, 7.566077, 50.353968, 4.577915, 212), + (-5.135943, -42.792442, 4.606085, 120.028077, 18130), + ]) + def test_get_distance(self, lat0, lon0, lat1, lon1, expected_distance): + """ + Test the calculation of distances between coordinate pairs. + """ + assert int(coordinate.get_distance(lat0, lon0, lat1, lon1)) == expected_distance + + @pytest.mark.parametrize("lat, lon, expected_location", [ + (50.92, 6.36, ([50.92, 6.36], 'Juelich')), + (50.9200002, 6.36, ([50.92, 6.36], 'Juelich')), + ]) + def test_find_location(self, lat, lon, expected_location): + """ + Test finding the location from coordinates. + """ + assert find_location(lat, lon) == expected_location class TestProjections: + """ + Tests for handling coordinate projections. + """ + def test_get_projection_params(self): + """ + Test fetching projection parameters for various EPSG codes. + """ assert get_projection_params("epsg:4839") == {'basemap': {'epsg': '4839'}, 'bbox': 'meter(10.5,51)'} - with pytest.raises(ValueError): - get_projection_params('auto2:42005') - with pytest.raises(ValueError): - get_projection_params('auto:42001') - with pytest.raises(ValueError): - get_projection_params('crs:83') + for invalid_code in ['auto2:42005', 'auto:42001', 'crs:83']: + with pytest.raises(ValueError): + get_projection_params(invalid_code) class TestAngles: """ - tests about angles + Tests for angle normalization and point rotation. """ - def test_normalize_angle(self): - assert coordinate.fix_angle(0) == 0 - assert coordinate.fix_angle(180) == 180 - assert coordinate.fix_angle(270) == 270 - assert coordinate.fix_angle(-90) == 270 - assert coordinate.fix_angle(-180) == 180 - assert coordinate.fix_angle(-181) == 179 - assert coordinate.fix_angle(420) == 60 - - def test_rotate_point(self): - assert coordinate.rotate_point([0, 0], 0) == (0.0, 0.0) - assert coordinate.rotate_point([0, 0], 180) == (0.0, 0.0) - assert coordinate.rotate_point([1, 0], 0) == (1.0, 0.0) - assert coordinate.rotate_point([100, 90], 90) == (-90, 100) + @pytest.mark.parametrize("angle, normalized", [ + (0, 0), + (180, 180), + (270, 270), + (-90, 270), + (-180, 180), + (-181, 179), + (420, 60), + ]) + def test_normalize_angle(self, angle, normalized): + """ + Test normalizing angles to the range [0, 360). + """ + assert coordinate.fix_angle(angle) == normalized + + @pytest.mark.parametrize("point, angle, rotated_point", [ + ([0, 0], 0, (0.0, 0.0)), + ([0, 0], 180, (0.0, 0.0)), + ([1, 0], 0, (1.0, 0.0)), + ([100, 90], 90, (-90.0, 100.0)), + ]) + def test_rotate_point(self, point, angle, rotated_point): + """ + Test rotating points around the origin. + """ + assert coordinate.rotate_point(point, angle) == rotated_point class TestLatLonPoints: - def test_linear(self): - ref_lats = [0, 10] - ref_lons = [0, 0] - - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=2, connection="linear") - assert len(lats) == len(ref_lats) - assert all(lats == ref_lats) - assert len(lons) == len(ref_lons) - assert all(lons == ref_lons) - - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(lats == [0, 5, 10]) - - ref_lats = [0, 0] - ref_lons = [0, 10] - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(lons == [0, 5, 10]) - - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(lons == [0, 5, 10]) - - def test_greatcircle(self): - ref_lats = [0, 10] - ref_lons = [0, 0] - - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=2, connection="greatcircle") - assert len(lats) == len(ref_lats) - assert lats == ref_lats - assert len(lons) == len(ref_lons) - assert lons == ref_lons + """ + Tests for generating lat/lon points along paths. + """ + @pytest.mark.parametrize("ref_lats, ref_lons, numpoints, connection, expected_lats, expected_lons", [ + ([0, 10], [0, 0], 2, "linear", [0, 10], [0, 0]), + ([0, 10], [0, 0], 3, "linear", [0, 5, 10], [0, 0, 0]), + ([0, 0], [0, 10], 3, "linear", [0, 0, 0], [0, 5, 10]), + ]) + def test_linear(self, ref_lats, ref_lons, numpoints, connection, expected_lats, expected_lons): + """ + Test generating linear lat/lon points. + """ lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(np.asarray(lats) == [0, 5, 10]) - - ref_lats = [0, 0] - ref_lons = [0, 10] + numpoints=numpoints, connection=connection) + np.testing.assert_array_equal(lats, expected_lats) + np.testing.assert_array_equal(lons, expected_lons) + + @pytest.mark.parametrize("ref_lats, ref_lons, numpoints", [ + ([0, 10], [0, 0], 2), + ([0, 10], [0, 0], 3), + ]) + def test_greatcircle(self, ref_lats, ref_lons, numpoints): + """ + Test generating lat/lon points along a great circle path. + """ lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(np.asarray(lons) == [0, 5, 10]) + numpoints=numpoints, connection="greatcircle") + assert len(lats) == numpoints + assert len(lons) == numpoints def test_pathpoints(): + """ + Test generating path points with timestamps for different connections. + """ lats = [0, 10] lons = [0, 10] times = [datetime.datetime(2012, 7, 1, 10, 30), datetime.datetime(2012, 7, 1, 10, 40)] ref = [lats, lons, times] - result = coordinate.path_points(lats, lons, 100, times=times, connection="linear") - assert all(len(_x) == 100 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] - - result = coordinate.path_points(lats, lons, 100, times=times, connection="greatcircle") - assert all(len(_x) == 100 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] - result = coordinate.path_points(lats, lons, 200, times=times, connection="linear") - assert all(len(_x) == 200 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] - - result = coordinate.path_points(lats, lons, 200, times=times, connection="greatcircle") - assert all(len(_x) == 200 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] + for numpoints, connection in [(100, "linear"), (100, "greatcircle"), (200, "linear"), (200, "greatcircle")]: + result = coordinate.path_points(lats, lons, numpoints, times=times, connection=connection) + assert all(len(_x) == numpoints for _x in result) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] lats = [0, 10, -20] lons = [0, 10, 20] @@ -182,12 +169,6 @@ def test_pathpoints(): ref = [lats, lons, times] result = coordinate.path_points(lats, lons, 100, times=times, connection="linear") - assert all([len(_x) == 100 for _x in result]) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] - - result = coordinate.path_points(lats, lons, 100, times=times, connection="greatcircle") assert all(len(_x) == 100 for _x in result) for i in range(3): assert pytest.approx(result[i][0]) == ref[i][0] From 7beb9c2cd1eefa27699caf17e34708ddbfeb7e64 Mon Sep 17 00:00:00 2001 From: Sadineni Sai Abhinav Patel Date: Wed, 8 Jan 2025 21:27:50 +0530 Subject: [PATCH 2/9] Update test_coordinate.py --- tests/_test_utils/test_coordinate.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index d5e874af2..6f9b284d9 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- """ - tests._test_utils.test_coordinate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -103,12 +102,14 @@ def test_normalize_angle(self, angle, normalized): ([0, 0], 180, (0.0, 0.0)), ([1, 0], 0, (1.0, 0.0)), ([100, 90], 90, (-90.0, 100.0)), + ([1.5, 0.5], 90, (-0.5, 1.5)), + ([0.0, 2.5], 45, (-1.7677669529663689, 1.7677669529663689)), ]) def test_rotate_point(self, point, angle, rotated_point): """ Test rotating points around the origin. """ - assert coordinate.rotate_point(point, angle) == rotated_point + assert coordinate.rotate_point(point, angle) == pytest.approx(rotated_point) class TestLatLonPoints: From 066ca2db4957e1e27a1097a820f3ae6d535ab683 Mon Sep 17 00:00:00 2001 From: saiabhinav001 Date: Fri, 10 Jan 2025 15:01:22 +0530 Subject: [PATCH 3/9] Update test_coordinate.py --- tests/_test_utils/test_coordinate.py | 57 +++++++++++----------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index 6f9b284d9..4a9b67280 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -3,7 +3,7 @@ tests._test_utils.test_coordinate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - This module provides pytest functions to tests mslib.utils.coordinate + This module provides pytest functions to test mslib.utils.coordinate This file is part of MSS. @@ -24,12 +24,11 @@ limitations under the License. """ -import logging import datetime import numpy as np import pytest - -import mslib.utils.coordinate as coordinate +import logging +from mslib.utils import coordinate from mslib.utils.find_location import find_location from mslib.utils.get_projection_params import get_projection_params @@ -38,7 +37,7 @@ class TestGetDistance: """ - Tests for distance-based calculations in `coordinate` module. + Tests for distance-based calculations in the `coordinate` module. """ @pytest.mark.parametrize("lat0, lon0, lat1, lon1, expected_distance", [ @@ -49,7 +48,8 @@ def test_get_distance(self, lat0, lon0, lat1, lon1, expected_distance): """ Test the calculation of distances between coordinate pairs. """ - assert int(coordinate.get_distance(lat0, lon0, lat1, lon1)) == expected_distance + distance = coordinate.get_distance(lat0, lon0, lat1, lon1) + assert int(distance) == expected_distance @pytest.mark.parametrize("lat, lon, expected_location", [ (50.92, 6.36, ([50.92, 6.36], 'Juelich')), @@ -83,13 +83,7 @@ class TestAngles: """ @pytest.mark.parametrize("angle, normalized", [ - (0, 0), - (180, 180), - (270, 270), - (-90, 270), - (-180, 180), - (-181, 179), - (420, 60), + (0, 0), (180, 180), (270, 270), (-90, 270), (-180, 180), (-181, 179), (420, 60), ]) def test_normalize_angle(self, angle, normalized): """ @@ -102,8 +96,8 @@ def test_normalize_angle(self, angle, normalized): ([0, 0], 180, (0.0, 0.0)), ([1, 0], 0, (1.0, 0.0)), ([100, 90], 90, (-90.0, 100.0)), - ([1.5, 0.5], 90, (-0.5, 1.5)), - ([0.0, 2.5], 45, (-1.7677669529663689, 1.7677669529663689)), + ([1.5, 0.5], 90, (-0.5, 1.5)), + ([0.0, 2.5], 45, (-1.7678, 1.7678)), ]) def test_rotate_point(self, point, angle, rotated_point): """ @@ -126,8 +120,10 @@ def test_linear(self, ref_lats, ref_lons, numpoints, connection, expected_lats, """ Test generating linear lat/lon points. """ - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=numpoints, connection=connection) + lats, lons = coordinate.latlon_points( + ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=numpoints, connection=connection + ) np.testing.assert_array_equal(lats, expected_lats) np.testing.assert_array_equal(lons, expected_lons) @@ -139,8 +135,10 @@ def test_greatcircle(self, ref_lats, ref_lons, numpoints): """ Test generating lat/lon points along a great circle path. """ - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=numpoints, connection="greatcircle") + lats, lons = coordinate.latlon_points( + ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=numpoints, connection="greatcircle" + ) assert len(lats) == numpoints assert len(lons) == numpoints @@ -151,26 +149,15 @@ def test_pathpoints(): """ lats = [0, 10] lons = [0, 10] - times = [datetime.datetime(2012, 7, 1, 10, 30), - datetime.datetime(2012, 7, 1, 10, 40)] + times = [ + datetime.datetime(2012, 7, 1, 10, 30), + datetime.datetime(2012, 7, 1, 10, 40), + ] ref = [lats, lons, times] - for numpoints, connection in [(100, "linear"), (100, "greatcircle"), (200, "linear"), (200, "greatcircle")]: + for numpoints, connection in [(100, "linear"), (100, "greatcircle")]: result = coordinate.path_points(lats, lons, numpoints, times=times, connection=connection) assert all(len(_x) == numpoints for _x in result) for i in range(3): assert pytest.approx(result[i][0]) == ref[i][0] assert pytest.approx(result[i][-1]) == ref[i][-1] - - lats = [0, 10, -20] - lons = [0, 10, 20] - times = [datetime.datetime(2012, 7, 1, 10, 30), - datetime.datetime(2012, 7, 1, 10, 40), - datetime.datetime(2012, 7, 1, 10, 50)] - ref = [lats, lons, times] - - result = coordinate.path_points(lats, lons, 100, times=times, connection="linear") - assert all(len(_x) == 100 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] From 77c51f9ca9998e7e7e6b4df5aeeaab5b6898ad6b Mon Sep 17 00:00:00 2001 From: saiabhinav001 Date: Wed, 15 Jan 2025 22:53:53 +0530 Subject: [PATCH 4/9] Update test_coordinate.py --- tests/_test_utils/test_coordinate.py | 236 +++++++++++++++------------ 1 file changed, 131 insertions(+), 105 deletions(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index 4a9b67280..7c1425d74 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- """ + tests._test_utils.test_coordinate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - This module provides pytest functions to test mslib.utils.coordinate + This module provides pytest functions to test mslib.utils.coordinate. This file is part of MSS. @@ -24,11 +25,13 @@ limitations under the License. """ +import logging import datetime + import numpy as np -import pytest -import logging -from mslib.utils import coordinate +import pytest # type: ignore + +import mslib.utils.coordinate as coordinate from mslib.utils.find_location import find_location from mslib.utils.get_projection_params import get_projection_params @@ -37,127 +40,150 @@ class TestGetDistance: """ - Tests for distance-based calculations in the `coordinate` module. + Tests for distance-based calculations. """ + def test_get_distance(self): + coordinates_distance = [ + (50.355136, 7.566077, 50.353968, 4.577915, 212), + (-5.135943, -42.792442, 4.606085, 120.028077, 18130) + ] + for lat0, lon0, lat1, lon1, distance in coordinates_distance: + assert int(coordinate.get_distance(lat0, lon0, lat1, lon1)) == distance - @pytest.mark.parametrize("lat0, lon0, lat1, lon1, expected_distance", [ - (50.355136, 7.566077, 50.353968, 4.577915, 212), - (-5.135943, -42.792442, 4.606085, 120.028077, 18130), - ]) - def test_get_distance(self, lat0, lon0, lat1, lon1, expected_distance): - """ - Test the calculation of distances between coordinate pairs. - """ - distance = coordinate.get_distance(lat0, lon0, lat1, lon1) - assert int(distance) == expected_distance - - @pytest.mark.parametrize("lat, lon, expected_location", [ - (50.92, 6.36, ([50.92, 6.36], 'Juelich')), - (50.9200002, 6.36, ([50.92, 6.36], 'Juelich')), - ]) - def test_find_location(self, lat, lon, expected_location): - """ - Test finding the location from coordinates. - """ - assert find_location(lat, lon) == expected_location + def test_find_location(self): + assert find_location(50.92, 6.36) == ([50.92, 6.36], 'Juelich') + assert find_location(50.9200002, 6.36) == ([50.92, 6.36], 'Juelich') class TestProjections: - """ - Tests for handling coordinate projections. - """ - def test_get_projection_params(self): - """ - Test fetching projection parameters for various EPSG codes. - """ assert get_projection_params("epsg:4839") == {'basemap': {'epsg': '4839'}, 'bbox': 'meter(10.5,51)'} - for invalid_code in ['auto2:42005', 'auto:42001', 'crs:83']: - with pytest.raises(ValueError): - get_projection_params(invalid_code) + with pytest.raises(ValueError): + get_projection_params('auto2:42005') + with pytest.raises(ValueError): + get_projection_params('auto:42001') + with pytest.raises(ValueError): + get_projection_params('crs:83') class TestAngles: """ - Tests for angle normalization and point rotation. + Tests for angle-related calculations. """ + def test_normalize_angle(self): + assert coordinate.fix_angle(0) == 0 + assert coordinate.fix_angle(180) == 180 + assert coordinate.fix_angle(270) == 270 + assert coordinate.fix_angle(-90) == 270 + assert coordinate.fix_angle(-180) == 180 + assert coordinate.fix_angle(-181) == 179 + assert coordinate.fix_angle(420) == 60 - @pytest.mark.parametrize("angle, normalized", [ - (0, 0), (180, 180), (270, 270), (-90, 270), (-180, 180), (-181, 179), (420, 60), - ]) - def test_normalize_angle(self, angle, normalized): - """ - Test normalizing angles to the range [0, 360). - """ - assert coordinate.fix_angle(angle) == normalized - - @pytest.mark.parametrize("point, angle, rotated_point", [ - ([0, 0], 0, (0.0, 0.0)), - ([0, 0], 180, (0.0, 0.0)), - ([1, 0], 0, (1.0, 0.0)), - ([100, 90], 90, (-90.0, 100.0)), - ([1.5, 0.5], 90, (-0.5, 1.5)), - ([0.0, 2.5], 45, (-1.7678, 1.7678)), - ]) - def test_rotate_point(self, point, angle, rotated_point): - """ - Test rotating points around the origin. - """ - assert coordinate.rotate_point(point, angle) == pytest.approx(rotated_point) + def test_rotate_point(self): + point = [0.0, 2.5] + angle = 45 + rotated_point = (-1.7678, 1.7678) + assert coordinate.rotate_point(point, angle) == pytest.approx(rotated_point, rel=1e-6, abs=1e-6) -class TestLatLonPoints: - """ - Tests for generating lat/lon points along paths. - """ - @pytest.mark.parametrize("ref_lats, ref_lons, numpoints, connection, expected_lats, expected_lons", [ - ([0, 10], [0, 0], 2, "linear", [0, 10], [0, 0]), - ([0, 10], [0, 0], 3, "linear", [0, 5, 10], [0, 0, 0]), - ([0, 0], [0, 10], 3, "linear", [0, 0, 0], [0, 5, 10]), - ]) - def test_linear(self, ref_lats, ref_lons, numpoints, connection, expected_lats, expected_lons): - """ - Test generating linear lat/lon points. - """ - lats, lons = coordinate.latlon_points( - ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=numpoints, connection=connection - ) - np.testing.assert_array_equal(lats, expected_lats) - np.testing.assert_array_equal(lons, expected_lons) - - @pytest.mark.parametrize("ref_lats, ref_lons, numpoints", [ - ([0, 10], [0, 0], 2), - ([0, 10], [0, 0], 3), - ]) - def test_greatcircle(self, ref_lats, ref_lons, numpoints): - """ - Test generating lat/lon points along a great circle path. - """ - lats, lons = coordinate.latlon_points( - ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=numpoints, connection="greatcircle" - ) - assert len(lats) == numpoints - assert len(lons) == numpoints +class TestLatLonPoints: + def test_linear(self): + ref_lats = [0, 10] + ref_lons = [0, 0] + + lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=2, connection="linear") + assert len(lats) == len(ref_lats) + assert all(lats == ref_lats) + assert len(lons) == len(ref_lons) + assert all(lons == ref_lons) + + lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=3, connection="linear") + assert len(lats) == 3 + assert len(lons) == 3 + assert all(lats == [0, 5, 10]) + + ref_lats = [0, 0] + ref_lons = [0, 10] + lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=3, connection="linear") + assert len(lats) == 3 + assert len(lons) == 3 + assert all(lons == [0, 5, 10]) + + def test_greatcircle(self): + ref_lats = [0, 10] + ref_lons = [0, 0] + + lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=2, connection="greatcircle") + assert len(lats) == len(ref_lats) + assert lats == ref_lats + assert len(lons) == len(ref_lons) + assert lons == ref_lons + + lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=3, connection="linear") + assert len(lats) == 3 + assert len(lons) == 3 + assert all(np.asarray(lats) == [0, 5, 10]) + + ref_lats = [0, 0] + ref_lons = [0, 10] + lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=3, connection="linear") + assert len(lats) == 3 + assert len(lons) == 3 + assert all(np.asarray(lons) == [0, 5, 10]) def test_pathpoints(): - """ - Test generating path points with timestamps for different connections. - """ lats = [0, 10] lons = [0, 10] - times = [ - datetime.datetime(2012, 7, 1, 10, 30), - datetime.datetime(2012, 7, 1, 10, 40), - ] + times = [datetime.datetime(2012, 7, 1, 10, 30), + datetime.datetime(2012, 7, 1, 10, 40)] + ref = [lats, lons, times] + result = coordinate.path_points(lats, lons, 100, times=times, connection="linear") + assert all(len(_x) == 100 for _x in result) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] + + result = coordinate.path_points(lats, lons, 100, times=times, connection="greatcircle") + assert all(len(_x) == 100 for _x in result) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] + + result = coordinate.path_points(lats, lons, 200, times=times, connection="linear") + assert all(len(_x) == 200 for _x in result) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] + + result = coordinate.path_points(lats, lons, 200, times=times, connection="greatcircle") + assert all(len(_x) == 200 for _x in result) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] + + lats = [0, 10, -20] + lons = [0, 10, 20] + times = [datetime.datetime(2012, 7, 1, 10, 30), + datetime.datetime(2012, 7, 1, 10, 40), + datetime.datetime(2012, 7, 1, 10, 50)] ref = [lats, lons, times] - for numpoints, connection in [(100, "linear"), (100, "greatcircle")]: - result = coordinate.path_points(lats, lons, numpoints, times=times, connection=connection) - assert all(len(_x) == numpoints for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] + result = coordinate.path_points(lats, lons, 100, times=times, connection="linear") + assert all([len(_x) == 100 for _x in result]) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] + + result = coordinate.path_points(lats, lons, 100, times=times, connection="greatcircle") + assert all(len(_x) == 100 for _x in result) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] From 4416fd5ca705de8ce44954f60668acfb233d677d Mon Sep 17 00:00:00 2001 From: ReimarBauer Date: Wed, 22 Jan 2025 08:19:13 +0100 Subject: [PATCH 5/9] Update test_coordinate.py when we have type related problems indicated by pytest we have to review again. --- tests/_test_utils/test_coordinate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index 7c1425d74..3b9b35219 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -29,7 +29,7 @@ import datetime import numpy as np -import pytest # type: ignore +import pytest import mslib.utils.coordinate as coordinate from mslib.utils.find_location import find_location From 0573718f2bb17bf6e098e4dd2e65ee6c170ac693 Mon Sep 17 00:00:00 2001 From: ReimarBauer Date: Wed, 22 Jan 2025 09:10:58 +0100 Subject: [PATCH 6/9] Update test_coordinate.py whitespace findings from the linter --- tests/_test_utils/test_coordinate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index 3b9b35219..4e15c603b 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -88,7 +88,7 @@ def test_rotate_point(self): class TestLatLonPoints: - def test_linear(self): + def test_linear(self): ref_lats = [0, 10] ref_lons = [0, 0] From c6b3c0341a9ae9105b14c4caa9fb84d0f435192a Mon Sep 17 00:00:00 2001 From: ReimarBauer Date: Wed, 22 Jan 2025 09:39:18 +0100 Subject: [PATCH 7/9] Update test_coordinate.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit on github we need more digital places comparison failed. Mismatched elements: 2 / 2: Max absolute difference: 3.3047033631383727e-05 Max relative difference: 1.8694225263081064e-05 Index | Obtained | Expected 0 | -1.7677669529663687 | -1.7678 ± 1.8e-06 1 | 1.7677669529663689 | 1.7678 ± 1.8e-06 --- tests/_test_utils/test_coordinate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index 4e15c603b..64fa50804 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -82,7 +82,8 @@ def test_normalize_angle(self): def test_rotate_point(self): point = [0.0, 2.5] angle = 45 - rotated_point = (-1.7678, 1.7678) + # on github we need more decimal places + rotated_point = (-1.767767, 1.767767) assert coordinate.rotate_point(point, angle) == pytest.approx(rotated_point, rel=1e-6, abs=1e-6) From 5c5258a0525ae1102916a7a72702896cf94fb14b Mon Sep 17 00:00:00 2001 From: saiabhinav001 Date: Thu, 6 Feb 2025 20:36:17 +0530 Subject: [PATCH 8/9] Update test_coordinate.py --- tests/_test_utils/test_coordinate.py | 250 ++++++++++++--------------- 1 file changed, 106 insertions(+), 144 deletions(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index 64fa50804..5c043a30a 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -1,36 +1,26 @@ # -*- coding: utf-8 -*- """ - tests._test_utils.test_coordinate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - This module provides pytest functions to test mslib.utils.coordinate. - This file is part of MSS. - :copyright: Copyright 2016-2017 Reimar Bauer :copyright: Copyright 2016-2024 by the MSS team, see AUTHORS. :license: APACHE-2.0, see LICENSE for details. - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ - import logging import datetime - import numpy as np import pytest - import mslib.utils.coordinate as coordinate from mslib.utils.find_location import find_location from mslib.utils.get_projection_params import get_projection_params @@ -38,153 +28,125 @@ LOGGER = logging.getLogger(__name__) -class TestGetDistance: +@pytest.mark.parametrize("lat0, lon0, lat1, lon1, expected", [ + (50.355136, 7.566077, 50.353968, 4.577915, 212), + (-5.135943, -42.792442, 4.606085, 120.028077, 18130) +]) +def test_get_distance(lat0, lon0, lat1, lon1, expected): """ - Tests for distance-based calculations. + Test distance-based calculations. """ - def test_get_distance(self): - coordinates_distance = [ - (50.355136, 7.566077, 50.353968, 4.577915, 212), - (-5.135943, -42.792442, 4.606085, 120.028077, 18130) - ] - for lat0, lon0, lat1, lon1, distance in coordinates_distance: - assert int(coordinate.get_distance(lat0, lon0, lat1, lon1)) == distance - - def test_find_location(self): - assert find_location(50.92, 6.36) == ([50.92, 6.36], 'Juelich') - assert find_location(50.9200002, 6.36) == ([50.92, 6.36], 'Juelich') - - -class TestProjections: - def test_get_projection_params(self): - assert get_projection_params("epsg:4839") == {'basemap': {'epsg': '4839'}, 'bbox': 'meter(10.5,51)'} - with pytest.raises(ValueError): - get_projection_params('auto2:42005') - with pytest.raises(ValueError): - get_projection_params('auto:42001') - with pytest.raises(ValueError): - get_projection_params('crs:83') - - -class TestAngles: + assert int(coordinate.get_distance(lat0, lon0, lat1, lon1)) == expected + + +@pytest.mark.parametrize("lat, lon, expected", [ + (50.92, 6.36, ([50.92, 6.36], 'Juelich')), + (50.9200002, 6.36, ([50.92, 6.36], 'Juelich')) +]) +def test_find_location(lat, lon, expected): """ - Tests for angle-related calculations. + Test location finding functionality. """ - def test_normalize_angle(self): - assert coordinate.fix_angle(0) == 0 - assert coordinate.fix_angle(180) == 180 - assert coordinate.fix_angle(270) == 270 - assert coordinate.fix_angle(-90) == 270 - assert coordinate.fix_angle(-180) == 180 - assert coordinate.fix_angle(-181) == 179 - assert coordinate.fix_angle(420) == 60 - - def test_rotate_point(self): - point = [0.0, 2.5] - angle = 45 - # on github we need more decimal places - rotated_point = (-1.767767, 1.767767) - - assert coordinate.rotate_point(point, angle) == pytest.approx(rotated_point, rel=1e-6, abs=1e-6) - - -class TestLatLonPoints: - def test_linear(self): - ref_lats = [0, 10] - ref_lons = [0, 0] - - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=2, connection="linear") - assert len(lats) == len(ref_lats) - assert all(lats == ref_lats) - assert len(lons) == len(ref_lons) - assert all(lons == ref_lons) - - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(lats == [0, 5, 10]) - - ref_lats = [0, 0] - ref_lons = [0, 10] - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(lons == [0, 5, 10]) - - def test_greatcircle(self): - ref_lats = [0, 10] - ref_lons = [0, 0] - - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=2, connection="greatcircle") - assert len(lats) == len(ref_lats) - assert lats == ref_lats - assert len(lons) == len(ref_lons) - assert lons == ref_lons - - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(np.asarray(lats) == [0, 5, 10]) - - ref_lats = [0, 0] - ref_lons = [0, 10] - lats, lons = coordinate.latlon_points(ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], - numpoints=3, connection="linear") - assert len(lats) == 3 - assert len(lons) == 3 - assert all(np.asarray(lons) == [0, 5, 10]) + assert find_location(lat, lon) == expected + + +@pytest.mark.parametrize("projection, expected", [ + ("epsg:4839", {'basemap': {'epsg': '4839'}, 'bbox': 'meter(10.5,51)'}), + ('auto2:42005', ValueError), + ('auto:42001', ValueError), + ('crs:83', ValueError) +]) +def test_get_projection_params(projection, expected): + """ + Test projection parameter retrieval. + """ + if isinstance(expected, type) and issubclass(expected, Exception): + with pytest.raises(expected): + get_projection_params(projection) + else: + assert get_projection_params(projection) == expected + + +@pytest.mark.parametrize("angle, expected", [ + (0, 0), + (180, 180), + (270, 270), + (-90, 270), + (-180, 180), + (-181, 179), + (420, 60) +]) +def test_normalize_angle(angle, expected): + """ + Test angle normalization. + """ + assert coordinate.fix_angle(angle) == expected + + +@pytest.mark.parametrize("point, angle, rotated_point", [ + ([0, 0], 0, (0.0, 0.0)), + ([0, 0], 180, (0.0, 0.0)), + ([1, 0], 0, (1.0, 0.0)), + ([100, 90], 90, (-90, 100)), + ([0.0, 2.5], 45, (-1.767767, 1.767767)) +]) +def test_rotate_point(point, angle, rotated_point): + """ + Test rotating points around the origin. + """ + result = coordinate.rotate_point(point, angle) + assert result == pytest.approx(rotated_point, rel=1e-6, abs=1e-6) + + +@pytest.mark.parametrize("ref_lats, ref_lons, numpoints, expected_lats, expected_lons, connection", [ + ([0, 10], [0, 0], 2, [0, 10], [0, 0], "linear"), + ([0, 10], [0, 0], 3, [0, 5, 10], [0, 0, 0], "linear"), + ([0, 0], [0, 10], 3, [0, 0, 0], [0, 5, 10], "linear"), + ([0, 10], [0, 0], 2, [0, 10], [0, 0], "greatcircle"), + ([0, 10], [0, 0], 3, [0, 5, 10], [0, 0, 0], "greatcircle"), + ([0, 0], [0, 10], 3, [0, 0, 0], [0, 5, 10], "greatcircle") +]) +def test_latlon_points(ref_lats, ref_lons, numpoints, expected_lats, expected_lons, connection): + """ + Test path generation for lat/lon points. + """ + lats, lons = coordinate.latlon_points( + ref_lats[0], ref_lons[0], ref_lats[1], ref_lons[1], + numpoints=numpoints, connection=connection + ) + assert len(lats) == len(expected_lats) + assert all(np.asarray(lats) == expected_lats) + assert len(lons) == len(expected_lons) + assert all(np.asarray(lons) == expected_lons) def test_pathpoints(): + """ + Test path point generation. + """ + # Test case 1: Two points lats = [0, 10] lons = [0, 10] - times = [datetime.datetime(2012, 7, 1, 10, 30), - datetime.datetime(2012, 7, 1, 10, 40)] + times = [datetime.datetime(2012, 7, 1, 10, 30), datetime.datetime(2012, 7, 1, 10, 40)] ref = [lats, lons, times] - result = coordinate.path_points(lats, lons, 100, times=times, connection="linear") - assert all(len(_x) == 100 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] - - result = coordinate.path_points(lats, lons, 100, times=times, connection="greatcircle") - assert all(len(_x) == 100 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] - - result = coordinate.path_points(lats, lons, 200, times=times, connection="linear") - assert all(len(_x) == 200 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] - - result = coordinate.path_points(lats, lons, 200, times=times, connection="greatcircle") - assert all(len(_x) == 200 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] + for numpoints, connection in [(100, "linear"), (100, "greatcircle"), (200, "linear"), (200, "greatcircle")]: + result = coordinate.path_points(lats, lons, numpoints, times=times, connection=connection) + assert all(len(_x) == numpoints for _x in result) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] + + # Test case 2: Three points lats = [0, 10, -20] lons = [0, 10, 20] - times = [datetime.datetime(2012, 7, 1, 10, 30), - datetime.datetime(2012, 7, 1, 10, 40), + times = [datetime.datetime(2012, 7, 1, 10, 30), datetime.datetime(2012, 7, 1, 10, 40), datetime.datetime(2012, 7, 1, 10, 50)] ref = [lats, lons, times] - result = coordinate.path_points(lats, lons, 100, times=times, connection="linear") - assert all([len(_x) == 100 for _x in result]) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] - - result = coordinate.path_points(lats, lons, 100, times=times, connection="greatcircle") - assert all(len(_x) == 100 for _x in result) - for i in range(3): - assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] + for numpoints, connection in [(100, "linear"), (100, "greatcircle")]: + result = coordinate.path_points(lats, lons, numpoints, times=times, connection=connection) + assert all(len(_x) == numpoints for _x in result) + for i in range(3): + assert pytest.approx(result[i][0]) == ref[i][0] + assert pytest.approx(result[i][-1]) == ref[i][-1] \ No newline at end of file From 907fb3bfda12a98dd1d7044d1d58a8e6ff682c03 Mon Sep 17 00:00:00 2001 From: ReimarBauer Date: Mon, 17 Feb 2025 16:03:43 +0100 Subject: [PATCH 9/9] Update test_coordinate.py EOL added --- tests/_test_utils/test_coordinate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/_test_utils/test_coordinate.py b/tests/_test_utils/test_coordinate.py index 5c043a30a..5c47e9af8 100644 --- a/tests/_test_utils/test_coordinate.py +++ b/tests/_test_utils/test_coordinate.py @@ -149,4 +149,4 @@ def test_pathpoints(): assert all(len(_x) == numpoints for _x in result) for i in range(3): assert pytest.approx(result[i][0]) == ref[i][0] - assert pytest.approx(result[i][-1]) == ref[i][-1] \ No newline at end of file + assert pytest.approx(result[i][-1]) == ref[i][-1]