Skip to main content

forge_guard/utils/
mod.rs

1//! Shared utilities — caching, formatting, and helper functions.
2
3mod cache;
4mod formatting;
5
6pub use cache::Cache;
7pub use formatting::*;
8
9use crate::core::ForgeGuardError;
10
11/// Get the number of available CPU cores for parallel execution.
12pub fn cpu_count() -> usize {
13    std::thread::available_parallelism()
14        .map(|n| n.get())
15        .unwrap_or(4)
16}
17
18/// Truncate a string to a maximum length with ellipsis.
19pub fn truncate(s: &str, max_len: usize) -> String {
20    if s.len() <= max_len {
21        s.to_string()
22    } else {
23        format!("{}...", &s[..max_len.saturating_sub(3)])
24    }
25}
26
27/// Read a file, trimming whitespace.
28pub fn read_file_trimmed(path: &std::path::Path) -> Result<String, ForgeGuardError> {
29    let content = std::fs::read_to_string(path)?;
30    Ok(content.trim().to_string())
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn test_cpu_count() {
39        let count = cpu_count();
40        assert!(count >= 1);
41    }
42
43    #[test]
44    fn test_truncate_short_string() {
45        assert_eq!(truncate("hello", 10), "hello");
46    }
47
48    #[test]
49    fn test_truncate_long_string() {
50        let result = truncate("hello world this is long", 10);
51        assert_eq!(result, "hello w...");
52        assert_eq!(result.len(), 10);
53    }
54
55    #[test]
56    fn test_truncate_exact() {
57        assert_eq!(truncate("hello", 5), "hello");
58    }
59
60    #[test]
61    fn test_truncate_empty() {
62        assert_eq!(truncate("", 5), "");
63    }
64
65    #[test]
66    fn test_format_duration_ms() {
67        let result = format_duration(0.05);
68        assert!(result.contains("50ms") || result.contains("0ms"));
69    }
70
71    #[test]
72    fn test_format_duration_seconds() {
73        let result = format_duration(5.5);
74        assert_eq!(result, "5.5s");
75    }
76
77    #[test]
78    fn test_format_duration_minutes() {
79        let result = format_duration(125.0);
80        assert_eq!(result, "2m 5s");
81    }
82
83    #[test]
84    fn test_format_duration_hours() {
85        let result = format_duration(3661.0);
86        assert_eq!(result, "1h 1m");
87    }
88
89    #[test]
90    fn test_format_number() {
91        assert_eq!(format_number(0), "0");
92        assert_eq!(format_number(100), "100");
93        assert_eq!(format_number(1000), "1,000");
94        assert_eq!(format_number(1000000), "1,000,000");
95    }
96
97    #[test]
98    fn test_format_pct() {
99        assert_eq!(format_pct(0.5), "50.0%");
100        assert_eq!(format_pct(1.0), "100.0%");
101        assert_eq!(format_pct(0.0), "0.0%");
102    }
103
104    #[test]
105    fn test_format_bytes() {
106        assert_eq!(format_bytes(0), "0 B");
107        assert_eq!(format_bytes(500), "500 B");
108        let kb = format_bytes(2048);
109        assert!(kb.contains("KB") || kb.contains("2.00"));
110        let mb = format_bytes(1048576);
111        assert!(mb.contains("MB") || mb.contains("1.00"));
112    }
113}