Tests: 79 total (32 new), covering LRU cache eviction, BBox validation, _parse_rgb error handling, colormap ID extraction, client retry logic, WMS response validation, dimension clamping, geocode caching, classification colormaps, and scientific notation interval parsing. Shutdown: register atexit handler to close httpx connection pool when the MCP server exits, since FastMCP Middleware has no on_shutdown hook.
72 lines
2.2 KiB
Python
72 lines
2.2 KiB
Python
"""Tests for mcgibs.models — Pydantic model validation."""
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from mcgibs.models import BBox, ColorMap, ColorMapEntry, ColorMapSet
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# BBox validation (M3 Hamilton fix)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_bbox_valid():
|
|
bbox = BBox(west=-120.0, south=30.0, east=-110.0, north=40.0)
|
|
assert bbox.west == -120.0
|
|
assert bbox.north == 40.0
|
|
|
|
|
|
def test_bbox_south_greater_than_north():
|
|
with pytest.raises(ValidationError, match=r"south.*must be <= north"):
|
|
BBox(west=0.0, south=50.0, east=10.0, north=40.0)
|
|
|
|
|
|
def test_bbox_latitude_out_of_range():
|
|
with pytest.raises(ValidationError, match="Latitudes must be in"):
|
|
BBox(west=0.0, south=-91.0, east=10.0, north=0.0)
|
|
|
|
|
|
def test_bbox_longitude_out_of_range():
|
|
with pytest.raises(ValidationError, match="Longitudes must be in"):
|
|
BBox(west=-181.0, south=0.0, east=0.0, north=10.0)
|
|
|
|
|
|
def test_bbox_wms_bbox_property():
|
|
bbox = BBox(west=-120.0, south=30.0, east=-110.0, north=40.0)
|
|
assert bbox.wms_bbox == "-120.0,30.0,-110.0,40.0"
|
|
|
|
|
|
def test_bbox_area_sq_deg():
|
|
bbox = BBox(west=0.0, south=0.0, east=10.0, north=10.0)
|
|
assert bbox.area_sq_deg == 100.0
|
|
|
|
|
|
def test_bbox_edge_values():
|
|
"""Extreme valid values: full globe."""
|
|
bbox = BBox(west=-180.0, south=-90.0, east=180.0, north=90.0)
|
|
assert bbox.area_sq_deg == 360.0 * 180.0
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ColorMapSet.data_map property
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_data_map_returns_first_non_nodata():
|
|
"""data_map should return the first ColorMap that has non-nodata entries."""
|
|
nodata_only = ColorMap(
|
|
entries=[ColorMapEntry(rgb=(0, 0, 0), nodata=True)],
|
|
)
|
|
data_map = ColorMap(
|
|
title="Real Data",
|
|
entries=[ColorMapEntry(rgb=(255, 0, 0), value="[0,1)")],
|
|
)
|
|
cms = ColorMapSet(maps=[nodata_only, data_map])
|
|
assert cms.data_map is data_map
|
|
|
|
|
|
def test_data_map_empty_set():
|
|
"""data_map should return None for empty ColorMapSet."""
|
|
cms = ColorMapSet(maps=[])
|
|
assert cms.data_map is None
|