testsAndMisc/python_pkg/geo_data/tests/test_poland_nature_part2.py

419 lines
16 KiB
Python
Raw Normal View History

"""Tests for forests, nature reserves, and landscape parks download paths."""
from __future__ import annotations
from typing import Any
from unittest.mock import MagicMock, patch
import geopandas as gpd
from shapely.geometry import Polygon
from python_pkg.geo_data._poland_nature import (
get_polish_forests,
get_polish_landscape_parks,
get_polish_nature_reserves,
)
def _make_relation_element(name: str, *, include_outer: bool = True) -> dict[str, Any]:
"""Create a mock OSM relation element."""
members = []
if include_outer:
members.append(
{
"role": "outer",
"geometry": [
{"lon": 0, "lat": 0},
{"lon": 1, "lat": 0},
{"lon": 1, "lat": 1},
{"lon": 0, "lat": 1},
],
}
)
return {"type": "relation", "tags": {"name": name}, "members": members}
_POLY = Polygon([(20, 50), (21, 50), (21, 51), (20, 51)])
class TestGetPolishForests:
"""Tests for get_polish_forests."""
@patch("python_pkg.geo_data._poland_nature.gpd.read_file")
@patch("python_pkg.geo_data._poland_nature.CACHE_DIR")
def test_cached_with_area(
self, mock_cache_dir: MagicMock, mock_read: MagicMock
) -> None:
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = True
mock_gdf = gpd.GeoDataFrame(
{"name": ["Puszcza Białowieska"], "area_km2": [600.0]},
geometry=[_POLY],
crs="EPSG:4326",
)
mock_read.return_value = mock_gdf
result = get_polish_forests()
assert result.iloc[0]["area_km2"] == 600.0
@patch("python_pkg.geo_data._poland_nature.gpd.read_file")
@patch("python_pkg.geo_data._poland_nature.CACHE_DIR")
def test_cached_without_area(
self, mock_cache_dir: MagicMock, mock_read: MagicMock
) -> None:
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = True
mock_gdf = gpd.GeoDataFrame(
{"name": ["Puszcza Białowieska"]},
geometry=[_POLY],
crs="EPSG:4326",
)
mock_read.return_value = mock_gdf
result = get_polish_forests()
assert len(result) == 1
def test_downloads_forests(self) -> None:
with (
patch("python_pkg.geo_data._poland_nature.sys.stdout"),
patch("python_pkg.geo_data._poland_nature.CACHE_DIR") as mock_cache_dir,
patch("python_pkg.geo_data._poland_nature._overpass_query") as mock_query,
patch("python_pkg.geo_data._poland_nature._ensure_cache_dir"),
patch(
"python_pkg.geo_data._poland_nature.gpd.GeoDataFrame.from_features"
) as mock_from_features,
patch(
"python_pkg.geo_data._poland_nature._add_area_column"
) as mock_add_area,
):
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = False
mock_query.return_value = {
"elements": [
# Valid forest with keyword
{
"type": "way",
"tags": {"name": "Puszcza Białowieska"},
"geometry": [
{"lon": 0, "lat": 0},
{"lon": 1, "lat": 0},
{"lon": 1, "lat": 1},
{"lon": 0, "lat": 1},
],
},
# Bory keyword
{
"type": "way",
"tags": {"name": "Bory Tucholskie"},
"geometry": [
{"lon": 2, "lat": 2},
{"lon": 3, "lat": 2},
{"lon": 3, "lat": 3},
{"lon": 2, "lat": 3},
],
},
# No forest keyword -> skip
{
"type": "way",
"tags": {"name": "Random Wood"},
"geometry": [
{"lon": 0, "lat": 0},
{"lon": 1, "lat": 0},
{"lon": 1, "lat": 1},
{"lon": 0, "lat": 1},
],
},
# Duplicate
{
"type": "way",
"tags": {"name": "Puszcza Białowieska"},
"geometry": [
{"lon": 0, "lat": 0},
{"lon": 1, "lat": 0},
{"lon": 1, "lat": 1},
{"lon": 0, "lat": 1},
],
},
# No name
{"type": "way", "tags": {}, "geometry": []},
# Geometry extraction fails (too few coords)
{
"type": "way",
"tags": {"name": "Las Mały"},
"geometry": [{"lon": 0, "lat": 0}],
},
]
}
mock_gdf = gpd.GeoDataFrame(
{"name": ["Puszcza Białowieska", "Bory Tucholskie"]},
geometry=[_POLY, _POLY],
crs="EPSG:4326",
)
mock_from_features.return_value = mock_gdf
gdf_with_area = mock_gdf.copy()
gdf_with_area["area_km2"] = [600.0, 300.0]
mock_add_area.return_value = gdf_with_area
result = get_polish_forests()
assert len(result) == 2
def test_downloads_forests_empty(self) -> None:
with (
patch("python_pkg.geo_data._poland_nature.sys.stdout"),
patch("python_pkg.geo_data._poland_nature.CACHE_DIR") as mock_cache_dir,
patch("python_pkg.geo_data._poland_nature._overpass_query") as mock_query,
patch("python_pkg.geo_data._poland_nature._ensure_cache_dir"),
patch(
"python_pkg.geo_data._poland_nature.gpd.GeoDataFrame.from_features"
) as mock_from_features,
patch(
"python_pkg.geo_data._poland_nature._add_area_column"
) as mock_add_area,
):
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = False
mock_query.return_value = {"elements": []}
empty_gdf = gpd.GeoDataFrame({"name": [], "geometry": []})
mock_from_features.return_value = empty_gdf
mock_add_area.return_value = empty_gdf
result = get_polish_forests()
assert len(result) == 0
class TestGetPolishNatureReserves:
"""Tests for get_polish_nature_reserves."""
@patch("python_pkg.geo_data._poland_nature.gpd.read_file")
@patch("python_pkg.geo_data._poland_nature.CACHE_DIR")
def test_cached_with_area(
self, mock_cache_dir: MagicMock, mock_read: MagicMock
) -> None:
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = True
mock_gdf = gpd.GeoDataFrame(
{"name": ["Rezerwat X"], "area_km2": [50.0]},
geometry=[_POLY],
crs="EPSG:4326",
)
mock_read.return_value = mock_gdf
result = get_polish_nature_reserves()
assert result.iloc[0]["area_km2"] == 50.0
@patch("python_pkg.geo_data._poland_nature.gpd.read_file")
@patch("python_pkg.geo_data._poland_nature.CACHE_DIR")
def test_cached_without_area(
self, mock_cache_dir: MagicMock, mock_read: MagicMock
) -> None:
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = True
mock_gdf = gpd.GeoDataFrame(
{"name": ["Rezerwat X"]},
geometry=[_POLY],
crs="EPSG:4326",
)
mock_read.return_value = mock_gdf
result = get_polish_nature_reserves()
assert len(result) == 1
def test_downloads_reserves(self) -> None:
with (
patch("python_pkg.geo_data._poland_nature.sys.stdout"),
patch("python_pkg.geo_data._poland_nature.CACHE_DIR") as mock_cache_dir,
patch("python_pkg.geo_data._poland_nature._overpass_query") as mock_query,
patch("python_pkg.geo_data._poland_nature._ensure_cache_dir"),
patch(
"python_pkg.geo_data._poland_nature.gpd.GeoDataFrame.from_features"
) as mock_from_features,
patch(
"python_pkg.geo_data._poland_nature._add_area_column"
) as mock_add_area,
):
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = False
mock_query.return_value = {
"elements": [
{
"type": "way",
"tags": {"name": "Rezerwat A"},
"geometry": [
{"lon": 0, "lat": 0},
{"lon": 1, "lat": 0},
{"lon": 1, "lat": 1},
{"lon": 0, "lat": 1},
],
},
# Duplicate
{
"type": "way",
"tags": {"name": "Rezerwat A"},
"geometry": [
{"lon": 0, "lat": 0},
{"lon": 1, "lat": 0},
{"lon": 1, "lat": 1},
{"lon": 0, "lat": 1},
],
},
# No name
{"type": "way", "tags": {}, "geometry": []},
# Geometry fails
{
"type": "way",
"tags": {"name": "Tiny"},
"geometry": [{"lon": 0, "lat": 0}],
},
]
}
mock_gdf = gpd.GeoDataFrame(
{"name": ["Rezerwat A"]},
geometry=[_POLY],
crs="EPSG:4326",
)
mock_from_features.return_value = mock_gdf
gdf_with_area = mock_gdf.copy()
gdf_with_area["area_km2"] = [50.0]
mock_add_area.return_value = gdf_with_area
result = get_polish_nature_reserves()
assert len(result) == 1
def test_downloads_reserves_empty(self) -> None:
with (
patch("python_pkg.geo_data._poland_nature.sys.stdout"),
patch("python_pkg.geo_data._poland_nature.CACHE_DIR") as mock_cache_dir,
patch("python_pkg.geo_data._poland_nature._overpass_query") as mock_query,
patch("python_pkg.geo_data._poland_nature._ensure_cache_dir"),
patch(
"python_pkg.geo_data._poland_nature.gpd.GeoDataFrame.from_features"
) as mock_from_features,
patch(
"python_pkg.geo_data._poland_nature._add_area_column"
) as mock_add_area,
):
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = False
mock_query.return_value = {"elements": []}
empty_gdf = gpd.GeoDataFrame({"name": [], "geometry": []})
mock_from_features.return_value = empty_gdf
mock_add_area.return_value = empty_gdf
result = get_polish_nature_reserves()
assert len(result) == 0
class TestGetPolishLandscapeParks:
"""Tests for get_polish_landscape_parks."""
@patch("python_pkg.geo_data._poland_nature.gpd.read_file")
@patch("python_pkg.geo_data._poland_nature.CACHE_DIR")
def test_cached_with_area(
self,
mock_cache_dir: MagicMock,
mock_read: MagicMock,
) -> None:
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = True
mock_gdf = gpd.GeoDataFrame(
{"name": ["Park Krajobrazowy X"], "area_km2": [100.0]},
geometry=[_POLY],
crs="EPSG:4326",
)
mock_read.return_value = mock_gdf
result = get_polish_landscape_parks()
assert result.iloc[0]["area_km2"] == 100.0
@patch("python_pkg.geo_data._poland_nature.gpd.read_file")
@patch("python_pkg.geo_data._poland_nature.CACHE_DIR")
def test_cached_without_area(
self,
mock_cache_dir: MagicMock,
mock_read: MagicMock,
) -> None:
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = True
mock_gdf = gpd.GeoDataFrame(
{"name": ["Park Krajobrazowy X"]},
geometry=[_POLY],
crs="EPSG:4326",
)
mock_read.return_value = mock_gdf
result = get_polish_landscape_parks()
assert len(result) == 1
@patch("python_pkg.geo_data._poland_nature.gpd.GeoDataFrame.from_features")
@patch("python_pkg.geo_data._poland_nature._ensure_cache_dir")
@patch("python_pkg.geo_data._poland_nature._overpass_query")
@patch("python_pkg.geo_data._poland_nature.CACHE_DIR")
@patch("python_pkg.geo_data._poland_nature.sys.stdout")
def test_downloads_landscape_parks(
self,
mock_stdout: MagicMock,
mock_cache_dir: MagicMock,
mock_query: MagicMock,
mock_ensure: MagicMock,
mock_from_features: MagicMock,
) -> None:
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = False
mock_query.return_value = {
"elements": [
_make_relation_element("Park Krajobrazowy A"),
# Not a relation -> skip
{
"type": "way",
"tags": {"name": "Park Krajobrazowy B"},
"geometry": [],
},
# No name
{"type": "relation", "tags": {}, "members": []},
# Duplicate
_make_relation_element("Park Krajobrazowy A"),
# No outer rings
_make_relation_element("Park Empty", include_outer=False),
]
}
mock_gdf = gpd.GeoDataFrame(
{"name": ["Park Krajobrazowy A"]},
geometry=[_POLY],
crs="EPSG:4326",
)
mock_from_features.return_value = mock_gdf
result = get_polish_landscape_parks()
assert len(result) == 1
@patch("python_pkg.geo_data._poland_nature.gpd.GeoDataFrame.from_features")
@patch("python_pkg.geo_data._poland_nature._ensure_cache_dir")
@patch("python_pkg.geo_data._poland_nature._overpass_query")
@patch("python_pkg.geo_data._poland_nature.CACHE_DIR")
@patch("python_pkg.geo_data._poland_nature.sys.stdout")
def test_downloads_landscape_parks_empty(
self,
mock_stdout: MagicMock,
mock_cache_dir: MagicMock,
mock_query: MagicMock,
mock_ensure: MagicMock,
mock_from_features: MagicMock,
) -> None:
mock_path = MagicMock()
mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path)
mock_path.exists.return_value = False
mock_query.return_value = {"elements": []}
empty_gdf = gpd.GeoDataFrame({"name": [], "geometry": []})
mock_from_features.return_value = empty_gdf
result = get_polish_landscape_parks()
assert len(result) == 0