Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
272 lines
8.8 KiB
Python
272 lines
8.8 KiB
Python
"""
|
|
Tests for AOI Packager Service
|
|
"""
|
|
import pytest
|
|
from unittest.mock import patch, MagicMock, AsyncMock
|
|
import json
|
|
|
|
import sys
|
|
sys.path.insert(0, '/app')
|
|
|
|
from services.aoi_packager import AOIPackagerService
|
|
|
|
|
|
class TestAOIPackagerService:
|
|
"""Tests for AOI Packager Service."""
|
|
|
|
@pytest.fixture
|
|
def service(self):
|
|
"""Create service instance."""
|
|
return AOIPackagerService()
|
|
|
|
def test_calculate_area_km2_small_polygon(self, service):
|
|
"""Test area calculation for small polygon."""
|
|
polygon = {
|
|
"type": "Polygon",
|
|
"coordinates": [
|
|
[
|
|
[9.19, 47.70],
|
|
[9.20, 47.70],
|
|
[9.20, 47.71],
|
|
[9.19, 47.71],
|
|
[9.19, 47.70],
|
|
]
|
|
],
|
|
}
|
|
area = service.calculate_area_km2(polygon)
|
|
# Should be approximately 1 km² (rough estimate)
|
|
assert 0.5 < area < 2.0
|
|
|
|
def test_calculate_area_km2_mainau(self, service):
|
|
"""Test area calculation for Mainau island polygon."""
|
|
polygon = {
|
|
"type": "Polygon",
|
|
"coordinates": [
|
|
[
|
|
[9.1875, 47.7055],
|
|
[9.1975, 47.7055],
|
|
[9.1975, 47.7115],
|
|
[9.1875, 47.7115],
|
|
[9.1875, 47.7055],
|
|
]
|
|
],
|
|
}
|
|
area = service.calculate_area_km2(polygon)
|
|
# Mainau template claims ~0.45 km²
|
|
assert 0.3 < area < 1.0
|
|
|
|
def test_is_within_germany_valid(self, service):
|
|
"""Test polygon within Germany."""
|
|
polygon = {
|
|
"type": "Polygon",
|
|
"coordinates": [
|
|
[
|
|
[9.19, 47.70],
|
|
[9.20, 47.70],
|
|
[9.20, 47.71],
|
|
[9.19, 47.71],
|
|
[9.19, 47.70],
|
|
]
|
|
],
|
|
}
|
|
assert service.is_within_germany(polygon) == True
|
|
|
|
def test_is_within_germany_outside(self, service):
|
|
"""Test polygon outside Germany."""
|
|
# Paris
|
|
polygon = {
|
|
"type": "Polygon",
|
|
"coordinates": [
|
|
[
|
|
[2.3, 48.8],
|
|
[2.4, 48.8],
|
|
[2.4, 48.9],
|
|
[2.3, 48.9],
|
|
[2.3, 48.8],
|
|
]
|
|
],
|
|
}
|
|
assert service.is_within_germany(polygon) == False
|
|
|
|
def test_validate_polygon_valid(self, service):
|
|
"""Test valid polygon validation."""
|
|
polygon = {
|
|
"type": "Polygon",
|
|
"coordinates": [
|
|
[
|
|
[9.19, 47.70],
|
|
[9.20, 47.70],
|
|
[9.20, 47.71],
|
|
[9.19, 47.71],
|
|
[9.19, 47.70],
|
|
]
|
|
],
|
|
}
|
|
is_valid, message = service.validate_polygon(polygon)
|
|
assert is_valid == True
|
|
assert message == "Valid"
|
|
|
|
def test_validate_polygon_not_closed(self, service):
|
|
"""Test polygon validation with unclosed ring."""
|
|
polygon = {
|
|
"type": "Polygon",
|
|
"coordinates": [
|
|
[
|
|
[9.19, 47.70],
|
|
[9.20, 47.70],
|
|
[9.20, 47.71],
|
|
[9.19, 47.71],
|
|
# Missing closing point
|
|
]
|
|
],
|
|
}
|
|
is_valid, message = service.validate_polygon(polygon)
|
|
assert is_valid == False
|
|
assert "closed" in message.lower()
|
|
|
|
def test_validate_polygon_wrong_type(self, service):
|
|
"""Test polygon validation with wrong geometry type."""
|
|
polygon = {
|
|
"type": "Point",
|
|
"coordinates": [9.19, 47.70],
|
|
}
|
|
is_valid, message = service.validate_polygon(polygon)
|
|
assert is_valid == False
|
|
assert "Polygon" in message
|
|
|
|
def test_estimate_bundle_size_low(self, service):
|
|
"""Test bundle size estimation for low quality."""
|
|
size = service.estimate_bundle_size_mb(1.0, "low")
|
|
assert size == 10.0
|
|
|
|
def test_estimate_bundle_size_medium(self, service):
|
|
"""Test bundle size estimation for medium quality."""
|
|
size = service.estimate_bundle_size_mb(1.0, "medium")
|
|
assert size == 25.0
|
|
|
|
def test_estimate_bundle_size_high(self, service):
|
|
"""Test bundle size estimation for high quality."""
|
|
size = service.estimate_bundle_size_mb(1.0, "high")
|
|
assert size == 50.0
|
|
|
|
def test_estimate_bundle_size_scales_with_area(self, service):
|
|
"""Test bundle size scales with area."""
|
|
size_1km = service.estimate_bundle_size_mb(1.0, "medium")
|
|
size_2km = service.estimate_bundle_size_mb(2.0, "medium")
|
|
assert size_2km == size_1km * 2
|
|
|
|
|
|
class TestGeoUtils:
|
|
"""Tests for geo utility functions."""
|
|
|
|
def test_lat_lon_to_tile_berlin(self):
|
|
"""Test tile conversion for Berlin."""
|
|
from utils.geo_utils import lat_lon_to_tile
|
|
|
|
# Berlin: 52.52, 13.405
|
|
x, y = lat_lon_to_tile(52.52, 13.405, 10)
|
|
# At zoom 10, Berlin should be around tile 550, 335
|
|
assert 540 < x < 560
|
|
assert 325 < y < 345
|
|
|
|
def test_tile_to_bounds(self):
|
|
"""Test tile to bounds conversion."""
|
|
from utils.geo_utils import tile_to_bounds
|
|
|
|
west, south, east, north = tile_to_bounds(10, 550, 335)
|
|
# Should return valid bounds
|
|
assert west < east
|
|
assert south < north
|
|
# Should be somewhere in Germany
|
|
assert 5 < west < 20
|
|
assert 45 < south < 60
|
|
|
|
def test_calculate_distance(self):
|
|
"""Test distance calculation."""
|
|
from utils.geo_utils import calculate_distance
|
|
|
|
# Berlin to Munich: ~504 km
|
|
dist = calculate_distance(52.52, 13.405, 48.1351, 11.582)
|
|
assert 450000 < dist < 550000 # meters
|
|
|
|
def test_get_germany_bounds(self):
|
|
"""Test Germany bounds."""
|
|
from utils.geo_utils import get_germany_bounds
|
|
|
|
west, south, east, north = get_germany_bounds()
|
|
assert west == 5.87
|
|
assert south == 47.27
|
|
assert east == 15.04
|
|
assert north == 55.06
|
|
|
|
|
|
class TestLicenseChecker:
|
|
"""Tests for license checker utility."""
|
|
|
|
def test_osm_source_allowed(self):
|
|
"""Test OSM source is allowed."""
|
|
from utils.license_checker import LicenseChecker, DataSource
|
|
|
|
assert LicenseChecker.is_source_allowed(DataSource.OPENSTREETMAP) == True
|
|
|
|
def test_copernicus_source_allowed(self):
|
|
"""Test Copernicus source is allowed."""
|
|
from utils.license_checker import LicenseChecker, DataSource
|
|
|
|
assert LicenseChecker.is_source_allowed(DataSource.COPERNICUS_DEM) == True
|
|
|
|
def test_google_source_forbidden(self):
|
|
"""Test Google source is forbidden."""
|
|
from utils.license_checker import LicenseChecker, DataSource
|
|
|
|
assert LicenseChecker.is_source_allowed(DataSource.GOOGLE) == False
|
|
|
|
def test_validate_osm_url(self):
|
|
"""Test OSM URL validation."""
|
|
from utils.license_checker import LicenseChecker
|
|
|
|
is_allowed, message = LicenseChecker.validate_url(
|
|
"https://tile.openstreetmap.org/10/550/335.png"
|
|
)
|
|
assert is_allowed == True
|
|
assert "ALLOWED" in message
|
|
|
|
def test_validate_google_url(self):
|
|
"""Test Google URL validation."""
|
|
from utils.license_checker import LicenseChecker
|
|
|
|
is_allowed, message = LicenseChecker.validate_url(
|
|
"https://maps.googleapis.com/maps/api/staticmap"
|
|
)
|
|
assert is_allowed == False
|
|
assert "FORBIDDEN" in message
|
|
|
|
def test_get_attribution_for_sources(self):
|
|
"""Test getting attribution for sources."""
|
|
from utils.license_checker import LicenseChecker, DataSource
|
|
|
|
sources = [DataSource.OPENSTREETMAP, DataSource.COPERNICUS_DEM]
|
|
attributions = LicenseChecker.get_attribution_for_sources(sources)
|
|
|
|
assert len(attributions) == 2
|
|
assert any("OpenStreetMap" in a["name"] for a in attributions)
|
|
assert any("Copernicus" in a["name"] for a in attributions)
|
|
|
|
def test_check_commercial_use_allowed(self):
|
|
"""Test commercial use check for allowed sources."""
|
|
from utils.license_checker import LicenseChecker, DataSource
|
|
|
|
sources = [DataSource.OPENSTREETMAP, DataSource.COPERNICUS_DEM]
|
|
allowed, issues = LicenseChecker.check_commercial_use(sources)
|
|
assert allowed == True
|
|
assert len(issues) == 0
|
|
|
|
def test_check_commercial_use_forbidden(self):
|
|
"""Test commercial use check with forbidden source."""
|
|
from utils.license_checker import LicenseChecker, DataSource
|
|
|
|
sources = [DataSource.OPENSTREETMAP, DataSource.GOOGLE]
|
|
allowed, issues = LicenseChecker.check_commercial_use(sources)
|
|
assert allowed == False
|
|
assert len(issues) > 0
|