1use std::collections::HashMap;
2use std::time::{Duration, Instant};
3
4pub struct CodeAnalyzer {
6 config: AnalyzerConfig,
8 history: AnalysisHistory,
10 baselines: HashMap<String, QualityBaseline>,
12}
13
14#[derive(Debug, Clone)]
16pub struct AnalyzerConfig {
17 pub analysis_depth: AnalysisDepth,
19 pub track_trends: bool,
21 pub max_analysis_time: Duration,
23 pub thresholds: QualityThresholds,
25}
26
27#[derive(Debug, Clone, PartialEq)]
29pub enum AnalysisDepth {
30 Surface,
32 Standard,
34 Deep,
36 Exhaustive,
38}
39
40#[derive(Debug, Clone)]
42pub struct QualityThresholds {
43 pub min_quality_score: f64,
45 pub max_complexity: u32,
47 pub min_coverage: f64,
49 pub max_technical_debt: f64,
51}
52
53#[derive(Debug)]
55struct AnalysisHistory {
56 results: Vec<AnalysisResult>,
58 max_entries: usize,
60}
61
62#[derive(Debug, Clone)]
64pub struct QualityBaseline {
65 pub component: String,
67 pub quality_score: f64,
69 pub complexity: u32,
71 pub performance: BaselinePerformance,
73 pub timestamp: Instant,
75}
76
77#[derive(Debug, Clone)]
79pub struct BaselinePerformance {
80 pub avg_execution_time: Duration,
82 pub memory_per_operation: usize,
84 pub error_rate: f64,
86}
87
88#[derive(Debug, Clone)]
90pub struct AnalysisReport {
91 pub component: String,
93 pub quality_assessment: QualityAssessment,
95 pub metrics: Vec<QualityMetric>,
97 pub issues: Vec<QualityIssue>,
99 pub performance_analysis: PerformanceAnalysis,
101 pub recommendations: Vec<Recommendation>,
103 pub trend_analysis: Option<TrendAnalysis>,
105 pub analysis_duration: Duration,
107}
108
109#[derive(Debug, Clone)]
111pub struct QualityAssessment {
112 pub overall_score: f64,
114 pub grade: QualityGrade,
116 pub confidence: f64,
118 pub strengths: Vec<String>,
120 pub weaknesses: Vec<String>,
122}
123
124#[derive(Debug, Clone, PartialEq)]
126pub enum QualityGrade {
127 A,
129 B,
131 C,
133 D,
135 F,
137}
138
139impl PartialOrd for QualityGrade {
140 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
141 Some(self.cmp(other))
142 }
143}
144
145impl Ord for QualityGrade {
146 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
147 let self_score = match self {
148 QualityGrade::A => 5,
149 QualityGrade::B => 4,
150 QualityGrade::C => 3,
151 QualityGrade::D => 2,
152 QualityGrade::F => 1,
153 };
154 let other_score = match other {
155 QualityGrade::A => 5,
156 QualityGrade::B => 4,
157 QualityGrade::C => 3,
158 QualityGrade::D => 2,
159 QualityGrade::F => 1,
160 };
161 self_score.cmp(&other_score)
162 }
163}
164
165impl Eq for QualityGrade {}
166
167#[derive(Debug, Clone)]
169pub struct QualityMetric {
170 pub name: String,
172 pub category: MetricCategory,
174 pub value: f64,
176 pub target: f64,
178 pub meets_target: bool,
180 pub weight: f64,
182 pub trend: TrendDirection,
184}
185
186#[derive(Debug, Clone, PartialEq)]
188pub enum MetricCategory {
189 Performance,
191 Reliability,
193 Maintainability,
195 Security,
197 Efficiency,
199}
200
201#[derive(Debug, Clone)]
203pub struct QualityIssue {
204 pub id: String,
206 pub title: String,
208 pub description: String,
210 pub severity: IssueSeverity,
212 pub category: IssueCategory,
214 pub location: Option<String>,
216 pub fix_effort: FixEffort,
218 pub impact: ImpactLevel,
220}
221
222#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
224pub enum IssueSeverity {
225 Minor,
227 Moderate,
229 Major,
231 Critical,
233 Blocker,
235}
236
237#[derive(Debug, Clone, PartialEq)]
239pub enum IssueCategory {
240 MemoryManagement,
242 Performance,
244 ThreadSafety,
246 ErrorHandling,
248 CodeStyle,
250 Design,
252}
253
254#[derive(Debug, Clone, PartialEq)]
256pub enum FixEffort {
257 Trivial,
259 Easy,
261 Medium,
263 Hard,
265 VeryHard,
267}
268
269#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
271pub enum ImpactLevel {
272 Minimal,
274 Low,
276 Medium,
278 High,
280 Critical,
282}
283
284#[derive(Debug, Clone)]
286pub struct PerformanceAnalysis {
287 pub score: f64,
289 pub bottlenecks: Vec<PerformanceBottleneck>,
291 pub memory_efficiency: f64,
293 pub cpu_efficiency: f64,
295 pub scalability: ScalabilityAssessment,
297}
298
299#[derive(Debug, Clone)]
301pub struct PerformanceBottleneck {
302 pub location: String,
304 pub bottleneck_type: BottleneckType,
306 pub severity: f64,
308 pub description: String,
310 pub optimization: String,
312}
313
314#[derive(Debug, Clone, PartialEq)]
316pub enum BottleneckType {
317 CpuBound,
319 MemoryBound,
321 IoBound,
323 LockContention,
325 CacheMiss,
327 AlgorithmInefficiency,
329}
330
331#[derive(Debug, Clone)]
333pub struct ScalabilityAssessment {
334 pub score: f64,
336 pub scaling_behavior: ScalingBehavior,
338 pub resource_scaling: ResourceScaling,
340 pub limitations: Vec<String>,
342}
343
344#[derive(Debug, Clone, PartialEq)]
346pub enum ScalingBehavior {
347 Constant,
349 Linear,
351 Logarithmic,
353 Quadratic,
355 Exponential,
357}
358
359#[derive(Debug, Clone)]
361pub struct ResourceScaling {
362 pub memory_factor: f64,
364 pub cpu_factor: f64,
366 pub network_factor: f64,
368}
369
370#[derive(Debug, Clone)]
372pub struct Recommendation {
373 pub title: String,
375 pub description: String,
377 pub priority: RecommendationPriority,
379 pub impact: ImpactLevel,
381 pub effort: FixEffort,
383 pub related_issues: Vec<String>,
385}
386
387#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
389pub enum RecommendationPriority {
390 Low,
392 Medium,
394 High,
396 Critical,
398}
399
400#[derive(Debug, Clone)]
402pub struct TrendAnalysis {
403 pub quality_trend: TrendDirection,
405 pub performance_trend: TrendDirection,
407 pub complexity_trend: TrendDirection,
409 pub confidence: f64,
411 pub time_period: Duration,
413}
414
415#[derive(Debug, Clone, PartialEq)]
417pub enum TrendDirection {
418 Improving,
420 Stable,
422 Declining,
424 Unknown,
426}
427
428#[derive(Debug, Clone)]
430struct AnalysisResult {
431 component: String,
432 quality_score: f64,
433}
434
435impl CodeAnalyzer {
436 pub fn new() -> Self {
438 Self {
439 config: AnalyzerConfig::default(),
440 history: AnalysisHistory {
441 results: Vec::new(),
442 max_entries: 100,
443 },
444 baselines: HashMap::new(),
445 }
446 }
447
448 pub fn with_config(config: AnalyzerConfig) -> Self {
450 Self {
451 config,
452 history: AnalysisHistory {
453 results: Vec::new(),
454 max_entries: 100,
455 },
456 baselines: HashMap::new(),
457 }
458 }
459
460 pub fn set_baseline(&mut self, component: &str, baseline: QualityBaseline) {
462 self.baselines.insert(component.to_string(), baseline);
463 }
464
465 pub fn analyze_quality(
467 &mut self,
468 component: &str,
469 context: &AnalysisContext,
470 ) -> AnalysisReport {
471 let start_time = Instant::now();
472
473 let metrics = self.calculate_quality_metrics(context);
475 let issues = self.detect_quality_issues(context);
476 let performance_analysis = self.analyze_performance(context);
477 let quality_assessment = self.assess_overall_quality(&metrics, &issues);
478 let recommendations = self.generate_recommendations(&issues, &performance_analysis);
479 let trend_analysis = if self.config.track_trends {
480 Some(self.analyze_trends(component))
481 } else {
482 None
483 };
484
485 let analysis_duration = start_time.elapsed();
486
487 self.store_analysis_result(component, &quality_assessment, &metrics);
489
490 AnalysisReport {
491 component: component.to_string(),
492 quality_assessment,
493 metrics,
494 issues,
495 performance_analysis,
496 recommendations,
497 trend_analysis,
498 analysis_duration,
499 }
500 }
501
502 fn calculate_quality_metrics(&self, context: &AnalysisContext) -> Vec<QualityMetric> {
503 vec![
504 QualityMetric {
506 name: "allocation_efficiency".to_string(),
507 category: MetricCategory::Performance,
508 value: context.performance_data.allocation_efficiency,
509 target: 0.95,
510 meets_target: context.performance_data.allocation_efficiency >= 0.95,
511 weight: 0.3,
512 trend: TrendDirection::Unknown,
513 },
514 QualityMetric {
516 name: "error_rate".to_string(),
517 category: MetricCategory::Reliability,
518 value: context.reliability_data.error_rate,
519 target: 0.01, meets_target: context.reliability_data.error_rate <= 0.01,
521 weight: 0.25,
522 trend: TrendDirection::Unknown,
523 },
524 QualityMetric {
526 name: "memory_efficiency".to_string(),
527 category: MetricCategory::Efficiency,
528 value: context.memory_data.efficiency_ratio,
529 target: 0.9,
530 meets_target: context.memory_data.efficiency_ratio >= 0.9,
531 weight: 0.2,
532 trend: TrendDirection::Unknown,
533 },
534 ]
535 }
536
537 fn detect_quality_issues(&self, context: &AnalysisContext) -> Vec<QualityIssue> {
538 let mut issues = Vec::new();
539
540 if context.memory_data.growth_rate > 1024.0 * 1024.0 {
542 issues.push(QualityIssue {
544 id: "memory_leak_detected".to_string(),
545 title: "Potential Memory Leak".to_string(),
546 description: format!(
547 "High memory growth rate: {:.2}MB/sec",
548 context.memory_data.growth_rate / (1024.0 * 1024.0)
549 ),
550 severity: IssueSeverity::Major,
551 category: IssueCategory::MemoryManagement,
552 location: Some("memory_tracking".to_string()),
553 fix_effort: FixEffort::Medium,
554 impact: ImpactLevel::High,
555 });
556 }
557
558 if context.performance_data.avg_latency > Duration::from_micros(100) {
560 issues.push(QualityIssue {
561 id: "high_latency".to_string(),
562 title: "High Operation Latency".to_string(),
563 description: format!(
564 "Average latency {:.2}µs exceeds threshold",
565 context.performance_data.avg_latency.as_micros()
566 ),
567 severity: IssueSeverity::Moderate,
568 category: IssueCategory::Performance,
569 location: Some("allocation_tracking".to_string()),
570 fix_effort: FixEffort::Easy,
571 impact: ImpactLevel::Medium,
572 });
573 }
574
575 issues
576 }
577
578 fn analyze_performance(&self, context: &AnalysisContext) -> PerformanceAnalysis {
579 let bottlenecks = self.identify_bottlenecks(context);
580 let memory_efficiency = context.memory_data.efficiency_ratio;
581 let cpu_efficiency = 1.0 - (context.performance_data.cpu_usage / 100.0);
582
583 let scalability = ScalabilityAssessment {
584 score: 0.8, scaling_behavior: ScalingBehavior::Linear,
586 resource_scaling: ResourceScaling {
587 memory_factor: 1.2,
588 cpu_factor: 1.1,
589 network_factor: 1.0,
590 },
591 limitations: vec!["Memory bandwidth may become bottleneck at scale".to_string()],
592 };
593
594 let score = (memory_efficiency + cpu_efficiency + scalability.score) / 3.0;
595
596 PerformanceAnalysis {
597 score,
598 bottlenecks,
599 memory_efficiency,
600 cpu_efficiency,
601 scalability,
602 }
603 }
604
605 fn identify_bottlenecks(&self, context: &AnalysisContext) -> Vec<PerformanceBottleneck> {
606 let mut bottlenecks = Vec::new();
607
608 if context.performance_data.cpu_usage > 80.0 {
609 bottlenecks.push(PerformanceBottleneck {
610 location: "allocation_tracking".to_string(),
611 bottleneck_type: BottleneckType::CpuBound,
612 severity: context.performance_data.cpu_usage / 100.0,
613 description: "High CPU usage in allocation tracking".to_string(),
614 optimization: "Consider optimizing hot paths or using faster data structures"
615 .to_string(),
616 });
617 }
618
619 if context.memory_data.fragmentation_ratio > 0.3 {
620 bottlenecks.push(PerformanceBottleneck {
621 location: "memory_management".to_string(),
622 bottleneck_type: BottleneckType::MemoryBound,
623 severity: context.memory_data.fragmentation_ratio,
624 description: "High memory fragmentation".to_string(),
625 optimization: "Implement memory compaction or use memory pools".to_string(),
626 });
627 }
628
629 bottlenecks
630 }
631
632 fn assess_overall_quality(
633 &self,
634 metrics: &[QualityMetric],
635 issues: &[QualityIssue],
636 ) -> QualityAssessment {
637 let weighted_score: f64 = metrics
639 .iter()
640 .map(|m| {
641 if m.meets_target {
642 m.weight
643 } else {
644 m.weight * (m.value / m.target)
645 }
646 })
647 .sum();
648
649 let total_weight: f64 = metrics.iter().map(|m| m.weight).sum();
650 let overall_score = if total_weight > 0.0 {
651 weighted_score / total_weight
652 } else {
653 0.0
654 };
655
656 let critical_penalty = issues
658 .iter()
659 .filter(|i| i.severity >= IssueSeverity::Critical)
660 .count() as f64
661 * 0.1;
662
663 let adjusted_score = (overall_score - critical_penalty).max(0.0);
664
665 let grade = match adjusted_score {
666 s if s >= 0.9 => QualityGrade::A,
667 s if s >= 0.8 => QualityGrade::B,
668 s if s >= 0.7 => QualityGrade::C,
669 s if s >= 0.6 => QualityGrade::D,
670 _ => QualityGrade::F,
671 };
672
673 let strengths = metrics
674 .iter()
675 .filter(|m| m.meets_target && m.value > m.target * 1.1)
676 .map(|m| format!("Excellent {}", m.name))
677 .collect();
678
679 let weaknesses = issues
680 .iter()
681 .filter(|i| i.severity >= IssueSeverity::Major)
682 .map(|i| i.title.clone())
683 .collect();
684
685 QualityAssessment {
686 overall_score: adjusted_score,
687 grade,
688 confidence: 0.85, strengths,
690 weaknesses,
691 }
692 }
693
694 fn generate_recommendations(
695 &self,
696 issues: &[QualityIssue],
697 performance: &PerformanceAnalysis,
698 ) -> Vec<Recommendation> {
699 let mut recommendations = Vec::new();
700
701 for issue in issues {
703 if issue.severity >= IssueSeverity::Major {
704 recommendations.push(Recommendation {
705 title: format!("Fix {}", issue.title),
706 description: format!("Address {} to improve quality", issue.description),
707 priority: match issue.severity {
708 IssueSeverity::Critical | IssueSeverity::Blocker => {
709 RecommendationPriority::Critical
710 }
711 IssueSeverity::Major => RecommendationPriority::High,
712 _ => RecommendationPriority::Medium,
713 },
714 impact: issue.impact.clone(),
715 effort: issue.fix_effort.clone(),
716 related_issues: vec![issue.id.clone()],
717 });
718 }
719 }
720
721 if performance.score < 0.8 {
723 recommendations.push(Recommendation {
724 title: "Improve Performance".to_string(),
725 description: "Overall performance score is below target".to_string(),
726 priority: RecommendationPriority::High,
727 impact: ImpactLevel::High,
728 effort: FixEffort::Medium,
729 related_issues: vec![],
730 });
731 }
732
733 recommendations
734 }
735
736 fn analyze_trends(&self, component: &str) -> TrendAnalysis {
737 let recent_results: Vec<_> = self
738 .history
739 .results
740 .iter()
741 .filter(|r| r.component == component)
742 .rev()
743 .take(10)
744 .collect();
745
746 if recent_results.len() < 3 {
747 return TrendAnalysis {
748 quality_trend: TrendDirection::Unknown,
749 performance_trend: TrendDirection::Unknown,
750 complexity_trend: TrendDirection::Unknown,
751 confidence: 0.0,
752 time_period: Duration::ZERO,
753 };
754 }
755
756 let scores: Vec<f64> = recent_results.iter().map(|r| r.quality_score).collect();
758 let quality_trend = if scores.first() > scores.last() {
759 TrendDirection::Improving
760 } else if scores.first() < scores.last() {
761 TrendDirection::Declining
762 } else {
763 TrendDirection::Stable
764 };
765
766 TrendAnalysis {
767 quality_trend,
768 performance_trend: TrendDirection::Stable,
769 complexity_trend: TrendDirection::Stable,
770 confidence: 0.7,
771 time_period: Duration::from_secs(3600), }
773 }
774
775 fn store_analysis_result(
776 &mut self,
777 component: &str,
778 assessment: &QualityAssessment,
779 _metrics: &[QualityMetric],
780 ) {
781 let result = AnalysisResult {
782 component: component.to_string(),
783 quality_score: assessment.overall_score,
784 };
785
786 self.history.results.push(result);
787
788 if self.history.results.len() > self.history.max_entries {
790 self.history
791 .results
792 .drain(0..self.history.results.len() - self.history.max_entries);
793 }
794 }
795}
796
797#[derive(Debug)]
799pub struct AnalysisContext {
800 pub performance_data: PerformanceData,
802 pub memory_data: MemoryData,
804 pub reliability_data: ReliabilityData,
806}
807
808#[derive(Debug)]
810pub struct PerformanceData {
811 pub avg_latency: Duration,
813 pub cpu_usage: f64,
815 pub allocation_efficiency: f64,
817 pub throughput: f64,
819}
820
821#[derive(Debug)]
823pub struct MemoryData {
824 pub current_usage: usize,
826 pub growth_rate: f64,
828 pub efficiency_ratio: f64,
830 pub fragmentation_ratio: f64,
832}
833
834#[derive(Debug)]
836pub struct ReliabilityData {
837 pub error_rate: f64,
839 pub success_rate: f64,
841 pub mtbf: Duration,
843}
844
845impl Default for AnalyzerConfig {
846 fn default() -> Self {
847 Self {
848 analysis_depth: AnalysisDepth::Standard,
849 track_trends: true,
850 max_analysis_time: Duration::from_secs(30),
851 thresholds: QualityThresholds::default(),
852 }
853 }
854}
855
856impl Default for QualityThresholds {
857 fn default() -> Self {
858 Self {
859 min_quality_score: 0.8,
860 max_complexity: 10,
861 min_coverage: 0.8,
862 max_technical_debt: 0.2,
863 }
864 }
865}
866
867impl Default for CodeAnalyzer {
868 fn default() -> Self {
869 Self::new()
870 }
871}
872
873#[cfg(test)]
874mod tests {
875 use super::*;
876
877 #[test]
878 fn test_code_analyzer_creation() {
879 let analyzer = CodeAnalyzer::new();
880 assert_eq!(analyzer.config.analysis_depth, AnalysisDepth::Standard);
881 assert!(analyzer.config.track_trends);
882 }
883
884 #[test]
885 fn test_quality_assessment() {
886 let analyzer = CodeAnalyzer::new();
887
888 let metrics = vec![QualityMetric {
889 name: "test_metric".to_string(),
890 category: MetricCategory::Performance,
891 value: 0.9,
892 target: 0.8,
893 meets_target: true,
894 weight: 1.0,
895 trend: TrendDirection::Stable,
896 }];
897
898 let issues = vec![];
899 let assessment = analyzer.assess_overall_quality(&metrics, &issues);
900
901 assert!(assessment.overall_score >= 0.8);
902 assert_eq!(assessment.grade, QualityGrade::A);
903 }
904
905 #[test]
906 fn test_quality_grades() {
907 assert!(QualityGrade::A > QualityGrade::B);
908 assert!(QualityGrade::B > QualityGrade::C);
909 assert!(QualityGrade::F < QualityGrade::D);
910 }
911
912 #[test]
913 fn test_code_analyzer_default() {
914 let analyzer = CodeAnalyzer::default();
915 assert_eq!(analyzer.config.analysis_depth, AnalysisDepth::Standard);
916 }
917
918 #[test]
919 fn test_code_analyzer_with_config() {
920 let config = AnalyzerConfig {
921 analysis_depth: AnalysisDepth::Deep,
922 track_trends: false,
923 max_analysis_time: Duration::from_secs(60),
924 thresholds: QualityThresholds::default(),
925 };
926 let analyzer = CodeAnalyzer::with_config(config.clone());
927 assert_eq!(analyzer.config.analysis_depth, AnalysisDepth::Deep);
928 assert!(!analyzer.config.track_trends);
929 }
930
931 #[test]
932 fn test_analyzer_config_default() {
933 let config = AnalyzerConfig::default();
934 assert_eq!(config.analysis_depth, AnalysisDepth::Standard);
935 assert!(config.track_trends);
936 assert_eq!(config.max_analysis_time, Duration::from_secs(30));
937 }
938
939 #[test]
940 fn test_quality_thresholds_default() {
941 let thresholds = QualityThresholds::default();
942 assert!((thresholds.min_quality_score - 0.8).abs() < f64::EPSILON);
943 assert_eq!(thresholds.max_complexity, 10);
944 assert!((thresholds.min_coverage - 0.8).abs() < f64::EPSILON);
945 }
946
947 #[test]
948 fn test_analysis_depth_variants() {
949 let depths = vec![
950 AnalysisDepth::Surface,
951 AnalysisDepth::Standard,
952 AnalysisDepth::Deep,
953 AnalysisDepth::Exhaustive,
954 ];
955
956 for depth in depths {
957 let config = AnalyzerConfig {
958 analysis_depth: depth.clone(),
959 ..Default::default()
960 };
961 assert_eq!(config.analysis_depth, depth);
962 }
963 }
964
965 #[test]
966 fn test_metric_category_variants() {
967 let categories = vec![
968 MetricCategory::Performance,
969 MetricCategory::Reliability,
970 MetricCategory::Maintainability,
971 MetricCategory::Security,
972 MetricCategory::Efficiency,
973 ];
974
975 for category in categories {
976 let metric = QualityMetric {
977 name: String::new(),
978 category: category.clone(),
979 value: 0.0,
980 target: 0.0,
981 meets_target: false,
982 weight: 0.0,
983 trend: TrendDirection::Unknown,
984 };
985 assert_eq!(metric.category, category);
986 }
987 }
988
989 #[test]
990 fn test_issue_severity_ordering() {
991 assert!(IssueSeverity::Blocker > IssueSeverity::Critical);
992 assert!(IssueSeverity::Critical > IssueSeverity::Major);
993 assert!(IssueSeverity::Major > IssueSeverity::Moderate);
994 assert!(IssueSeverity::Moderate > IssueSeverity::Minor);
995 }
996
997 #[test]
998 fn test_issue_category_variants() {
999 let categories = vec![
1000 IssueCategory::MemoryManagement,
1001 IssueCategory::Performance,
1002 IssueCategory::ThreadSafety,
1003 IssueCategory::ErrorHandling,
1004 IssueCategory::CodeStyle,
1005 IssueCategory::Design,
1006 ];
1007
1008 for category in categories {
1009 let issue = QualityIssue {
1010 id: String::new(),
1011 title: String::new(),
1012 description: String::new(),
1013 severity: IssueSeverity::Minor,
1014 category: category.clone(),
1015 location: None,
1016 fix_effort: FixEffort::Trivial,
1017 impact: ImpactLevel::Minimal,
1018 };
1019 assert_eq!(issue.category, category);
1020 }
1021 }
1022
1023 #[test]
1024 fn test_fix_effort_variants() {
1025 let efforts = vec![
1026 FixEffort::Trivial,
1027 FixEffort::Easy,
1028 FixEffort::Medium,
1029 FixEffort::Hard,
1030 FixEffort::VeryHard,
1031 ];
1032
1033 for effort in efforts {
1034 let issue = QualityIssue {
1035 id: String::new(),
1036 title: String::new(),
1037 description: String::new(),
1038 severity: IssueSeverity::Minor,
1039 category: IssueCategory::CodeStyle,
1040 location: None,
1041 fix_effort: effort.clone(),
1042 impact: ImpactLevel::Minimal,
1043 };
1044 assert_eq!(issue.fix_effort, effort);
1045 }
1046 }
1047
1048 #[test]
1049 fn test_impact_level_ordering() {
1050 assert!(ImpactLevel::Critical > ImpactLevel::High);
1051 assert!(ImpactLevel::High > ImpactLevel::Medium);
1052 assert!(ImpactLevel::Medium > ImpactLevel::Low);
1053 assert!(ImpactLevel::Low > ImpactLevel::Minimal);
1054 }
1055
1056 #[test]
1057 fn test_trend_direction_variants() {
1058 let trends = vec![
1059 TrendDirection::Improving,
1060 TrendDirection::Stable,
1061 TrendDirection::Declining,
1062 TrendDirection::Unknown,
1063 ];
1064
1065 for trend in trends {
1066 let metric = QualityMetric {
1067 name: String::new(),
1068 category: MetricCategory::Performance,
1069 value: 0.0,
1070 target: 0.0,
1071 meets_target: false,
1072 weight: 0.0,
1073 trend: trend.clone(),
1074 };
1075 assert_eq!(metric.trend, trend);
1076 }
1077 }
1078
1079 #[test]
1080 fn test_bottleneck_type_variants() {
1081 let types = vec![
1082 BottleneckType::CpuBound,
1083 BottleneckType::MemoryBound,
1084 BottleneckType::IoBound,
1085 BottleneckType::LockContention,
1086 BottleneckType::CacheMiss,
1087 BottleneckType::AlgorithmInefficiency,
1088 ];
1089
1090 for bottleneck_type in types {
1091 let bottleneck = PerformanceBottleneck {
1092 location: String::new(),
1093 bottleneck_type: bottleneck_type.clone(),
1094 severity: 0.0,
1095 description: String::new(),
1096 optimization: String::new(),
1097 };
1098 assert_eq!(bottleneck.bottleneck_type, bottleneck_type);
1099 }
1100 }
1101
1102 #[test]
1103 fn test_scaling_behavior_variants() {
1104 let behaviors = vec![
1105 ScalingBehavior::Constant,
1106 ScalingBehavior::Linear,
1107 ScalingBehavior::Logarithmic,
1108 ScalingBehavior::Quadratic,
1109 ScalingBehavior::Exponential,
1110 ];
1111
1112 for behavior in behaviors {
1113 let assessment = ScalabilityAssessment {
1114 score: 0.0,
1115 scaling_behavior: behavior.clone(),
1116 resource_scaling: ResourceScaling {
1117 memory_factor: 0.0,
1118 cpu_factor: 0.0,
1119 network_factor: 0.0,
1120 },
1121 limitations: vec![],
1122 };
1123 assert_eq!(assessment.scaling_behavior, behavior);
1124 }
1125 }
1126
1127 #[test]
1128 fn test_recommendation_priority_ordering() {
1129 assert!(RecommendationPriority::Critical > RecommendationPriority::High);
1130 assert!(RecommendationPriority::High > RecommendationPriority::Medium);
1131 assert!(RecommendationPriority::Medium > RecommendationPriority::Low);
1132 }
1133
1134 #[test]
1135 fn test_set_baseline() {
1136 let mut analyzer = CodeAnalyzer::new();
1137 let baseline = QualityBaseline {
1138 component: "test_component".to_string(),
1139 quality_score: 0.9,
1140 complexity: 5,
1141 performance: BaselinePerformance {
1142 avg_execution_time: Duration::from_millis(100),
1143 memory_per_operation: 1024,
1144 error_rate: 0.01,
1145 },
1146 timestamp: Instant::now(),
1147 };
1148
1149 analyzer.set_baseline("test_component", baseline);
1150 }
1151
1152 #[test]
1153 fn test_analyze_quality_basic() {
1154 let mut analyzer = CodeAnalyzer::new();
1155 let context = AnalysisContext {
1156 performance_data: PerformanceData {
1157 avg_latency: Duration::from_micros(50),
1158 cpu_usage: 50.0,
1159 allocation_efficiency: 0.95,
1160 throughput: 1000.0,
1161 },
1162 memory_data: MemoryData {
1163 current_usage: 1024 * 1024,
1164 growth_rate: 100.0,
1165 efficiency_ratio: 0.9,
1166 fragmentation_ratio: 0.1,
1167 },
1168 reliability_data: ReliabilityData {
1169 error_rate: 0.005,
1170 success_rate: 0.995,
1171 mtbf: Duration::from_secs(3600),
1172 },
1173 };
1174
1175 let report = analyzer.analyze_quality("test_component", &context);
1176
1177 assert_eq!(report.component, "test_component");
1178 assert!(!report.metrics.is_empty());
1179 assert!(report.trend_analysis.is_some());
1180 }
1181
1182 #[test]
1183 fn test_analyze_quality_no_trends() {
1184 let config = AnalyzerConfig {
1185 track_trends: false,
1186 ..Default::default()
1187 };
1188 let mut analyzer = CodeAnalyzer::with_config(config);
1189 let context = AnalysisContext {
1190 performance_data: PerformanceData {
1191 avg_latency: Duration::from_micros(50),
1192 cpu_usage: 50.0,
1193 allocation_efficiency: 0.95,
1194 throughput: 1000.0,
1195 },
1196 memory_data: MemoryData {
1197 current_usage: 1024 * 1024,
1198 growth_rate: 100.0,
1199 efficiency_ratio: 0.9,
1200 fragmentation_ratio: 0.1,
1201 },
1202 reliability_data: ReliabilityData {
1203 error_rate: 0.005,
1204 success_rate: 0.995,
1205 mtbf: Duration::from_secs(3600),
1206 },
1207 };
1208
1209 let report = analyzer.analyze_quality("test_component", &context);
1210
1211 assert!(report.trend_analysis.is_none());
1212 }
1213
1214 #[test]
1215 fn test_analyze_quality_memory_leak_detection() {
1216 let mut analyzer = CodeAnalyzer::new();
1217 let context = AnalysisContext {
1218 performance_data: PerformanceData {
1219 avg_latency: Duration::from_micros(50),
1220 cpu_usage: 50.0,
1221 allocation_efficiency: 0.95,
1222 throughput: 1000.0,
1223 },
1224 memory_data: MemoryData {
1225 current_usage: 1024 * 1024,
1226 growth_rate: 2.0 * 1024.0 * 1024.0,
1227 efficiency_ratio: 0.9,
1228 fragmentation_ratio: 0.1,
1229 },
1230 reliability_data: ReliabilityData {
1231 error_rate: 0.005,
1232 success_rate: 0.995,
1233 mtbf: Duration::from_secs(3600),
1234 },
1235 };
1236
1237 let report = analyzer.analyze_quality("test_component", &context);
1238
1239 assert!(!report.issues.is_empty());
1240 assert!(report.issues.iter().any(|i| i.id == "memory_leak_detected"));
1241 }
1242
1243 #[test]
1244 fn test_analyze_quality_high_latency_detection() {
1245 let mut analyzer = CodeAnalyzer::new();
1246 let context = AnalysisContext {
1247 performance_data: PerformanceData {
1248 avg_latency: Duration::from_micros(200),
1249 cpu_usage: 50.0,
1250 allocation_efficiency: 0.95,
1251 throughput: 1000.0,
1252 },
1253 memory_data: MemoryData {
1254 current_usage: 1024 * 1024,
1255 growth_rate: 100.0,
1256 efficiency_ratio: 0.9,
1257 fragmentation_ratio: 0.1,
1258 },
1259 reliability_data: ReliabilityData {
1260 error_rate: 0.005,
1261 success_rate: 0.995,
1262 mtbf: Duration::from_secs(3600),
1263 },
1264 };
1265
1266 let report = analyzer.analyze_quality("test_component", &context);
1267
1268 assert!(!report.issues.is_empty());
1269 assert!(report.issues.iter().any(|i| i.id == "high_latency"));
1270 }
1271
1272 #[test]
1273 fn test_analyze_quality_cpu_bottleneck() {
1274 let mut analyzer = CodeAnalyzer::new();
1275 let context = AnalysisContext {
1276 performance_data: PerformanceData {
1277 avg_latency: Duration::from_micros(50),
1278 cpu_usage: 90.0,
1279 allocation_efficiency: 0.95,
1280 throughput: 1000.0,
1281 },
1282 memory_data: MemoryData {
1283 current_usage: 1024 * 1024,
1284 growth_rate: 100.0,
1285 efficiency_ratio: 0.9,
1286 fragmentation_ratio: 0.1,
1287 },
1288 reliability_data: ReliabilityData {
1289 error_rate: 0.005,
1290 success_rate: 0.995,
1291 mtbf: Duration::from_secs(3600),
1292 },
1293 };
1294
1295 let report = analyzer.analyze_quality("test_component", &context);
1296
1297 assert!(!report.performance_analysis.bottlenecks.is_empty());
1298 assert!(report
1299 .performance_analysis
1300 .bottlenecks
1301 .iter()
1302 .any(|b| matches!(b.bottleneck_type, BottleneckType::CpuBound)));
1303 }
1304
1305 #[test]
1306 fn test_analyze_quality_memory_bottleneck() {
1307 let mut analyzer = CodeAnalyzer::new();
1308 let context = AnalysisContext {
1309 performance_data: PerformanceData {
1310 avg_latency: Duration::from_micros(50),
1311 cpu_usage: 50.0,
1312 allocation_efficiency: 0.95,
1313 throughput: 1000.0,
1314 },
1315 memory_data: MemoryData {
1316 current_usage: 1024 * 1024,
1317 growth_rate: 100.0,
1318 efficiency_ratio: 0.9,
1319 fragmentation_ratio: 0.5,
1320 },
1321 reliability_data: ReliabilityData {
1322 error_rate: 0.005,
1323 success_rate: 0.995,
1324 mtbf: Duration::from_secs(3600),
1325 },
1326 };
1327
1328 let report = analyzer.analyze_quality("test_component", &context);
1329
1330 assert!(!report.performance_analysis.bottlenecks.is_empty());
1331 assert!(report
1332 .performance_analysis
1333 .bottlenecks
1334 .iter()
1335 .any(|b| matches!(b.bottleneck_type, BottleneckType::MemoryBound)));
1336 }
1337
1338 #[test]
1339 fn test_quality_metric_creation() {
1340 let metric = QualityMetric {
1341 name: "test_metric".to_string(),
1342 category: MetricCategory::Performance,
1343 value: 0.85,
1344 target: 0.9,
1345 meets_target: false,
1346 weight: 0.25,
1347 trend: TrendDirection::Improving,
1348 };
1349
1350 assert_eq!(metric.name, "test_metric");
1351 assert!(!metric.meets_target);
1352 }
1353
1354 #[test]
1355 fn test_quality_issue_creation() {
1356 let issue = QualityIssue {
1357 id: "ISSUE-001".to_string(),
1358 title: "Test Issue".to_string(),
1359 description: "Test description".to_string(),
1360 severity: IssueSeverity::Major,
1361 category: IssueCategory::MemoryManagement,
1362 location: Some("src/main.rs:42".to_string()),
1363 fix_effort: FixEffort::Medium,
1364 impact: ImpactLevel::High,
1365 };
1366
1367 assert_eq!(issue.id, "ISSUE-001");
1368 assert!(issue.location.is_some());
1369 }
1370
1371 #[test]
1372 fn test_performance_bottleneck_creation() {
1373 let bottleneck = PerformanceBottleneck {
1374 location: "hot_function".to_string(),
1375 bottleneck_type: BottleneckType::CpuBound,
1376 severity: 0.8,
1377 description: "High CPU usage".to_string(),
1378 optimization: "Use caching".to_string(),
1379 };
1380
1381 assert_eq!(bottleneck.location, "hot_function");
1382 assert!((bottleneck.severity - 0.8).abs() < f64::EPSILON);
1383 }
1384
1385 #[test]
1386 fn test_recommendation_creation() {
1387 let recommendation = Recommendation {
1388 title: "Fix memory leak".to_string(),
1389 description: "Address memory leak in module X".to_string(),
1390 priority: RecommendationPriority::Critical,
1391 impact: ImpactLevel::Critical,
1392 effort: FixEffort::Hard,
1393 related_issues: vec!["ISSUE-001".to_string()],
1394 };
1395
1396 assert_eq!(recommendation.priority, RecommendationPriority::Critical);
1397 assert_eq!(recommendation.related_issues.len(), 1);
1398 }
1399
1400 #[test]
1401 fn test_quality_baseline_creation() {
1402 let baseline = QualityBaseline {
1403 component: "module_a".to_string(),
1404 quality_score: 0.85,
1405 complexity: 7,
1406 performance: BaselinePerformance {
1407 avg_execution_time: Duration::from_millis(50),
1408 memory_per_operation: 2048,
1409 error_rate: 0.02,
1410 },
1411 timestamp: Instant::now(),
1412 };
1413
1414 assert_eq!(baseline.component, "module_a");
1415 assert!((baseline.quality_score - 0.85).abs() < f64::EPSILON);
1416 }
1417
1418 #[test]
1419 fn test_baseline_performance_creation() {
1420 let perf = BaselinePerformance {
1421 avg_execution_time: Duration::from_millis(100),
1422 memory_per_operation: 4096,
1423 error_rate: 0.01,
1424 };
1425
1426 assert_eq!(perf.memory_per_operation, 4096);
1427 assert!((perf.error_rate - 0.01).abs() < f64::EPSILON);
1428 }
1429
1430 #[test]
1431 fn test_scalability_assessment_creation() {
1432 let assessment = ScalabilityAssessment {
1433 score: 0.75,
1434 scaling_behavior: ScalingBehavior::Linear,
1435 resource_scaling: ResourceScaling {
1436 memory_factor: 1.5,
1437 cpu_factor: 1.2,
1438 network_factor: 1.0,
1439 },
1440 limitations: vec!["Memory bandwidth".to_string()],
1441 };
1442
1443 assert!((assessment.score - 0.75).abs() < f64::EPSILON);
1444 assert_eq!(assessment.limitations.len(), 1);
1445 }
1446
1447 #[test]
1448 fn test_resource_scaling_creation() {
1449 let scaling = ResourceScaling {
1450 memory_factor: 2.0,
1451 cpu_factor: 1.5,
1452 network_factor: 1.0,
1453 };
1454
1455 assert!((scaling.memory_factor - 2.0).abs() < f64::EPSILON);
1456 }
1457
1458 #[test]
1459 fn test_trend_analysis_creation() {
1460 let trend = TrendAnalysis {
1461 quality_trend: TrendDirection::Improving,
1462 performance_trend: TrendDirection::Stable,
1463 complexity_trend: TrendDirection::Declining,
1464 confidence: 0.85,
1465 time_period: Duration::from_secs(3600),
1466 };
1467
1468 assert_eq!(trend.quality_trend, TrendDirection::Improving);
1469 assert!((trend.confidence - 0.85).abs() < f64::EPSILON);
1470 }
1471
1472 #[test]
1473 fn test_analysis_context_creation() {
1474 let context = AnalysisContext {
1475 performance_data: PerformanceData {
1476 avg_latency: Duration::from_micros(100),
1477 cpu_usage: 60.0,
1478 allocation_efficiency: 0.9,
1479 throughput: 500.0,
1480 },
1481 memory_data: MemoryData {
1482 current_usage: 2048,
1483 growth_rate: 50.0,
1484 efficiency_ratio: 0.85,
1485 fragmentation_ratio: 0.15,
1486 },
1487 reliability_data: ReliabilityData {
1488 error_rate: 0.01,
1489 success_rate: 0.99,
1490 mtbf: Duration::from_secs(7200),
1491 },
1492 };
1493
1494 assert!((context.performance_data.cpu_usage - 60.0).abs() < f64::EPSILON);
1495 assert_eq!(context.memory_data.current_usage, 2048);
1496 }
1497
1498 #[test]
1499 fn test_performance_data_creation() {
1500 let data = PerformanceData {
1501 avg_latency: Duration::from_micros(75),
1502 cpu_usage: 45.0,
1503 allocation_efficiency: 0.92,
1504 throughput: 750.0,
1505 };
1506
1507 assert_eq!(data.avg_latency, Duration::from_micros(75));
1508 }
1509
1510 #[test]
1511 fn test_memory_data_creation() {
1512 let data = MemoryData {
1513 current_usage: 4096,
1514 growth_rate: 100.0,
1515 efficiency_ratio: 0.88,
1516 fragmentation_ratio: 0.12,
1517 };
1518
1519 assert_eq!(data.current_usage, 4096);
1520 }
1521
1522 #[test]
1523 fn test_reliability_data_creation() {
1524 let data = ReliabilityData {
1525 error_rate: 0.005,
1526 success_rate: 0.995,
1527 mtbf: Duration::from_secs(86400),
1528 };
1529
1530 assert!((data.error_rate - 0.005).abs() < f64::EPSILON);
1531 }
1532
1533 #[test]
1534 fn test_quality_grade_equality() {
1535 assert_eq!(QualityGrade::A, QualityGrade::A);
1536 assert_ne!(QualityGrade::A, QualityGrade::B);
1537 }
1538
1539 #[test]
1540 fn test_quality_grade_ord() {
1541 let grades = vec![
1542 QualityGrade::F,
1543 QualityGrade::D,
1544 QualityGrade::C,
1545 QualityGrade::B,
1546 QualityGrade::A,
1547 ];
1548 let mut sorted = grades.clone();
1549 sorted.sort();
1550 assert_eq!(
1551 sorted,
1552 vec![
1553 QualityGrade::F,
1554 QualityGrade::D,
1555 QualityGrade::C,
1556 QualityGrade::B,
1557 QualityGrade::A
1558 ]
1559 );
1560 }
1561
1562 #[test]
1563 fn test_analysis_report_creation() {
1564 let report = AnalysisReport {
1565 component: "test".to_string(),
1566 quality_assessment: QualityAssessment {
1567 overall_score: 0.85,
1568 grade: QualityGrade::B,
1569 confidence: 0.9,
1570 strengths: vec!["Good performance".to_string()],
1571 weaknesses: vec![],
1572 },
1573 metrics: vec![],
1574 issues: vec![],
1575 performance_analysis: PerformanceAnalysis {
1576 score: 0.8,
1577 bottlenecks: vec![],
1578 memory_efficiency: 0.85,
1579 cpu_efficiency: 0.75,
1580 scalability: ScalabilityAssessment {
1581 score: 0.7,
1582 scaling_behavior: ScalingBehavior::Linear,
1583 resource_scaling: ResourceScaling {
1584 memory_factor: 1.0,
1585 cpu_factor: 1.0,
1586 network_factor: 1.0,
1587 },
1588 limitations: vec![],
1589 },
1590 },
1591 recommendations: vec![],
1592 trend_analysis: None,
1593 analysis_duration: Duration::from_millis(100),
1594 };
1595
1596 assert_eq!(report.component, "test");
1597 }
1598
1599 #[test]
1600 fn test_quality_assessment_creation() {
1601 let assessment = QualityAssessment {
1602 overall_score: 0.92,
1603 grade: QualityGrade::A,
1604 confidence: 0.95,
1605 strengths: vec!["Fast execution".to_string(), "Low memory".to_string()],
1606 weaknesses: vec!["Complex code".to_string()],
1607 };
1608
1609 assert_eq!(assessment.strengths.len(), 2);
1610 assert_eq!(assessment.weaknesses.len(), 1);
1611 }
1612
1613 #[test]
1614 fn test_performance_analysis_creation() {
1615 let analysis = PerformanceAnalysis {
1616 score: 0.88,
1617 bottlenecks: vec![],
1618 memory_efficiency: 0.9,
1619 cpu_efficiency: 0.85,
1620 scalability: ScalabilityAssessment {
1621 score: 0.8,
1622 scaling_behavior: ScalingBehavior::Logarithmic,
1623 resource_scaling: ResourceScaling {
1624 memory_factor: 1.2,
1625 cpu_factor: 1.1,
1626 network_factor: 1.0,
1627 },
1628 limitations: vec![],
1629 },
1630 };
1631
1632 assert!((analysis.score - 0.88).abs() < f64::EPSILON);
1633 }
1634}