Decouple report generation from logging

This commit is contained in:
Marc Plano-Lesay 2025-05-02 09:33:25 +10:00
parent df2e6ab126
commit 8158fdcab3
Signed by: kernald
GPG key ID: 66A41B08CC62A6CF
2 changed files with 196 additions and 31 deletions

View file

@ -194,9 +194,8 @@ async fn main() -> Result<()> {
}
}
// Generate report
if let Err(e) = report::generate_report(&action_results, total_new_links) {
warn!("Failed to generate report: {}", e);
for line in report::generate_report(&action_results, total_new_links).lines() {
info!("{}", line);
}
Ok(())

View file

@ -1,7 +1,6 @@
use crate::actions::action::ProcessedMagnets;
use color_eyre::eyre::Result;
use console::{style, Emoji};
use log::info;
use std::collections::HashMap;
static SPARKLES: Emoji = Emoji("", ":sparkles:");
@ -13,10 +12,12 @@ static WARNING: Emoji = Emoji("⚠️", ":warning:");
pub fn generate_report(
action_results: &HashMap<String, ProcessedMagnets>,
total_new_links: usize,
) -> Result<()> {
info!("");
info!(
"{} {} {}",
) -> String {
let mut report = String::new();
report.push_str("\n");
report.push_str(&format!(
"{} {} {}\n",
SPARKLES,
style("Report Summary").bold().underlined(),
style(format!(
@ -25,8 +26,8 @@ pub fn generate_report(
))
.bold()
.green(),
);
info!("");
));
report.push_str("\n");
for (action_name, processed_magnets) in action_results {
let success_count = processed_magnets.success.len();
@ -34,59 +35,224 @@ pub fn generate_report(
let total_count = success_count + failed_count;
// Section header for each action
info!("");
info!(
"{} {} {}",
report.push_str("\n");
report.push_str(&format!(
"{} {} {}\n",
ROCKET,
style(format!("{}", action_name)).bold().underlined().cyan(),
style(format!("({} new links)", total_count)).bold()
);
));
if failed_count == 0 && success_count == 0 {
info!("");
report.push_str("\n");
continue;
}
// Success/failure summary
if failed_count > 0 {
info!(
" {} Success: {}, {} Failure: {}",
report.push_str(&format!(
" {} Success: {}, {} Failure: {}\n",
style("").green(),
style(success_count).bold().green(),
style("").red(),
style(failed_count).bold().red()
);
));
} else {
info!(
" {} Success: {}",
report.push_str(&format!(
" {} Success: {}\n",
style("").green(),
style(success_count).bold().green()
);
));
}
info!("");
report.push_str("\n");
// List successful magnets
if success_count > 0 {
info!(
" {} {}",
report.push_str(&format!(
" {} {}\n",
style("").green(),
style("Added:").bold().green()
);
));
for magnet in &processed_magnets.success {
info!(" {} {}", LINK, style(&magnet.title).italic());
report.push_str(&format!(
" {} {}\n",
LINK,
style(&magnet.title).italic()
));
}
info!("");
report.push_str("\n");
}
// List failed magnets
if failed_count > 0 {
info!(" {} {}", style("").red(), style("Failed:").bold().red());
report.push_str(&format!(
" {} {}\n",
style("").red(),
style("Failed:").bold().red()
));
for magnet in &processed_magnets.failed {
info!(" {} {}", WARNING, style(&magnet.title).italic());
report.push_str(&format!(
" {} {}\n",
WARNING,
style(&magnet.title).italic()
));
}
info!("");
report.push_str("\n");
}
}
Ok(())
report
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::Magnet;
use chrono::{DateTime, NaiveDateTime};
// Helper function to strip ANSI color codes from a string for testing
fn strip_ansi_codes(s: &str) -> String {
// This regex matches ANSI escape codes
let re = regex::Regex::new(r"\x1B\[[0-9;]*[a-zA-Z]").unwrap();
re.replace_all(s, "").to_string()
}
fn create_test_magnet(title: &str) -> Magnet {
Magnet {
id: Some(1),
title: title.to_string(),
submitter: "test_user".to_string(),
subreddit: "test_subreddit".to_string(),
link: "magnet:?xt=urn:btih:test".to_string(),
published_at: DateTime::from_timestamp(0, 0).unwrap().naive_utc(),
imdb_id: None,
}
}
#[test]
fn test_generate_report_empty() {
let action_results = HashMap::new();
let total_new_links = 0;
let report = generate_report(&action_results, total_new_links);
let clean_report = strip_ansi_codes(&report);
assert!(clean_report.contains("Report Summary"));
assert!(clean_report.contains("0 new links added to the database"));
}
#[test]
fn test_generate_report_only_success() {
let mut action_results = HashMap::new();
let processed_magnets = ProcessedMagnets {
success: vec![
create_test_magnet("Test Success 1"),
create_test_magnet("Test Success 2"),
],
failed: vec![],
};
action_results.insert("TestAction".to_string(), processed_magnets);
let total_new_links = 2;
let report = strip_ansi_codes(&generate_report(&action_results, total_new_links));
assert!(report.contains("Report Summary"));
assert!(report.contains("2 new links added to the database"));
assert!(report.contains("TestAction"));
assert!(report.contains("Success: 2"));
assert!(report.contains("Test Success 1"));
assert!(report.contains("Test Success 2"));
assert!(!report.contains("Failure:"));
}
#[test]
fn test_generate_report_only_failed() {
let mut action_results = HashMap::new();
let processed_magnets = ProcessedMagnets {
success: vec![],
failed: vec![
create_test_magnet("Test Failed 1"),
create_test_magnet("Test Failed 2"),
],
};
action_results.insert("TestAction".to_string(), processed_magnets);
let total_new_links = 0;
let report = strip_ansi_codes(&generate_report(&action_results, total_new_links));
assert!(report.contains("Report Summary"));
assert!(report.contains("0 new links added to the database"));
assert!(report.contains("TestAction"));
assert!(report.contains("Success: 0"));
assert!(report.contains("Failure: 2"));
assert!(report.contains("Test Failed 1"));
assert!(report.contains("Test Failed 2"));
}
#[test]
fn test_generate_report_success_and_failed() {
let mut action_results = HashMap::new();
let processed_magnets = ProcessedMagnets {
success: vec![create_test_magnet("Test Success 1")],
failed: vec![create_test_magnet("Test Failed 1")],
};
action_results.insert("TestAction".to_string(), processed_magnets);
let total_new_links = 1;
let report = strip_ansi_codes(&generate_report(&action_results, total_new_links));
assert!(report.contains("Report Summary"));
assert!(report.contains("1 new links added to the database"));
assert!(report.contains("TestAction"));
assert!(report.contains("Success: 1"));
assert!(report.contains("Failure: 1"));
assert!(report.contains("Test Success 1"));
assert!(report.contains("Test Failed 1"));
}
#[test]
fn test_generate_report_multiple_actions() {
let mut action_results = HashMap::new();
let processed_magnets1 = ProcessedMagnets {
success: vec![
create_test_magnet("Action1 Success 1"),
create_test_magnet("Action1 Success 2"),
],
failed: vec![create_test_magnet("Action1 Failed 1")],
};
let processed_magnets2 = ProcessedMagnets {
success: vec![create_test_magnet("Action2 Success 1")],
failed: vec![],
};
let processed_magnets3 = ProcessedMagnets {
success: vec![],
failed: vec![],
};
action_results.insert("Action1".to_string(), processed_magnets1);
action_results.insert("Action2".to_string(), processed_magnets2);
action_results.insert("EmptyAction".to_string(), processed_magnets3);
let total_new_links = 3;
let report = strip_ansi_codes(&generate_report(&action_results, total_new_links));
assert!(report.contains("Report Summary"));
assert!(report.contains("3 new links added to the database"));
assert!(report.contains("Action1"));
assert!(report.contains("Action1 Success 1"));
assert!(report.contains("Action1 Success 2"));
assert!(report.contains("Action1 Failed 1"));
assert!(report.contains("Action2"));
assert!(report.contains("Action2 Success 1"));
assert!(report.contains("EmptyAction"));
}
}