#![allow(dead_code)]
use presentar_core::Color;
#[must_use]
pub(crate) fn gpu_temp_color(temp: u32) -> Color {
if temp > 85 {
Color::new(1.0, 0.3, 0.3, 1.0) } else if temp > 70 {
Color::new(1.0, 0.8, 0.2, 1.0) } else {
Color::new(0.3, 0.9, 0.3, 1.0) }
}
#[must_use]
pub(crate) fn gpu_proc_badge(process_type: &str) -> (&'static str, Color) {
match process_type.to_uppercase().as_str() {
"C" | "COMPUTE" => ("C", Color::new(0.0, 0.8, 1.0, 1.0)), "G" | "GRAPHICS" => ("G", Color::new(1.0, 0.0, 1.0, 1.0)), _ => ("?", Color::new(0.5, 0.5, 0.5, 1.0)), }
}
pub(crate) const POWER_COLOR: Color = Color {
r: 0.7,
g: 0.7,
b: 0.7,
a: 1.0,
};
pub(crate) const HEADER_COLOR: Color = Color {
r: 0.5,
g: 0.5,
b: 0.5,
a: 1.0,
};
pub(crate) const PROC_INFO_COLOR: Color = Color {
r: 0.8,
g: 0.8,
b: 0.8,
a: 1.0,
};
pub(crate) const VRAM_GRAPH_COLOR: Color = Color {
r: 0.6,
g: 0.4,
b: 1.0,
a: 1.0,
};
#[must_use]
pub(crate) fn build_gpu_bar(percent: f32, bar_width: usize) -> String {
let filled = (((percent / 100.0) * bar_width as f32) as usize).min(bar_width);
"█".repeat(filled) + &"░".repeat(bar_width.saturating_sub(filled))
}
#[must_use]
pub(crate) fn format_gpu_row(label: &str, bar: &str, percent: f32) -> String {
format!("{label} {bar} {:>3}%", percent as u32)
}
#[must_use]
pub(crate) fn format_vram_row(bar: &str, used_mb: u64, total_mb: u64) -> String {
format!("VRAM {bar} {used_mb}M/{total_mb}M")
}
#[must_use]
pub(crate) fn format_proc_util(util: Option<f32>) -> String {
util.map_or_else(|| " -".to_string(), |u| format!("{u:>3.0}"))
}
#[must_use]
pub(crate) fn truncate_name(name: &str, max_len: usize) -> &str {
if name.len() > max_len {
&name[..max_len]
} else {
name
}
}
#[must_use]
pub(crate) fn build_gpu_title(
name: &str,
temp: Option<u32>,
power: Option<f32>,
minimal: bool,
) -> String {
if minimal {
name.to_string()
} else {
let temp_str = temp.map(|t| format!(" │ {t}°C")).unwrap_or_default();
let power_str = power.map(|p| format!(" │ {p:.0}W")).unwrap_or_default();
format!("{name}{temp_str}{power_str}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_temp_color_red() {
let color = gpu_temp_color(90);
assert!(color.r > 0.8 && color.g < 0.5, "Should be red above 85°C");
}
#[test]
fn test_temp_color_yellow() {
let color = gpu_temp_color(75);
assert!(color.r > 0.8 && color.g > 0.5, "Should be yellow 70-85°C");
}
#[test]
fn test_temp_color_green() {
let color = gpu_temp_color(60);
assert!(color.g > 0.8 && color.r < 0.5, "Should be green below 70°C");
}
#[test]
fn test_proc_badge_compute() {
let (badge, color) = gpu_proc_badge("C");
assert_eq!(badge, "C");
assert!(color.b > 0.8, "Compute should be cyan");
}
#[test]
fn test_proc_badge_compute_full() {
let (badge, _) = gpu_proc_badge("COMPUTE");
assert_eq!(badge, "C");
}
#[test]
fn test_proc_badge_graphics() {
let (badge, color) = gpu_proc_badge("G");
assert_eq!(badge, "G");
assert!(color.r > 0.8 && color.b > 0.8, "Graphics should be magenta");
}
#[test]
fn test_proc_badge_graphics_full() {
let (badge, _) = gpu_proc_badge("GRAPHICS");
assert_eq!(badge, "G");
}
#[test]
fn test_proc_badge_unknown() {
let (badge, color) = gpu_proc_badge("unknown");
assert_eq!(badge, "?");
assert!(
color.r == color.g && color.g == color.b,
"Unknown should be gray"
);
}
#[test]
fn test_power_color() {
assert!((POWER_COLOR.r - POWER_COLOR.g).abs() < 0.01);
assert!((POWER_COLOR.g - POWER_COLOR.b).abs() < 0.01);
}
#[test]
fn test_header_color() {
assert!(HEADER_COLOR.r == HEADER_COLOR.g && HEADER_COLOR.g == HEADER_COLOR.b);
}
#[test]
fn test_proc_info_color() {
assert!(PROC_INFO_COLOR.r > 0.7);
assert!(PROC_INFO_COLOR.g > 0.7);
assert!(PROC_INFO_COLOR.b > 0.7);
}
#[test]
fn test_vram_graph_color() {
assert!(VRAM_GRAPH_COLOR.r > 0.5 && VRAM_GRAPH_COLOR.b > 0.8);
}
#[test]
fn test_gpu_bar_full() {
let bar = build_gpu_bar(100.0, 10);
assert_eq!(bar.chars().filter(|&c| c == '█').count(), 10);
}
#[test]
fn test_gpu_bar_empty() {
let bar = build_gpu_bar(0.0, 10);
assert_eq!(bar.chars().filter(|&c| c == '░').count(), 10);
}
#[test]
fn test_gpu_bar_half() {
let bar = build_gpu_bar(50.0, 10);
assert_eq!(bar.chars().filter(|&c| c == '█').count(), 5);
}
#[test]
fn test_format_gpu_row() {
let bar = build_gpu_bar(75.0, 10);
let row = format_gpu_row("GPU", &bar, 75.0);
assert!(row.contains("GPU"));
assert!(row.contains("75%"));
}
#[test]
fn test_format_vram_row() {
let bar = build_gpu_bar(50.0, 10);
let row = format_vram_row(&bar, 4096, 8192);
assert!(row.contains("VRAM"));
assert!(row.contains("4096M"));
assert!(row.contains("8192M"));
}
#[test]
fn test_format_proc_util_value() {
let s = format_proc_util(Some(75.0));
assert!(s.contains("75"));
}
#[test]
fn test_format_proc_util_none() {
let s = format_proc_util(None);
assert!(s.contains("-"));
}
#[test]
fn test_truncate_name_short() {
let name = truncate_name("firefox", 12);
assert_eq!(name, "firefox");
}
#[test]
fn test_truncate_name_long() {
let name = truncate_name("verylongprocessname", 12);
assert_eq!(name.len(), 12);
}
#[test]
fn test_build_title_minimal() {
let title = build_gpu_title("GTX 1080", Some(65), Some(150.0), true);
assert_eq!(title, "GTX 1080");
}
#[test]
fn test_build_title_full() {
let title = build_gpu_title("RTX 3080", Some(70), Some(200.0), false);
assert!(title.contains("RTX 3080"));
assert!(title.contains("70°C"));
assert!(title.contains("200W"));
}
#[test]
fn test_build_title_no_temp() {
let title = build_gpu_title("GPU", None, Some(100.0), false);
assert!(!title.contains("°C"));
assert!(title.contains("100W"));
}
#[test]
fn test_build_title_no_power() {
let title = build_gpu_title("GPU", Some(50), None, false);
assert!(title.contains("50°C"));
assert!(!title.contains("W"));
}
#[test]
fn test_temp_boundary_85() {
let below = gpu_temp_color(84);
let above = gpu_temp_color(86);
assert!(above.r > below.r || below.g > above.g);
}
#[test]
fn test_temp_boundary_70() {
let below = gpu_temp_color(69);
let above = gpu_temp_color(71);
assert!(above.r > below.r);
}
#[test]
fn test_gpu_bar_overflow() {
let bar = build_gpu_bar(150.0, 10);
assert_eq!(bar.chars().count(), 10, "Bar should not overflow width");
assert_eq!(bar.chars().filter(|&c| c == '█').count(), 10);
}
#[test]
fn test_proc_badge_case() {
let (badge1, _) = gpu_proc_badge("compute");
let (badge2, _) = gpu_proc_badge("COMPUTE");
assert_eq!(badge1, badge2);
}
#[test]
fn test_temp_zero() {
let color = gpu_temp_color(0);
assert!(color.g > 0.8);
}
}