"""Tests for domain schemas and configuration.""" from datetime import datetime, timezone import pytest from pydantic import ValidationError from gps_denied.config import AppSettings, get_settings from gps_denied.schemas import CameraParameters, Geofences, GPSPoint, Polygon from gps_denied.schemas.events import ( FlightCompletedEvent, FrameProcessedEvent, SSEEventType, SSEMessage, ) from gps_denied.schemas.flight import ( BatchMetadata, BatchResponse, FlightCreateRequest, FlightDetailResponse, FlightResponse, FlightStatusResponse, UserFixRequest, Waypoint, ) # ── GPSPoint ────────────────────────────────────────────────────────────── class TestGPSPoint: def test_valid(self): p = GPSPoint(lat=48.275, lon=37.385) assert p.lat == 48.275 def test_lat_out_of_range(self): with pytest.raises(ValidationError): GPSPoint(lat=91, lon=0) def test_lon_out_of_range(self): with pytest.raises(ValidationError): GPSPoint(lat=0, lon=181) def test_serialization_roundtrip(self): p = GPSPoint(lat=-12.5, lon=130.0) assert GPSPoint.model_validate_json(p.model_dump_json()) == p # ── CameraParameters ───────────────────────────────────────────────────── class TestCameraParameters: def test_valid(self): cam = CameraParameters( focal_length=25, sensor_width=23.5, sensor_height=15.6, resolution_width=6252, resolution_height=4168, ) assert cam.resolution_width == 6252 def test_negative_focal_length(self): with pytest.raises(ValidationError): CameraParameters( focal_length=-1, sensor_width=23.5, sensor_height=15.6, resolution_width=6252, resolution_height=4168, ) # ── FlightCreateRequest ────────────────────────────────────────────────── class TestFlightCreateRequest: def test_minimal_valid(self): req = FlightCreateRequest( name="Test_Flight", start_gps=GPSPoint(lat=48.275, lon=37.385), camera_params=CameraParameters( focal_length=25, sensor_width=23.5, sensor_height=15.6, resolution_width=6252, resolution_height=4168, ), altitude=400, ) assert req.name == "Test_Flight" assert req.description == "" assert req.geofences.polygons == [] def test_empty_name_rejected(self): with pytest.raises(ValidationError): FlightCreateRequest( name="", start_gps=GPSPoint(lat=0, lon=0), camera_params=CameraParameters( focal_length=25, sensor_width=23.5, sensor_height=15.6, resolution_width=6252, resolution_height=4168, ), altitude=400, ) # ── Waypoint ────────────────────────────────────────────────────────────── class TestWaypoint: def test_valid(self): wp = Waypoint( id="wp_001", lat=48.123, lon=37.456, confidence=0.95, timestamp=datetime.now(tz=timezone.utc), ) assert wp.refined is False def test_confidence_out_of_range(self): with pytest.raises(ValidationError): Waypoint( id="wp_001", lat=48.123, lon=37.456, confidence=1.5, timestamp=datetime.now(tz=timezone.utc), ) # ── SSE Events ──────────────────────────────────────────────────────────── class TestSSEEvents: def test_event_types(self): assert SSEEventType.FRAME_PROCESSED == "frame_processed" assert SSEEventType.FLIGHT_COMPLETED == "flight_completed" def test_frame_event_serialization(self): evt = FrameProcessedEvent( frame_id=237, gps=GPSPoint(lat=48.123, lon=37.456), confidence=0.95, timestamp=datetime.now(tz=timezone.utc), ) data = evt.model_dump() assert data["frame_id"] == 237 def test_sse_message(self): msg = SSEMessage( event=SSEEventType.FLIGHT_COMPLETED, data={"frames_total": 100, "frames_processed": 100}, ) assert msg.event == "flight_completed" # ── Configuration ───────────────────────────────────────────────────────── class TestConfig: def test_defaults(self): settings = get_settings() assert "sqlite" in settings.db.url assert settings.api.port == 8000 assert settings.tiles.provider == "google" def test_rotation_iterations(self): settings = get_settings() assert settings.rotation.rotation_iterations == 12 # 360 / 30 def test_recovery_defaults(self): settings = get_settings() assert settings.recovery.search_grid_sizes == [1, 4, 9, 16, 25]