use crate::prelude::*;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_documentation_completeness() {
assert!(HyperliquidDataFetcher::supported_intervals().len() > 0);
let commission = HyperliquidCommission::default();
assert!(commission.maker_rate > 0.0);
assert!(commission.taker_rate > 0.0);
let error = HyperliquidBacktestError::UnsupportedInterval("invalid".to_string());
let user_message = error.user_message();
assert!(user_message.contains("Supported intervals"));
assert!(user_message.contains("💡"));
}
#[test]
fn test_api_stability() {
let commission = HyperliquidCommission::new(0.001, 0.002, true);
assert_eq!(commission.maker_rate, 0.001);
assert_eq!(commission.taker_rate, 0.002);
assert_eq!(commission.funding_enabled, true);
let error = HyperliquidBacktestError::Network("test".to_string());
assert_eq!(error.category(), "network");
assert!(error.is_recoverable());
let validation_error = HyperliquidBacktestError::Validation("test".to_string());
assert_eq!(validation_error.category(), "validation");
assert!(validation_error.is_user_error());
}
#[test]
fn test_error_handling_quality() {
let errors = vec![
HyperliquidBacktestError::UnsupportedInterval("2h".to_string()),
HyperliquidBacktestError::InvalidTimeRange { start: 100, end: 50 },
HyperliquidBacktestError::Network("Connection failed".to_string()),
HyperliquidBacktestError::RateLimit("Too many requests".to_string()),
HyperliquidBacktestError::Validation("Invalid parameter".to_string()),
];
for error in errors {
let user_message = error.user_message();
assert!(user_message.contains("💡"));
assert!(user_message.len() > error.to_string().len());
assert!(!error.category().is_empty());
}
}
#[test]
fn test_prelude_completeness() {
use crate::prelude::*;
let _: Option<HyperliquidData> = None;
let _: Option<HyperliquidDataFetcher> = None;
let _: Option<HyperliquidBacktest> = None;
let _: Option<HyperliquidCommission> = None;
let _: Option<OrderType> = None;
let _: Option<Box<dyn HyperliquidStrategy>> = None;
let _: Option<TradingSignal> = None;
let _: Option<SignalStrength> = None;
let _: Option<HyperliquidBacktestError> = None;
let _: Option<Result<()>> = None;
let _: Option<FundingReport> = None;
let _: Option<FundingDistribution> = None;
let _: Option<DateTime<FixedOffset>> = None;
}
#[test]
fn test_default_implementations() {
let commission = HyperliquidCommission::default();
assert!(commission.maker_rate < commission.taker_rate); assert!(commission.maker_rate > 0.0); assert!(commission.taker_rate < 0.01); assert!(commission.funding_enabled);
let config = FundingAwareConfig::default();
assert!(config.funding_threshold > 0.0); assert!(config.funding_weight > 0.0 && config.funding_weight <= 1.0); assert!(config.use_funding_direction); }
#[test]
fn test_validation_methods() {
assert!(HyperliquidDataFetcher::is_interval_supported("1h"));
assert!(HyperliquidDataFetcher::is_interval_supported("1d"));
assert!(!HyperliquidDataFetcher::is_interval_supported("2h"));
assert!(!HyperliquidDataFetcher::is_interval_supported("invalid"));
let intervals = HyperliquidDataFetcher::supported_intervals();
assert!(intervals.contains(&"1h"));
assert!(intervals.contains(&"1d"));
assert!(intervals.len() >= 4); }
#[test]
fn test_error_conversions() {
let parse_error: std::num::ParseFloatError = "invalid".parse::<f64>().unwrap_err();
let converted: HyperliquidBacktestError = parse_error.into();
assert!(matches!(converted, HyperliquidBacktestError::NumberParsing(_)));
let json_error = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
let converted: HyperliquidBacktestError = json_error.into();
assert!(matches!(converted, HyperliquidBacktestError::JsonParsing(_)));
}
#[test]
fn test_helper_constructors() {
let api_error = HyperliquidBacktestError::api_error("test message");
assert!(matches!(api_error, HyperliquidBacktestError::HyperliquidApi(_)));
let validation_error = HyperliquidBacktestError::validation_error("test validation");
assert!(matches!(validation_error, HyperliquidBacktestError::Validation(_)));
let config_error = HyperliquidBacktestError::config_error("test config");
assert!(matches!(config_error, HyperliquidBacktestError::Configuration(_)));
}
#[test]
fn test_signal_types() {
let long_signal = TradingSignal::new(1.0, SignalStrength::Strong);
assert!(long_signal.is_long());
assert!(!long_signal.is_short());
assert!(!long_signal.is_neutral());
let short_signal = TradingSignal::new(-0.5, SignalStrength::Medium);
assert!(!short_signal.is_long());
assert!(short_signal.is_short());
assert!(!short_signal.is_neutral());
let neutral_signal = TradingSignal::new(0.0, SignalStrength::Weak);
assert!(!neutral_signal.is_long());
assert!(!neutral_signal.is_short());
assert!(neutral_signal.is_neutral());
}
#[test]
fn test_commission_calculations() {
let commission = HyperliquidCommission::new(0.001, 0.002, true);
let maker_fee = commission.calculate_fee(OrderType::LimitMaker, 1000.0);
assert_eq!(maker_fee, 1.0);
let taker_fee = commission.calculate_fee(OrderType::Market, 1000.0);
assert_eq!(taker_fee, 2.0);
let limit_taker_fee = commission.calculate_fee(OrderType::LimitTaker, 1000.0);
assert_eq!(limit_taker_fee, 2.0);
let scenario_fee = commission.calculate_scenario_fee(
TradingScenario::OpenPosition,
OrderType::LimitMaker,
1000.0
);
assert_eq!(scenario_fee, 1.0);
}
}