fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
271
geo-service/tests/test_aoi.py
Normal file
271
geo-service/tests/test_aoi.py
Normal file
@@ -0,0 +1,271 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user