Files
tradingagents/tests/test_symbol_utils.py
Yijia-Xiao e3bc872982 chore(lint): make the repository ruff-clean under the strict select
Clear the deferred full-repo lint backlog so the whole tree passes the strict
ruff select (E,W,F,I,B,UP,C4,SIM). Mechanical fixes dominate: import sorting,
pep585/604 annotations, dropped dead imports, and whitespace. The few semantic
changes are behavior-preserving: declare __all__ on the agent_utils and
alpha_vantage re-export hubs; expand 'from x import *' to explicit names; use
immutable tuple defaults instead of mutable list defaults; contextlib.suppress
for try/except/pass; and narrow an over-broad assertRaises.
2026-06-14 16:38:36 +00:00

82 lines
2.9 KiB
Python

"""Tests for symbol normalization and the no-data routing sentinel."""
import unittest
import pytest
from tradingagents.dataflows.symbol_utils import (
NoMarketDataError,
is_yahoo_safe,
normalize_symbol,
)
@pytest.mark.unit
class TestNormalizeSymbol(unittest.TestCase):
def test_plain_equities_unchanged(self):
for sym in ("AAPL", "MSFT", "TSM", "BRK.B", "0700.HK", "^GSPC", "GC=F"):
self.assertEqual(normalize_symbol(sym), sym)
def test_lowercases_are_upper(self):
self.assertEqual(normalize_symbol("aapl"), "AAPL")
self.assertEqual(normalize_symbol(" msft "), "MSFT")
def test_metal_aliases_map_to_futures(self):
self.assertEqual(normalize_symbol("XAUUSD"), "GC=F")
self.assertEqual(normalize_symbol("XAUUSD+"), "GC=F") # broker CFD suffix
self.assertEqual(normalize_symbol("xauusd+"), "GC=F")
self.assertEqual(normalize_symbol("GOLD"), "GC=F")
self.assertEqual(normalize_symbol("XAGUSD"), "SI=F")
def test_energy_and_index_aliases(self):
self.assertEqual(normalize_symbol("USOIL"), "CL=F")
self.assertEqual(normalize_symbol("SPX500"), "^GSPC")
self.assertEqual(normalize_symbol("NAS100"), "^NDX")
self.assertEqual(normalize_symbol("US30"), "^DJI")
def test_forex_pairs_get_x_suffix(self):
self.assertEqual(normalize_symbol("EURUSD"), "EURUSD=X")
self.assertEqual(normalize_symbol("GBPJPY"), "GBPJPY=X")
self.assertEqual(normalize_symbol("eurusd"), "EURUSD=X")
def test_crypto_pairs_get_dash_usd(self):
self.assertEqual(normalize_symbol("BTCUSD"), "BTC-USD")
self.assertEqual(normalize_symbol("ETHUSD"), "ETH-USD")
def test_six_letter_non_currency_left_alone(self):
# GOOGLE-style 6-letter tickers that aren't two currency codes
# must not be mangled into a fake forex pair.
self.assertEqual(normalize_symbol("ABCDEF"), "ABCDEF")
def test_empty_input_passthrough(self):
self.assertEqual(normalize_symbol(""), "")
@pytest.mark.unit
class TestNoMarketDataError(unittest.TestCase):
def test_message_includes_resolution(self):
err = NoMarketDataError("XAUUSD+", "GC=F", "no rows")
self.assertIn("XAUUSD+", str(err))
self.assertIn("GC=F", str(err))
self.assertEqual(err.symbol, "XAUUSD+")
self.assertEqual(err.canonical, "GC=F")
def test_canonical_defaults_to_symbol(self):
err = NoMarketDataError("FOOBAR")
self.assertEqual(err.canonical, "FOOBAR")
@pytest.mark.unit
class TestIsYahooSafe(unittest.TestCase):
def test_accepts_structural_chars(self):
for sym in ("AAPL", "GC=F", "^GSPC", "BRK.B", "BTC-USD"):
self.assertTrue(is_yahoo_safe(sym))
def test_rejects_slash_and_space(self):
for sym in ("a/b", "AA PL", ""):
self.assertFalse(is_yahoo_safe(sym))
if __name__ == "__main__":
unittest.main()