"""Tests for exposure profile Pydantic models and endpoint logic.""" import uuid from datetime import datetime, timezone import pytest from pydantic import ValidationError from services.symbol_registry.exposure import ( VALID_MARKET_POSITION_TIERS, VALID_SOURCES, ExposureProfileCreate, ExposureProfileResponse, _row_to_profile, ) # --- ExposureProfileCreate validation --- def test_create_defaults(): p = ExposureProfileCreate() assert p.geographic_revenue_mix == {} assert p.supply_chain_regions == [] assert p.key_input_commodities == [] assert p.regulatory_jurisdictions == [] assert p.market_position_tier == "regional" assert p.export_dependency_pct == 0.0 assert p.source == "manual" assert p.confidence == 1.0 def test_create_with_full_data(): p = ExposureProfileCreate( geographic_revenue_mix={"US": 0.6, "EU": 0.3, "CN": 0.1}, supply_chain_regions=["CN", "TW", "KR"], key_input_commodities=["lithium", "cobalt"], regulatory_jurisdictions=["US", "EU"], market_position_tier="global_leader", export_dependency_pct=0.45, source="manual", confidence=0.95, ) assert p.geographic_revenue_mix["US"] == 0.6 assert len(p.supply_chain_regions) == 3 assert p.market_position_tier == "global_leader" def test_create_all_valid_tiers(): for tier in VALID_MARKET_POSITION_TIERS: p = ExposureProfileCreate(market_position_tier=tier) assert p.market_position_tier == tier def test_create_rejects_invalid_tier(): with pytest.raises(ValidationError): ExposureProfileCreate(market_position_tier="mega_corp") def test_create_all_valid_sources(): for src in VALID_SOURCES: p = ExposureProfileCreate(source=src) assert p.source == src def test_create_rejects_invalid_source(): with pytest.raises(ValidationError): ExposureProfileCreate(source="guessed") def test_create_rejects_export_dependency_above_1(): with pytest.raises(ValidationError): ExposureProfileCreate(export_dependency_pct=1.5) def test_create_rejects_export_dependency_below_0(): with pytest.raises(ValidationError): ExposureProfileCreate(export_dependency_pct=-0.1) def test_create_rejects_confidence_above_1(): with pytest.raises(ValidationError): ExposureProfileCreate(confidence=1.1) def test_create_rejects_confidence_below_0(): with pytest.raises(ValidationError): ExposureProfileCreate(confidence=-0.5) # --- _row_to_profile helper --- def test_row_to_profile_converts_uuids(): """UUID fields should be converted to strings.""" uid = uuid.uuid4() now = datetime.now(timezone.utc) class FakeRecord(dict): pass row = FakeRecord( id=uid, company_id=uid, geographic_revenue_mix={"US": 0.5}, supply_chain_regions=["US"], key_input_commodities=[], regulatory_jurisdictions=[], market_position_tier="regional", export_dependency_pct=0.0, source="manual", confidence=1.0, version=1, active=True, created_at=now, updated_at=now, ) result = _row_to_profile(row) assert result["id"] == str(uid) assert result["company_id"] == str(uid) def test_row_to_profile_parses_json_string(): """geographic_revenue_mix stored as JSON string should be parsed.""" uid = uuid.uuid4() now = datetime.now(timezone.utc) class FakeRecord(dict): pass row = FakeRecord( id=uid, company_id=uid, geographic_revenue_mix='{"US": 0.7, "EU": 0.3}', supply_chain_regions=["US"], key_input_commodities=[], regulatory_jurisdictions=[], market_position_tier="regional", export_dependency_pct=0.0, source="manual", confidence=1.0, version=1, active=True, created_at=now, updated_at=now, ) result = _row_to_profile(row) assert result["geographic_revenue_mix"] == {"US": 0.7, "EU": 0.3} # --- ExposureProfileResponse model --- def test_response_model_accepts_valid_data(): now = datetime.now(timezone.utc) resp = ExposureProfileResponse( id=str(uuid.uuid4()), company_id=str(uuid.uuid4()), geographic_revenue_mix={"US": 0.5, "EU": 0.5}, supply_chain_regions=["CN"], key_input_commodities=["oil"], regulatory_jurisdictions=["US"], market_position_tier="multinational", export_dependency_pct=0.3, source="inferred", confidence=0.8, version=3, active=True, created_at=now, updated_at=now, ) assert resp.version == 3 assert resp.source == "inferred"