use crate::profiles::UserProfile;
use crate::terminal;
use crate::theme::{Colors, Theme};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum LetterGrade {
APlus,
A,
AMinus,
BPlus,
B,
BMinus,
CPlus,
C,
CMinus,
D,
F,
}
impl LetterGrade {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::APlus => "A+",
Self::A => "A",
Self::AMinus => "A-",
Self::BPlus => "B+",
Self::B => "B",
Self::BMinus => "B-",
Self::CPlus => "C+",
Self::C => "C",
Self::CMinus => "C-",
Self::D => "D",
Self::F => "F",
}
}
#[must_use]
pub fn color_str(&self, nc: bool, theme: Theme) -> String {
let s = self.as_str();
if nc {
return format!("[{s}]");
}
match self {
Self::APlus | Self::A | Self::AMinus | Self::BPlus | Self::B => Colors::good(s, theme),
Self::BMinus | Self::CPlus | Self::C | Self::CMinus | Self::D => Colors::warn(s, theme),
Self::F => Colors::bad(s, theme),
}
}
#[must_use]
pub fn emoji(&self) -> &'static str {
if terminal::no_emoji() {
return "";
}
match self {
Self::APlus | Self::A | Self::AMinus => "⚡",
Self::BPlus | Self::B => "✅",
Self::BMinus | Self::CPlus | Self::C => "⚠️",
Self::CMinus | Self::D => "❌",
Self::F => "🚫",
}
}
#[must_use]
pub fn score(&self) -> f64 {
match self {
Self::APlus => 100.0,
Self::A => 95.0,
Self::AMinus => 90.0,
Self::BPlus => 85.0,
Self::B => 80.0,
Self::BMinus => 75.0,
Self::CPlus => 70.0,
Self::C => 65.0,
Self::CMinus => 60.0,
Self::D => 50.0,
Self::F => 25.0,
}
}
#[must_use]
pub fn description(&self) -> &'static str {
match self {
Self::APlus => "Exceptional",
Self::A => "Excellent",
Self::AMinus => "Very Good",
Self::BPlus => "Good+",
Self::B => "Good",
Self::BMinus => "Above Average",
Self::CPlus => "Average+",
Self::C => "Average",
Self::CMinus => "Below Average",
Self::D => "Poor",
Self::F => "Unacceptable",
}
}
}
#[must_use]
pub fn grade_ping(ping_ms: f64, profile: UserProfile) -> LetterGrade {
let excellent = profile.excellent_ping_threshold();
let good = excellent * 3.0;
let average = excellent * 6.0;
if ping_ms <= excellent * 0.5 {
LetterGrade::APlus
} else if ping_ms <= excellent {
LetterGrade::A
} else if ping_ms <= excellent * 1.5 {
LetterGrade::AMinus
} else if ping_ms <= good {
LetterGrade::B
} else if ping_ms <= good * 1.5 {
LetterGrade::C
} else if ping_ms <= average {
LetterGrade::D
} else {
LetterGrade::F
}
}
#[must_use]
pub fn grade_jitter(jitter_ms: f64, profile: UserProfile) -> LetterGrade {
let excellent = profile.excellent_jitter_threshold();
let good = excellent * 3.0;
let average = excellent * 8.0;
if jitter_ms <= excellent * 0.5 {
LetterGrade::APlus
} else if jitter_ms <= excellent {
LetterGrade::A
} else if jitter_ms <= excellent * 2.0 {
LetterGrade::B
} else if jitter_ms <= good {
LetterGrade::C
} else if jitter_ms <= average {
LetterGrade::D
} else {
LetterGrade::F
}
}
#[must_use]
pub fn grade_download(speed_mbps: f64, profile: UserProfile) -> LetterGrade {
let excellent = profile.excellent_speed_threshold();
let good = excellent * 0.4;
let average = excellent * 0.15;
if speed_mbps >= excellent * 2.0 {
LetterGrade::APlus
} else if speed_mbps >= excellent {
LetterGrade::A
} else if speed_mbps >= excellent * 0.75 {
LetterGrade::B
} else if speed_mbps >= good {
LetterGrade::C
} else if speed_mbps >= average {
LetterGrade::D
} else {
LetterGrade::F
}
}
#[must_use]
pub fn grade_upload(speed_mbps: f64, profile: UserProfile) -> LetterGrade {
let excellent = profile.excellent_speed_threshold() * 0.5;
let good = excellent * 0.4;
let average = excellent * 0.15;
if speed_mbps >= excellent * 2.0 {
LetterGrade::APlus
} else if speed_mbps >= excellent {
LetterGrade::A
} else if speed_mbps >= excellent * 0.75 {
LetterGrade::B
} else if speed_mbps >= good {
LetterGrade::C
} else if speed_mbps >= average {
LetterGrade::D
} else {
LetterGrade::F
}
}
#[must_use]
pub fn grade_bufferbloat(added_latency_ms: f64) -> LetterGrade {
if added_latency_ms < 3.0 {
LetterGrade::APlus
} else if added_latency_ms < 5.0 {
LetterGrade::A
} else if added_latency_ms < 10.0 {
LetterGrade::AMinus
} else if added_latency_ms < 20.0 {
LetterGrade::BPlus
} else if added_latency_ms < 30.0 {
LetterGrade::B
} else if added_latency_ms < 50.0 {
LetterGrade::C
} else if added_latency_ms < 100.0 {
LetterGrade::D
} else {
LetterGrade::F
}
}
#[must_use]
pub fn grade_stability(cv_pct: f64) -> LetterGrade {
if cv_pct < 3.0 {
LetterGrade::APlus
} else if cv_pct < 5.0 {
LetterGrade::A
} else if cv_pct < 8.0 {
LetterGrade::B
} else if cv_pct < 15.0 {
LetterGrade::C
} else if cv_pct < 25.0 {
LetterGrade::D
} else {
LetterGrade::F
}
}
#[must_use]
pub fn grade_overall(
ping: Option<f64>,
jitter: Option<f64>,
download_bps: Option<f64>,
upload_bps: Option<f64>,
profile: UserProfile,
) -> LetterGrade {
let (ping_w, jitter_w, dl_w, ul_w) = profile.scoring_weights();
let mut total_score = 0.0;
let mut total_weight = 0.0;
if let Some(p) = ping {
total_score += grade_ping(p, profile).score() * ping_w;
total_weight += ping_w;
}
if let Some(j) = jitter {
total_score += grade_jitter(j, profile).score() * jitter_w;
total_weight += jitter_w;
}
if let Some(dl) = download_bps {
total_score += grade_download(dl / 1_000_000.0, profile).score() * dl_w;
total_weight += dl_w;
}
if let Some(ul) = upload_bps {
total_score += grade_upload(ul / 1_000_000.0, profile).score() * ul_w;
total_weight += ul_w;
}
if total_weight == 0.0 {
return LetterGrade::F;
}
let avg_score = total_score / total_weight;
score_to_grade(avg_score)
}
#[must_use]
pub fn score_to_grade(score: f64) -> LetterGrade {
if score >= 97.0 {
LetterGrade::APlus
} else if score >= 93.0 {
LetterGrade::A
} else if score >= 90.0 {
LetterGrade::AMinus
} else if score >= 87.0 {
LetterGrade::BPlus
} else if score >= 80.0 {
LetterGrade::B
} else if score >= 77.0 {
LetterGrade::BMinus
} else if score >= 70.0 {
LetterGrade::CPlus
} else if score >= 65.0 {
LetterGrade::C
} else if score >= 60.0 {
LetterGrade::CMinus
} else if score >= 50.0 {
LetterGrade::D
} else {
LetterGrade::F
}
}
#[must_use]
pub fn format_grade_line(
label: &str,
grade: LetterGrade,
value: Option<&str>,
nc: bool,
theme: Theme,
) -> String {
let emoji = grade.emoji();
let grade_display = grade.color_str(nc, theme);
let value_str = value.map(|v| format!(" ({v})")).unwrap_or_default();
if nc || terminal::no_emoji() {
format!(" {label:>14}: {grade_display}{value_str}")
} else {
format!(" {label:>14}: {emoji} {grade_display}{value_str}")
}
}
#[must_use]
pub fn grade_badge(grade: LetterGrade, nc: bool, theme: Theme) -> String {
let emoji = grade.emoji();
let grade_display = grade.color_str(nc, theme);
if nc {
format!("[{grade_display}]")
} else if terminal::no_emoji() {
grade_display.clone()
} else {
format!("{emoji} {grade_display}")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::theme::Theme;
#[test]
fn test_letter_grade_ordering() {
assert!(LetterGrade::APlus.score() > LetterGrade::A.score());
assert!(LetterGrade::A.score() > LetterGrade::AMinus.score());
assert!(LetterGrade::B.score() > LetterGrade::C.score());
assert!(LetterGrade::F.score() < LetterGrade::D.score());
}
#[test]
fn test_letter_grade_as_str_all_variants() {
assert_eq!(LetterGrade::APlus.as_str(), "A+");
assert_eq!(LetterGrade::A.as_str(), "A");
assert_eq!(LetterGrade::AMinus.as_str(), "A-");
assert_eq!(LetterGrade::BPlus.as_str(), "B+");
assert_eq!(LetterGrade::B.as_str(), "B");
assert_eq!(LetterGrade::BMinus.as_str(), "B-");
assert_eq!(LetterGrade::CPlus.as_str(), "C+");
assert_eq!(LetterGrade::C.as_str(), "C");
assert_eq!(LetterGrade::CMinus.as_str(), "C-");
assert_eq!(LetterGrade::D.as_str(), "D");
assert_eq!(LetterGrade::F.as_str(), "F");
}
#[test]
fn test_letter_grade_score_all_variants() {
assert_eq!(LetterGrade::APlus.score(), 100.0);
assert_eq!(LetterGrade::A.score(), 95.0);
assert_eq!(LetterGrade::AMinus.score(), 90.0);
assert_eq!(LetterGrade::BPlus.score(), 85.0);
assert_eq!(LetterGrade::B.score(), 80.0);
assert_eq!(LetterGrade::BMinus.score(), 75.0);
assert_eq!(LetterGrade::CPlus.score(), 70.0);
assert_eq!(LetterGrade::C.score(), 65.0);
assert_eq!(LetterGrade::CMinus.score(), 60.0);
assert_eq!(LetterGrade::D.score(), 50.0);
assert_eq!(LetterGrade::F.score(), 25.0);
}
#[test]
fn test_letter_grade_description_all_variants() {
assert_eq!(LetterGrade::APlus.description(), "Exceptional");
assert_eq!(LetterGrade::A.description(), "Excellent");
assert_eq!(LetterGrade::AMinus.description(), "Very Good");
assert_eq!(LetterGrade::BPlus.description(), "Good+");
assert_eq!(LetterGrade::B.description(), "Good");
assert_eq!(LetterGrade::BMinus.description(), "Above Average");
assert_eq!(LetterGrade::CPlus.description(), "Average+");
assert_eq!(LetterGrade::C.description(), "Average");
assert_eq!(LetterGrade::CMinus.description(), "Below Average");
assert_eq!(LetterGrade::D.description(), "Poor");
assert_eq!(LetterGrade::F.description(), "Unacceptable");
}
#[test]
fn test_letter_grade_color_str_nc_mode() {
assert_eq!(LetterGrade::A.color_str(true, Theme::Dark), "[A]");
assert_eq!(LetterGrade::F.color_str(true, Theme::Dark), "[F]");
assert_eq!(LetterGrade::BPlus.color_str(true, Theme::Dark), "[B+]");
}
#[test]
fn test_letter_grade_color_str_all_grades() {
for grade in &[
LetterGrade::APlus,
LetterGrade::A,
LetterGrade::AMinus,
LetterGrade::BPlus,
LetterGrade::B,
LetterGrade::BMinus,
LetterGrade::CPlus,
LetterGrade::C,
LetterGrade::CMinus,
LetterGrade::D,
LetterGrade::F,
] {
let colored = grade.color_str(false, Theme::Dark);
assert!(
!colored.is_empty(),
"Grade {:?} should have color output",
grade
);
assert!(
colored.contains(grade.as_str()),
"Colored output should contain grade string"
);
}
}
#[test]
fn test_letter_grade_color_str_different_themes() {
let grade = LetterGrade::A;
let dark = grade.color_str(false, Theme::Dark);
let light = grade.color_str(false, Theme::Light);
assert!(!dark.is_empty());
assert!(!light.is_empty());
assert!(dark.contains("A"));
assert!(light.contains("A"));
}
#[test]
fn test_grade_ping_excellent() {
let p = UserProfile::PowerUser;
assert_eq!(grade_ping(3.0, p), LetterGrade::APlus);
assert_eq!(grade_ping(5.0, p), LetterGrade::APlus);
assert_eq!(grade_ping(6.0, p), LetterGrade::A);
assert_eq!(grade_ping(10.0, p), LetterGrade::A);
assert_eq!(grade_ping(11.0, p), LetterGrade::AMinus);
assert_eq!(grade_ping(15.0, p), LetterGrade::AMinus);
}
#[test]
fn test_grade_ping_good_to_fail() {
let p = UserProfile::PowerUser;
assert_eq!(grade_ping(20.0, p), LetterGrade::B);
assert_eq!(grade_ping(30.0, p), LetterGrade::B);
assert_eq!(grade_ping(40.0, p), LetterGrade::C);
assert_eq!(grade_ping(45.0, p), LetterGrade::C);
assert_eq!(grade_ping(50.0, p), LetterGrade::D);
assert_eq!(grade_ping(60.0, p), LetterGrade::D);
assert_eq!(grade_ping(61.0, p), LetterGrade::F);
assert_eq!(grade_ping(500.0, p), LetterGrade::F);
}
#[test]
fn test_grade_ping_gamer_profile() {
let g = UserProfile::Gamer;
assert_eq!(grade_ping(2.0, g), LetterGrade::APlus);
assert_eq!(grade_ping(3.0, g), LetterGrade::A);
assert_eq!(grade_ping(5.0, g), LetterGrade::A);
assert_eq!(grade_ping(7.0, g), LetterGrade::AMinus);
assert_eq!(grade_ping(10.0, g), LetterGrade::B);
assert_eq!(grade_ping(100.0, g), LetterGrade::F);
}
#[test]
fn test_grade_ping_streamer_profile() {
let s = UserProfile::Streamer;
assert_eq!(grade_ping(10.0, s), LetterGrade::APlus);
assert_eq!(grade_ping(30.0, s), LetterGrade::A);
assert_eq!(grade_ping(200.0, s), LetterGrade::F);
}
#[test]
fn test_grade_jitter_excellent() {
let p = UserProfile::PowerUser;
assert_eq!(grade_jitter(0.5, p), LetterGrade::APlus);
assert_eq!(grade_jitter(1.0, p), LetterGrade::APlus);
assert_eq!(grade_jitter(1.5, p), LetterGrade::A);
assert_eq!(grade_jitter(2.0, p), LetterGrade::A);
assert_eq!(grade_jitter(3.0, p), LetterGrade::B);
assert_eq!(grade_jitter(4.0, p), LetterGrade::B);
}
#[test]
fn test_grade_jitter_good_to_fail() {
let p = UserProfile::PowerUser;
assert_eq!(grade_jitter(5.0, p), LetterGrade::C);
assert_eq!(grade_jitter(10.0, p), LetterGrade::D);
assert_eq!(grade_jitter(16.0, p), LetterGrade::D);
assert_eq!(grade_jitter(50.0, p), LetterGrade::F);
}
#[test]
fn test_grade_download_excellent() {
let p = UserProfile::PowerUser;
assert_eq!(grade_download(1000.0, p), LetterGrade::APlus);
assert_eq!(grade_download(500.0, p), LetterGrade::A);
assert_eq!(grade_download(400.0, p), LetterGrade::B);
assert_eq!(grade_download(375.0, p), LetterGrade::B);
}
#[test]
fn test_grade_download_good_to_fail() {
let p = UserProfile::PowerUser;
assert_eq!(grade_download(200.0, p), LetterGrade::C);
assert_eq!(grade_download(75.0, p), LetterGrade::D);
assert_eq!(grade_download(50.0, p), LetterGrade::F);
assert_eq!(grade_download(1.0, p), LetterGrade::F);
}
#[test]
fn test_grade_download_streamer_profile() {
let s = UserProfile::Streamer;
assert_eq!(grade_download(400.0, s), LetterGrade::APlus);
assert_eq!(grade_download(200.0, s), LetterGrade::A);
assert_eq!(grade_download(100.0, s), LetterGrade::C);
assert_eq!(grade_download(80.0, s), LetterGrade::C);
assert_eq!(grade_download(40.0, s), LetterGrade::D);
assert_eq!(grade_download(10.0, s), LetterGrade::F);
}
#[test]
fn test_grade_download_gamer_profile() {
let g = UserProfile::Gamer;
assert_eq!(grade_download(200.0, g), LetterGrade::APlus);
assert_eq!(grade_download(100.0, g), LetterGrade::A);
assert_eq!(grade_download(50.0, g), LetterGrade::C);
}
#[test]
fn test_grade_upload_excellent() {
let p = UserProfile::PowerUser;
assert_eq!(grade_upload(500.0, p), LetterGrade::APlus);
assert_eq!(grade_upload(250.0, p), LetterGrade::A);
assert_eq!(grade_upload(200.0, p), LetterGrade::B);
}
#[test]
fn test_grade_upload_good_to_fail() {
let p = UserProfile::PowerUser;
assert_eq!(grade_upload(100.0, p), LetterGrade::C);
assert_eq!(grade_upload(40.0, p), LetterGrade::D);
assert_eq!(grade_upload(1.0, p), LetterGrade::F);
}
#[test]
fn test_grade_bufferbloat_all_levels() {
assert_eq!(grade_bufferbloat(0.0), LetterGrade::APlus);
assert_eq!(grade_bufferbloat(2.0), LetterGrade::APlus);
assert_eq!(grade_bufferbloat(3.0), LetterGrade::A);
assert_eq!(grade_bufferbloat(4.0), LetterGrade::A);
assert_eq!(grade_bufferbloat(5.0), LetterGrade::AMinus);
assert_eq!(grade_bufferbloat(8.0), LetterGrade::AMinus);
assert_eq!(grade_bufferbloat(15.0), LetterGrade::BPlus);
assert_eq!(grade_bufferbloat(25.0), LetterGrade::B);
assert_eq!(grade_bufferbloat(40.0), LetterGrade::C);
assert_eq!(grade_bufferbloat(75.0), LetterGrade::D);
assert_eq!(grade_bufferbloat(100.0), LetterGrade::F);
assert_eq!(grade_bufferbloat(200.0), LetterGrade::F);
}
#[test]
fn test_grade_bufferbloat_boundary_cases() {
assert_eq!(grade_bufferbloat(2.999), LetterGrade::APlus);
assert_eq!(grade_bufferbloat(3.001), LetterGrade::A);
assert_eq!(grade_bufferbloat(4.999), LetterGrade::A);
assert_eq!(grade_bufferbloat(5.001), LetterGrade::AMinus);
assert_eq!(grade_bufferbloat(9.999), LetterGrade::AMinus);
assert_eq!(grade_bufferbloat(10.001), LetterGrade::BPlus);
}
#[test]
fn test_grade_stability_all_levels() {
assert_eq!(grade_stability(0.0), LetterGrade::APlus);
assert_eq!(grade_stability(2.0), LetterGrade::APlus);
assert_eq!(grade_stability(3.0), LetterGrade::A);
assert_eq!(grade_stability(4.0), LetterGrade::A);
assert_eq!(grade_stability(5.0), LetterGrade::B);
assert_eq!(grade_stability(7.0), LetterGrade::B);
assert_eq!(grade_stability(10.0), LetterGrade::C);
assert_eq!(grade_stability(20.0), LetterGrade::D);
assert_eq!(grade_stability(50.0), LetterGrade::F);
}
#[test]
fn test_score_to_grade_all_levels() {
assert_eq!(score_to_grade(97.0), LetterGrade::APlus);
assert_eq!(score_to_grade(100.0), LetterGrade::APlus);
assert_eq!(score_to_grade(93.0), LetterGrade::A);
assert_eq!(score_to_grade(96.99), LetterGrade::A);
assert_eq!(score_to_grade(90.0), LetterGrade::AMinus);
assert_eq!(score_to_grade(92.99), LetterGrade::AMinus);
assert_eq!(score_to_grade(87.0), LetterGrade::BPlus);
assert_eq!(score_to_grade(89.99), LetterGrade::BPlus);
assert_eq!(score_to_grade(80.0), LetterGrade::B);
assert_eq!(score_to_grade(86.99), LetterGrade::B);
assert_eq!(score_to_grade(77.0), LetterGrade::BMinus);
assert_eq!(score_to_grade(79.99), LetterGrade::BMinus);
assert_eq!(score_to_grade(70.0), LetterGrade::CPlus);
assert_eq!(score_to_grade(76.99), LetterGrade::CPlus);
assert_eq!(score_to_grade(65.0), LetterGrade::C);
assert_eq!(score_to_grade(69.99), LetterGrade::C);
assert_eq!(score_to_grade(60.0), LetterGrade::CMinus);
assert_eq!(score_to_grade(64.99), LetterGrade::CMinus);
assert_eq!(score_to_grade(50.0), LetterGrade::D);
assert_eq!(score_to_grade(59.99), LetterGrade::D);
assert_eq!(score_to_grade(49.99), LetterGrade::F);
assert_eq!(score_to_grade(0.0), LetterGrade::F);
}
#[test]
fn test_score_to_grade_boundary_cases() {
assert_eq!(score_to_grade(96.99), LetterGrade::A); assert_eq!(score_to_grade(92.99), LetterGrade::AMinus); assert_eq!(score_to_grade(86.99), LetterGrade::B); assert_eq!(score_to_grade(79.99), LetterGrade::BMinus); assert_eq!(score_to_grade(76.99), LetterGrade::CPlus); assert_eq!(score_to_grade(69.99), LetterGrade::C); assert_eq!(score_to_grade(64.99), LetterGrade::CMinus); assert_eq!(score_to_grade(59.99), LetterGrade::D); }
#[test]
fn test_grade_overall_all_none() {
let p = UserProfile::PowerUser;
let grade = grade_overall(None, None, None, None, p);
assert_eq!(grade, LetterGrade::F);
}
#[test]
fn test_grade_overall_excellent() {
let p = UserProfile::PowerUser;
let grade = grade_overall(
Some(5.0), Some(1.0), Some(600_000_000.0), Some(300_000_000.0), p,
);
assert!(grade.score() >= LetterGrade::A.score());
}
#[test]
fn test_grade_overall_poor() {
let p = UserProfile::PowerUser;
let grade = grade_overall(
Some(200.0), Some(50.0), Some(5_000_000.0), Some(1_000_000.0), p,
);
assert!(grade.score() <= LetterGrade::F.score());
}
#[test]
fn test_grade_overall_partial_data() {
let p = UserProfile::PowerUser;
let grade = grade_overall(Some(5.0), None, Some(600_000_000.0), None, p);
assert!(grade.score() >= LetterGrade::A.score());
let grade = grade_overall(None, None, Some(600_000_000.0), None, p);
assert!(grade.score() >= LetterGrade::A.score());
let grade = grade_overall(Some(5.0), None, None, None, p);
assert!(grade.score() >= LetterGrade::A.score());
let grade = grade_overall(None, Some(1.0), None, None, p);
assert!(grade.score() >= LetterGrade::A.score());
}
#[test]
fn test_grade_overall_mixed_quality() {
let p = UserProfile::PowerUser;
let grade = grade_overall(Some(5.0), None, Some(5_000_000.0), None, p);
assert!(grade.score() <= LetterGrade::D.score());
assert!(grade.score() >= LetterGrade::F.score());
}
#[test]
fn test_format_grade_line_with_value() {
let grade = LetterGrade::A;
let line = format_grade_line("Ping", grade, Some("5.2 ms"), false, Theme::Dark);
assert!(line.contains("Ping"));
assert!(line.contains("5.2 ms"));
assert!(line.contains("A"));
}
#[test]
fn test_format_grade_line_without_value() {
let grade = LetterGrade::B;
let line = format_grade_line("Jitter", grade, None, false, Theme::Dark);
assert!(line.contains("Jitter"));
assert!(line.contains("B"));
assert!(!line.contains("()"));
}
#[test]
fn test_format_grade_line_nc_mode() {
let grade = LetterGrade::C;
let line = format_grade_line("Download", grade, Some("100 Mbps"), true, Theme::Dark);
assert!(line.contains("["));
assert!(line.contains("]"));
}
#[test]
fn test_format_grade_line_all_grade_levels() {
let metrics = ["Ping", "Jitter", "Download", "Upload", "Bufferbloat"];
for grade in &[
LetterGrade::APlus,
LetterGrade::A,
LetterGrade::B,
LetterGrade::C,
LetterGrade::D,
LetterGrade::F,
] {
for metric in &metrics {
let line = format_grade_line(metric, *grade, Some("value"), false, Theme::Dark);
assert!(!line.is_empty());
}
}
}
#[test]
fn test_grade_badge_nc_mode() {
let badge = grade_badge(LetterGrade::A, true, Theme::Dark);
assert!(badge.starts_with('['));
assert!(badge.ends_with(']'));
assert!(badge.contains('A'));
}
#[test]
fn test_grade_badge_colored_mode() {
let badge = grade_badge(LetterGrade::B, false, Theme::Dark);
assert!(badge.contains('B'));
assert!(!badge.is_empty());
}
#[test]
fn test_grade_badge_all_grades() {
for grade in &[
LetterGrade::APlus,
LetterGrade::A,
LetterGrade::B,
LetterGrade::C,
LetterGrade::F,
] {
let badge = grade_badge(*grade, false, Theme::Dark);
assert!(!badge.is_empty());
assert!(badge.contains(grade.as_str()));
}
}
#[test]
fn test_letter_grade_is_copy() {
let grade = LetterGrade::BPlus;
let _copied = grade; assert_eq!(grade, _copied);
}
#[test]
fn test_letter_grade_debug() {
let grade = LetterGrade::C;
let debug_str = format!("{:?}", grade);
assert!(debug_str.contains("C"));
}
#[test]
fn test_letter_grade_partial_eq() {
assert_eq!(LetterGrade::A, LetterGrade::A);
assert_ne!(LetterGrade::A, LetterGrade::B);
assert_eq!(LetterGrade::APlus, LetterGrade::APlus);
}
#[test]
fn test_letter_grade_ord() {
assert!(LetterGrade::APlus < LetterGrade::A);
assert!(LetterGrade::A < LetterGrade::B);
assert!(LetterGrade::B < LetterGrade::C);
assert!(LetterGrade::C < LetterGrade::D);
assert!(LetterGrade::D < LetterGrade::F);
}
}