summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Houts <16907671+ahouts@users.noreply.github.com>2021-06-29 18:46:41 -0500
committerGitHub <noreply@github.com>2021-06-29 19:46:41 -0400
commit53a30046d1d3504964f8f6cff8b8201dbeae09c0 (patch)
tree8e875d9c2381e776dc7e3ccded7c693233db6208 /src
parent72e5a544fc92eb5313a1fa895bd5b9042a8cc601 (diff)
test(battery): add battery tests (#2795)
Add some tests to the battery module, make it testable by mocking out the code that fetches battery info.
Diffstat (limited to 'src')
-rw-r--r--src/context.rs5
-rw-r--r--src/modules/battery.rs350
-rw-r--r--src/modules/mod.rs3
-rw-r--r--src/test/mod.rs9
4 files changed, 326 insertions, 41 deletions
diff --git a/src/context.rs b/src/context.rs
index 451ce53c0..9c3a88dff 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -50,6 +50,9 @@ pub struct Context<'a> {
#[cfg(test)]
pub cmd: HashMap<&'a str, Option<CommandOutput>>,
+ #[cfg(feature = "battery")]
+ pub battery_info_provider: &'a (dyn crate::modules::BatteryInfoProvider + Send + Sync),
+
/// Timeout for the execution of commands
cmd_timeout: Duration,
}
@@ -122,6 +125,8 @@ impl<'a> Context<'a> {
env: HashMap::new(),
#[cfg(test)]
cmd: HashMap::new(),
+ #[cfg(feature = "battery")]
+ battery_info_provider: &crate::modules::BatteryStatusProviderImpl,
cmd_timeout,
}
}
diff --git a/src/modules/battery.rs b/src/modules/battery.rs
index b47677294..630d5faa7 100644
--- a/src/modules/battery.rs
+++ b/src/modules/battery.rs
@@ -1,5 +1,7 @@
use super::{Context, Module, RootModuleConfig, Shell};
use crate::configs::battery::BatteryConfig;
+#[cfg(test)]
+use mockall::automock;
use crate::formatter::StringFormatter;
@@ -12,7 +14,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
_ => "%",
};
- let battery_status = get_battery_status()?;
+ let battery_status = get_battery_status(context)?;
let BatteryStatus { state, percentage } = battery_status;
let mut module = context.new_module("battery");
@@ -75,46 +77,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
}
}
-fn get_battery_status() -> Option<BatteryStatus> {
- let battery_manager = battery::Manager::new().ok()?;
- let batteries = battery_manager.batteries().ok()?;
- let battery_contructor = batteries
- .filter_map(|battery| match battery {
- Ok(battery) => {
- log::debug!("Battery found: {:?}", battery);
- Some(BatteryInfo {
- energy: battery.energy().value,
- energy_full: battery.energy_full().value,
- state: battery.state(),
- })
- }
- Err(e) => {
- let level = if cfg!(target_os = "linux") {
- log::Level::Info
- } else {
- log::Level::Warn
- };
- log::log!(level, "Unable to access battery information:\n{}", &e);
- None
- }
- })
- .fold(
- BatteryInfo {
- energy: 0.0,
- energy_full: 0.0,
- state: battery::State::Unknown,
- },
- |mut acc, x| {
- acc.energy += x.energy;
- acc.energy_full += x.energy_full;
- acc.state = merge_battery_states(acc.state, x.state);
- acc
- },
- );
- if battery_contructor.energy_full != 0.0 {
+fn get_battery_status(context: &Context) -> Option<BatteryStatus> {
+ let battery_info = context.battery_info_provider.get_battery_info()?;
+ if battery_info.energy_full != 0.0 {
let battery = BatteryStatus {
- percentage: battery_contructor.energy / battery_contructor.energy_full * 100.0,
- state: battery_contructor.state,
+ percentage: battery_info.energy / battery_info.energy_full * 100.0,
+ state: battery_info.state,
};
log::debug!("Battery status: {:?}", battery);
Some(battery)
@@ -145,7 +113,7 @@ fn merge_battery_states(state1: battery::State, state2: battery::State) -> batte
}
}
-struct BatteryInfo {
+pub struct BatteryInfo {
energy: f32,
energy_full: f32,
state: battery::State,
@@ -156,3 +124,303 @@ struct BatteryStatus {
percentage: f32,
state: battery::State,
}
+
+#[cfg_attr(test, automock)]
+pub trait BatteryInfoProvider {
+ fn get_battery_info(&self) -> Option<BatteryInfo>;
+}
+
+pub struct BatteryStatusProviderImpl;
+
+impl BatteryInfoProvider for BatteryStatusProviderImpl {
+ fn get_battery_info(&self) -> Option<BatteryInfo> {
+ let battery_manager = battery::Manager::new().ok()?;
+ let batteries = battery_manager.batteries().ok()?;
+ Some(
+ batteries
+ .filter_map(|battery| match battery {
+ Ok(battery) => {
+ log::debug!("Battery found: {:?}", battery);
+ Some(BatteryInfo {
+ energy: battery.energy().value,
+ energy_full: battery.energy_full().value,
+ state: battery.state(),
+ })
+ }
+ Err(e) => {
+ let level = if cfg!(target_os = "linux") {
+ log::Level::Info
+ } else {
+ log::Level::Warn
+ };
+ log::log!(level, "Unable to access battery information:\n{}", &e);
+ None
+ }
+ })
+ .fold(
+ BatteryInfo {
+ energy: 0.0,
+ energy_full: 0.0,
+ state: battery::State::Unknown,
+ },
+ |mut acc, x| {
+ acc.energy += x.energy;
+ acc.energy_full += x.energy_full;
+ acc.state = merge_battery_states(acc.state, x.state);
+ acc
+ },
+ ),
+ )
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::test::ModuleRenderer;
+ use ansi_term::Color;
+
+ #[test]
+ fn no_battery_status() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| None);
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 100
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = None;
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn ignores_zero_capacity_battery() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 0.0,
+ energy_full: 0.0,
+ state: battery::State::Full,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 100
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = None;
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn battery_full() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 1000.0,
+ energy_full: 1000.0,
+ state: battery::State::Full,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 100
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = Some(String::from(" 100% "));
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn battery_charging() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 800.0,
+ energy_full: 1000.0,
+ state: battery::State::Charging,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 90
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = Some(String::from(" 80% "));
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn battery_discharging() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 800.0,
+ energy_full: 1000.0,
+ state: battery::State::Discharging,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 100
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = Some(String::from(" 80% "));
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn battery_unknown() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 0.0,
+ energy_full: 1.0,
+ state: battery::State::Unknown,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 100
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = Some(String::from(" 0% "));
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn battery_empty() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 0.0,
+ energy_full: 1000.0,
+ state: battery::State::Empty,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 100
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = Some(String::from(" 0% "));
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn battery_hidden_when_percentage_above_threshold() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 600.0,
+ energy_full: 1000.0,
+ state: battery::State::Full,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 50
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = None;
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn battery_uses_style() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 400.0,
+ energy_full: 1000.0,
+ state: battery::State::Discharging,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 50
+ style = "bold red"
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = Some(format!("{} ", Color::Red.bold().paint(" 40%")));
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn battery_displayed_precision() {
+ let mut mock = MockBatteryInfoProvider::new();
+
+ mock.expect_get_battery_info().times(1).returning(|| {
+ Some(BatteryInfo {
+ energy: 129.87654,
+ energy_full: 1000.0,
+ state: battery::State::Discharging,
+ })
+ });
+
+ let actual = ModuleRenderer::new("battery")
+ .config(toml::toml! {
+ [[battery.display]]
+ threshold = 100
+ style = ""
+ })
+ .battery_info_provider(&mock)
+ .collect();
+ let expected = Some(String::from(" 13% "));
+
+ assert_eq!(expected, actual);
+ }
+}
diff --git a/src/modules/mod.rs b/src/modules/mod.rs
index 674a0fc5b..781bc732a 100644
--- a/src/modules/mod.rs
+++ b/src/modules/mod.rs
@@ -64,6 +64,9 @@ mod zig;
#[cfg(feature = "battery")]
mod battery;
+#[cfg(feature = "battery")]
+pub use self::battery::{BatteryInfoProvider, BatteryStatusProviderImpl};
+
use crate::config::RootModuleConfig;
use crate::context::{Context, Shell};
use crate::module::Module;
diff --git a/src/test/mod.rs b/src/test/mod.rs
index c81d5958b..299b6f309 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -121,6 +121,15 @@ impl<'a> ModuleRenderer<'a> {
self
}
+ #[cfg(feature = "battery")]
+ pub fn battery_info_provider(
+ mut self,
+ battery_info_provider: &'a (dyn crate::modules::BatteryInfoProvider + Send + Sync),
+ ) -> Self {
+ self.context.battery_info_provider = battery_info_provider;
+ self
+ }
+
/// Renders the module returning its output
pub fn collect(self) -> Option<String> {
let ret = crate::print::get_module(self.name, self.context);