"""Pure-function tests for app.services.instrument_map.t212_ticker_to_yahoo. Catalogue sync and DB-backed resolution are covered by integration tests against the live container, not here. """ from __future__ import annotations import pytest pytest.importorskip("httpx") pytest.importorskip("sqlalchemy") from app.services.instrument_map import t212_ticker_to_yahoo # --- Single-letter exchange suffix (the common LSE case) ------------------- def test_lse_pence_listing(): # iShares Physical Gold on LSE, quoted in GBX. assert t212_ticker_to_yahoo("SGLNl_EQ", "SGLN") == "SGLN.L" assert t212_ticker_to_yahoo("BAl_EQ", "BA") == "BA.L" assert t212_ticker_to_yahoo("BPl_EQ", "BP") == "BP.L" assert t212_ticker_to_yahoo("VEURl_EQ", "VEUR") == "VEUR.L" def test_amsterdam(): # Shell dual-listed on Amsterdam. assert t212_ticker_to_yahoo("SHELLa_EQ", "SHELL") == "SHELL.AS" def test_paris(): # TotalEnergies on Paris — T212 still uses the legacy FP shortcode in # the ticker, but the resolver uses whatever shortName T212 passes. assert t212_ticker_to_yahoo("FPp_EQ", "TTE") == "TTE.PA" assert t212_ticker_to_yahoo("FPp_EQ", "FP") == "FP.PA" def test_frankfurt(): assert t212_ticker_to_yahoo("SAPd_EQ", "SAP") == "SAP.DE" def test_swiss(): assert t212_ticker_to_yahoo("VFEMs_EQ", "VFEM") == "VFEM.SW" def test_milan(): assert t212_ticker_to_yahoo("ENIm_EQ", "ENI") == "ENI.MI" # --- Country-code suffix (US + Canada + EU countries) ---------------------- def test_us_listing_bare(): # NYSE/NASDAQ — Yahoo uses the bare ticker. assert t212_ticker_to_yahoo("EQNR_US_EQ", "EQNR") == "EQNR" assert t212_ticker_to_yahoo("AAPL_US_EQ", "AAPL") == "AAPL" assert t212_ticker_to_yahoo("SHEL_US_EQ", "SHEL") == "SHEL" def test_country_code_with_uk(): assert t212_ticker_to_yahoo("ABC_GB_EQ", "ABC") == "ABC.L" def test_country_code_with_germany(): assert t212_ticker_to_yahoo("ALV_DE_EQ", "ALV") == "ALV.DE" def test_country_code_with_canada(): assert t212_ticker_to_yahoo("RY_CA_EQ", "RY") == "RY.TO" # --- Edge cases ------------------------------------------------------------ def test_unknown_letter_returns_none(): assert t212_ticker_to_yahoo("FOOz_EQ", "FOO") is None def test_unknown_country_returns_none(): assert t212_ticker_to_yahoo("FOO_ZZ_EQ", "FOO") is None def test_no_eq_suffix_returns_none(): assert t212_ticker_to_yahoo("SGLN", "SGLN") is None assert t212_ticker_to_yahoo("SGLNl", "SGLN") is None def test_empty_strings(): assert t212_ticker_to_yahoo("", "") is None assert t212_ticker_to_yahoo("_EQ", "") is None # --- Full user-portfolio mapping check ------------------------------------- @pytest.mark.parametrize("t212_ticker,short,expected", [ # Mappings derived from probing T212's instruments endpoint earlier # for the user's actual 13 holdings. ("SGLNl_EQ", "SGLN", "SGLN.L"), ("IGLSl_EQ", "IGLS", "IGLS.L"), ("VEURl_EQ", "VEUR", "VEUR.L"), ("HMCHl_EQ", "HMCH", "HMCH.L"), ("INRGl_EQ", "INRG", "INRG.L"), ("VFEMl_EQ", "VFEM", "VFEM.L"), ("VJPNl_EQ", "VJPN", "VJPN.L"), ("BAl_EQ", "BA", "BA.L"), ("NATPl_EQ", "NATP", "NATP.L"), ("BPl_EQ", "BP", "BP.L"), # Paris-listed TotalEnergies ("FPp_EQ", "TTE", "TTE.PA"), # US-listed Equinor + Shell ("EQNR_US_EQ", "EQNR", "EQNR"), ("SHEL_US_EQ", "SHEL", "SHEL"), ]) def test_user_portfolio_mappings(t212_ticker, short, expected): assert t212_ticker_to_yahoo(t212_ticker, short) == expected