175 lines
4.7 KiB
Python
175 lines
4.7 KiB
Python
"""Tests for exposure profile Pydantic models and endpoint logic."""
|
|
import json
|
|
import uuid
|
|
from datetime import datetime, timezone
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from services.symbol_registry.exposure import (
|
|
ExposureProfileCreate,
|
|
ExposureProfileResponse,
|
|
VALID_MARKET_POSITION_TIERS,
|
|
VALID_SOURCES,
|
|
_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"
|