// Bug #26 & #27: Missing regime_features field in TradingState // TDD Test Suite - These tests should FAIL before fixes and PASS after use ml::dqn::agent::TradingState; /// Test 1: Direct TradingState initialization with regime_features /// This test validates that TradingState can be initialized with regime_features field #[test] fn test_trading_state_with_regime_features_direct_init() { let state = TradingState { price_features: vec![100.0, 101.0, 99.0, 100.5], // OHLC technical_indicators: vec![0.5; 16], market_features: vec![0.3; 16], portfolio_features: vec![1.0, 0.0, 0.0001], // [value, position, spread] regime_features: Vec::new(), // Should compile after Bug #26-27 fix }; // Validate regime_features field exists and is accessible assert!(state.regime_features.is_empty()); } /// Test 2: TradingState with non-empty regime_features /// Validates that regime_features can hold actual data #[test] fn test_trading_state_with_populated_regime_features() { let regime_data = vec![0.1, 0.2, 0.3, 0.4, 0.5]; // Example regime detection features let state = TradingState { price_features: vec![100.0; 4], technical_indicators: vec![0.0; 16], market_features: vec![0.0; 16], portfolio_features: vec![1.0, 0.0, 0.0001], regime_features: regime_data.clone(), }; assert_eq!(state.regime_features.len(), 5); assert_eq!(state.regime_features, regime_data); } /// Test 3: TradingState Default trait includes regime_features /// Validates that Default implementation includes regime_features #[test] fn test_trading_state_default_has_regime_features() { let state = TradingState::default(); // Default should initialize regime_features as empty vector assert!(state.regime_features.is_empty()); } /// Test 4: TradingState::new() includes regime_features /// Validates that constructors initialize regime_features #[test] fn test_trading_state_new_includes_regime_features() { use common::types::Price; // Use canonical common crate Price type use rust_decimal::Decimal; let price = Price::from_f64(100.0).unwrap(); let portfolio_val = Decimal::try_from(1000.0).unwrap(); let state = TradingState::new( vec![price, price, price, price], vec![0.5; 16], vec![0.3; 16], vec![portfolio_val, Decimal::ZERO, Decimal::try_from(0.0001).unwrap()], ); // Should have regime_features field (empty by default) assert!(state.regime_features.is_empty()); } /// Test 5: TradingState::from_normalized() includes regime_features /// Validates that alternative constructors initialize regime_features #[test] fn test_trading_state_from_normalized_includes_regime_features() { let state = TradingState::from_normalized( vec![100.0; 4], vec![0.5; 16], vec![0.3; 16], vec![1.0, 0.0, 0.0001], ); // Should have regime_features field (empty by default) assert!(state.regime_features.is_empty()); } /// Test 6: TradingState to_vector() includes regime_features /// Validates that serialization includes regime features #[test] fn test_trading_state_to_vector_includes_regime_features() { let state = TradingState { price_features: vec![100.0; 4], // 4 elements technical_indicators: vec![0.5; 16], // 16 elements market_features: vec![0.3; 16], // 16 elements portfolio_features: vec![1.0, 0.0, 0.0001], // 3 elements regime_features: vec![0.1, 0.2], // 2 elements }; let vec = state.to_vector(); // Total should be 4 + 16 + 16 + 3 + 2 = 41 assert_eq!(vec.len(), 41); // Verify last 2 elements are regime features assert_eq!(vec[39], 0.1); assert_eq!(vec[40], 0.2); } /// Test 7: TradingState dimension() includes regime_features /// Validates that dimension calculation includes regime features #[test] fn test_trading_state_dimension_includes_regime_features() { let state = TradingState { price_features: vec![100.0; 4], // 4 technical_indicators: vec![0.5; 16], // 16 market_features: vec![0.3; 16], // 16 portfolio_features: vec![1.0, 0.0, 0.0001], // 3 regime_features: vec![0.1, 0.2, 0.3], // 3 }; // Total dimension: 4 + 16 + 16 + 3 + 3 = 42 assert_eq!(state.dimension(), 42); } /// Test 8: TradingState is_valid() considers regime_features /// Validates that validation logic handles regime features correctly #[test] fn test_trading_state_is_valid_with_regime_features() { // Valid state with regime features let valid_state = TradingState { price_features: vec![100.0; 4], technical_indicators: vec![0.5; 16], market_features: vec![0.3; 16], portfolio_features: vec![1.0, 0.0, 0.0001], regime_features: vec![0.1, 0.2], }; assert!(valid_state.is_valid()); // Valid state with empty regime features (regime features are optional) let valid_state_no_regime = TradingState { price_features: vec![100.0; 4], technical_indicators: vec![0.5; 16], market_features: vec![0.3; 16], portfolio_features: vec![1.0, 0.0, 0.0001], regime_features: Vec::new(), }; assert!(valid_state_no_regime.is_valid()); }