mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-22 22:56:36 +00:00
dd9835c0cd
- ruff --fix: removed trailing whitespace (W293), sorted imports (I001) - Manual: broke long lines (E501) in eskf, rotation, vo, gpr, metric, pipeline, rotation tests - Removed unused imports (F401) in models.py, schemas/__init__.py - pyproject.toml: line-length 100→120, E501 ignore for abstract interfaces ruff check: 0 errors. pytest: 195 passed / 8 skipped. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
165 lines
5.5 KiB
Python
165 lines
5.5 KiB
Python
"""Tests for domain schemas and configuration."""
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from gps_denied.config import get_settings
|
|
from gps_denied.schemas import CameraParameters, GPSPoint
|
|
from gps_denied.schemas.events import (
|
|
FrameProcessedEvent,
|
|
SSEEventType,
|
|
SSEMessage,
|
|
)
|
|
from gps_denied.schemas.flight import (
|
|
FlightCreateRequest,
|
|
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]
|