use std::collections::HashMap;
use std::sync::Arc;
use crate::core::types::{ExchangeId, ExchangeResult};
use crate::core::traits::Credentials;
use crate::connector_manager::{AnyConnector, ConnectorFactory, ConnectorRegistry, Features};
use super::env_loader;
pub struct TestHarness {
credentials: HashMap<ExchangeId, Credentials>,
}
impl TestHarness {
pub fn new() -> Self {
Self {
credentials: env_loader::load_credentials(),
}
}
pub fn available_exchanges(&self) -> Vec<ExchangeId> {
self.credentials.keys().copied().collect()
}
pub fn all_exchanges() -> Vec<ExchangeId> {
let registry = ConnectorRegistry::new();
registry.list_all().iter().map(|m| m.id).collect()
}
pub async fn create_public(&self, id: ExchangeId, testnet: bool) -> ExchangeResult<Arc<AnyConnector>> {
ConnectorFactory::create_public(id, testnet).await
}
pub async fn create_authenticated(
&self,
id: ExchangeId,
) -> Option<ExchangeResult<Arc<AnyConnector>>> {
let creds = self.credentials.get(&id)?.clone();
Some(ConnectorFactory::create_authenticated(id, creds).await)
}
pub fn test_symbol(id: ExchangeId) -> &'static str {
match id {
ExchangeId::Binance
| ExchangeId::Bybit
| ExchangeId::OKX
| ExchangeId::KuCoin
| ExchangeId::Kraken
| ExchangeId::GateIO
| ExchangeId::Bitfinex
| ExchangeId::Bitstamp
| ExchangeId::Gemini
| ExchangeId::MEXC
| ExchangeId::HTX
| ExchangeId::Bitget
| ExchangeId::BingX
| ExchangeId::Phemex
| ExchangeId::CryptoCom
| ExchangeId::Upbit => "BTC/USDT",
ExchangeId::Coinbase => "BTC-USD",
ExchangeId::Deribit => "BTC-PERPETUAL",
ExchangeId::HyperLiquid => "BTC",
ExchangeId::Lighter => "BTC/USDC",
ExchangeId::Paradex => "BTC-USD-PERP",
ExchangeId::Dydx => "BTC-USD",
ExchangeId::Uniswap => "ETH/USDC",
ExchangeId::Jupiter => "SOL/USDC",
ExchangeId::Raydium => "SOL/USDC",
ExchangeId::Gmx => "BTC/USD",
ExchangeId::Polymarket => "BTC-2024",
ExchangeId::Polygon
| ExchangeId::Finnhub
| ExchangeId::Tiingo
| ExchangeId::Twelvedata
| ExchangeId::Alpaca => "AAPL",
ExchangeId::AngelOne
| ExchangeId::Zerodha
| ExchangeId::Fyers
| ExchangeId::Dhan
| ExchangeId::Upstox => "RELIANCE",
ExchangeId::JQuants => "7203",
ExchangeId::Krx => "005930",
ExchangeId::Tinkoff | ExchangeId::Moex => "SBER",
ExchangeId::Futu => "00700",
ExchangeId::Oanda | ExchangeId::AlphaVantage | ExchangeId::Dukascopy => "EUR/USD",
ExchangeId::Coinglass
| ExchangeId::CryptoCompare
| ExchangeId::WhaleAlert
| ExchangeId::Bitquery
| ExchangeId::DefiLlama => "BTC/USD",
ExchangeId::Fred => "GDP",
ExchangeId::Bls => "LNS14000000",
ExchangeId::YahooFinance => "AAPL",
ExchangeId::Ib => "AAPL",
ExchangeId::Custom(_) => "BTC/USDT",
}
}
pub fn features(id: ExchangeId) -> Option<Features> {
let registry = ConnectorRegistry::new();
registry.get(&id).map(|m| m.supported_features)
}
}
impl Default for TestHarness {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_harness_new() {
let h = TestHarness::new();
let _ = h.available_exchanges();
}
#[test]
fn test_all_exchanges_non_empty() {
let all = TestHarness::all_exchanges();
assert!(!all.is_empty(), "registry should have at least one exchange");
}
#[test]
fn test_test_symbol_binance() {
assert_eq!(TestHarness::test_symbol(ExchangeId::Binance), "BTC/USDT");
}
#[test]
fn test_test_symbol_coinbase() {
assert_eq!(TestHarness::test_symbol(ExchangeId::Coinbase), "BTC-USD");
}
#[test]
fn test_test_symbol_alpaca() {
assert_eq!(TestHarness::test_symbol(ExchangeId::Alpaca), "AAPL");
}
#[test]
fn test_test_symbol_oanda() {
assert_eq!(TestHarness::test_symbol(ExchangeId::Oanda), "EUR/USD");
}
#[test]
fn test_features_binance() {
let f = TestHarness::features(ExchangeId::Binance);
assert!(f.is_some());
assert!(f.unwrap().market_data);
}
}