"""Tests for python_pkg.geo_data._poland_admin module.""" from __future__ import annotations import json from unittest.mock import MagicMock, patch import geopandas as gpd from shapely.geometry import Polygon from python_pkg.geo_data._poland_admin import ( _get_powiaty_population, _query_wikidata, get_poland_boundary, get_polish_gminy, get_polish_powiaty, get_polish_wojewodztwa, ) class TestQueryWikidata: """Tests for _query_wikidata.""" @patch("python_pkg.geo_data._poland_admin.requests.get") def test_successful_query(self, mock_get: MagicMock) -> None: mock_response = MagicMock() mock_response.json.return_value = { "results": {"bindings": [{"name": {"value": "test"}}]} } mock_get.return_value = mock_response result = _query_wikidata("SELECT ?x WHERE {}") assert result == [{"name": {"value": "test"}}] mock_response.raise_for_status.assert_called_once() class TestGetPowiatyPopulation: """Tests for _get_powiaty_population.""" @patch("python_pkg.geo_data._poland_admin.CACHE_DIR") def test_cached(self, mock_cache_dir: MagicMock) -> None: mock_path = MagicMock() mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path) mock_path.exists.return_value = True mock_path.read_text.return_value = json.dumps({"Kraków": 780000}) result = _get_powiaty_population() assert result == {"Kraków": 780000} @patch("python_pkg.geo_data._poland_admin._ensure_cache_dir") @patch("python_pkg.geo_data._poland_admin._query_wikidata") @patch("python_pkg.geo_data._poland_admin.CACHE_DIR") @patch("python_pkg.geo_data._poland_admin.sys.stdout") def test_downloads_and_caches( self, mock_stdout: MagicMock, mock_cache_dir: MagicMock, mock_query: MagicMock, mock_ensure: MagicMock, ) -> None: mock_path = MagicMock() mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path) mock_path.exists.return_value = False mock_query.return_value = [ { "powiatLabel": {"value": "powiat krakowski"}, "population": {"value": "100000"}, }, { "powiatLabel": {"value": "powiat wadowicki"}, "population": {"value": "bad_value"}, }, { "powiatLabel": {"value": ""}, "population": {"value": "50000"}, }, { "population": {"value": "30000"}, }, ] result = _get_powiaty_population() assert "krakowski" in result mock_path.write_text.assert_called_once() @patch("python_pkg.geo_data._poland_admin._ensure_cache_dir") @patch("python_pkg.geo_data._poland_admin._query_wikidata") @patch("python_pkg.geo_data._poland_admin.CACHE_DIR") @patch("python_pkg.geo_data._poland_admin.sys.stdout") def test_empty_label_skipped( self, mock_stdout: MagicMock, mock_cache_dir: MagicMock, mock_query: MagicMock, mock_ensure: MagicMock, ) -> None: mock_path = MagicMock() mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path) mock_path.exists.return_value = False mock_query.return_value = [ {"powiatLabel": {"value": ""}, "population": {"value": "1000"}}, ] result = _get_powiaty_population() assert len(result) == 0 class TestGetPolishWojewodztwa: """Tests for get_polish_wojewodztwa.""" @patch("python_pkg.geo_data._poland_admin._download_github_geojson") def test_returns_geodataframe(self, mock_download: MagicMock) -> None: mock_gdf = MagicMock(spec=gpd.GeoDataFrame) mock_download.return_value = mock_gdf result = get_polish_wojewodztwa() assert result is mock_gdf class TestGetPolishPowiaty: """Tests for get_polish_powiaty.""" @patch("python_pkg.geo_data._poland_admin._get_powiaty_population") @patch("python_pkg.geo_data._poland_admin._download_github_geojson") def test_with_population( self, mock_download: MagicMock, mock_pop: MagicMock ) -> None: gdf = gpd.GeoDataFrame( {"nazwa": ["powiat krakowski", "powiat Wadowice", "powiat xyz", ""]}, geometry=[ Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), ], crs="EPSG:4326", ) mock_download.return_value = gdf mock_pop.return_value = {"krakowski": 100000, "wadowice": 50000} result = get_polish_powiaty() assert "population" in result.columns # krakowski matched directly assert result.iloc[0]["population"] == 100000 # Wadowice matched case-insensitively assert result.iloc[1]["population"] == 50000 class TestGetPolishGminy: """Tests for get_polish_gminy.""" @patch("python_pkg.geo_data._poland_admin.gpd.read_file") @patch("python_pkg.geo_data._poland_admin.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": ["A", "B"], "area_km2": [200.0, 100.0], }, geometry=[ Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), Polygon([(2, 2), (3, 2), (3, 3), (2, 3)]), ], crs="EPSG:4326", ) mock_read.return_value = mock_gdf result = get_polish_gminy() assert result.iloc[0]["area_km2"] == 200.0 @patch("python_pkg.geo_data._poland_admin.gpd.read_file") @patch("python_pkg.geo_data._poland_admin.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": ["A"]}, geometry=[Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])], crs="EPSG:4326", ) mock_read.return_value = mock_gdf result = get_polish_gminy() assert len(result) == 1 def test_downloads_from_osm(self) -> None: with ( patch("python_pkg.geo_data._poland_admin.sys.stdout"), patch("python_pkg.geo_data._poland_admin.CACHE_DIR") as mock_cache_dir, patch("python_pkg.geo_data._poland_admin._overpass_query") as mock_query, patch("python_pkg.geo_data._poland_admin._ensure_cache_dir"), patch( "python_pkg.geo_data._poland_admin.gpd.GeoDataFrame.from_features" ) as mock_from_features, patch("python_pkg.geo_data._common._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": "relation", "tags": {"name": "Gmina A"}, "members": [ { "role": "outer", "geometry": [ {"lon": 0, "lat": 0}, {"lon": 1, "lat": 0}, {"lon": 1, "lat": 1}, {"lon": 0, "lat": 1}, ], } ], }, # Duplicate name - should be skipped { "type": "relation", "tags": {"name": "Gmina A"}, "members": [ { "role": "outer", "geometry": [ {"lon": 2, "lat": 2}, {"lon": 3, "lat": 2}, {"lon": 3, "lat": 3}, {"lon": 2, "lat": 3}, ], } ], }, # Not a relation - should be skipped {"type": "way", "tags": {"name": "Way"}}, # No name {"type": "relation", "tags": {}}, # No outer rings { "type": "relation", "tags": {"name": "Empty"}, "members": [], }, ] } mock_gdf = gpd.GeoDataFrame( {"name": ["Gmina A"], "area_km2": [100.0]}, geometry=[Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])], crs="EPSG:4326", ) mock_from_features.return_value = mock_gdf mock_add_area.return_value = mock_gdf result = get_polish_gminy() assert len(result) == 1 class TestGetPolandBoundary: """Tests for get_poland_boundary.""" @patch("python_pkg.geo_data._poland_admin.gpd.read_file") @patch("python_pkg.geo_data._poland_admin.CACHE_DIR") def test_cached(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 = MagicMock(spec=gpd.GeoDataFrame) mock_read.return_value = mock_gdf result = get_poland_boundary() assert result is mock_gdf @patch("python_pkg.geo_data._poland_admin.gpd.GeoDataFrame.to_file") @patch("python_pkg.geo_data._poland_admin._ensure_cache_dir") @patch("python_pkg.geo_data._poland_admin.get_polish_wojewodztwa") @patch("python_pkg.geo_data._poland_admin.CACHE_DIR") def test_dissolves_from_wojewodztwa( self, mock_cache_dir: MagicMock, mock_woj: MagicMock, mock_ensure: MagicMock, mock_to_file: MagicMock, ) -> None: mock_path = MagicMock() mock_cache_dir.__truediv__ = MagicMock(return_value=mock_path) mock_path.exists.return_value = False woj_gdf = gpd.GeoDataFrame( {"name": ["woj1", "woj2"]}, geometry=[ Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), Polygon([(1, 0), (2, 0), (2, 1), (1, 1)]), ], crs="EPSG:4326", ) mock_woj.return_value = woj_gdf result = get_poland_boundary() assert len(result) == 1