diff --git a/Makefile b/Makefile index 74b6a694e..b4e463020 100644 --- a/Makefile +++ b/Makefile @@ -188,7 +188,8 @@ TEST_PROGS := \ truncate \ tsort \ unlink \ - unexpand + unexpand \ + wc TEST ?= $(TEST_PROGS) diff --git a/src/wc/wc.rs b/src/wc/wc.rs index 3149a3d4b..11e23403e 100644 --- a/src/wc/wc.rs +++ b/src/wc/wc.rs @@ -25,8 +25,44 @@ use std::str::from_utf8; #[macro_use] mod util; +struct Settings { + show_bytes: bool, + show_chars: bool, + show_lines: bool, + show_words: bool, + show_max_line_length: bool, +} + +impl Settings { + fn new(matches: &Matches) -> Settings { + let settings = Settings { + show_bytes: matches.opt_present("bytes"), + show_chars: matches.opt_present("chars"), + show_lines: matches.opt_present("lines"), + show_words: matches.opt_present("words"), + show_max_line_length: matches.opt_present("L"), + }; + + if settings.show_bytes + || settings.show_chars + || settings.show_lines + || settings.show_words + || settings.show_max_line_length { + return settings; + } + + Settings { + show_bytes: true, + show_chars: false, + show_lines: true, + show_words: true, + show_max_line_length: false, + } + } +} + struct Result { - filename: String, + title: String, bytes: usize, chars: usize, lines: usize, @@ -73,7 +109,9 @@ pub fn uumain(args: Vec) -> i32 { matches.free.push("-".to_string()); } - match wc(&matches) { + let settings = Settings::new(&matches); + + match wc(matches.free, &settings) { Ok(()) => ( /* pass */ ), Err(e) => return e } @@ -93,7 +131,7 @@ fn is_word_seperator(byte: u8) -> bool { byte == SPACE || byte == TAB || byte == CR || byte == SYN || byte == FF } -pub fn wc(matches: &Matches) -> StdResult<(), i32> { +fn wc(files: Vec, settings: &Settings) -> StdResult<(), i32> { let mut total_line_count: usize = 0; let mut total_word_count: usize = 0; let mut total_char_count: usize = 0; @@ -101,9 +139,9 @@ pub fn wc(matches: &Matches) -> StdResult<(), i32> { let mut total_longest_line_length: usize = 0; let mut results = vec!(); - let mut max_str_len: usize = 0; + let mut max_width: usize = 0; - for path in matches.free.iter() { + for path in files.iter() { let mut reader = try!(open(&path[..])); let mut line_count: usize = 0; @@ -154,7 +192,7 @@ pub fn wc(matches: &Matches) -> StdResult<(), i32> { } results.push(Result { - filename: path.to_string(), + title: path.to_string(), bytes: byte_count, chars: char_count, lines: line_count, @@ -172,51 +210,47 @@ pub fn wc(matches: &Matches) -> StdResult<(), i32> { } // used for formatting - max_str_len = total_byte_count.to_string().len(); + max_width = total_byte_count.to_string().len() + 1; } for result in results.iter() { - print_stats(&result.filename[..], result.lines, result.words, result.chars, result.bytes, result.max_line_length, matches, max_str_len); + print_stats(settings, &result, max_width); } - if matches.free.len() > 1 { - print_stats("total", total_line_count, total_word_count, total_char_count, total_byte_count, total_longest_line_length, matches, max_str_len); + if files.len() > 1 { + let result = Result { + title: "total".to_string(), + bytes: total_byte_count, + chars: total_char_count, + lines: total_line_count, + words: total_word_count, + max_line_length: total_longest_line_length, + }; + print_stats(settings, &result, max_width); } Ok(()) } -fn print_stats(filename: &str, line_count: usize, word_count: usize, char_count: usize, - byte_count: usize, longest_line_length: usize, matches: &Matches, max_str_len: usize) { - if matches.opt_present("lines") { - print!("{:1$}", line_count, max_str_len); +fn print_stats(settings: &Settings, result: &Result, max_width: usize) { + if settings.show_lines { + print!("{:1$}", result.lines, max_width); } - if matches.opt_present("words") { - print!("{:1$}", word_count, max_str_len); + if settings.show_words { + print!("{:1$}", result.words, max_width); } - if matches.opt_present("bytes") { - print!("{:1$}", byte_count, max_str_len); + if settings.show_bytes { + print!("{:1$}", result.bytes, max_width); } - if matches.opt_present("chars") { - print!("{:1$}", char_count, max_str_len); + if settings.show_chars { + print!("{:1$}", result.chars, max_width); } - if matches.opt_present("max-line-length") { - print!("{:1$}", longest_line_length, max_str_len); + if settings.show_max_line_length { + print!("{:1$}", result.max_line_length, max_width); } - // defaults - if !matches.opt_present("bytes") - && !matches.opt_present("chars") - && !matches.opt_present("lines") - && !matches.opt_present("words") - && !matches.opt_present("max-line-length") { - print!("{:1$}", line_count, max_str_len); - print!("{:1$}", word_count, max_str_len + 1); - print!("{:1$}", byte_count, max_str_len + 1); - } - - if filename != "-" { - println!(" {}", filename); + if result.title != "-" { + println!(" {}", result.title); } else { println!(""); diff --git a/test/fixtures/wc/alice_in_wonderland.txt b/test/fixtures/wc/alice_in_wonderland.txt new file mode 100644 index 000000000..a95562a1c --- /dev/null +++ b/test/fixtures/wc/alice_in_wonderland.txt @@ -0,0 +1,5 @@ +Alice was beginning to get very tired of sitting by +her sister on the bank, and of having nothing to do: once or twice +she had peeped into the book her sister was reading, but it had no +pictures or conversations in it, "and what is the use of a book," +thought Alice "without pictures or conversation?" diff --git a/test/fixtures/wc/lorem_ipsum.txt b/test/fixtures/wc/lorem_ipsum.txt new file mode 100644 index 000000000..16752446c --- /dev/null +++ b/test/fixtures/wc/lorem_ipsum.txt @@ -0,0 +1,13 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing +elit. Nunc interdum suscipit sem vel ornare. Proin euismod, justo +sed mollis dictum, eros urna ultricies augue, eu pharetra mi ex id +ante. Duis convallis porttitor aliquam. Nunc vitae tincidunt ex. +Suspendisse iaculis ligula ac diam consectetur lacinia. Donec vel +velit dui. Etiam fringilla, dolor quis tempor vehicula, lacus +turpis bibendum velit, et pellentesque elit odio a magna. Cras +vulputate tortor non libero vehicula euismod. Aliquam tincidunt +nisl eget enim cursus, viverra sagittis magna commodo. Cras rhoncus +egestas leo nec blandit. Suspendisse potenti. Etiam ullamcorper +leo vel lacus vestibulum, cursus semper eros efficitur. In hac +habitasse platea dictumst. Phasellus scelerisque vehicula +fringilla. diff --git a/test/fixtures/wc/moby_dick.txt b/test/fixtures/wc/moby_dick.txt new file mode 100644 index 000000000..193dc8e35 --- /dev/null +++ b/test/fixtures/wc/moby_dick.txt @@ -0,0 +1,18 @@ +Call me Ishmael. Some years ago - never mind how long +precisely - having little or no money in my purse, and nothing +particular to interest me on shore, I thought I would sail about a +little and see the watery part of the world. It is a way I have of +driving off the spleen and regulating the circulation. Whenever I +find myself growing grim about the mouth; whenever it is a damp, +drizzly November in my soul; whenever I find myself involuntarily +pausing before coffin warehouses, and bringing up the rear of every +funeral I meet; and especially whenever my hypos get such an upper +hand of me, that it requires a strong moral principle to prevent me +from deliberately stepping into the street, and methodically +knocking people's hats off - then, I account it high time to get to +sea as soon as I can. This is my substitute for pistol and ball. +With a philosophical flourish Cato throws himself upon his sword; I +quietly take to the ship. There is nothing surprising in this. If +they but knew it, almost all men in their degree, some time or +other, cherish very nearly the same feelings towards the ocean with +me. diff --git a/test/wc.rs b/test/wc.rs new file mode 100644 index 000000000..5cb8f3b59 --- /dev/null +++ b/test/wc.rs @@ -0,0 +1,57 @@ +use std::process::Command; +use util::*; + +static PROGNAME: &'static str = "./wc"; + +#[path = "common/util.rs"] +#[macro_use] +mod util; + +#[test] +fn test_stdin_default() { + let mut cmd = Command::new(PROGNAME); + let result = run_piped_stdin(&mut cmd, get_file_contents("lorem_ipsum.txt")); + assert_eq!(result.stdout, " 13 109 772\n"); +} + +#[test] +fn test_stdin_only_bytes() { + let mut cmd = Command::new(PROGNAME); + let result = run_piped_stdin(&mut cmd.args(&["-c"]), get_file_contents("lorem_ipsum.txt")); + assert_eq!(result.stdout, " 772\n"); +} + +#[test] +fn test_stdin_all_counts() { + let mut cmd = Command::new(PROGNAME); + let result = run_piped_stdin(&mut cmd.args(&["-c", "-m", "-l", "-L", "-w"]), get_file_contents("alice_in_wonderland.txt")); + assert_eq!(result.stdout, " 5 57 302 302 66\n"); +} + +#[test] +fn test_single_default() { + let mut cmd = Command::new(PROGNAME); + let result = run(&mut cmd.arg("moby_dick.txt")); + assert_eq!(result.stdout, " 18 204 1115 moby_dick.txt\n"); +} + +#[test] +fn test_single_only_lines() { + let mut cmd = Command::new(PROGNAME); + let result = run(&mut cmd.args(&["-l", "moby_dick.txt"])); + assert_eq!(result.stdout, " 18 moby_dick.txt\n"); +} + +#[test] +fn test_single_all_counts() { + let mut cmd = Command::new(PROGNAME); + let result = run(&mut cmd.args(&["-c", "-l", "-L", "-m", "-w", "alice_in_wonderland.txt"])); + assert_eq!(result.stdout, " 5 57 302 302 66 alice_in_wonderland.txt\n"); +} + +#[test] +fn test_multiple_default() { + let mut cmd = Command::new(PROGNAME); + let result = run(&mut cmd.args(&["lorem_ipsum.txt", "moby_dick.txt", "alice_in_wonderland.txt"])); + assert_eq!(result.stdout, " 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 5 57 302 alice_in_wonderland.txt\n 36 370 2189 total\n"); +}