From 0fa08757fa6953a1aa7734e20917b88ef46c8391 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 31 Mar 2023 08:16:46 +0200 Subject: [PATCH] wc: implement --total --- src/uu/wc/src/wc.rs | 83 +++++++++++++++++++++++++++++++++------- tests/by-util/test_wc.rs | 56 +++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 14 deletions(-) diff --git a/src/uu/wc/src/wc.rs b/src/uu/wc/src/wc.rs index 0b7b164a8..984722dd1 100644 --- a/src/uu/wc/src/wc.rs +++ b/src/uu/wc/src/wc.rs @@ -42,6 +42,7 @@ struct Settings { show_max_line_length: bool, files0_from_stdin_mode: bool, title_quoting_style: QuotingStyle, + total_when: TotalWhen, } impl Settings { @@ -65,6 +66,7 @@ impl Settings { show_max_line_length: matches.get_flag(options::MAX_LINE_LENGTH), files0_from_stdin_mode, title_quoting_style, + total_when: matches.get_one::(options::TOTAL).unwrap().into(), }; if settings.show_bytes @@ -84,6 +86,7 @@ impl Settings { show_max_line_length: false, files0_from_stdin_mode, title_quoting_style: settings.title_quoting_style, + total_when: settings.total_when, } } @@ -107,6 +110,7 @@ pub mod options { pub static FILES0_FROM: &str = "files0-from"; pub static LINES: &str = "lines"; pub static MAX_LINE_LENGTH: &str = "max-line-length"; + pub static TOTAL: &str = "total"; pub static WORDS: &str = "words"; } @@ -160,6 +164,37 @@ impl Input { } } +/// When to show the "total" line +#[derive(PartialEq)] +enum TotalWhen { + Auto, + Always, + Only, + Never, +} + +impl From<&String> for TotalWhen { + fn from(s: &String) -> Self { + match s.as_ref() { + "auto" => Self::Auto, + "always" => Self::Always, + "only" => Self::Only, + "never" => Self::Never, + _ => unreachable!("Should have been caught by clap"), + } + } +} + +impl TotalWhen { + fn is_total_row_visible(&self, num_inputs: usize) -> bool { + match self { + Self::Auto => num_inputs > 1, + Self::Always | Self::Only => true, + Self::Never => false, + } + } +} + #[derive(Debug)] enum WcError { FilesDisabled(String), @@ -246,6 +281,15 @@ pub fn uu_app() -> Command { .help("print the length of the longest line") .action(ArgAction::SetTrue), ) + .arg( + Arg::new(options::TOTAL) + .long(options::TOTAL) + .value_parser(["auto", "always", "only", "never"]) + .default_value("auto") + .hide_default_value(true) + .value_name("WHEN") + .help("when to print a line with total counts"), + ) .arg( Arg::new(options::WORDS) .short('w') @@ -561,11 +605,19 @@ fn compute_number_width(inputs: &[Input], settings: &Settings) -> usize { } fn wc(inputs: &[Input], settings: &Settings) -> UResult<()> { - let number_width = compute_number_width(inputs, settings); - let mut total_word_count = WordCount::default(); - let num_inputs = inputs.len(); + let (number_width, are_stats_visible, total_row_title) = + if settings.total_when == TotalWhen::Only { + (1, false, None) + } else { + let number_width = compute_number_width(inputs, settings); + let title = Some(String::from("total")); + + (number_width, true, title) + }; + + let is_total_row_visible = settings.total_when.is_total_row_visible(inputs.len()); for input in inputs { let word_count = match word_count_from_input(input, settings) { @@ -595,20 +647,23 @@ fn wc(inputs: &[Input], settings: &Settings) -> UResult<()> { }; total_word_count += word_count; let result = word_count.with_title(input.to_title(&settings.title_quoting_style)); - if let Err(err) = print_stats(settings, &result, number_width) { - show!(USimpleError::new( - 1, - format!( - "failed to print result for {}: {}", - &result.title.unwrap_or_else(|| String::from("")), - err, - ), - )); + + if are_stats_visible { + if let Err(err) = print_stats(settings, &result, number_width) { + show!(USimpleError::new( + 1, + format!( + "failed to print result for {}: {}", + &result.title.unwrap_or_else(|| String::from("")), + err, + ), + )); + } } } - if num_inputs > 1 { - let total_result = total_word_count.with_title(Some(String::from("total"))); + if is_total_row_visible { + let total_result = total_word_count.with_title(total_row_title); if let Err(err) = print_stats(settings, &total_result, number_width) { show!(USimpleError::new( 1, diff --git a/tests/by-util/test_wc.rs b/tests/by-util/test_wc.rs index 3cda99270..4516f770f 100644 --- a/tests/by-util/test_wc.rs +++ b/tests/by-util/test_wc.rs @@ -464,3 +464,59 @@ fn test_files0_from_with_stdin_try_read_from_stdin() { .stderr_contains(MSG) .stdout_is(""); } + +#[test] +fn test_total_auto() { + new_ucmd!() + .args(&["lorem_ipsum.txt", "--total=auto"]) + .run() + .stdout_is(" 13 109 772 lorem_ipsum.txt\n"); + + new_ucmd!() + .args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=auto"]) + .run() + .stdout_is( + " 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 31 313 1887 total\n", + ); +} + +#[test] +fn test_total_always() { + new_ucmd!() + .args(&["lorem_ipsum.txt", "--total=always"]) + .run() + .stdout_is(" 13 109 772 lorem_ipsum.txt\n 13 109 772 total\n"); + + new_ucmd!() + .args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=always"]) + .run() + .stdout_is( + " 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 31 313 1887 total\n", + ); +} + +#[test] +fn test_total_never() { + new_ucmd!() + .args(&["lorem_ipsum.txt", "--total=never"]) + .run() + .stdout_is(" 13 109 772 lorem_ipsum.txt\n"); + + new_ucmd!() + .args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=never"]) + .run() + .stdout_is(" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n"); +} + +#[test] +fn test_total_only() { + new_ucmd!() + .args(&["lorem_ipsum.txt", "--total=only"]) + .run() + .stdout_is("13 109 772\n"); + + new_ucmd!() + .args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=only"]) + .run() + .stdout_is("31 313 1887\n"); +}