Browse Source

meli/utilities: add print utilities for tests

Add:

- eprint_step_fn():  Returns a closure that prints a formatted message,
  without a trailing newline, and prefixed with an increasing counter.
- eprintln_ok_fn(): Returns a closure that prints the string " OK\n" to
  `stderr` with optional color formatting.

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
Manos Pitsidianakis 7 months ago
parent
commit
03df2ac1
3 changed files with 98 additions and 22 deletions
  1. 31 21
      meli/src/sqlite3/tests.rs
  2. 1 1
      meli/src/utilities.rs
  3. 66 0
      meli/src/utilities/tests.rs

+ 31 - 21
meli/src/sqlite3/tests.rs

@@ -32,6 +32,7 @@ use sealed_test::prelude::*;
 use tempfile::TempDir;
 
 use super::*;
+use crate::utilities::tests::{eprint_step_fn, eprintln_ok_fn};
 
 #[test]
 fn test_sqlite3_query_to_sql() {
@@ -104,6 +105,14 @@ fn test_sqlite3_reindex() {
     const ACCOUNT_NAME: &str = "test";
     const DB_FILE_SHOULD_EXIST_ERR_MSG: &str = "A db file should now exist, after indexing.";
 
+    let eprintln_ok = eprintln_ok_fn();
+    let mut eprint_step_closure = eprint_step_fn();
+    macro_rules! eprint_step {
+        ($($arg:tt)+) => {{
+            eprint_step_closure(format_args!($($arg)+));
+        }};
+    }
+
     /// Helper functions
     mod helpers {
         use super::*;
@@ -181,7 +190,7 @@ fn test_sqlite3_reindex() {
 
     let temp_dir = TempDir::new().unwrap();
 
-    print!("Sanitize environment...");
+    eprint_step!("Sanitize environment...");
     for var in [
         "PAGER",
         "MANPATH",
@@ -204,8 +213,8 @@ fn test_sqlite3_reindex() {
         temp_dir.path().join(".local").join(".share"),
     );
 
-    println!(" OK");
-    print!("Create maildir backend we will use for the sqlite3 index database...");
+    eprintln_ok();
+    eprint_step!("Create maildir backend we will use for the sqlite3 index database...");
     let backend_event_queue = Arc::new(Mutex::new(VecDeque::with_capacity(16)));
 
     let backend_event_consumer = {
@@ -221,8 +230,8 @@ fn test_sqlite3_reindex() {
     let acc_name = Arc::<str>::from(maildir.account_name.to_string());
     let collection = melib::Collection::default();
 
-    println!(" OK");
-    print!(
+    eprintln_ok();
+    eprint_step!(
         "Confirm the root mailbox was created by fetching all mailboxes and inspecting their \
          contents..."
     );
@@ -246,8 +255,8 @@ fn test_sqlite3_reindex() {
     assert_eq!(mailbox.special_usage(), SpecialUsageMailbox::Normal);
     assert_eq!(mailbox.count().unwrap(), (0, 0));
 
-    println!(" OK");
-    print!("Insert actual email into our backend...");
+    eprintln_ok();
+    eprint_step!("Insert actual email into our backend...");
 
     macro_rules! batch_entry {
         ($path:literal) => {
@@ -265,8 +274,8 @@ fn test_sqlite3_reindex() {
         batch_entry!("../../../melib/tests/data/git-am-breakage-with-MIME-decoding.mbox.gz"),
     ];
 
-    println!(" OK");
-    print!(
+    eprintln_ok();
+    eprint_step!(
         "Perform a save operation for {} emails...",
         mail_batch.len()
     );
@@ -280,8 +289,8 @@ fn test_sqlite3_reindex() {
         .collect::<Result<Vec<()>>>()
         .unwrap();
 
-    println!(" OK");
-    print!(
+    eprintln_ok();
+    eprint_step!(
         "Perform a manual refresh operation, since we have not spawned any watcher threads with \
          `MailBackend::watch` (we do not need to)..."
     );
@@ -311,8 +320,8 @@ fn test_sqlite3_reindex() {
         }
     }
 
-    println!(" OK");
-    print!("Backend setup over, we're now finally ready to test sqlite3 indexing...");
+    eprintln_ok();
+    eprint_step!("Backend setup over, we're now finally ready to test sqlite3 indexing...");
     let backend_mutex = Arc::new(RwLock::new(maildir as Box<dyn MailBackend>));
 
     assert_eq!(
@@ -345,8 +354,8 @@ fn test_sqlite3_reindex() {
     );
 
     assert_eq!(list_xdg_data_home_dir_entries(), vec![db_path.clone()],);
-    println!(" OK");
-    print!("Ensure re-indexing for a second time does not trigger any errors...");
+    eprintln_ok();
+    eprint_step!("Ensure re-indexing for a second time does not trigger any errors...");
     perform_reindex(
         Arc::clone(&acc_name),
         collection.clone(),
@@ -358,8 +367,8 @@ fn test_sqlite3_reindex() {
     assert_eq!(db_path, db_path_2);
     assert_eq!(list_xdg_data_home_dir_entries(), vec![db_path],);
 
-    println!(" OK");
-    print!("Search for all envelopes, as a smoke test...");
+    eprintln_ok();
+    eprint_step!("Search for all envelopes, as a smoke test...");
     let search_results = perform_search(&acc_name, Query::Body(String::new()));
     assert_eq!(
         search_results.len(),
@@ -375,8 +384,8 @@ fn test_sqlite3_reindex() {
             .collect::<HashSet<EnvelopeHash>>(),
         *collection.get_mailbox(root_mailbox_hash)
     );
-    println!(" OK");
-    print!(
+    eprintln_ok();
+    eprint_step!(
         "Search for torvalds as a submitter, since he sent all those patches we inserted into the \
          backend. So this should return all envelopes as well..."
     );
@@ -393,8 +402,8 @@ fn test_sqlite3_reindex() {
             .collect::<HashSet<EnvelopeHash>>(),
     );
 
-    println!(" OK");
-    print!("Search for only specific recipients, which should not return all envelopes...");
+    eprintln_ok();
+    eprint_step!("Search for only specific recipients, which should not return all envelopes...");
     let search_results = perform_search(&acc_name, Query::To("marc.stevens@cwi.nl".into()));
     assert_eq!(
         search_results.len(),
@@ -415,4 +424,5 @@ fn test_sqlite3_reindex() {
             .map(|env| env.hash())
             .collect::<HashSet<EnvelopeHash>>()
     );
+    eprintln_ok();
 }

+ 1 - 1
meli/src/utilities.rs

@@ -45,7 +45,7 @@ mod tables;
 pub use self::tables::*;
 
 #[cfg(test)]
-mod tests;
+pub mod tests;
 
 pub type AutoCompleteFn = Box<dyn Fn(&Context, &str) -> Vec<AutoCompleteEntry> + Send + Sync>;
 

+ 66 - 0
meli/src/utilities/tests.rs

@@ -176,3 +176,69 @@ fn test_utilities_text_input_field() {
     assert_eq!(field.as_str(), EMOJIGRAM);
     _ = tmpdir.close();
 }
+
+/// Returns a closure that prints the string " OK\n" to `stderr`.
+///
+/// If `stderr` is a TTY, the output will contain escape code sequences to
+/// change the foreground color of the text with the second indexed color
+/// (usually green).
+pub fn eprintln_ok_fn() -> Box<dyn Fn()> {
+    if crate::terminal::is_tty() && std::env::var_os("NO_COLOR").is_none() {
+        struct SetAf2(String);
+        struct Sgr0(String);
+        fn get_tput_sequences() -> Option<(SetAf2, Sgr0)> {
+            use std::process::{Command, Stdio};
+
+            let setaf_2 = SetAf2(
+                String::from_utf8(
+                    Command::new("tput")
+                        .args(["setaf", "2"])
+                        .stdout(Stdio::piped())
+                        .stdin(Stdio::null())
+                        .stderr(Stdio::inherit())
+                        .output()
+                        .ok()?
+                        .stdout,
+                )
+                .ok()?,
+            );
+
+            let sgr0 = Sgr0(
+                String::from_utf8(
+                    Command::new("tput")
+                        .arg("sgr0")
+                        .stdout(Stdio::piped())
+                        .stdin(Stdio::null())
+                        .stderr(Stdio::inherit())
+                        .output()
+                        .ok()?
+                        .stdout,
+                )
+                .ok()?,
+            );
+            Some((setaf_2, sgr0))
+        }
+
+        if let Some((SetAf2(setaf_2), Sgr0(sgr0))) = get_tput_sequences() {
+            return Box::new(move || {
+                eprintln!(" {setaf_2}OK{sgr0}");
+            });
+        }
+    }
+
+    Box::new(|| {
+        eprintln!(" OK");
+    })
+}
+
+/// Returns a closure that prints a formatted message, without a trailing
+/// newline, and prefixed with an increasing counter.
+pub fn eprint_step_fn() -> Box<dyn FnMut(std::fmt::Arguments) -> usize> {
+    let mut counter = 1;
+    Box::new(move |args: std::fmt::Arguments| {
+        let step = counter;
+        eprint!("{step}. {}", args);
+        counter += 1;
+        step
+    })
+}