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 fn update_rule_stats(&mut self, rule_id: &str, duration: Duration, failed: bool) {
420 let stats = self
421 .rule_stats
422 .entry(rule_id.to_string())
423 .or_insert(RuleStats {
424 execution_count: 0,
425 total_time: Duration::ZERO,
426 failure_count: 0,
427 avg_time: Duration::ZERO,
428 });
429
430 stats.execution_count += 1;
431 stats.total_time += duration;
432 if failed {
433 stats.failure_count += 1;
434 }
435 stats.avg_time = stats.total_time / stats.execution_count as u32;
436 }
437
438 fn calculate_summary(&self, results: &[RuleResult]) -> ValidationSummary {
439 let total_rules = results.len();
440 let passed_rules = results.iter().filter(|r| r.passed).count();
441 let failed_rules = total_rules - passed_rules;
442
443 let mut critical_issues = 0;
444 let mut errors = 0;
445 let mut warnings = 0;
446
447 for result in results {
448 if !result.passed {
449 if let Some(rule) = self.rules.iter().find(|r| r.id == result.rule_id) {
450 match rule.severity {
451 ValidationSeverity::Critical => critical_issues += 1,
452 ValidationSeverity::Error => errors += 1,
453 ValidationSeverity::Warning => warnings += 1,
454 _ => {}
455 }
456 }
457 }
458 }
459
460 let quality_score = if total_rules > 0 {
461 passed_rules as f64 / total_rules as f64
462 } else {
463 1.0
464 };
465
466 ValidationSummary {
467 total_rules,
468 passed_rules,
469 failed_rules,
470 critical_issues,
471 errors,
472 warnings,
473 quality_score,
474 }
475 }
476
477 fn determine_status(&self, summary: &ValidationSummary) -> ValidationStatus {
478 if summary.critical_issues > 0 {
479 ValidationStatus::CriticalIssuesFound
480 } else if summary.errors > 0 {
481 ValidationStatus::ErrorsFound
482 } else if summary.warnings > 0 {
483 ValidationStatus::WarningsFound
484 } else {
485 ValidationStatus::Passed
486 }
487 }
488}
489
490fn validate_memory_leaks(context: &ValidationContext) -> Result<(), ValidationError> {
492 if context.memory_info.growth_rate > 10.0 * 1024.0 * 1024.0 {
493 return Err(ValidationError {
495 message: format!(
496 "High memory growth rate detected: {:.2}MB/sec",
497 context.memory_info.growth_rate / (1024.0 * 1024.0)
498 ),
499 suggestion: Some("Check for memory leaks in allocation tracking".to_string()),
500 location: Some(context.operation_name.clone()),
501 });
502 }
503
504 if context.memory_info.fragmentation_ratio > 0.5 {
505 return Err(ValidationError {
506 message: format!(
507 "High memory fragmentation: {:.1}%",
508 context.memory_info.fragmentation_ratio * 100.0
509 ),
510 suggestion: Some("Consider implementing memory compaction".to_string()),
511 location: Some(context.operation_name.clone()),
512 });
513 }
514
515 Ok(())
516}
517
518fn validate_allocation_overhead(context: &ValidationContext) -> Result<(), ValidationError> {
519 let overhead_ratio =
520 context.metrics.peak_memory as f64 / (context.memory_info.current_usage as f64).max(1.0);
521
522 if overhead_ratio > 0.1 {
523 return Err(ValidationError {
525 message: format!("High tracking overhead: {:.1}%", overhead_ratio * 100.0),
526 suggestion: Some(
527 "Optimize tracking data structures to reduce memory overhead".to_string(),
528 ),
529 location: Some(context.operation_name.clone()),
530 });
531 }
532
533 Ok(())
534}
535
536fn validate_tracking_latency(context: &ValidationContext) -> Result<(), ValidationError> {
537 if context.metrics.avg_duration > Duration::from_micros(100) {
538 return Err(ValidationError {
539 message: format!(
540 "High tracking latency: {:.2}µs",
541 context.metrics.avg_duration.as_micros()
542 ),
543 suggestion: Some("Optimize allocation tracking path for lower latency".to_string()),
544 location: Some(context.operation_name.clone()),
545 });
546 }
547
548 Ok(())
549}
550
551fn validate_symbol_performance(context: &ValidationContext) -> Result<(), ValidationError> {
552 if context.operation_name.contains("symbol")
553 && context.metrics.avg_duration > Duration::from_millis(10)
554 {
555 return Err(ValidationError {
556 message: format!(
557 "Slow symbol resolution: {:.2}ms",
558 context.metrics.avg_duration.as_millis()
559 ),
560 suggestion: Some("Consider symbol caching or preloading".to_string()),
561 location: Some(context.operation_name.clone()),
562 });
563 }
564
565 Ok(())
566}
567
568fn validate_error_handling(context: &ValidationContext) -> Result<(), ValidationError> {
569 let coverage_ratio = if context.error_handling.error_points > 0 {
570 context.error_handling.handled_error_points as f64
571 / context.error_handling.error_points as f64
572 } else {
573 1.0
574 };
575
576 if coverage_ratio < 0.9 {
577 return Err(ValidationError {
578 message: format!(
579 "Low error handling coverage: {:.1}%",
580 coverage_ratio * 100.0
581 ),
582 suggestion: Some("Add error handling for unhandled error points".to_string()),
583 location: Some(context.operation_name.clone()),
584 });
585 }
586
587 if !context.error_handling.has_recovery && context.operation_name.contains("critical") {
588 return Err(ValidationError {
589 message: "Critical operation lacks recovery mechanism".to_string(),
590 suggestion: Some("Implement recovery strategies for critical operations".to_string()),
591 location: Some(context.operation_name.clone()),
592 });
593 }
594
595 Ok(())
596}
597
598fn validate_thread_safety(context: &ValidationContext) -> Result<(), ValidationError> {
599 if context.thread_safety.shared_resources > 0 && !context.thread_safety.is_thread_safe {
600 return Err(ValidationError {
601 message: "Operation accesses shared resources without thread safety".to_string(),
602 suggestion: Some("Add proper synchronization for shared resource access".to_string()),
603 location: Some(context.operation_name.clone()),
604 });
605 }
606
607 if context.thread_safety.contention_level > 0.3 {
608 return Err(ValidationError {
609 message: format!(
610 "High lock contention: {:.1}%",
611 context.thread_safety.contention_level * 100.0
612 ),
613 suggestion: Some(
614 "Consider lock-free alternatives or finer-grained locking".to_string(),
615 ),
616 location: Some(context.operation_name.clone()),
617 });
618 }
619
620 Ok(())
621}
622
623impl Default for ValidationConfig {
624 fn default() -> Self {
625 Self {
626 fail_fast: false,
627 max_validation_time: Duration::from_secs(10),
628 enable_deep_checks: true,
629 min_severity: ValidationSeverity::Info,
630 }
631 }
632}
633
634impl Default for QualityValidator {
635 fn default() -> Self {
636 Self::new()
637 }
638}
639
640#[cfg(test)]
641mod tests {
642 use super::*;
643
644 #[test]
645 fn test_validator_creation() {
646 let validator = QualityValidator::new();
647 assert!(!validator.rules.is_empty());
648 assert!(validator.rule_stats.is_empty());
649 }
650
651 #[test]
652 fn test_rule_management() {
653 let mut validator = QualityValidator::new();
654 let initial_count = validator.rules.len();
655
656 let custom_rule = ValidationRule {
657 id: "test_rule".to_string(),
658 name: "Test Rule".to_string(),
659 description: "Test rule description".to_string(),
660 category: RuleCategory::CodeStyle,
661 severity: ValidationSeverity::Info,
662 enabled: true,
663 validator: |_| Ok(()),
664 };
665
666 validator.add_rule(custom_rule);
667 assert_eq!(validator.rules.len(), initial_count + 1);
668
669 assert!(validator.remove_rule("test_rule"));
670 assert_eq!(validator.rules.len(), initial_count);
671 assert!(!validator.remove_rule("nonexistent_rule"));
672 }
673
674 #[test]
675 fn test_validation_context() {
676 let context = ValidationContext {
677 operation_name: "test_operation".to_string(),
678 metrics: OperationMetrics {
679 avg_duration: Duration::from_micros(50),
680 peak_memory: 1024,
681 success_rate: 0.95,
682 allocation_count: 100,
683 cpu_usage: 5.0,
684 },
685 memory_info: MemoryInfo {
686 current_usage: 1024 * 1024,
687 peak_usage: 2 * 1024 * 1024,
688 active_allocations: 100,
689 fragmentation_ratio: 0.1,
690 growth_rate: 0.0,
691 },
692 error_handling: ErrorHandlingInfo {
693 has_error_handling: true,
694 error_points: 10,
695 handled_error_points: 9,
696 has_recovery: true,
697 },
698 thread_safety: ThreadSafetyInfo {
699 is_thread_safe: true,
700 shared_resources: 2,
701 has_synchronization: true,
702 contention_level: 0.1,
703 },
704 };
705
706 let mut validator = QualityValidator::new();
707 let result = validator.validate(&context);
708
709 assert!(matches!(
710 result.status,
711 ValidationStatus::Passed | ValidationStatus::WarningsFound
712 ));
713 assert!(result.summary.quality_score >= 0.0);
714 assert!(result.summary.quality_score <= 1.0);
715 }
716
717 #[test]
718 fn test_validator_default() {
719 let validator = QualityValidator::default();
720 assert!(!validator.rules.is_empty());
721 }
722
723 #[test]
724 fn test_validator_with_config() {
725 let config = ValidationConfig {
726 fail_fast: true,
727 max_validation_time: Duration::from_secs(5),
728 enable_deep_checks: false,
729 min_severity: ValidationSeverity::Warning,
730 };
731 let validator = QualityValidator::with_config(config);
732 assert!(!validator.rules.is_empty());
733 }
734
735 #[test]
736 fn test_validation_config_default() {
737 let config = ValidationConfig::default();
738 assert!(!config.fail_fast);
739 assert_eq!(config.max_validation_time, Duration::from_secs(10));
740 assert!(config.enable_deep_checks);
741 assert_eq!(config.min_severity, ValidationSeverity::Info);
742 }
743
744 #[test]
745 fn test_set_rule_enabled() {
746 let mut validator = QualityValidator::new();
747
748 assert!(validator.set_rule_enabled("memory_leak_check", false));
749 let rule = validator
750 .rules
751 .iter()
752 .find(|r| r.id == "memory_leak_check")
753 .unwrap();
754 assert!(!rule.enabled);
755
756 assert!(validator.set_rule_enabled("memory_leak_check", true));
757 let rule = validator
758 .rules
759 .iter()
760 .find(|r| r.id == "memory_leak_check")
761 .unwrap();
762 assert!(rule.enabled);
763
764 assert!(!validator.set_rule_enabled("nonexistent_rule", true));
765 }
766
767 #[test]
768 fn test_get_rule_statistics() {
769 let mut validator = QualityValidator::new();
770 let context = create_passing_context();
771
772 validator.validate(&context);
773
774 let stats = validator.get_rule_statistics();
775 assert!(!stats.is_empty());
776 }
777
778 #[test]
779 fn test_reset_statistics() {
780 let mut validator = QualityValidator::new();
781 let context = create_passing_context();
782
783 validator.validate(&context);
784 assert!(!validator.rule_stats.is_empty());
785
786 validator.reset_statistics();
787 assert!(validator.rule_stats.is_empty());
788 }
789
790 #[test]
791 fn test_validate_memory_leaks_high_growth_rate() {
792 let mut context = create_passing_context();
793 context.memory_info.growth_rate = 20.0 * 1024.0 * 1024.0; let result = validate_memory_leaks(&context);
796 assert!(result.is_err());
797 assert!(result
798 .unwrap_err()
799 .message
800 .contains("High memory growth rate"));
801 }
802
803 #[test]
804 fn test_validate_memory_leaks_high_fragmentation() {
805 let mut context = create_passing_context();
806 context.memory_info.fragmentation_ratio = 0.6;
807
808 let result = validate_memory_leaks(&context);
809 assert!(result.is_err());
810 assert!(result
811 .unwrap_err()
812 .message
813 .contains("High memory fragmentation"));
814 }
815
816 #[test]
817 fn test_validate_memory_leaks_passing() {
818 let context = create_passing_context();
819 let result = validate_memory_leaks(&context);
820 assert!(result.is_ok());
821 }
822
823 #[test]
824 fn test_validate_allocation_overhead_high() {
825 let mut context = create_passing_context();
826 context.metrics.peak_memory = 500 * 1024; context.memory_info.current_usage = 1024;
828
829 let result = validate_allocation_overhead(&context);
830 assert!(result.is_err());
831 assert!(result
832 .unwrap_err()
833 .message
834 .contains("High tracking overhead"));
835 }
836
837 #[test]
838 fn test_validate_allocation_overhead_passing() {
839 let context = create_passing_context();
840 let result = validate_allocation_overhead(&context);
841 assert!(result.is_ok());
842 }
843
844 #[test]
845 fn test_validate_tracking_latency_high() {
846 let mut context = create_passing_context();
847 context.metrics.avg_duration = Duration::from_micros(200);
848
849 let result = validate_tracking_latency(&context);
850 assert!(result.is_err());
851 assert!(result
852 .unwrap_err()
853 .message
854 .contains("High tracking latency"));
855 }
856
857 #[test]
858 fn test_validate_tracking_latency_passing() {
859 let context = create_passing_context();
860 let result = validate_tracking_latency(&context);
861 assert!(result.is_ok());
862 }
863
864 #[test]
865 fn test_validate_symbol_performance_slow() {
866 let mut context = create_passing_context();
867 context.operation_name = "symbol_resolution".to_string();
868 context.metrics.avg_duration = Duration::from_millis(20);
869
870 let result = validate_symbol_performance(&context);
871 assert!(result.is_err());
872 assert!(result
873 .unwrap_err()
874 .message
875 .contains("Slow symbol resolution"));
876 }
877
878 #[test]
879 fn test_validate_symbol_performance_passing() {
880 let mut context = create_passing_context();
881 context.operation_name = "symbol_resolution".to_string();
882 context.metrics.avg_duration = Duration::from_millis(5);
883
884 let result = validate_symbol_performance(&context);
885 assert!(result.is_ok());
886 }
887
888 #[test]
889 fn test_validate_error_handling_low_coverage() {
890 let mut context = create_passing_context();
891 context.error_handling.error_points = 10;
892 context.error_handling.handled_error_points = 5; let result = validate_error_handling(&context);
895 assert!(result.is_err());
896 assert!(result
897 .unwrap_err()
898 .message
899 .contains("Low error handling coverage"));
900 }
901
902 #[test]
903 fn test_validate_error_handling_critical_no_recovery() {
904 let mut context = create_passing_context();
905 context.operation_name = "critical_operation".to_string();
906 context.error_handling.has_recovery = false;
907
908 let result = validate_error_handling(&context);
909 assert!(result.is_err());
910 assert!(result
911 .unwrap_err()
912 .message
913 .contains("Critical operation lacks recovery"));
914 }
915
916 #[test]
917 fn test_validate_error_handling_passing() {
918 let context = create_passing_context();
919 let result = validate_error_handling(&context);
920 assert!(result.is_ok());
921 }
922
923 #[test]
924 fn test_validate_thread_safety_not_safe() {
925 let mut context = create_passing_context();
926 context.thread_safety.is_thread_safe = false;
927 context.thread_safety.shared_resources = 2;
928
929 let result = validate_thread_safety(&context);
930 assert!(result.is_err());
931 assert!(result
932 .unwrap_err()
933 .message
934 .contains("shared resources without thread safety"));
935 }
936
937 #[test]
938 fn test_validate_thread_safety_high_contention() {
939 let mut context = create_passing_context();
940 context.thread_safety.contention_level = 0.5;
941
942 let result = validate_thread_safety(&context);
943 assert!(result.is_err());
944 assert!(result.unwrap_err().message.contains("High lock contention"));
945 }
946
947 #[test]
948 fn test_validate_thread_safety_passing() {
949 let context = create_passing_context();
950 let result = validate_thread_safety(&context);
951 assert!(result.is_ok());
952 }
953
954 #[test]
955 fn test_validation_status_critical() {
956 let mut validator = QualityValidator::new();
957 let mut context = create_passing_context();
958 context.memory_info.growth_rate = 20.0 * 1024.0 * 1024.0;
959
960 let result = validator.validate(&context);
961 assert_eq!(result.status, ValidationStatus::CriticalIssuesFound);
962 assert!(result.summary.critical_issues > 0);
963 }
964
965 #[test]
966 fn test_validation_status_errors_found() {
967 let mut validator = QualityValidator::new();
968 let mut context = create_passing_context();
969 context.metrics.avg_duration = Duration::from_micros(200);
970
971 let result = validator.validate(&context);
972 assert!(matches!(
973 result.status,
974 ValidationStatus::ErrorsFound | ValidationStatus::CriticalIssuesFound
975 ));
976 }
977
978 #[test]
979 fn test_validation_status_warnings_found() {
980 let mut validator = QualityValidator::new();
981 let mut context = create_passing_context();
982 context.metrics.peak_memory = 500 * 1024;
983 context.memory_info.current_usage = 1024;
984
985 let result = validator.validate(&context);
986 assert!(matches!(
987 result.status,
988 ValidationStatus::WarningsFound | ValidationStatus::Passed
989 ));
990 }
991
992 #[test]
993 fn test_validation_status_passed() {
994 let mut validator = QualityValidator::new();
995 let context = create_passing_context();
996
997 let result = validator.validate(&context);
998 assert!(matches!(
999 result.status,
1000 ValidationStatus::Passed | ValidationStatus::WarningsFound
1001 ));
1002 }
1003
1004 #[test]
1005 fn test_fail_fast_config() {
1006 let config = ValidationConfig {
1007 fail_fast: true,
1008 ..Default::default()
1009 };
1010 let mut validator = QualityValidator::with_config(config);
1011 let mut context = create_passing_context();
1012 context.memory_info.growth_rate = 20.0 * 1024.0 * 1024.0;
1013
1014 let result = validator.validate(&context);
1015 assert_eq!(result.status, ValidationStatus::CriticalIssuesFound);
1016 }
1017
1018 #[test]
1019 fn test_rule_category_variants() {
1020 let categories = vec![
1021 RuleCategory::MemorySafety,
1022 RuleCategory::Performance,
1023 RuleCategory::CodeStyle,
1024 RuleCategory::ErrorHandling,
1025 RuleCategory::ThreadSafety,
1026 RuleCategory::ResourceManagement,
1027 ];
1028
1029 for category in categories {
1030 let rule = ValidationRule {
1031 id: "test".to_string(),
1032 name: "Test".to_string(),
1033 description: String::new(),
1034 category: category.clone(),
1035 severity: ValidationSeverity::Info,
1036 enabled: true,
1037 validator: |_| Ok(()),
1038 };
1039 assert_eq!(rule.category, category);
1040 }
1041 }
1042
1043 #[test]
1044 fn test_validation_severity_ordering() {
1045 assert!(ValidationSeverity::Critical > ValidationSeverity::Error);
1046 assert!(ValidationSeverity::Error > ValidationSeverity::Warning);
1047 assert!(ValidationSeverity::Warning > ValidationSeverity::Style);
1048 assert!(ValidationSeverity::Style > ValidationSeverity::Info);
1049 }
1050
1051 #[test]
1052 fn test_validation_severity_equality() {
1053 assert_eq!(ValidationSeverity::Critical, ValidationSeverity::Critical);
1054 assert_ne!(ValidationSeverity::Critical, ValidationSeverity::Error);
1055 }
1056
1057 #[test]
1058 fn test_validation_error_creation() {
1059 let error = ValidationError {
1060 message: "Test error".to_string(),
1061 suggestion: Some("Fix it".to_string()),
1062 location: Some("test.rs:10".to_string()),
1063 };
1064
1065 assert_eq!(error.message, "Test error");
1066 assert!(error.suggestion.is_some());
1067 assert!(error.location.is_some());
1068 }
1069
1070 #[test]
1071 fn test_validation_error_no_suggestion() {
1072 let error = ValidationError {
1073 message: "Test error".to_string(),
1074 suggestion: None,
1075 location: None,
1076 };
1077
1078 assert!(error.suggestion.is_none());
1079 assert!(error.location.is_none());
1080 }
1081
1082 #[test]
1083 fn test_rule_result_passed() {
1084 let result = RuleResult {
1085 rule_id: "test_rule".to_string(),
1086 passed: true,
1087 error: None,
1088 execution_time: Duration::from_micros(10),
1089 };
1090
1091 assert!(result.passed);
1092 assert!(result.error.is_none());
1093 }
1094
1095 #[test]
1096 fn test_rule_result_failed() {
1097 let result = RuleResult {
1098 rule_id: "test_rule".to_string(),
1099 passed: false,
1100 error: Some(ValidationError {
1101 message: "Failed".to_string(),
1102 suggestion: None,
1103 location: None,
1104 }),
1105 execution_time: Duration::from_micros(10),
1106 };
1107
1108 assert!(!result.passed);
1109 assert!(result.error.is_some());
1110 }
1111
1112 #[test]
1113 fn test_validation_summary_creation() {
1114 let summary = ValidationSummary {
1115 total_rules: 10,
1116 passed_rules: 8,
1117 failed_rules: 2,
1118 critical_issues: 1,
1119 errors: 1,
1120 warnings: 0,
1121 quality_score: 0.8,
1122 };
1123
1124 assert_eq!(summary.total_rules, 10);
1125 assert_eq!(summary.passed_rules, 8);
1126 assert!((summary.quality_score - 0.8).abs() < f64::EPSILON);
1127 }
1128
1129 #[test]
1130 fn test_operation_metrics_creation() {
1131 let metrics = OperationMetrics {
1132 avg_duration: Duration::from_micros(50),
1133 peak_memory: 1024,
1134 success_rate: 0.95,
1135 allocation_count: 100,
1136 cpu_usage: 5.0,
1137 };
1138
1139 assert_eq!(metrics.avg_duration, Duration::from_micros(50));
1140 assert_eq!(metrics.allocation_count, 100);
1141 }
1142
1143 #[test]
1144 fn test_memory_info_creation() {
1145 let info = MemoryInfo {
1146 current_usage: 1024,
1147 peak_usage: 2048,
1148 active_allocations: 10,
1149 fragmentation_ratio: 0.1,
1150 growth_rate: 100.0,
1151 };
1152
1153 assert_eq!(info.current_usage, 1024);
1154 assert_eq!(info.peak_usage, 2048);
1155 }
1156
1157 #[test]
1158 fn test_error_handling_info_creation() {
1159 let info = ErrorHandlingInfo {
1160 has_error_handling: true,
1161 error_points: 5,
1162 handled_error_points: 4,
1163 has_recovery: true,
1164 };
1165
1166 assert!(info.has_error_handling);
1167 assert_eq!(info.error_points, 5);
1168 }
1169
1170 #[test]
1171 fn test_thread_safety_info_creation() {
1172 let info = ThreadSafetyInfo {
1173 is_thread_safe: true,
1174 shared_resources: 3,
1175 has_synchronization: true,
1176 contention_level: 0.1,
1177 };
1178
1179 assert!(info.is_thread_safe);
1180 assert_eq!(info.shared_resources, 3);
1181 }
1182
1183 #[test]
1184 fn test_validation_result_creation() {
1185 let result = ValidationResult {
1186 status: ValidationStatus::Passed,
1187 rule_results: vec![],
1188 summary: ValidationSummary {
1189 total_rules: 0,
1190 passed_rules: 0,
1191 failed_rules: 0,
1192 critical_issues: 0,
1193 errors: 0,
1194 warnings: 0,
1195 quality_score: 1.0,
1196 },
1197 validation_overhead: Duration::from_micros(100),
1198 };
1199
1200 assert_eq!(result.status, ValidationStatus::Passed);
1201 assert!(result.rule_results.is_empty());
1202 }
1203
1204 #[test]
1205 fn test_validation_status_equality() {
1206 assert_eq!(ValidationStatus::Passed, ValidationStatus::Passed);
1207 assert_ne!(ValidationStatus::Passed, ValidationStatus::ErrorsFound);
1208 }
1209
1210 #[test]
1211 fn test_rule_stats_creation() {
1212 let stats = RuleStats {
1213 execution_count: 10,
1214 total_time: Duration::from_millis(100),
1215 failure_count: 2,
1216 avg_time: Duration::from_millis(10),
1217 };
1218
1219 assert_eq!(stats.execution_count, 10);
1220 assert_eq!(stats.failure_count, 2);
1221 }
1222
1223 #[test]
1224 fn test_disabled_rule_not_executed() {
1225 let mut validator = QualityValidator::new();
1226 validator.set_rule_enabled("memory_leak_check", false);
1227
1228 let mut context = create_passing_context();
1229 context.memory_info.growth_rate = 20.0 * 1024.0 * 1024.0;
1230
1231 let result = validator.validate(&context);
1232 assert_ne!(result.status, ValidationStatus::CriticalIssuesFound);
1233 }
1234
1235 #[test]
1236 fn test_multiple_validations_accumulate_stats() {
1237 let mut validator = QualityValidator::new();
1238 let context = create_passing_context();
1239
1240 validator.validate(&context);
1241 validator.validate(&context);
1242 validator.validate(&context);
1243
1244 let stats = validator.get_rule_statistics();
1245 for stat in stats.values() {
1246 assert_eq!(stat.execution_count, 3);
1247 }
1248 }
1249
1250 #[test]
1251 fn test_validation_rule_debug() {
1252 let rule = ValidationRule {
1253 id: "test".to_string(),
1254 name: "Test".to_string(),
1255 description: String::new(),
1256 category: RuleCategory::MemorySafety,
1257 severity: ValidationSeverity::Info,
1258 enabled: true,
1259 validator: |_| Ok(()),
1260 };
1261
1262 let debug_str = format!("{:?}", rule);
1263 assert!(debug_str.contains("ValidationRule"));
1264 }
1265
1266 #[test]
1267 fn test_validation_rule_clone() {
1268 let rule = ValidationRule {
1269 id: "test".to_string(),
1270 name: "Test".to_string(),
1271 description: String::new(),
1272 category: RuleCategory::MemorySafety,
1273 severity: ValidationSeverity::Info,
1274 enabled: true,
1275 validator: |_| Ok(()),
1276 };
1277
1278 let cloned = rule.clone();
1279 assert_eq!(cloned.id, rule.id);
1280 assert_eq!(cloned.severity, rule.severity);
1281 }
1282
1283 #[test]
1284 fn test_validation_context_debug() {
1285 let context = create_passing_context();
1286 let debug_str = format!("{:?}", context);
1287 assert!(debug_str.contains("ValidationContext"));
1288 }
1289
1290 #[test]
1291 fn test_zero_error_points_coverage() {
1292 let mut context = create_passing_context();
1293 context.error_handling.error_points = 0;
1294 context.error_handling.handled_error_points = 0;
1295
1296 let result = validate_error_handling(&context);
1297 assert!(result.is_ok());
1298 }
1299
1300 #[test]
1301 fn test_quality_score_calculation() {
1302 let mut validator = QualityValidator::new();
1303 let context = create_passing_context();
1304
1305 let result = validator.validate(&context);
1306 let expected_score = result.summary.passed_rules as f64 / result.summary.total_rules as f64;
1307 assert!((result.summary.quality_score - expected_score).abs() < f64::EPSILON);
1308 }
1309
1310 fn create_passing_context() -> ValidationContext {
1311 ValidationContext {
1312 operation_name: "test_operation".to_string(),
1313 metrics: OperationMetrics {
1314 avg_duration: Duration::from_micros(10),
1315 peak_memory: 100,
1316 success_rate: 0.99,
1317 allocation_count: 10,
1318 cpu_usage: 1.0,
1319 },
1320 memory_info: MemoryInfo {
1321 current_usage: 1024 * 1024,
1322 peak_usage: 2 * 1024 * 1024,
1323 active_allocations: 10,
1324 fragmentation_ratio: 0.1,
1325 growth_rate: 0.0,
1326 },
1327 error_handling: ErrorHandlingInfo {
1328 has_error_handling: true,
1329 error_points: 10,
1330 handled_error_points: 10,
1331 has_recovery: true,
1332 },
1333 thread_safety: ThreadSafetyInfo {
1334 is_thread_safe: true,
1335 shared_resources: 0,
1336 has_synchronization: true,
1337 contention_level: 0.0,
1338 },
1339 }
1340 }
1341}