"""
GeoSight MCP Server Tests
"""
import pytest
import numpy as np
from unittest.mock import AsyncMock, patch
# Configure pytest for async
pytestmark = pytest.mark.asyncio
class TestGeocoding:
"""Tests for geocoding utilities."""
async def test_resolve_location_with_coords(self):
"""Test location resolution with coordinates."""
from geosight.tools.geocoding import resolve_location
lat, lon, name = await resolve_location(latitude=40.7128, longitude=-74.0060)
assert lat == 40.7128
assert lon == -74.0060
assert "40.7128" in name
async def test_geocode_location_name(self):
"""Test geocoding a location name."""
from geosight.tools.geocoding import get_location_info
with patch("httpx.AsyncClient.get") as mock_get:
mock_get.return_value = AsyncMock()
mock_get.return_value.json.return_value = [{
"lat": "40.7128",
"lon": "-74.0060",
"display_name": "New York, USA",
"boundingbox": ["40.4774", "40.9176", "-74.2591", "-73.7004"],
"address": {"city": "New York", "country": "USA"},
}]
mock_get.return_value.raise_for_status = lambda: None
# Test would run with mocked HTTP
class TestGeoUtils:
"""Tests for geospatial utilities."""
def test_create_bbox_from_point(self):
"""Test bounding box creation."""
from geosight.utils.geo import create_bbox_from_point
bbox = create_bbox_from_point(40.0, -74.0, 10.0)
assert bbox.south < 40.0 < bbox.north
assert bbox.west < -74.0 < bbox.east
assert bbox.center == pytest.approx((40.0, -74.0), rel=0.01)
def test_haversine_distance(self):
"""Test haversine distance calculation."""
from geosight.utils.geo import haversine_distance
# NYC to LA approximately 3944 km
distance = haversine_distance(40.7128, -74.0060, 34.0522, -118.2437)
assert 3900 < distance < 4000
def test_bbox_to_polygon(self):
"""Test bounding box to polygon conversion."""
from geosight.utils.geo import BoundingBox
bbox = BoundingBox(west=-74.0, south=40.0, east=-73.0, north=41.0)
coords = bbox.to_polygon_coords()
assert len(coords) == 5 # Closed polygon
assert coords[0] == coords[-1] # First == Last
class TestVisualization:
"""Tests for visualization utilities."""
def test_create_index_colormap_ndvi(self):
"""Test NDVI colormap creation."""
from geosight.utils.visualization import create_index_colormap
data = np.array([[0.0, 0.5], [0.3, 0.8]])
rgb = create_index_colormap(data, "ndvi")
assert rgb.shape == (2, 2, 3)
assert rgb.dtype == np.uint8
def test_array_to_base64_png(self):
"""Test base64 PNG encoding."""
from geosight.utils.visualization import array_to_base64_png
image = np.random.randint(0, 255, (100, 100, 3), dtype=np.uint8)
base64_str = array_to_base64_png(image)
assert isinstance(base64_str, str)
assert len(base64_str) > 0
def test_create_classification_map(self):
"""Test classification map creation."""
from geosight.utils.visualization import create_classification_map
classification = np.array([[0, 1], [2, 0]])
colors = {0: "#FF0000", 1: "#00FF00", 2: "#0000FF"}
rgb = create_classification_map(classification, colors)
assert rgb.shape == (2, 2, 3)
assert rgb[0, 0, 0] == 255 # Red
class TestIndices:
"""Tests for spectral index calculations."""
async def test_ndvi_calculation(self):
"""Test NDVI calculation tool."""
from geosight.tools.indices import calculate_ndvi
result = await calculate_ndvi(
start_date="2024-01-01",
end_date="2024-01-31",
latitude=40.0,
longitude=-74.0,
radius_km=5.0,
)
assert "summary" in result
assert "statistics" in result
assert "image_base64" in result
async def test_ndwi_calculation(self):
"""Test NDWI calculation tool."""
from geosight.tools.indices import calculate_ndwi
result = await calculate_ndwi(
start_date="2024-01-01",
end_date="2024-01-31",
latitude=40.0,
longitude=-74.0,
)
assert "summary" in result
assert "water_coverage_pct" in result.get("statistics", {})
class TestModels:
"""Tests for ML models."""
async def test_land_cover_classifier(self):
"""Test land cover classification."""
from geosight.models.land_cover import LandCoverClassifier
classifier = LandCoverClassifier()
image = np.random.rand(256, 256, 3)
classification, confidence = await classifier.classify(image)
assert classification.shape == (256, 256)
assert confidence.shape == (256, 256)
assert confidence.min() >= 0 and confidence.max() <= 1
async def test_change_detector(self):
"""Test change detection."""
from geosight.models.change_detector import ChangeDetector
detector = ChangeDetector()
before = np.random.rand(100, 100)
after = np.random.rand(100, 100)
mask, magnitude = await detector.detect(before, after)
assert mask.shape == (100, 100)
assert magnitude.shape == (100, 100)
async def test_object_detector(self):
"""Test object detection."""
from geosight.models.object_detector import ObjectDetector
detector = ObjectDetector()
image = np.random.randint(0, 255, (512, 512, 3), dtype=np.uint8)
detections = await detector.detect(image)
assert isinstance(detections, list)
if detections:
assert hasattr(detections[0], "class_name")
assert hasattr(detections[0], "confidence")
class TestCache:
"""Tests for caching utilities."""
async def test_in_memory_cache(self):
"""Test in-memory cache operations."""
from geosight.utils.cache import InMemoryCache
cache = InMemoryCache(max_size=10)
await cache.set("key1", {"data": "value1"})
result = await cache.get("key1")
assert result == {"data": "value1"}
async def test_cache_ttl(self):
"""Test cache TTL expiration."""
import asyncio
from geosight.utils.cache import InMemoryCache
cache = InMemoryCache(default_ttl=1)
await cache.set("key1", "value1", ttl=1)
# Should exist immediately
assert await cache.get("key1") == "value1"
# Wait for expiration
await asyncio.sleep(1.5)
# Should be expired
assert await cache.get("key1") is None
class TestTools:
"""Integration tests for MCP tools."""
async def test_search_imagery(self):
"""Test imagery search tool."""
from geosight.tools.imagery import search_imagery
result = await search_imagery(
start_date="2024-01-01",
end_date="2024-01-31",
latitude=40.0,
longitude=-74.0,
)
assert "summary" in result
assert "items" in result
async def test_detect_land_cover(self):
"""Test land cover detection tool."""
from geosight.tools.classification import detect_land_cover
result = await detect_land_cover(
date="2024-01-15",
latitude=40.0,
longitude=-74.0,
radius_km=5.0,
)
assert "summary" in result
assert "statistics" in result
async def test_generate_report(self):
"""Test report generation tool."""
from geosight.tools.reports import generate_report
result = await generate_report(
start_date="2024-01-01",
end_date="2024-01-31",
latitude=40.0,
longitude=-74.0,
analyses=["ndvi"],
)
assert "summary" in result
assert "report_content" in result
# Fixtures
@pytest.fixture
def sample_imagery():
"""Generate sample satellite imagery."""
return np.random.rand(256, 256, 4).astype(np.float32)
@pytest.fixture
def sample_bbox():
"""Generate sample bounding box."""
from geosight.utils.geo import BoundingBox
return BoundingBox(west=-74.0, south=40.0, east=-73.5, north=40.5)