leenfetch_core/modules/linux/info/
battery.rs1use crate::modules::{enums::BatteryDisplayMode, utils::get_bar};
2use std::fs;
3use std::path::Path;
4
5pub fn get_battery(display_mode: BatteryDisplayMode) -> Vec<String> {
6 collect_batteries(Path::new("/sys/class/power_supply/"), display_mode)
7}
8
9fn collect_batteries(root: &Path, display_mode: BatteryDisplayMode) -> Vec<String> {
10 let entries = match fs::read_dir(root) {
11 Ok(e) => e,
12 Err(_) => return Vec::new(),
13 };
14
15 let mut results = Vec::with_capacity(2); for entry in entries.flatten() {
18 let name = entry.file_name();
19 let name_str = name.to_string_lossy();
20
21 if !(name_str.starts_with("BAT")
23 || name_str == "axp288_fuel_gauge"
24 || name_str.starts_with("CMB"))
25 {
26 continue;
27 }
28
29 let path = entry.path();
30
31 let capacity = match fs::read_to_string(path.join("capacity")) {
32 Ok(v) => match v.trim().parse::<u8>() {
33 Ok(num) => num,
34 Err(_) => continue,
35 },
36 Err(_) => continue,
37 };
38
39 let status = fs::read_to_string(path.join("status"))
40 .ok()
41 .map(|s| s.trim().to_string())
42 .unwrap_or_else(|| "Unknown".to_string());
43
44 let line = match display_mode {
45 BatteryDisplayMode::Bar => get_bar(capacity),
46 BatteryDisplayMode::InfoBar => {
47 format!("{}% [{}] {}", capacity, status, get_bar(capacity))
48 }
49 BatteryDisplayMode::BarInfo => {
50 format!("{} {}% [{}]", get_bar(capacity), capacity, status)
51 }
52 BatteryDisplayMode::Off => format!("{}% [{}]", capacity, status),
53 };
54
55 results.push(format!("({}): {}", name_str, line));
56 }
57
58 results
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use crate::modules::enums::BatteryDisplayMode;
65 use std::fs;
66 use std::time::{SystemTime, UNIX_EPOCH};
67
68 fn setup_battery(temp_root: &Path, name: &str, capacity: &str, status: &str) {
69 let battery_path = temp_root.join(name);
70 fs::create_dir_all(&battery_path).unwrap();
71 fs::write(battery_path.join("capacity"), capacity).unwrap();
72 fs::write(battery_path.join("status"), status).unwrap();
73 }
74
75 #[test]
76 fn collects_batteries_with_info_bar() {
77 let unique = SystemTime::now()
78 .duration_since(UNIX_EPOCH)
79 .unwrap()
80 .as_nanos();
81 let root = std::env::temp_dir().join(format!("leenfetch_battery_test_{unique}"));
82 setup_battery(&root, "BAT0", "75", "Charging");
83
84 let entries = collect_batteries(&root, BatteryDisplayMode::InfoBar);
85 assert_eq!(entries.len(), 1);
86 let info = &entries[0];
87 assert!(info.contains("(BAT0):"), "missing battery label: {info}");
88 assert!(info.contains("75%"), "missing percentage: {info}");
89 assert!(info.contains("Charging"), "missing status: {info}");
90
91 fs::remove_dir_all(root).unwrap();
92 }
93
94 #[test]
95 fn ignores_non_battery_entries() {
96 let unique = SystemTime::now()
97 .duration_since(UNIX_EPOCH)
98 .unwrap()
99 .as_nanos();
100 let root = std::env::temp_dir().join(format!("leenfetch_battery_nonbattery_{unique}"));
101 setup_battery(&root, "AC0", "100", "Full");
102 setup_battery(&root, "BAT1", "55", "Discharging");
103
104 let entries = collect_batteries(&root, BatteryDisplayMode::Off);
105 assert_eq!(entries.len(), 1);
106 assert!(
107 entries[0].contains("BAT1"),
108 "unexpected entries: {:?}",
109 entries
110 );
111
112 fs::remove_dir_all(root).unwrap();
113 }
114}