# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, # pragma pylint: disable=protected-access, C0103 import datetime from unittest.mock import MagicMock import pytest from requests.exceptions import RequestException from freqtrade.rpc.fiat_convert import CryptoToFiatConverter from tests.conftest import log_has, log_has_re def test_fiat_convert_is_supported(mocker): fiat_convert = CryptoToFiatConverter() assert fiat_convert._is_supported_fiat(fiat='USD') is True assert fiat_convert._is_supported_fiat(fiat='usd') is True assert fiat_convert._is_supported_fiat(fiat='abc') is False assert fiat_convert._is_supported_fiat(fiat='ABC') is False def test_fiat_convert_find_price(mocker): fiat_convert = CryptoToFiatConverter() fiat_convert._coinlistings = {} fiat_convert._backoff = 0 mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._load_cryptomap', return_value=None) assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='EUR') == 0.0 with pytest.raises(ValueError, match=r'The fiat ABC is not supported.'): fiat_convert._find_price(crypto_symbol='BTC', fiat_symbol='ABC') assert fiat_convert.get_price(crypto_symbol='XRP', fiat_symbol='USD') == 0.0 mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price', return_value=12345.0) assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='USD') == 12345.0 assert fiat_convert.get_price(crypto_symbol='btc', fiat_symbol='usd') == 12345.0 mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price', return_value=13000.2) assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='EUR') == 13000.2 def test_fiat_convert_unsupported_crypto(mocker, caplog): mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._coinlistings', return_value=[]) fiat_convert = CryptoToFiatConverter() assert fiat_convert._find_price(crypto_symbol='CRYPTO_123', fiat_symbol='EUR') == 0.0 assert log_has('unsupported crypto-symbol CRYPTO_123 - returning 0.0', caplog) def test_fiat_convert_get_price(mocker): find_price = mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price', return_value=28000.0) fiat_convert = CryptoToFiatConverter() with pytest.raises(ValueError, match=r'The fiat us dollar is not supported.'): fiat_convert.get_price(crypto_symbol='btc', fiat_symbol='US Dollar') # Check the value return by the method pair_len = len(fiat_convert._pair_price) assert pair_len == 0 assert fiat_convert.get_price(crypto_symbol='btc', fiat_symbol='usd') == 28000.0 assert fiat_convert._pair_price['btc/usd'] == 28000.0 assert len(fiat_convert._pair_price) == 1 assert find_price.call_count == 1 # Verify the cached is used fiat_convert._pair_price['btc/usd'] = 9867.543 assert fiat_convert.get_price(crypto_symbol='btc', fiat_symbol='usd') == 9867.543 assert find_price.call_count == 1 def test_fiat_convert_same_currencies(mocker): fiat_convert = CryptoToFiatConverter() assert fiat_convert.get_price(crypto_symbol='USD', fiat_symbol='USD') == 1.0 def test_fiat_convert_two_FIAT(mocker): fiat_convert = CryptoToFiatConverter() assert fiat_convert.get_price(crypto_symbol='USD', fiat_symbol='EUR') == 0.0 def test_loadcryptomap(mocker): fiat_convert = CryptoToFiatConverter() assert len(fiat_convert._coinlistings) == 2 assert fiat_convert._get_gekko_id("btc") == "bitcoin" def test_fiat_init_network_exception(mocker): # Because CryptoToFiatConverter is a Singleton we reset the listings listmock = MagicMock(side_effect=RequestException) mocker.patch.multiple( 'freqtrade.rpc.fiat_convert.CoinGeckoAPI', get_coins_list=listmock, ) # with pytest.raises(RequestEsxception): fiat_convert = CryptoToFiatConverter() fiat_convert._coinlistings = {} fiat_convert._load_cryptomap() assert len(fiat_convert._coinlistings) == 0 def test_fiat_convert_without_network(mocker): # Because CryptoToFiatConverter is a Singleton we reset the value of _coingekko fiat_convert = CryptoToFiatConverter() cmc_temp = CryptoToFiatConverter._coingekko CryptoToFiatConverter._coingekko = None assert fiat_convert._coingekko is None assert fiat_convert._find_price(crypto_symbol='btc', fiat_symbol='usd') == 0.0 CryptoToFiatConverter._coingekko = cmc_temp def test_fiat_too_many_requests_response(mocker, caplog): # Because CryptoToFiatConverter is a Singleton we reset the listings req_exception = "429 Too Many Requests" listmock = MagicMock(return_value="{}", side_effect=RequestException(req_exception)) mocker.patch.multiple( 'freqtrade.rpc.fiat_convert.CoinGeckoAPI', get_coins_list=listmock, ) # with pytest.raises(RequestEsxception): fiat_convert = CryptoToFiatConverter() fiat_convert._coinlistings = {} fiat_convert._load_cryptomap() assert len(fiat_convert._coinlistings) == 0 assert fiat_convert._backoff > datetime.datetime.now().timestamp() assert log_has( 'Too many requests for Coingecko API, backing off and trying again later.', caplog ) def test_fiat_multiple_coins(mocker, caplog): fiat_convert = CryptoToFiatConverter() fiat_convert._coinlistings = [ {'id': 'helium', 'symbol': 'hnt', 'name': 'Helium'}, {'id': 'hymnode', 'symbol': 'hnt', 'name': 'Hymnode'}, {'id': 'bitcoin', 'symbol': 'btc', 'name': 'Bitcoin'}, {'id': 'ethereum', 'symbol': 'eth', 'name': 'Ethereum'}, {'id': 'ethereum-wormhole', 'symbol': 'eth', 'name': 'Ethereum Wormhole'}, ] assert fiat_convert._get_gekko_id('btc') == 'bitcoin' assert fiat_convert._get_gekko_id('hnt') is None assert fiat_convert._get_gekko_id('eth') == 'ethereum' assert log_has('Found multiple mappings in goingekko for hnt.', caplog) def test_fiat_invalid_response(mocker, caplog): # Because CryptoToFiatConverter is a Singleton we reset the listings listmock = MagicMock(return_value=None) mocker.patch.multiple( 'freqtrade.rpc.fiat_convert.CoinGeckoAPI', get_coins_list=listmock, ) # with pytest.raises(RequestEsxception): fiat_convert = CryptoToFiatConverter() fiat_convert._coinlistings = [] fiat_convert._load_cryptomap() assert len(fiat_convert._coinlistings) == 0 assert log_has_re('Could not load FIAT Cryptocurrency map for the following problem: .*', caplog) def test_convert_amount(mocker): mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter.get_price', return_value=12345.0) fiat_convert = CryptoToFiatConverter() result = fiat_convert.convert_amount( crypto_amount=1.23, crypto_symbol="BTC", fiat_symbol="USD" ) assert result == 15184.35 result = fiat_convert.convert_amount( crypto_amount=1.23, crypto_symbol="BTC", fiat_symbol="BTC" ) assert result == 1.23 result = fiat_convert.convert_amount( crypto_amount="1.23", crypto_symbol="BTC", fiat_symbol="BTC" ) assert result == 1.23