#![allow( clippy::assertions_on_constants, clippy::assertions_on_result_states, clippy::clone_on_copy, clippy::decimal_literal_representation, clippy::doc_markdown, clippy::empty_line_after_doc_comments, clippy::field_reassign_with_default, clippy::get_unwrap, clippy::identity_op, clippy::inconsistent_digit_grouping, clippy::indexing_slicing, clippy::integer_division, clippy::len_zero, clippy::let_underscore_must_use, clippy::manual_div_ceil, clippy::manual_let_else, clippy::manual_range_contains, clippy::modulo_arithmetic, clippy::needless_range_loop, clippy::non_ascii_literal, clippy::redundant_clone, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_match_else, clippy::str_to_string, clippy::string_slice, clippy::tests_outside_test_module, clippy::too_many_lines, clippy::unnecessary_wraps, clippy::unseparated_literal_suffix, clippy::use_debug, clippy::useless_vec, clippy::wildcard_enum_match_arm, clippy::else_if_without_else, clippy::expect_used, clippy::missing_const_for_fn, clippy::similar_names, clippy::type_complexity, clippy::collapsible_else_if, clippy::doc_lazy_continuation, clippy::items_after_test_module, clippy::map_clone, clippy::multiple_unsafe_ops_per_block, clippy::unwrap_or_default, clippy::assign_op_pattern, clippy::needless_borrow, clippy::println_empty_string, clippy::unnecessary_cast, clippy::used_underscore_binding, clippy::create_dir, clippy::implicit_saturating_sub, clippy::exit, clippy::expect_fun_call, clippy::too_many_arguments, clippy::unnecessary_map_or, clippy::unwrap_used, dead_code, unused_imports, unused_variables, clippy::cloned_ref_to_slice_refs, clippy::neg_multiply, clippy::while_let_loop, clippy::bool_assert_comparison, clippy::excessive_precision, clippy::trivially_copy_pass_by_ref, clippy::op_ref, clippy::redundant_closure, clippy::unnecessary_lazy_evaluations, clippy::if_then_some_else_none, clippy::unnecessary_to_owned, clippy::single_component_path_imports, )] //! Rainbow DQN Tests //! //! Tests for Rainbow DQN types: //! - RainbowAgentConfig from rainbow_config.rs //! - RainbowAgentMetrics from rainbow_config.rs (8 fields) #![allow(unused_crate_dependencies)] use ml::dqn::{RainbowAgentConfig, RainbowAgentMetrics}; /// Test: Basic Rainbow agent configuration creation #[test] fn test_rainbow_config_creation() { let config = RainbowAgentConfig::default(); // Verify default values exist and are reasonable assert!(config.learning_rate > 0.0); assert!(config.gamma > 0.0 && config.gamma <= 1.0); assert!(config.batch_size > 0); assert!(config.replay_buffer_size > 0); assert!(config.min_replay_size > 0); assert!(config.target_update_freq > 0); } /// Test: Rainbow agent metrics structure #[test] fn test_rainbow_metrics_structure() { let metrics = RainbowAgentMetrics { total_steps: 100, replay_buffer_size: 5000, exploration_rate: 0.5, current_loss: 0.25, ..Default::default() }; assert_eq!(metrics.total_steps, 100); assert_eq!(metrics.replay_buffer_size, 5000); assert_eq!(metrics.exploration_rate, 0.5); assert_eq!(metrics.current_loss, 0.25); } /// Test: Config validation - learning rate bounds #[test] fn test_config_learning_rate_validation() { let mut config = RainbowAgentConfig::default(); config.learning_rate = 0.001; assert!(config.learning_rate > 0.0); config.learning_rate = 0.1; assert!(config.learning_rate > 0.0); } /// Test: Config validation - gamma bounds #[test] fn test_config_gamma_validation() { let mut config = RainbowAgentConfig::default(); config.gamma = 0.99; assert!(config.gamma > 0.0 && config.gamma <= 1.0); config.gamma = 0.95; assert!(config.gamma > 0.0 && config.gamma <= 1.0); } /// Test: Config validation - batch size #[test] fn test_config_batch_size_validation() { let mut config = RainbowAgentConfig::default(); config.batch_size = 32; assert!(config.batch_size > 0); config.batch_size = 64; assert!(config.batch_size > 0); } /// Test: Config validation - replay buffer size #[test] fn test_config_replay_buffer_size() { let config = RainbowAgentConfig::default(); // Replay buffer should be larger than min replay size assert!(config.replay_buffer_size >= config.min_replay_size); // Replay buffer should be larger than batch size assert!(config.replay_buffer_size >= config.batch_size); } /// Test: Config validation - priority parameters #[test] fn test_config_priority_parameters() { let config = RainbowAgentConfig::default(); // Priority alpha should be in (0, 1] assert!(config.priority_alpha > 0.0 && config.priority_alpha <= 1.0); // Priority beta should be in (0, 1] assert!(config.priority_beta > 0.0 && config.priority_beta <= 1.0); // Priority beta increment should be small positive assert!(config.priority_beta_increment > 0.0); assert!(config.priority_beta_increment < 0.01); } /// Test: Config validation - update frequencies #[test] fn test_config_update_frequencies() { let config = RainbowAgentConfig::default(); assert!(config.target_update_freq > 0); assert!(config.train_freq > 0); assert!(config.noise_reset_freq > 0); } /// Test: Metrics with realistic training values #[test] fn test_metrics_realistic_values() { let metrics = RainbowAgentMetrics { total_steps: 100000, replay_buffer_size: 50000, exploration_rate: 0.15, current_loss: 0.25, ..Default::default() }; assert_eq!(metrics.total_steps, 100000); assert_eq!(metrics.replay_buffer_size, 50000); assert_eq!(metrics.exploration_rate, 0.15); assert_eq!(metrics.current_loss, 0.25); } /// Test: Config clone functionality #[test] fn test_config_clone() { let config = RainbowAgentConfig::default(); let cloned = config.clone(); assert_eq!(cloned.learning_rate, config.learning_rate); assert_eq!(cloned.gamma, config.gamma); assert_eq!(cloned.batch_size, config.batch_size); assert_eq!(cloned.replay_buffer_size, config.replay_buffer_size); } /// Test: Config serialize/deserialize compatibility #[test] fn test_config_serialization() { let config = RainbowAgentConfig::default(); let json = serde_json::to_string(&config); assert!(json.is_ok()); if let Ok(json_str) = json { let deserialized: Result = serde_json::from_str(&json_str); assert!(deserialized.is_ok()); if let Ok(c) = deserialized { assert_eq!(c.learning_rate, config.learning_rate); assert_eq!(c.gamma, config.gamma); } } } /// Test: Config with custom values #[test] fn test_config_custom_values() { let mut config = RainbowAgentConfig::default(); config.device = "cuda".to_string(); config.min_replay_size = 5000; config.replay_buffer_size = 50000; config.batch_size = 64; config.learning_rate = 0.0005; config.gamma = 0.95; config.target_update_freq = 2000; config.train_freq = 8; config.priority_alpha = 0.7; config.priority_beta = 0.5; config.noise_reset_freq = 200; assert_eq!(config.device, "cuda"); assert_eq!(config.min_replay_size, 5000); assert_eq!(config.replay_buffer_size, 50000); assert_eq!(config.batch_size, 64); assert_eq!(config.learning_rate, 0.0005); assert_eq!(config.gamma, 0.95); assert_eq!(config.target_update_freq, 2000); assert_eq!(config.train_freq, 8); assert_eq!(config.priority_alpha, 0.7); assert_eq!(config.priority_beta, 0.5); assert_eq!(config.noise_reset_freq, 200); } /// Test: Exploration rate tracking #[test] fn test_exploration_rate_tracking() { let metrics1 = RainbowAgentMetrics { exploration_rate: 1.0, ..Default::default() }; assert_eq!(metrics1.exploration_rate, 1.0); let metrics2 = RainbowAgentMetrics { total_steps: 50000, replay_buffer_size: 50000, exploration_rate: 0.5, current_loss: 1.5, ..Default::default() }; assert_eq!(metrics2.exploration_rate, 0.5); let metrics3 = RainbowAgentMetrics { total_steps: 100000, replay_buffer_size: 100000, exploration_rate: 0.1, current_loss: 0.5, ..Default::default() }; assert_eq!(metrics3.exploration_rate, 0.1); } /// Test: Loss tracking over time #[test] fn test_loss_tracking() { let early_metrics = RainbowAgentMetrics { total_steps: 1000, replay_buffer_size: 1000, exploration_rate: 0.9, current_loss: 5.0, ..Default::default() }; assert_eq!(early_metrics.current_loss, 5.0); let mid_metrics = RainbowAgentMetrics { total_steps: 50000, replay_buffer_size: 50000, exploration_rate: 0.5, current_loss: 1.0, ..Default::default() }; assert_eq!(mid_metrics.current_loss, 1.0); let late_metrics = RainbowAgentMetrics { total_steps: 100000, replay_buffer_size: 100000, exploration_rate: 0.1, current_loss: 0.1, ..Default::default() }; assert_eq!(late_metrics.current_loss, 0.1); } /// Test: Replay buffer size tracking #[test] fn test_replay_buffer_tracking() { let config = RainbowAgentConfig::default(); let metrics = RainbowAgentMetrics { total_steps: 10000, replay_buffer_size: config.replay_buffer_size, exploration_rate: 0.5, current_loss: 0.25, ..Default::default() }; assert_eq!(metrics.replay_buffer_size, config.replay_buffer_size); } /// Test: Device configuration #[test] fn test_device_configuration() { let mut config = RainbowAgentConfig::default(); assert_eq!(config.device, "cpu"); config.device = "cuda".to_string(); assert_eq!(config.device, "cuda"); config.device = "cuda:0".to_string(); assert_eq!(config.device, "cuda:0"); } /// Test: Config network settings #[test] fn test_config_network_settings() { let config = RainbowAgentConfig::default(); let _ = &config.network_config; } /// Test: Metrics with zero values #[test] fn test_metrics_zero_values() { let metrics = RainbowAgentMetrics { total_steps: 0, replay_buffer_size: 0, exploration_rate: 0.0, current_loss: 0.0, ..Default::default() }; assert_eq!(metrics.total_steps, 0); assert_eq!(metrics.replay_buffer_size, 0); assert_eq!(metrics.exploration_rate, 0.0); assert_eq!(metrics.current_loss, 0.0); } /// Test: Metrics with max values #[test] fn test_metrics_max_values() { let metrics = RainbowAgentMetrics { total_steps: u64::MAX, replay_buffer_size: 1000000, exploration_rate: 1.0, current_loss: 100.0, ..Default::default() }; assert_eq!(metrics.total_steps, u64::MAX); assert_eq!(metrics.replay_buffer_size, 1000000); assert_eq!(metrics.exploration_rate, 1.0); assert_eq!(metrics.current_loss, 100.0); } /// Test: Training progress simulation #[test] fn test_training_progress_simulation() { // Early training let early = RainbowAgentMetrics { total_steps: 100, replay_buffer_size: 100, exploration_rate: 0.99, current_loss: 10.0, ..Default::default() }; // Mid training let mid = RainbowAgentMetrics { total_steps: 50000, replay_buffer_size: 50000, exploration_rate: 0.5, current_loss: 2.0, ..Default::default() }; // Late training let late = RainbowAgentMetrics { total_steps: 100000, replay_buffer_size: 100000, exploration_rate: 0.05, current_loss: 0.5, ..Default::default() }; // Verify progression assert!(early.exploration_rate > mid.exploration_rate); assert!(mid.exploration_rate > late.exploration_rate); assert!(early.current_loss > mid.current_loss); assert!(mid.current_loss > late.current_loss); } /// Test: Config default device is CPU #[test] fn test_config_default_device() { let config = RainbowAgentConfig::default(); assert_eq!(config.device, "cpu"); } /// Test: Config default learning rate is reasonable #[test] fn test_config_default_learning_rate() { let config = RainbowAgentConfig::default(); assert!(config.learning_rate > 0.0); assert!(config.learning_rate < 0.01); // Reasonable upper bound for DQN } /// Test: Config default gamma is reasonable #[test] fn test_config_default_gamma() { let config = RainbowAgentConfig::default(); assert!(config.gamma > 0.9); // Should be high for RL assert!(config.gamma <= 1.0); }