Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 101 additions & 143 deletions tests/_test_utils/test_coordinate.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
# -*- coding: utf-8 -*-
"""

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.

: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.
Expand All @@ -26,169 +19,134 @@
"""
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

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.
"""
# we don't test the utils method here, may be that method should me refactored off
assert int(coordinate.get_distance(lat0, lon0, lat1, lon1)) == expected

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("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):
"""
Test location finding functionality.
"""
assert find_location(lat, lon) == expected


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')
@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


class TestAngles:
@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):
"""
tests about angles
Test rotating points around the origin.
"""

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see why the old tests should be removed. They provide coverage for corner cases and have no issues with decimal points. The new test is a good addition, though.

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)


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

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])
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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the description of eric:

https://pytest-with-eric.com/pytest-advanced/pytest-approx/#Example-Code-To-Test-Pytest-Approx

I would expect:

assert result[i][0] == pytest.approx(ref[i][0])
assert result[i][-1] == pytest.approx(ref[i][-1])

assert pytest.approx(result[i][0]) == ref[i][0]
assert pytest.approx(result[i][-1]) == ref[i][-1]
Loading