#![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, )] //! Comprehensive ML Safety Framework Tests //! //! Tests for enterprise-grade safety controls covering: //! - Configuration validation //! - Safety error handling //! - Bounds checking //! - NaN/Infinity detection //! - Resource limits //! - Timeout management //! - Prediction validation #![allow(unused_crate_dependencies)] use ml::safety::{MLSafetyConfig, MLSafetyError}; /// Test: Default safety configuration #[test] fn test_safety_config_defaults() { let config = MLSafetyConfig::default(); // Verify safety is enabled by default assert!(config.safety_enabled, "Safety must be enabled by default"); // Verify reasonable tensor limits assert_eq!(config.max_tensor_elements, 100_000_000); assert!(config.max_tensor_elements > 0); // Verify timeout configuration assert_eq!(config.max_inference_timeout_ms, 5000); assert!(config.max_inference_timeout_ms > 0); // Verify GPU memory limits assert_eq!(config.max_gpu_memory_bytes, 8 * 1024 * 1024 * 1024); // 8GB assert!(config.max_gpu_memory_bytes > 0); // Verify drift detection assert_eq!(config.drift_sensitivity, 0.7); assert!(config.drift_sensitivity >= 0.0 && config.drift_sensitivity <= 1.0); // Verify financial precision assert_eq!(config.financial_precision, 6); assert!(config.financial_precision > 0); // Verify safety flags assert!(config.nan_infinity_checks); assert!(config.bounds_checking); assert!(config.auto_fallback); // Verify prediction bounds assert_eq!(config.max_prediction_value, 1e6); assert_eq!(config.min_prediction_value, -1e6); assert!(config.max_prediction_value > config.min_prediction_value); // Verify retry configuration assert_eq!(config.max_retries, 3); assert!(config.max_retries > 0); } /// Test: Custom safety configuration #[test] fn test_safety_config_customization() { let mut config = MLSafetyConfig::default(); // Customize configuration config.max_tensor_elements = 50_000_000; config.max_inference_timeout_ms = 10000; config.drift_sensitivity = 0.9; config.financial_precision = 8; config.max_retries = 5; // Verify custom values assert_eq!(config.max_tensor_elements, 50_000_000); assert_eq!(config.max_inference_timeout_ms, 10000); assert_eq!(config.drift_sensitivity, 0.9); assert_eq!(config.financial_precision, 8); assert_eq!(config.max_retries, 5); } /// Test: Safety configuration validation - tensor limits #[test] fn test_safety_config_tensor_limits() { let config = MLSafetyConfig::default(); // Tensor elements must be positive assert!(config.max_tensor_elements > 0); // Reasonable upper bound (prevent OOM) assert!(config.max_tensor_elements <= 1_000_000_000); // 1B elements max } /// Test: Safety configuration validation - timeout limits #[test] fn test_safety_config_timeout_limits() { let config = MLSafetyConfig::default(); // Timeout must be positive assert!(config.max_inference_timeout_ms > 0); // Reasonable timeout (not too short, not too long) assert!(config.max_inference_timeout_ms >= 100); // At least 100ms assert!(config.max_inference_timeout_ms <= 60000); // At most 60s } /// Test: Safety configuration validation - drift sensitivity #[test] fn test_safety_config_drift_sensitivity_bounds() { let config = MLSafetyConfig::default(); // Drift sensitivity must be in [0.0, 1.0] assert!(config.drift_sensitivity >= 0.0); assert!(config.drift_sensitivity <= 1.0); } /// Test: Safety configuration validation - prediction bounds #[test] fn test_safety_config_prediction_bounds() { let config = MLSafetyConfig::default(); // Min must be less than max assert!(config.min_prediction_value < config.max_prediction_value); // Bounds must be finite assert!(config.min_prediction_value.is_finite()); assert!(config.max_prediction_value.is_finite()); // Reasonable bounds assert!(config.max_prediction_value.abs() <= 1e12); assert!(config.min_prediction_value.abs() <= 1e12); } /// Test: Safety configuration - production safety requirements #[test] fn test_safety_config_production_requirements() { let config = MLSafetyConfig::default(); // Production must have safety enabled assert!( config.safety_enabled, "Production requires safety_enabled = true" ); // Production must have NaN/Infinity checks assert!( config.nan_infinity_checks, "Production requires nan_infinity_checks = true" ); // Production must have bounds checking assert!( config.bounds_checking, "Production requires bounds_checking = true" ); // Production must have auto-fallback assert!( config.auto_fallback, "Production requires auto_fallback = true" ); } /// Test: MLSafetyError variants - math safety #[test] fn test_safety_error_math_safety() { let error = MLSafetyError::MathSafety { reason: "Division by zero".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("Mathematical safety violation")); assert!(error_msg.contains("Division by zero")); } /// Test: MLSafetyError variants - tensor safety #[test] fn test_safety_error_tensor_safety() { let error = MLSafetyError::TensorSafety { reason: "Shape mismatch".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("Tensor safety violation")); assert!(error_msg.contains("Shape mismatch")); } /// Test: MLSafetyError variants - financial validation #[test] fn test_safety_error_financial_validation() { let error = MLSafetyError::FinancialValidation { reason: "Price out of range".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("Financial validation failed")); assert!(error_msg.contains("Price out of range")); } /// Test: MLSafetyError variants - bounds check #[test] fn test_safety_error_bounds_check() { let error = MLSafetyError::BoundsCheck { index: 100, length: 50, }; let error_msg = format!("{}", error); assert!(error_msg.contains("Bounds check failed")); assert!(error_msg.contains("100")); assert!(error_msg.contains("50")); } /// Test: MLSafetyError variants - memory safety #[test] fn test_safety_error_memory_safety() { let error = MLSafetyError::MemorySafety { reason: "Allocation failed".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("Memory safety violation")); assert!(error_msg.contains("Allocation failed")); } /// Test: MLSafetyError variants - timeout #[test] fn test_safety_error_timeout() { let error = MLSafetyError::Timeout { timeout_ms: 5000 }; let error_msg = format!("{}", error); assert!(error_msg.contains("Timeout exceeded")); assert!(error_msg.contains("5000ms")); } /// Test: MLSafetyError variants - model drift #[test] fn test_safety_error_model_drift() { let error = MLSafetyError::ModelDrift { drift_score: 0.85, threshold: 0.7, }; let error_msg = format!("{}", error); assert!(error_msg.contains("Model drift detected")); assert!(error_msg.contains("0.850")); // Formatted with 3 decimals assert!(error_msg.contains("0.700")); } /// Test: MLSafetyError variants - GPU failure #[test] fn test_safety_error_gpu_failure() { let error = MLSafetyError::GPUFailure { reason: "CUDA out of memory".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("GPU operation failed")); assert!(error_msg.contains("CUDA out of memory")); } /// Test: MLSafetyError variants - invalid float #[test] fn test_safety_error_invalid_float() { let error = MLSafetyError::InvalidFloat { operation: "matrix_multiply".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("NaN or Infinity detected")); assert!(error_msg.contains("matrix_multiply")); } /// Test: MLSafetyError variants - prediction out of bounds #[test] fn test_safety_error_prediction_out_of_bounds() { let error = MLSafetyError::PredictionOutOfBounds { value: 2e6, min: -1e6, max: 1e6, }; let error_msg = format!("{}", error); assert!(error_msg.contains("Prediction value out of bounds")); assert!(error_msg.contains("2000000")); // 2e6 } /// Test: MLSafetyError variants - resource unavailable #[test] fn test_safety_error_resource_unavailable() { let error = MLSafetyError::ResourceUnavailable { resource: "GPU:0".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("Resource unavailable")); assert!(error_msg.contains("GPU:0")); } /// Test: MLSafetyError variants - resource exhausted #[test] fn test_safety_error_resource_exhausted() { let error = MLSafetyError::ResourceExhausted { resource: "System memory".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("System resource exhausted")); assert!(error_msg.contains("System memory")); } /// Test: MLSafetyError variants - validation error #[test] fn test_safety_error_validation() { let error = MLSafetyError::ValidationError { message: "Invalid model configuration".to_string(), }; let error_msg = format!("{}", error); assert!(error_msg.contains("Validation error")); assert!(error_msg.contains("Invalid model configuration")); } /// Test: Safety configuration - edge case tensor size #[test] fn test_safety_config_edge_case_tensor_size() { let mut config = MLSafetyConfig::default(); // Test very small tensor limit config.max_tensor_elements = 1; assert_eq!(config.max_tensor_elements, 1); // Test very large tensor limit config.max_tensor_elements = 1_000_000_000; assert_eq!(config.max_tensor_elements, 1_000_000_000); } /// Test: Safety configuration - edge case timeout #[test] fn test_safety_config_edge_case_timeout() { let mut config = MLSafetyConfig::default(); // Test minimal timeout config.max_inference_timeout_ms = 1; assert_eq!(config.max_inference_timeout_ms, 1); // Test large timeout config.max_inference_timeout_ms = 60000; // 60 seconds assert_eq!(config.max_inference_timeout_ms, 60000); } /// Test: Safety configuration - disable safety (not recommended for production) #[test] fn test_safety_config_disable_safety() { let mut config = MLSafetyConfig::default(); // Can disable safety (for testing only!) config.safety_enabled = false; assert!(!config.safety_enabled); // Warning: This is dangerous in production // Verify other safety checks can still be individually configured assert!(config.nan_infinity_checks); assert!(config.bounds_checking); } /// Test: Safety configuration - GPU memory limits #[test] fn test_safety_config_gpu_memory_limits() { let config = MLSafetyConfig::default(); // GPU memory must be positive assert!(config.max_gpu_memory_bytes > 0); // Reasonable GPU memory limit (1MB to 64GB) assert!(config.max_gpu_memory_bytes >= 1024 * 1024); // At least 1MB assert!(config.max_gpu_memory_bytes <= 64 * 1024 * 1024 * 1024); // At most 64GB } /// Test: Safety configuration - retry limits #[test] fn test_safety_config_retry_limits() { let config = MLSafetyConfig::default(); // Retries must be positive assert!(config.max_retries > 0); // Reasonable retry count (1-10) assert!(config.max_retries >= 1); assert!(config.max_retries <= 10); } /// Test: Safety configuration - financial precision #[test] fn test_safety_config_financial_precision() { let config = MLSafetyConfig::default(); // Precision must be positive assert!(config.financial_precision > 0); // Reasonable precision (4-10 decimal places) assert!(config.financial_precision >= 4); assert!(config.financial_precision <= 10); } /// Test: Safety configuration cloning #[test] fn test_safety_config_cloning() { let config1 = MLSafetyConfig::default(); let config2 = config1.clone(); // Verify all fields are cloned correctly assert_eq!(config1.safety_enabled, config2.safety_enabled); assert_eq!(config1.max_tensor_elements, config2.max_tensor_elements); assert_eq!( config1.max_inference_timeout_ms, config2.max_inference_timeout_ms ); assert_eq!(config1.max_gpu_memory_bytes, config2.max_gpu_memory_bytes); assert_eq!(config1.drift_sensitivity, config2.drift_sensitivity); assert_eq!(config1.financial_precision, config2.financial_precision); assert_eq!(config1.nan_infinity_checks, config2.nan_infinity_checks); assert_eq!(config1.max_prediction_value, config2.max_prediction_value); assert_eq!(config1.min_prediction_value, config2.min_prediction_value); assert_eq!(config1.bounds_checking, config2.bounds_checking); assert_eq!(config1.auto_fallback, config2.auto_fallback); assert_eq!(config1.max_retries, config2.max_retries); } /// Test: Safety configuration serialization roundtrip #[test] fn test_safety_config_serialization() { let config = MLSafetyConfig::default(); // Serialize to JSON let json = serde_json::to_string(&config).expect("Should serialize"); // Deserialize back let deserialized: MLSafetyConfig = serde_json::from_str(&json).expect("Should deserialize"); // Verify fields match assert_eq!(config.safety_enabled, deserialized.safety_enabled); assert_eq!(config.max_tensor_elements, deserialized.max_tensor_elements); assert_eq!( config.max_inference_timeout_ms, deserialized.max_inference_timeout_ms ); }