speedtest-tui 0.1.1

A terminal-based network speed test tool with real-time gauges and graphs
#![allow(dead_code)]

use std::time::Duration;

pub fn format_speed_mbps(bytes_per_sec: f64) -> f64 {
    (bytes_per_sec * 8.0) / 1_000_000.0
}

pub fn format_duration(duration: Duration) -> String {
    let secs = duration.as_secs();
    if secs < 60 {
        format!("{}s", secs)
    } else if secs < 3600 {
        format!("{}m {}s", secs / 60, secs % 60)
    } else {
        format!("{}h {}m", secs / 3600, (secs % 3600) / 60)
    }
}

pub fn lerp(start: f64, end: f64, t: f64) -> f64 {
    start + (end - start) * t.clamp(0.0, 1.0)
}

pub fn ease_out_cubic(t: f64) -> f64 {
    let t = t.clamp(0.0, 1.0);
    1.0 - (1.0 - t).powi(3)
}

pub fn calculate_gauge_scale(speed_mbps: f64) -> f64 {
    const SCALES: [f64; 9] = [
        10.0, 50.0, 100.0, 250.0, 500.0, 1000.0, 2500.0, 5000.0, 10000.0,
    ];

    for scale in SCALES {
        if speed_mbps <= scale * 0.8 {
            return scale;
        }
    }
    SCALES[SCALES.len() - 1]
}

pub fn calculate_jitter(samples: &[f64]) -> f64 {
    if samples.len() < 2 {
        return 0.0;
    }
    let mean = samples.iter().sum::<f64>() / samples.len() as f64;
    let variance = samples.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / samples.len() as f64;
    variance.sqrt()
}

pub fn format_bytes(bytes: u64) -> String {
    humansize::format_size(bytes, humansize::BINARY)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_format_speed_mbps() {
        assert!((format_speed_mbps(125_000_000.0) - 1000.0).abs() < 0.001);
        assert!((format_speed_mbps(12_500_000.0) - 100.0).abs() < 0.001);
    }

    #[test]
    fn test_calculate_gauge_scale() {
        assert_eq!(calculate_gauge_scale(5.0), 10.0);
        assert_eq!(calculate_gauge_scale(45.0), 100.0);
        assert_eq!(calculate_gauge_scale(800.0), 1000.0);
    }

    #[test]
    fn test_calculate_jitter() {
        let samples = vec![10.0, 12.0, 11.0, 10.5, 11.5];
        let jitter = calculate_jitter(&samples);
        assert!(jitter > 0.0 && jitter < 2.0);
    }
}