diff --git a/src/rules.rs b/src/rules.rs index 41b3f87..b449f96 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -202,9 +202,11 @@ impl Rules { current_labels.append(&mut ls); } - if label.is_some() && current_labels.contains(label.unwrap()) { - log::warn!("a rule already applies to label {}", label.unwrap()); - return self; + if let Some(label_ref) = label { + if current_labels.contains(label_ref) { + log::warn!("a rule already applies to label {}", label_ref); + return self; + } } let id = if let Some((_, max)) = self.rules.iter().max_by_key(|(_, r)| r.id()) { @@ -497,8 +499,15 @@ impl Rules { /// * IO errors when writing to the file system /// * File system permission errors pub fn save(&self) -> Result<()> { - let home_dir = env::home_dir().unwrap(); + let home_dir = env::home_dir().ok_or_else(|| { + Error::HomeExpansionFailed("~/.cull-gmail/rules.toml".to_string()) + })?; let path = PathBuf::new().join(home_dir).join(".cull-gmail/rules.toml"); + + // Ensure directory exists + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } let res = toml::to_string(self); log::trace!("toml conversion result: {res:#?}"); @@ -536,7 +545,9 @@ impl Rules { /// * TOML parsing errors if the file is malformed /// * File not found errors if the configuration doesn't exist pub fn load() -> Result { - let home_dir = env::home_dir().unwrap(); + let home_dir = env::home_dir().ok_or_else(|| { + Error::HomeExpansionFailed("~/.cull-gmail/rules.toml".to_string()) + })?; let path = PathBuf::new().join(home_dir).join(".cull-gmail/rules.toml"); log::trace!("Loading config from {}", path.display()); @@ -584,7 +595,10 @@ mod tests { fn setup_test_environment() { get_test_logger(); // Clean up any existing test files - let home_dir = env::home_dir().unwrap(); + let Some(home_dir) = env::home_dir() else { + // Skip cleanup if home directory cannot be determined + return; + }; let test_config_dir = home_dir.join(".cull-gmail"); let test_rules_file = test_config_dir.join("rules.toml"); if test_rules_file.exists() { diff --git a/src/rules/eol_rule.rs b/src/rules/eol_rule.rs index cb99f99..dc7624d 100644 --- a/src/rules/eol_rule.rs +++ b/src/rules/eol_rule.rs @@ -320,7 +320,7 @@ impl EolRule { /// Describe the action that will be performed by the rule and its conditions fn get_action_period_count_strings(&self) -> (String, usize, String) { let count = &self.retention[2..]; - let count = count.parse::().unwrap(); + let count = count.parse::().unwrap_or(0); // Default to 0 if parsing fails let mut period = match self.retention.chars().nth(0) { Some('d') => "day", Some('w') => "week", @@ -375,11 +375,11 @@ impl EolRule { let deadline = match message_age { MessageAge::Days(c) => { let delta = TimeDelta::days(c); - today.checked_sub_signed(delta).unwrap() + today.checked_sub_signed(delta)? } MessageAge::Weeks(c) => { let delta = TimeDelta::weeks(c); - today.checked_sub_signed(delta).unwrap() + today.checked_sub_signed(delta)? } MessageAge::Months(c) => { let day = today.day(); @@ -398,7 +398,7 @@ impl EolRule { Local .with_ymd_and_hms(new_year, new_month, day, 0, 0, 0) - .unwrap() + .single()? } MessageAge::Years(c) => { let day = today.day(); @@ -408,7 +408,7 @@ impl EolRule { Local .with_ymd_and_hms(new_year, month, day, 0, 0, 0) - .unwrap() + .single()? } }; @@ -477,8 +477,8 @@ mod test { fn test_eol_query_for_eol_rule_5_years() { let rule = build_test_rule(crate::MessageAge::Years(5)); - let test_today = Local.with_ymd_and_hms(2025, 9, 15, 0, 0, 0).unwrap(); - let query = rule.calculate_for_date(test_today).unwrap(); + let test_today = Local.with_ymd_and_hms(2025, 9, 15, 0, 0, 0).single().unwrap(); + let query = rule.calculate_for_date(test_today).expect("Failed to calculate query"); assert_eq!("before: 2020-09-15", query); } @@ -487,8 +487,8 @@ mod test { fn test_eol_query_for_eol_rule_1_month() { let rule = build_test_rule(crate::MessageAge::Months(1)); - let test_today = Local.with_ymd_and_hms(2025, 9, 15, 0, 0, 0).unwrap(); - let query = rule.calculate_for_date(test_today).unwrap(); + let test_today = Local.with_ymd_and_hms(2025, 9, 15, 0, 0, 0).single().unwrap(); + let query = rule.calculate_for_date(test_today).expect("Failed to calculate query"); assert_eq!("before: 2025-08-15", query); } @@ -497,8 +497,8 @@ mod test { fn test_eol_query_for_eol_rule_13_weeks() { let rule = build_test_rule(crate::MessageAge::Weeks(13)); - let test_today = Local.with_ymd_and_hms(2025, 9, 15, 0, 0, 0).unwrap(); - let query = rule.calculate_for_date(test_today).unwrap(); + let test_today = Local.with_ymd_and_hms(2025, 9, 15, 0, 0, 0).single().unwrap(); + let query = rule.calculate_for_date(test_today).expect("Failed to calculate query"); assert_eq!("before: 2025-06-16", query); } @@ -507,8 +507,8 @@ mod test { fn test_eol_query_for_eol_rule_365_days() { let rule = build_test_rule(crate::MessageAge::Days(365)); - let test_today = Local.with_ymd_and_hms(2025, 9, 15, 0, 0, 0).unwrap(); - let query = rule.calculate_for_date(test_today).unwrap(); + let test_today = Local.with_ymd_and_hms(2025, 9, 15, 0, 0, 0).single().unwrap(); + let query = rule.calculate_for_date(test_today).expect("Failed to calculate query"); assert_eq!("before: 2024-09-15", query); }