From 826d8a65302016fecdd326f894875f937b8ce845 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Sat, 30 May 2015 16:34:26 -0400 Subject: [PATCH 1/4] Add newline when printing lines. --- src/head/head.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/head/head.rs b/src/head/head.rs index 6b4998b20..0ce2a961f 100644 --- a/src/head/head.rs +++ b/src/head/head.rs @@ -170,7 +170,7 @@ fn head(reader: &mut BufReader, count: usize, use_bytes: bool) -> bo } } else { for line in reader.lines().take(count) { - if !pipe_print!("{}", line.unwrap()) { + if !pipe_println!("{}", line.unwrap()) { return false; } } From b008ed103d086d8444db9dc0d68f6970bbc5c000 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Sat, 30 May 2015 17:54:16 -0400 Subject: [PATCH 2/4] Improve descriptions of available options. --- src/head/head.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/head/head.rs b/src/head/head.rs index 0ce2a961f..c0c27004a 100644 --- a/src/head/head.rs +++ b/src/head/head.rs @@ -41,8 +41,8 @@ pub fn uumain(args: Vec) -> i32 { opts.optopt("c", "bytes", "Print the first K bytes. With the leading '-', print all but the last K bytes", "[-]K"); opts.optopt("n", "lines", "Print the first K lines. With the leading '-', print all but the last K lines", "[-]K"); - opts.optflag("h", "help", "help"); - opts.optflag("V", "version", "version"); + opts.optflag("h", "help", "display this help and exit"); + opts.optflag("V", "version", "output version information and exit"); let given_options = match opts.parse(&args) { Ok (m) => { m } From 1580daea7c6d49aec2041b6afd74d91a33cc9169 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Sat, 30 May 2015 17:55:25 -0400 Subject: [PATCH 3/4] Refactor utility settings into dedicated struct. This will make it easier to add support for additional options, such as verbosity and negative byte/line counts. --- src/head/head.rs | 60 +++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/head/head.rs b/src/head/head.rs index c0c27004a..804f862e0 100644 --- a/src/head/head.rs +++ b/src/head/head.rs @@ -25,13 +25,29 @@ mod util; static NAME: &'static str = "head"; static VERSION: &'static str = "1.0.0"; +enum FilterMode { + Bytes(usize), + Lines(usize), +} + +struct Settings { + mode: FilterMode, +} + +impl Default for Settings { + fn default() -> Settings { + Settings { + mode: FilterMode::Lines(10), + } + } +} + pub fn uumain(args: Vec) -> i32 { - let mut line_count = 10usize; - let mut byte_count = 0usize; + let mut settings: Settings = Default::default(); // handle obsolete -number syntax let options = match obsolete(&args[1..]) { - (args, Some(n)) => { line_count = n; args }, + (args, Some(n)) => { settings.mode = FilterMode::Lines(n); args }, (args, None) => args }; @@ -68,7 +84,7 @@ pub fn uumain(args: Vec) -> i32 { return 1; } match n.parse::() { - Ok(m) => { line_count = m } + Ok(m) => { settings.mode = FilterMode::Lines(m) } Err(e) => { show_error!("invalid line count '{}': {}", n, e); return 1; @@ -77,7 +93,7 @@ pub fn uumain(args: Vec) -> i32 { } None => match given_options.opt_str("c") { Some(count) => match count.parse::() { - Ok(m) => byte_count = m, + Ok(m) => settings.mode = FilterMode::Bytes(m), Err(e)=> { show_error!("invalid byte count '{}': {}", count, e); return 1; @@ -89,16 +105,9 @@ pub fn uumain(args: Vec) -> i32 { let files = given_options.free; - let count = - if use_bytes { - byte_count - } else { - line_count - }; - if files.is_empty() { let mut buffer = BufReader::new(stdin()); - head(&mut buffer, count, use_bytes); + head(&mut buffer, &settings); } else { let mut multiple = false; let mut firstime = true; @@ -117,7 +126,7 @@ pub fn uumain(args: Vec) -> i32 { let path = Path::new(file); let reader = File::open(&path).unwrap(); let mut buffer = BufReader::new(reader); - if !head(&mut buffer, count, use_bytes) { + if !head(&mut buffer, &settings) { break; } } @@ -161,17 +170,20 @@ fn obsolete(options: &[String]) -> (Vec, Option) { } // TODO: handle errors on read -fn head(reader: &mut BufReader, count: usize, use_bytes: bool) -> bool { - if use_bytes { - for byte in reader.bytes().take(count) { - if !pipe_print!("{}", byte.unwrap() as char) { - return false; +fn head(reader: &mut BufReader, settings: &Settings) -> bool { + match settings.mode { + FilterMode::Bytes(count) => { + for byte in reader.bytes().take(count) { + if !pipe_print!("{}", byte.unwrap() as char) { + return false; + } } - } - } else { - for line in reader.lines().take(count) { - if !pipe_println!("{}", line.unwrap()) { - return false; + }, + FilterMode::Lines(count) => { + for line in reader.lines().take(count) { + if !pipe_println!("{}", line.unwrap()) { + return false; + } } } } From 133a6c5563e8b2fbfe18bcccad3b4c084acaa2f4 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Sat, 30 May 2015 18:54:28 -0400 Subject: [PATCH 4/4] Add initial tests for head. --- Makefile | 1 + test/fixtures/head/lorem_ipsum.txt | 24 +++++++ .../fixtures/head/lorem_ipsum_1_line.expected | 1 + .../head/lorem_ipsum_5_chars.expected | 1 + .../head/lorem_ipsum_default.expected | 10 +++ test/head.rs | 65 +++++++++++++++++++ 6 files changed, 102 insertions(+) create mode 100644 test/fixtures/head/lorem_ipsum.txt create mode 100644 test/fixtures/head/lorem_ipsum_1_line.expected create mode 100644 test/fixtures/head/lorem_ipsum_5_chars.expected create mode 100644 test/fixtures/head/lorem_ipsum_default.expected create mode 100644 test/head.rs diff --git a/Makefile b/Makefile index 957fcbb40..74b6a694e 100644 --- a/Makefile +++ b/Makefile @@ -170,6 +170,7 @@ TEST_PROGS := \ false \ fold \ hashsum \ + head \ mkdir \ mv \ nl \ diff --git a/test/fixtures/head/lorem_ipsum.txt b/test/fixtures/head/lorem_ipsum.txt new file mode 100644 index 000000000..5d974b854 --- /dev/null +++ b/test/fixtures/head/lorem_ipsum.txt @@ -0,0 +1,24 @@ +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/head/lorem_ipsum_1_line.expected b/test/fixtures/head/lorem_ipsum_1_line.expected new file mode 100644 index 000000000..409369c4e --- /dev/null +++ b/test/fixtures/head/lorem_ipsum_1_line.expected @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, diff --git a/test/fixtures/head/lorem_ipsum_5_chars.expected b/test/fixtures/head/lorem_ipsum_5_chars.expected new file mode 100644 index 000000000..77aaba021 --- /dev/null +++ b/test/fixtures/head/lorem_ipsum_5_chars.expected @@ -0,0 +1 @@ +Lorem \ No newline at end of file diff --git a/test/fixtures/head/lorem_ipsum_default.expected b/test/fixtures/head/lorem_ipsum_default.expected new file mode 100644 index 000000000..7b721fd08 --- /dev/null +++ b/test/fixtures/head/lorem_ipsum_default.expected @@ -0,0 +1,10 @@ +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. diff --git a/test/head.rs b/test/head.rs new file mode 100644 index 000000000..f92c8cbac --- /dev/null +++ b/test/head.rs @@ -0,0 +1,65 @@ +use std::process::Command; +use util::*; + +static PROGNAME: &'static str = "./head"; +static INPUT: &'static str = "lorem_ipsum.txt"; + +#[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(INPUT)); + assert_eq!(result.stdout, get_file_contents("lorem_ipsum_default.expected")); +} + +#[test] +fn test_stdin_1_line_obsolete() { + let mut cmd = Command::new(PROGNAME); + let result = run_piped_stdin(&mut cmd.args(&["-1"]), get_file_contents(INPUT)); + assert_eq!(result.stdout, get_file_contents("lorem_ipsum_1_line.expected")); +} + +#[test] +fn test_stdin_1_line() { + let mut cmd = Command::new(PROGNAME); + let result = run_piped_stdin(&mut cmd.args(&["-n", "1"]), get_file_contents(INPUT)); + assert_eq!(result.stdout, get_file_contents("lorem_ipsum_1_line.expected")); +} + +#[test] +fn test_stdin_5_chars() { + let mut cmd = Command::new(PROGNAME); + let result = run_piped_stdin(&mut cmd.args(&["-c", "5"]), get_file_contents(INPUT)); + assert_eq!(result.stdout, get_file_contents("lorem_ipsum_5_chars.expected")); +} + +#[test] +fn test_single_default() { + let mut cmd = Command::new(PROGNAME); + let result = run(&mut cmd.arg(INPUT)); + assert_eq!(result.stdout, get_file_contents("lorem_ipsum_default.expected")); +} + +#[test] +fn test_single_1_line_obsolete() { + let mut cmd = Command::new(PROGNAME); + let result = run(&mut cmd.args(&["-1", INPUT])); + assert_eq!(result.stdout, get_file_contents("lorem_ipsum_1_line.expected")); +} + +#[test] +fn test_single_1_line() { + let mut cmd = Command::new(PROGNAME); + let result = run(&mut cmd.args(&["-n", "1", INPUT])); + assert_eq!(result.stdout, get_file_contents("lorem_ipsum_1_line.expected")); +} + +#[test] +fn test_single_5_chars() { + let mut cmd = Command::new(PROGNAME); + let result = run(&mut cmd.args(&["-c", "5", INPUT])); + assert_eq!(result.stdout, get_file_contents("lorem_ipsum_5_chars.expected")); +}