use crate::priority::UnifiedAnalysis;
use std::cmp::Ordering;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SortCriteria {
Score,
Coverage,
Complexity,
FilePath,
FunctionName,
}
impl SortCriteria {
pub fn display_name(&self) -> &'static str {
match self {
SortCriteria::Score => "score",
SortCriteria::Coverage => "coverage",
SortCriteria::Complexity => "complexity",
SortCriteria::FilePath => "file path",
SortCriteria::FunctionName => "function name",
}
}
pub fn all() -> &'static [SortCriteria] {
&[
SortCriteria::Score,
SortCriteria::Coverage,
SortCriteria::Complexity,
SortCriteria::FilePath,
SortCriteria::FunctionName,
]
}
}
fn tiebreaker(analysis: &UnifiedAnalysis, a: usize, b: usize) -> Ordering {
let item_a = analysis.items.get(a);
let item_b = analysis.items.get(b);
match (item_a, item_b) {
(Some(a), Some(b)) => {
match a.location.file.cmp(&b.location.file) {
Ordering::Equal => {
a.location.line.cmp(&b.location.line)
}
other => other,
}
}
(None, None) => Ordering::Equal,
(None, Some(_)) => Ordering::Less,
(Some(_), None) => Ordering::Greater,
}
}
pub fn sort_indices(indices: &mut [usize], analysis: &UnifiedAnalysis, criteria: SortCriteria) {
match criteria {
SortCriteria::Score => {
indices.sort_by(|&a, &b| {
let score_a = analysis
.items
.get(a)
.map(|item| item.unified_score.final_score)
.unwrap_or(0.0);
let score_b = analysis
.items
.get(b)
.map(|item| item.unified_score.final_score)
.unwrap_or(0.0);
match score_b.partial_cmp(&score_a).unwrap_or(Ordering::Equal) {
Ordering::Equal => tiebreaker(analysis, a, b),
other => other,
}
});
}
SortCriteria::Coverage => {
indices.sort_by(|&a, &b| {
let cov_a = analysis
.items
.get(a)
.and_then(|item| item.transitive_coverage.as_ref().map(|c| c.direct));
let cov_b = analysis
.items
.get(b)
.and_then(|item| item.transitive_coverage.as_ref().map(|c| c.direct));
let primary = match (cov_a, cov_b) {
(None, None) => Ordering::Equal,
(None, Some(_)) => Ordering::Less, (Some(_), None) => Ordering::Greater,
(Some(a), Some(b)) => a.partial_cmp(&b).unwrap_or(Ordering::Equal),
};
match primary {
Ordering::Equal => tiebreaker(analysis, a, b),
other => other,
}
});
}
SortCriteria::Complexity => {
indices.sort_by(|&a, &b| {
let comp_a = analysis.items.get(a).map(|item| item.cyclomatic_complexity);
let comp_b = analysis.items.get(b).map(|item| item.cyclomatic_complexity);
match comp_b.cmp(&comp_a) {
Ordering::Equal => tiebreaker(analysis, a, b),
other => other,
}
});
}
SortCriteria::FilePath => {
indices.sort_by(|&a, &b| {
let path_a = analysis.items.get(a).map(|item| &item.location.file);
let path_b = analysis.items.get(b).map(|item| &item.location.file);
let primary = match (path_a, path_b) {
(Some(a), Some(b)) => a.cmp(b),
(None, None) => Ordering::Equal,
(None, Some(_)) => Ordering::Less,
(Some(_), None) => Ordering::Greater,
};
match primary {
Ordering::Equal => {
let line_a = analysis.items.get(a).map(|item| item.location.line);
let line_b = analysis.items.get(b).map(|item| item.location.line);
line_a.cmp(&line_b)
}
other => other,
}
});
}
SortCriteria::FunctionName => {
indices.sort_by(|&a, &b| {
let name_a = analysis.items.get(a).map(|item| &item.location.function);
let name_b = analysis.items.get(b).map(|item| &item.location.function);
let primary = match (name_a, name_b) {
(Some(a), Some(b)) => a.cmp(b),
(None, None) => Ordering::Equal,
(None, Some(_)) => Ordering::Less,
(Some(_), None) => Ordering::Greater,
};
match primary {
Ordering::Equal => tiebreaker(analysis, a, b),
other => other,
}
});
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sort_criteria_display() {
assert_eq!(SortCriteria::Score.display_name(), "score");
assert_eq!(SortCriteria::Coverage.display_name(), "coverage");
assert_eq!(SortCriteria::Complexity.display_name(), "complexity");
assert_eq!(SortCriteria::FilePath.display_name(), "file path");
assert_eq!(SortCriteria::FunctionName.display_name(), "function name");
}
#[test]
fn test_all_sort_criteria() {
let all = SortCriteria::all();
assert_eq!(all.len(), 5);
assert!(all.contains(&SortCriteria::Score));
assert!(all.contains(&SortCriteria::Coverage));
assert!(all.contains(&SortCriteria::Complexity));
}
}