"""Unit tests for CoinGecko pricing provider.""" import pytest from unittest.mock import Mock, patch, MagicMock from decimal import Decimal import httpx from src.data.providers.coingecko_provider import CoinGeckoProvider @pytest.fixture def provider(): """Create a CoinGecko provider instance.""" return CoinGeckoProvider() @pytest.fixture def mock_response(): """Create a mock HTTP response.""" response = Mock() response.status_code = 200 response.json = Mock(return_value={ 'bitcoin': { 'usd': 50000.0, 'usd_24h_change': 2.5, 'usd_24h_vol': 1000000.0, } }) return response class TestCoinGeckoProvider: """Tests for CoinGeckoProvider.""" def test_init(self, provider): """Test provider initialization.""" assert provider.name == "CoinGecko" assert not provider.supports_websocket assert not provider._connected @patch('src.data.providers.coingecko_provider.httpx.Client') def test_connect_success(self, mock_client_class, provider, mock_response): """Test successful connection.""" mock_client = Mock() mock_client.get = Mock(return_value=mock_response) mock_client_class.return_value = mock_client result = provider.connect() assert result is True assert provider._connected is True @patch('src.data.providers.coingecko_provider.httpx.Client') def test_connect_failure(self, mock_client_class, provider): """Test connection failure.""" mock_client = Mock() mock_client.get = Mock(side_effect=Exception("Connection failed")) mock_client_class.return_value = mock_client result = provider.connect() assert result is False assert not provider._connected def test_parse_symbol(self, provider): """Test symbol parsing.""" coin_id, currency = provider._parse_symbol('BTC/USD') assert coin_id == 'bitcoin' assert currency == 'usd' coin_id, currency = provider._parse_symbol('ETH/USDT') assert coin_id == 'ethereum' assert currency == 'usd' # USDT maps to USD @patch('src.data.providers.coingecko_provider.httpx.Client') def test_get_ticker(self, mock_client_class, provider, mock_response): """Test getting ticker data.""" mock_client = Mock() mock_client.get = Mock(return_value=mock_response) mock_client_class.return_value = mock_client provider.connect() ticker = provider.get_ticker('BTC/USD') assert ticker['symbol'] == 'BTC/USD' assert isinstance(ticker['last'], Decimal) assert ticker['last'] > 0 assert 'timestamp' in ticker @patch('src.data.providers.coingecko_provider.httpx.Client') def test_get_ohlcv(self, mock_client_class, provider): """Test getting OHLCV data.""" mock_response = Mock() mock_response.status_code = 200 mock_response.json = Mock(return_value=[ [1609459200000, 50000, 51000, 49000, 50000], ]) mock_client = Mock() mock_client.get = Mock(return_value=mock_response) mock_client_class.return_value = mock_client provider.connect() ohlcv = provider.get_ohlcv('BTC/USD', '1h', limit=10) assert len(ohlcv) > 0 # CoinGecko returns 5 elements, we add volume as 0 assert len(ohlcv[0]) == 6 def test_normalize_symbol(self, provider): """Test symbol normalization.""" normalized = provider.normalize_symbol('btc-usdt') assert normalized == 'BTC/USDT'