sklears_compose/enhanced_error_messages/
functions.rs1use crate::error::{Result, SklearsComposeError};
6use std::collections::{HashMap, VecDeque};
7use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
8
9use super::types::{
10 ActionableSuggestion, ContextCollectionConfig, ContextType, DataErrorSuggestionGenerator,
11 EnhancedErrorContext, EnvironmentContextProvider, ErrorCategory, ErrorContextCollector,
12 ErrorFormatter, ErrorMessageEnhancer, ErrorPatternAnalyzer, FormatterConfig,
13 PatternAnalysisConfig, RecoveryAdvisor, RecoveryConfig, RecoveryOutcome, SuggestionEngine,
14 SuggestionEngineConfig,
15};
16
17pub trait ContextProvider: std::fmt::Debug + Send + Sync {
19 fn collect_context(&self, error: &SklearsComposeError) -> Result<HashMap<String, String>>;
20 fn context_type(&self) -> ContextType;
21}
22pub trait SuggestionGenerator: std::fmt::Debug + Send + Sync {
24 fn generate_suggestions(
25 &self,
26 error: &SklearsComposeError,
27 context: &EnhancedErrorContext,
28 ) -> Result<Vec<ActionableSuggestion>>;
29 fn error_types(&self) -> Vec<String>;
30}
31pub trait AutoRecoveryHandler: std::fmt::Debug + Send + Sync {
33 fn can_recover(&self, error: &SklearsComposeError) -> bool;
34 fn attempt_recovery(
35 &self,
36 error: &SklearsComposeError,
37 context: &EnhancedErrorContext,
38 ) -> Result<RecoveryOutcome>;
39}
40pub trait DurationExt {
41 fn from_mins(minutes: u64) -> Duration;
42}
43impl DurationExt for Duration {
44 fn from_mins(minutes: u64) -> Duration {
45 Duration::from_secs(minutes * 60)
46 }
47}
48#[allow(non_snake_case)]
49#[cfg(test)]
50mod tests {
51 use super::*;
52 #[test]
53 fn test_error_enhancer_creation() {
54 let enhancer = ErrorMessageEnhancer::new();
55 assert!(enhancer.config.enable_pattern_analysis);
56 }
57 #[test]
58 fn test_error_enhancement() {
59 let enhancer = ErrorMessageEnhancer::new();
60 let error = SklearsComposeError::InvalidConfiguration("Test error".to_string());
61 let result = enhancer.enhance_error(&error);
62 assert!(result.is_ok());
63 let enhanced = result.unwrap();
64 assert!(!enhanced.enhanced_message.is_empty());
65 assert!(!enhanced.original_error.is_empty());
66 }
67 #[test]
68 fn test_context_collection() {
69 let config = ContextCollectionConfig {
70 enable_detailed_context: true,
71 max_context_size: 1000,
72 context_timeout: Duration::from_secs(1),
73 };
74 let mut collector = ErrorContextCollector::new(config);
75 let error = SklearsComposeError::InvalidConfiguration("Test".to_string());
76 let result = collector.collect_context(&error);
77 assert!(result.is_ok());
78 }
79 #[test]
80 fn test_suggestion_generation() {
81 let config = SuggestionEngineConfig {
82 max_suggestions: 3,
83 confidence_threshold: 0.5,
84 enable_machine_learning: false,
85 };
86 let engine = SuggestionEngine::new(config);
87 let error = SklearsComposeError::InvalidData {
88 reason: "shape mismatch".to_string(),
89 };
90 let context = EnhancedErrorContext::default();
91 let result = engine.generate_suggestions(&error, &context);
92 assert!(result.is_ok());
93 }
94 #[test]
95 fn test_error_classification() {
96 let config = PatternAnalysisConfig {
97 max_patterns: 100,
98 pattern_similarity_threshold: 0.8,
99 learning_rate: 0.01,
100 };
101 let mut analyzer = ErrorPatternAnalyzer::new(config);
102 let error = SklearsComposeError::InvalidData {
103 reason: "test".to_string(),
104 };
105 let context = EnhancedErrorContext::default();
106 let result = analyzer.analyze_error(&error, &context);
107 assert!(result.is_ok());
108 let classification = result.unwrap();
109 assert!(matches!(classification.category, ErrorCategory::DataError));
110 }
111 #[test]
112 fn test_recovery_strategies() {
113 let config = RecoveryConfig {
114 enable_auto_recovery: true,
115 max_recovery_attempts: 3,
116 recovery_timeout: Duration::from_secs(10),
117 };
118 let advisor = RecoveryAdvisor::new(config);
119 let error = SklearsComposeError::InvalidConfiguration("test".to_string());
120 let context = EnhancedErrorContext::default();
121 let result = advisor.generate_recovery_strategies(&error, &context);
122 assert!(result.is_ok());
123 let strategies = result.unwrap();
124 assert!(!strategies.is_empty());
125 }
126 #[test]
127 fn test_error_formatting() {
128 let config = FormatterConfig {
129 default_language: "en".to_string(),
130 include_technical_details: true,
131 max_message_length: 1000,
132 };
133 let formatter = ErrorFormatter::new(config);
134 let error = SklearsComposeError::InvalidConfiguration("test error".to_string());
135 let context = EnhancedErrorContext::default();
136 let suggestions = Vec::new();
137 let result = formatter.format_error(&error, &context, &suggestions);
138 assert!(result.is_ok());
139 let formatted = result.unwrap();
140 assert!(formatted.contains("ERROR:"));
141 assert!(formatted.contains("test error"));
142 }
143 #[test]
144 fn test_learning_from_resolution() {
145 let enhancer = ErrorMessageEnhancer::new();
146 let error = SklearsComposeError::InvalidConfiguration("test".to_string());
147 let result = enhancer.learn_from_resolution(&error, "test_suggestion", true);
148 assert!(result.is_ok());
149 }
150 #[test]
151 fn test_statistics_export() {
152 let enhancer = ErrorMessageEnhancer::new();
153 let result = enhancer.export_statistics();
154 assert!(result.is_ok());
155 let stats = result.unwrap();
156 assert!(stats.success_rate >= 0.0 && stats.success_rate <= 1.0);
157 }
158 #[test]
159 fn test_context_providers() {
160 let provider = EnvironmentContextProvider::new();
161 let error = SklearsComposeError::InvalidConfiguration("test".to_string());
162 let result = provider.collect_context(&error);
163 assert!(result.is_ok());
164 let context = result.unwrap();
165 assert!(context.contains_key("os"));
166 assert_eq!(provider.context_type(), ContextType::Environment);
167 }
168 #[test]
169 fn test_suggestion_generators() {
170 let generator = DataErrorSuggestionGenerator::new();
171 let error = SklearsComposeError::InvalidData {
172 reason: "shape mismatch".to_string(),
173 };
174 let context = EnhancedErrorContext::default();
175 let result = generator.generate_suggestions(&error, &context);
176 assert!(result.is_ok());
177 let suggestions = result.unwrap();
178 assert!(!suggestions.is_empty());
179 assert_eq!(generator.error_types(), vec!["DataError".to_string()]);
180 }
181}