1use std::collections::HashMap;
2use std::time::{Duration, Instant};
3
4pub struct QualityValidator {
6 rules: Vec<ValidationRule>,
8 rule_stats: HashMap<String, RuleStats>,
10 config: ValidationConfig,
12}
13
14#[derive(Debug, Clone)]
16pub struct ValidationRule {
17 pub id: String,
19 pub name: String,
21 pub description: String,
23 pub category: RuleCategory,
25 pub severity: ValidationSeverity,
27 pub enabled: bool,
29 pub validator: ValidationFunction,
31}
32
33#[derive(Debug, Clone, PartialEq)]
35pub enum RuleCategory {
36 MemorySafety,
38 Performance,
40 CodeStyle,
42 ErrorHandling,
44 ThreadSafety,
46 ResourceManagement,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
52pub enum ValidationSeverity {
53 Info,
55 Style,
57 Warning,
59 Error,
61 Critical,
63}
64
65pub type ValidationFunction = fn(&ValidationContext) -> Result<(), ValidationError>;
67
68#[derive(Debug)]
70pub struct ValidationContext {
71 pub operation_name: String,
73 pub metrics: OperationMetrics,
75 pub memory_info: MemoryInfo,
77 pub error_handling: ErrorHandlingInfo,
79 pub thread_safety: ThreadSafetyInfo,
81}
82
83#[derive(Debug, Clone)]
85pub struct OperationMetrics {
86 pub avg_duration: Duration,
88 pub peak_memory: usize,
90 pub success_rate: f64,
92 pub allocation_count: usize,
94 pub cpu_usage: f64,
96}
97
98#[derive(Debug, Clone)]
100pub struct MemoryInfo {
101 pub current_usage: usize,
103 pub peak_usage: usize,
105 pub active_allocations: usize,
107 pub fragmentation_ratio: f64,
109 pub growth_rate: f64,
111}
112
113#[derive(Debug, Clone)]
115pub struct ErrorHandlingInfo {
116 pub has_error_handling: bool,
118 pub error_points: usize,
120 pub handled_error_points: usize,
122 pub has_recovery: bool,
124}
125
126#[derive(Debug, Clone)]
128pub struct ThreadSafetyInfo {
129 pub is_thread_safe: bool,
131 pub shared_resources: usize,
133 pub has_synchronization: bool,
135 pub contention_level: f64,
137}
138
139#[derive(Debug, Clone)]
141pub struct ValidationError {
142 pub message: String,
144 pub suggestion: Option<String>,
146 pub location: Option<String>,
148}
149
150#[derive(Debug, Clone)]
152pub struct ValidationResult {
153 pub status: ValidationStatus,
155 pub rule_results: Vec<RuleResult>,
157 pub summary: ValidationSummary,
159 pub validation_overhead: Duration,
161}
162
163#[derive(Debug, Clone, PartialEq)]
165pub enum ValidationStatus {
166 Passed,
168 WarningsFound,
170 ErrorsFound,
172 CriticalIssuesFound,
174}
175
176#[derive(Debug, Clone)]
178pub struct RuleResult {
179 pub rule_id: String,
181 pub passed: bool,
183 pub error: Option<ValidationError>,
185 pub execution_time: Duration,
187}
188
189#[derive(Debug, Clone)]
191pub struct ValidationSummary {
192 pub total_rules: usize,
194 pub passed_rules: usize,
196 pub failed_rules: usize,
198 pub critical_issues: usize,
200 pub errors: usize,
202 pub warnings: usize,
204 pub quality_score: f64,
206}
207
208#[derive(Debug, Clone)]
210pub struct ValidationConfig {
211 pub fail_fast: bool,
213 pub max_validation_time: Duration,
215 pub enable_deep_checks: bool,
217 pub min_severity: ValidationSeverity,
219}
220
221#[derive(Debug, Clone)]
223pub struct RuleStats {
224 execution_count: usize,
226 total_time: Duration,
228 failure_count: usize,
230 avg_time: Duration,
232}
233
234impl QualityValidator {
235 pub fn new() -> Self {
237 let mut validator = Self {
238 rules: Vec::new(),
239 rule_stats: HashMap::new(),
240 config: ValidationConfig::default(),
241 };
242
243 validator.add_default_rules();
244 validator
245 }
246
247 pub fn with_config(config: ValidationConfig) -> Self {
249 let mut validator = Self {
250 rules: Vec::new(),
251 rule_stats: HashMap::new(),
252 config,
253 };
254
255 validator.add_default_rules();
256 validator
257 }
258
259 pub fn add_rule(&mut self, rule: ValidationRule) {
261 self.rules.push(rule);
262 }
263
264 pub fn remove_rule(&mut self, rule_id: &str) -> bool {
266 if let Some(pos) = self.rules.iter().position(|r| r.id == rule_id) {
267 self.rules.remove(pos);
268 self.rule_stats.remove(rule_id);
269 true
270 } else {
271 false
272 }
273 }
274
275 pub fn set_rule_enabled(&mut self, rule_id: &str, enabled: bool) -> bool {
277 if let Some(rule) = self.rules.iter_mut().find(|r| r.id == rule_id) {
278 rule.enabled = enabled;
279 true
280 } else {
281 false
282 }
283 }
284
285 pub fn validate(&mut self, context: &ValidationContext) -> ValidationResult {
287 let start_time = Instant::now();
288 let mut rule_results = Vec::new();
289 let mut should_stop = false;
290
291 let rules_info: Vec<_> = self
293 .rules
294 .iter()
295 .filter(|rule| rule.enabled)
296 .map(|rule| (rule.id.clone(), rule.severity.clone(), rule.validator))
297 .collect();
298
299 for (rule_id, severity, validator) in rules_info {
300 if should_stop && self.config.fail_fast {
301 break;
302 }
303
304 let rule_start = Instant::now();
305 let result = validator(context);
306 let rule_duration = rule_start.elapsed();
307
308 self.update_rule_stats(&rule_id, rule_duration, result.is_err());
310
311 let rule_result = RuleResult {
312 rule_id,
313 passed: result.is_ok(),
314 error: result.err(),
315 execution_time: rule_duration,
316 };
317
318 if !rule_result.passed && severity >= ValidationSeverity::Critical {
319 should_stop = true;
320 }
321
322 rule_results.push(rule_result);
323
324 if start_time.elapsed() > self.config.max_validation_time {
326 break;
327 }
328 }
329
330 let validation_overhead = start_time.elapsed();
331 let summary = self.calculate_summary(&rule_results);
332 let status = self.determine_status(&summary);
333
334 ValidationResult {
335 status,
336 rule_results,
337 summary,
338 validation_overhead,
339 }
340 }
341
342 pub fn get_rule_statistics(&self) -> &HashMap<String, RuleStats> {
344 &self.rule_stats
345 }
346
347 pub fn reset_statistics(&mut self) {
349 self.rule_stats.clear();
350 }
351
352 fn add_default_rules(&mut self) {
353 self.add_rule(ValidationRule {
355 id: "memory_leak_check".to_string(),
356 name: "Memory Leak Detection".to_string(),
357 description: "Check for potential memory leaks in tracking operations".to_string(),
358 category: RuleCategory::MemorySafety,
359 severity: ValidationSeverity::Critical,
360 enabled: true,
361 validator: validate_memory_leaks,
362 });
363
364 self.add_rule(ValidationRule {
365 id: "allocation_overhead_check".to_string(),
366 name: "Allocation Overhead Check".to_string(),
367 description: "Ensure allocation tracking overhead is within acceptable limits"
368 .to_string(),
369 category: RuleCategory::Performance,
370 severity: ValidationSeverity::Warning,
371 enabled: true,
372 validator: validate_allocation_overhead,
373 });
374
375 self.add_rule(ValidationRule {
377 id: "tracking_latency_check".to_string(),
378 name: "Tracking Latency Check".to_string(),
379 description: "Verify allocation tracking latency is acceptable".to_string(),
380 category: RuleCategory::Performance,
381 severity: ValidationSeverity::Error,
382 enabled: true,
383 validator: validate_tracking_latency,
384 });
385
386 self.add_rule(ValidationRule {
387 id: "symbol_resolution_performance".to_string(),
388 name: "Symbol Resolution Performance".to_string(),
389 description: "Check symbol resolution performance metrics".to_string(),
390 category: RuleCategory::Performance,
391 severity: ValidationSeverity::Warning,
392 enabled: true,
393 validator: validate_symbol_performance,
394 });
395
396 self.add_rule(ValidationRule {
398 id: "error_handling_coverage".to_string(),
399 name: "Error Handling Coverage".to_string(),
400 description: "Ensure proper error handling in critical paths".to_string(),
401 category: RuleCategory::ErrorHandling,
402 severity: ValidationSeverity::Error,
403 enabled: true,
404 validator: validate_error_handling,
405 });
406
407 self.add_rule(ValidationRule {
409 id: "thread_safety_check".to_string(),
410 name: "Thread Safety Check".to_string(),
411 description: "Verify thread safety of concurrent operations".to_string(),
412 category: RuleCategory::ThreadSafety,
413 severity: ValidationSeverity::Critical,
414 enabled: true,
415 validator: validate_thread_safety,
416 });
417 }
418
419 #[allow(dead_code)]
420 fn execute_rule(
421 &self,
422 rule: &ValidationRule,
423 context: &ValidationContext,
424 ) -> Result<(), ValidationError> {
425 (rule.validator)(context)
426 }
427
428 fn update_rule_stats(&mut self, rule_id: &str, duration: Duration, failed: bool) {
429 let stats = self
430 .rule_stats
431 .entry(rule_id.to_string())
432 .or_insert(RuleStats {
433 execution_count: 0,
434 total_time: Duration::ZERO,
435 failure_count: 0,
436 avg_time: Duration::ZERO,
437 });
438
439 stats.execution_count += 1;
440 stats.total_time += duration;
441 if failed {
442 stats.failure_count += 1;
443 }
444 stats.avg_time = stats.total_time / stats.execution_count as u32;
445 }
446
447 fn calculate_summary(&self, results: &[RuleResult]) -> ValidationSummary {
448 let total_rules = results.len();
449 let passed_rules = results.iter().filter(|r| r.passed).count();
450 let failed_rules = total_rules - passed_rules;
451
452 let mut critical_issues = 0;
453 let mut errors = 0;
454 let mut warnings = 0;
455
456 for result in results {
457 if !result.passed {
458 if let Some(rule) = self.rules.iter().find(|r| r.id == result.rule_id) {
459 match rule.severity {
460 ValidationSeverity::Critical => critical_issues += 1,
461 ValidationSeverity::Error => errors += 1,
462 ValidationSeverity::Warning => warnings += 1,
463 _ => {}
464 }
465 }
466 }
467 }
468
469 let quality_score = if total_rules > 0 {
470 passed_rules as f64 / total_rules as f64
471 } else {
472 1.0
473 };
474
475 ValidationSummary {
476 total_rules,
477 passed_rules,
478 failed_rules,
479 critical_issues,
480 errors,
481 warnings,
482 quality_score,
483 }
484 }
485
486 fn determine_status(&self, summary: &ValidationSummary) -> ValidationStatus {
487 if summary.critical_issues > 0 {
488 ValidationStatus::CriticalIssuesFound
489 } else if summary.errors > 0 {
490 ValidationStatus::ErrorsFound
491 } else if summary.warnings > 0 {
492 ValidationStatus::WarningsFound
493 } else {
494 ValidationStatus::Passed
495 }
496 }
497}
498
499fn validate_memory_leaks(context: &ValidationContext) -> Result<(), ValidationError> {
501 if context.memory_info.growth_rate > 10.0 * 1024.0 * 1024.0 {
502 return Err(ValidationError {
504 message: format!(
505 "High memory growth rate detected: {:.2}MB/sec",
506 context.memory_info.growth_rate / (1024.0 * 1024.0)
507 ),
508 suggestion: Some("Check for memory leaks in allocation tracking".to_string()),
509 location: Some(context.operation_name.clone()),
510 });
511 }
512
513 if context.memory_info.fragmentation_ratio > 0.5 {
514 return Err(ValidationError {
515 message: format!(
516 "High memory fragmentation: {:.1}%",
517 context.memory_info.fragmentation_ratio * 100.0
518 ),
519 suggestion: Some("Consider implementing memory compaction".to_string()),
520 location: Some(context.operation_name.clone()),
521 });
522 }
523
524 Ok(())
525}
526
527fn validate_allocation_overhead(context: &ValidationContext) -> Result<(), ValidationError> {
528 let overhead_ratio =
529 context.metrics.peak_memory as f64 / (context.memory_info.current_usage as f64).max(1.0);
530
531 if overhead_ratio > 0.1 {
532 return Err(ValidationError {
534 message: format!("High tracking overhead: {:.1}%", overhead_ratio * 100.0),
535 suggestion: Some(
536 "Optimize tracking data structures to reduce memory overhead".to_string(),
537 ),
538 location: Some(context.operation_name.clone()),
539 });
540 }
541
542 Ok(())
543}
544
545fn validate_tracking_latency(context: &ValidationContext) -> Result<(), ValidationError> {
546 if context.metrics.avg_duration > Duration::from_micros(100) {
547 return Err(ValidationError {
548 message: format!(
549 "High tracking latency: {:.2}µs",
550 context.metrics.avg_duration.as_micros()
551 ),
552 suggestion: Some("Optimize allocation tracking path for lower latency".to_string()),
553 location: Some(context.operation_name.clone()),
554 });
555 }
556
557 Ok(())
558}
559
560fn validate_symbol_performance(context: &ValidationContext) -> Result<(), ValidationError> {
561 if context.operation_name.contains("symbol")
562 && context.metrics.avg_duration > Duration::from_millis(10)
563 {
564 return Err(ValidationError {
565 message: format!(
566 "Slow symbol resolution: {:.2}ms",
567 context.metrics.avg_duration.as_millis()
568 ),
569 suggestion: Some("Consider symbol caching or preloading".to_string()),
570 location: Some(context.operation_name.clone()),
571 });
572 }
573
574 Ok(())
575}
576
577fn validate_error_handling(context: &ValidationContext) -> Result<(), ValidationError> {
578 let coverage_ratio = if context.error_handling.error_points > 0 {
579 context.error_handling.handled_error_points as f64
580 / context.error_handling.error_points as f64
581 } else {
582 1.0
583 };
584
585 if coverage_ratio < 0.9 {
586 return Err(ValidationError {
587 message: format!(
588 "Low error handling coverage: {:.1}%",
589 coverage_ratio * 100.0
590 ),
591 suggestion: Some("Add error handling for unhandled error points".to_string()),
592 location: Some(context.operation_name.clone()),
593 });
594 }
595
596 if !context.error_handling.has_recovery && context.operation_name.contains("critical") {
597 return Err(ValidationError {
598 message: "Critical operation lacks recovery mechanism".to_string(),
599 suggestion: Some("Implement recovery strategies for critical operations".to_string()),
600 location: Some(context.operation_name.clone()),
601 });
602 }
603
604 Ok(())
605}
606
607fn validate_thread_safety(context: &ValidationContext) -> Result<(), ValidationError> {
608 if context.thread_safety.shared_resources > 0 && !context.thread_safety.is_thread_safe {
609 return Err(ValidationError {
610 message: "Operation accesses shared resources without thread safety".to_string(),
611 suggestion: Some("Add proper synchronization for shared resource access".to_string()),
612 location: Some(context.operation_name.clone()),
613 });
614 }
615
616 if context.thread_safety.contention_level > 0.3 {
617 return Err(ValidationError {
618 message: format!(
619 "High lock contention: {:.1}%",
620 context.thread_safety.contention_level * 100.0
621 ),
622 suggestion: Some(
623 "Consider lock-free alternatives or finer-grained locking".to_string(),
624 ),
625 location: Some(context.operation_name.clone()),
626 });
627 }
628
629 Ok(())
630}
631
632impl Default for ValidationConfig {
633 fn default() -> Self {
634 Self {
635 fail_fast: false,
636 max_validation_time: Duration::from_secs(10),
637 enable_deep_checks: true,
638 min_severity: ValidationSeverity::Info,
639 }
640 }
641}
642
643impl Default for QualityValidator {
644 fn default() -> Self {
645 Self::new()
646 }
647}
648
649#[cfg(test)]
650mod tests {
651 use super::*;
652
653 #[test]
654 fn test_validator_creation() {
655 let validator = QualityValidator::new();
656 assert!(!validator.rules.is_empty());
657 assert!(validator.rule_stats.is_empty());
658 }
659
660 #[test]
661 fn test_rule_management() {
662 let mut validator = QualityValidator::new();
663 let initial_count = validator.rules.len();
664
665 let custom_rule = ValidationRule {
666 id: "test_rule".to_string(),
667 name: "Test Rule".to_string(),
668 description: "Test rule description".to_string(),
669 category: RuleCategory::CodeStyle,
670 severity: ValidationSeverity::Info,
671 enabled: true,
672 validator: |_| Ok(()),
673 };
674
675 validator.add_rule(custom_rule);
676 assert_eq!(validator.rules.len(), initial_count + 1);
677
678 assert!(validator.remove_rule("test_rule"));
679 assert_eq!(validator.rules.len(), initial_count);
680 assert!(!validator.remove_rule("nonexistent_rule"));
681 }
682
683 #[test]
684 fn test_validation_context() {
685 let context = ValidationContext {
686 operation_name: "test_operation".to_string(),
687 metrics: OperationMetrics {
688 avg_duration: Duration::from_micros(50),
689 peak_memory: 1024,
690 success_rate: 0.95,
691 allocation_count: 100,
692 cpu_usage: 5.0,
693 },
694 memory_info: MemoryInfo {
695 current_usage: 1024 * 1024,
696 peak_usage: 2 * 1024 * 1024,
697 active_allocations: 100,
698 fragmentation_ratio: 0.1,
699 growth_rate: 0.0,
700 },
701 error_handling: ErrorHandlingInfo {
702 has_error_handling: true,
703 error_points: 10,
704 handled_error_points: 9,
705 has_recovery: true,
706 },
707 thread_safety: ThreadSafetyInfo {
708 is_thread_safe: true,
709 shared_resources: 2,
710 has_synchronization: true,
711 contention_level: 0.1,
712 },
713 };
714
715 let mut validator = QualityValidator::new();
716 let result = validator.validate(&context);
717
718 assert!(matches!(
719 result.status,
720 ValidationStatus::Passed | ValidationStatus::WarningsFound
721 ));
722 assert!(result.summary.quality_score >= 0.0);
723 assert!(result.summary.quality_score <= 1.0);
724 }
725}