From 6d51a4d3a69918237d0def3addf9e5d11f5207cd Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Wed, 23 Jul 2025 11:19:22 -0400 Subject: [PATCH] Duration to String enhanced with tests Adds checks for if a bit in a u8 is set or clear --- src/duration_to_string.rs | 36 ---------------- src/duration_to_string/duration_to_string.rs | 38 +++++++++++++++++ src/duration_to_string/mod.rs | 2 + src/duration_to_string/tests.rs | 43 ++++++++++++++++++++ src/number_system_conversion.rs | 23 +++++++++-- tests/data_to_text.rs | 1 - tests/number_system_conversion.rs | 32 ++++++++++++++- 7 files changed, 133 insertions(+), 42 deletions(-) delete mode 100644 src/duration_to_string.rs create mode 100644 src/duration_to_string/duration_to_string.rs create mode 100644 src/duration_to_string/mod.rs create mode 100644 src/duration_to_string/tests.rs diff --git a/src/duration_to_string.rs b/src/duration_to_string.rs deleted file mode 100644 index 2c0ac2f..0000000 --- a/src/duration_to_string.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::time::Duration; - -pub fn duration_to_string(to_convert: Duration) -> String { - let mut total_seconds = to_convert.as_secs() as u32; - let mut working_string = String::new(); - - if total_seconds > 86400 { - // days - let num_days = (total_seconds / SECONDS_IN_DAY) as u32; - working_string = format!("{} days", num_days); - total_seconds = total_seconds - (num_days * SECONDS_IN_DAY); - } - - if total_seconds > 3600 { - // hours - let num_hours = (total_seconds / SECONDS_IN_HOUR) as u32; - if num_hours > 0 { - working_string = format!("{} {} hours", working_string, num_hours); - total_seconds = total_seconds - (num_hours * SECONDS_IN_HOUR); - } - } - if total_seconds > 60 { - let num_minutes = (total_seconds / SECONDS_IN_MINUTE) as u32; - if num_minutes > 0 { - working_string = format!("{} {} minutes", working_string, num_minutes); - total_seconds = total_seconds - (num_minutes * SECONDS_IN_MINUTE); - } - // minutes - } - - - working_string = format!("{} {} seconds", working_string, total_seconds); - - working_string -} - diff --git a/src/duration_to_string/duration_to_string.rs b/src/duration_to_string/duration_to_string.rs new file mode 100644 index 0000000..66f6de4 --- /dev/null +++ b/src/duration_to_string/duration_to_string.rs @@ -0,0 +1,38 @@ +use std::time::Duration; + +pub const SECONDS_IN_MINUTE: u32 = 60; +pub const SECONDS_IN_HOUR: u32 = SECONDS_IN_MINUTE * 60; +pub const SECONDS_IN_DAY: u32 = SECONDS_IN_HOUR * 24; + +pub fn duration_to_string(to_convert: Duration, show_zeros: Option) -> String { + const SECONDS_IN_DAY: u32 = 86400; + const SECONDS_IN_HOUR: u32 = 3600; + const SECONDS_IN_MINUTE: u32 = 60; + + let should_show_zero = show_zeros.unwrap_or(false); + let mut total_seconds = to_convert.as_secs() as u32; + let mut parts = Vec::new(); + + let units = [ + (SECONDS_IN_DAY, "day"), + (SECONDS_IN_HOUR, "hour"), + (SECONDS_IN_MINUTE, "minute"), + (1, "second"), + ]; + + for &(unit_seconds, unit_name) in &units { + let count = total_seconds / unit_seconds; + total_seconds %= unit_seconds; + + if count > 0 || should_show_zero { + let label = if count == 1 { + unit_name.to_string() + } else { + format!("{}s", unit_name) + }; + parts.push(format!("{} {}", count, label)); + } + } + + parts.join(" ") +} diff --git a/src/duration_to_string/mod.rs b/src/duration_to_string/mod.rs new file mode 100644 index 0000000..8786feb --- /dev/null +++ b/src/duration_to_string/mod.rs @@ -0,0 +1,2 @@ +pub mod duration_to_string; +mod tests; diff --git a/src/duration_to_string/tests.rs b/src/duration_to_string/tests.rs new file mode 100644 index 0000000..d075b22 --- /dev/null +++ b/src/duration_to_string/tests.rs @@ -0,0 +1,43 @@ +use std::time::Duration; +use crate::duration_to_string::duration_to_string::duration_to_string; + +#[cfg(test)] +mod test { + use super::*; + use crate::duration_to_string::duration_to_string::*; + + #[test] + fn multi_duration_to_string() { + let params: Vec<(&str, Duration, Option)> = vec![ + ("1 second", Duration::from_secs(1), Some(false)), + ("4 seconds", Duration::from_secs(4), Some(false)), + ("1 minute", Duration::from_secs(SECONDS_IN_MINUTE as u64), Some(false)), + ("4 minutes", Duration::from_secs((SECONDS_IN_MINUTE * 4) as u64), Some(false)), + ("1 hour", Duration::from_secs(SECONDS_IN_HOUR as u64), Some(false)), + ("4 hours", Duration::from_secs((SECONDS_IN_HOUR * 4) as u64), Some(false)), + ("4 hours 5 minutes", Duration::from_secs((SECONDS_IN_HOUR * 4 + SECONDS_IN_MINUTE * 5) as u64), Some(false)), + ("1 day", Duration::from_secs(SECONDS_IN_DAY as u64), Some(false)), + ("0 days 0 hours 0 minutes 1 second", Duration::from_secs(1), Some(true)), + ("0 days 0 hours 0 minutes 4 seconds", Duration::from_secs(4), Some(true)), + ("0 days 0 hours 1 minute 0 seconds", Duration::from_secs(SECONDS_IN_MINUTE as u64), Some(true)), + ("0 days 0 hours 4 minutes 0 seconds", Duration::from_secs((SECONDS_IN_MINUTE * 4) as u64), Some(true)), + ("0 days 1 hour 0 minutes 0 seconds", Duration::from_secs(SECONDS_IN_HOUR as u64), Some(true)), + ("0 days 4 hours 0 minutes 0 seconds", Duration::from_secs((SECONDS_IN_HOUR * 4) as u64), Some(true)), + ("0 days 4 hours 5 minutes 0 seconds", Duration::from_secs((SECONDS_IN_HOUR * 4 + SECONDS_IN_MINUTE * 5) as u64), Some(true)), + ("1 day 0 hours 0 minutes 0 seconds", Duration::from_secs(SECONDS_IN_DAY as u64), Some(true)), + ("1 day 0 hours 0 minutes 1 second", Duration::from_secs((SECONDS_IN_DAY + 1) as u64), Some(true)), + ("1 second", Duration::from_secs(1), None), + ("4 seconds", Duration::from_secs(4), None), + ("1 minute", Duration::from_secs(SECONDS_IN_MINUTE as u64), None), + ("4 minutes", Duration::from_secs((SECONDS_IN_MINUTE * 4) as u64), None), + ("1 hour", Duration::from_secs(SECONDS_IN_HOUR as u64), None), + ("4 hours", Duration::from_secs((SECONDS_IN_HOUR * 4) as u64), None), + ("4 hours 5 minutes", Duration::from_secs((SECONDS_IN_HOUR * 4 + SECONDS_IN_MINUTE * 5) as u64), None), + ("1 day", Duration::from_secs(SECONDS_IN_DAY as u64), None), + ]; + + for (expected, actual, show) in params { + assert_eq!(expected, duration_to_string(actual, show)); + } + } +} diff --git a/src/number_system_conversion.rs b/src/number_system_conversion.rs index dea05c9..1c92559 100644 --- a/src/number_system_conversion.rs +++ b/src/number_system_conversion.rs @@ -8,12 +8,12 @@ impl NumberSystemConversion { /// ex: 0xff -> true, true, true, true, true, true, true, true /// 0xa0 -> true, false, true, false, false, false, false, false pub fn byte_to_bool(from: u8) -> [bool; 8] { - let mut return_values = [false; 8]; + let mut result = [false; 8]; for i in 0..8 { - let new_value = from >> i & 0x1 == 1; - return_values[i as usize] = new_value; + // Extract the i-th bit and convert it to a boolean + result[i] = ((from >> i) & 1) != 0; } - return_values + result } /// bool_to_byte @@ -114,4 +114,19 @@ impl NumberSystemConversion { pub fn clear_low_bits(to_clear: u16) -> u16 { to_clear & 0xff00 } + + /// is_bit_set + /// + /// Checks if a specified bit is set + pub fn is_bit_set(to_check: u8, bit_to_check: u8) -> bool { + (to_check >> bit_to_check) & 0x01 == 1 + } + + /// is_bit_clear + /// + /// Checks if a specified bit is clear + /// LSB = 0 MSB = 7 + pub fn is_bit_clear(to_check: u8, bit_to_check: u8) -> bool { + (to_check >> bit_to_check) & 0x01 != 1 + } } diff --git a/tests/data_to_text.rs b/tests/data_to_text.rs index 2b3912c..f126fa9 100644 --- a/tests/data_to_text.rs +++ b/tests/data_to_text.rs @@ -8,7 +8,6 @@ fn read_bin(source: &str) -> Vec { fn read_display(source: &str) -> String { let full_path = format!("/home/tmerritt/Projects/trevors_utilities/resources/data_to_text/{}.display", source); - // println!("FULL PATH DIS: [{}]", full_path); std::fs::read_to_string(full_path).unwrap() } diff --git a/tests/number_system_conversion.rs b/tests/number_system_conversion.rs index 4e860ed..9c9e851 100644 --- a/tests/number_system_conversion.rs +++ b/tests/number_system_conversion.rs @@ -147,4 +147,34 @@ fn clear_low_bits() { NumberSystemConversion::clear_low_bits(src), dst); } -} \ No newline at end of file +} + +#[test] +fn is_bit_set_checks() { + let params = vec![ + (0b0000_0001, vec![true, false, false, false, false, false, false, false]), + (0b1111_1111, vec![true, true, true, true, true, true, true, true]), + (0b1010_1010, vec![false, true, false, true, false, true, false, true]) + ]; + + for (base, options) in params { + for (index, expected) in options.iter().enumerate() { + assert_eq!(*expected, NumberSystemConversion::is_bit_set(base, index as u8)); + } + } +} + +#[test] +fn is_bit_clear_checks() { + let params = vec![ + (0b0000_0001, vec![false, true, true, true, true, true, true, true]), + (0b1111_1111, vec![false, false, false, false, false, false, false, false]), + (0b1010_1010, vec![true, false, true, false, true, false, true, false]) + ]; + + for (base, options) in params { + for (index, expected) in options.iter().enumerate() { + assert_eq!(*expected, NumberSystemConversion::is_bit_clear(base, index as u8)); + } + } +}