From 622a084ea68d95fb062b54c43dd15de662286b7b Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 14 Jul 2019 21:31:51 +0100 Subject: [PATCH] run: factor out mainloop and add tests --- src/bin/hexyl.rs | 32 +----------------- src/lib.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 32 deletions(-) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index 33c854f..8621bd2 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -15,8 +15,6 @@ use atty::Stream; use hexyl::{BorderStyle, Printer}; -const BUFFER_SIZE: usize = 256; - fn run() -> Result<(), Box> { let app = App::new(crate_name!()) .setting(AppSettings::ColorAuto) @@ -121,35 +119,7 @@ fn run() -> Result<(), Box> { let mut stdout_lock = stdout.lock(); let mut printer = Printer::new(&mut stdout_lock, show_color, border_style, squeeze); - - let mut buffer = [0; BUFFER_SIZE]; - 'mainloop: loop { - let size = reader.read(&mut buffer)?; - if size == 0 { - break; - } - - if cancelled.load(Ordering::SeqCst) { - eprintln!("hexyl has been cancelled."); - std::process::exit(130); // Set exit code to 128 + SIGINT - } - - for b in &buffer[..size] { - let res = printer.print_byte(*b); - - if res.is_err() { - // Broken pipe - break 'mainloop; - } - } - } - - // Finish last line - printer.print_textline().ok(); - if !printer.header_was_printed() { - printer.header(); - } - printer.footer(); + printer.print_all(&mut reader, Some(cancelled))?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index c7aad67..bc062ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,18 @@ pub mod squeezer; -use std::io::{self, Write}; +use std::io::{self, Read, Write}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; use ansi_term::Color; use ansi_term::Color::Fixed; use squeezer::{SqueezeAction, Squeezer}; +type Cancelled = Arc; + +const BUFFER_SIZE: usize = 256; + const COLOR_NULL: Color = Fixed(242); // grey const COLOR_OFFSET: Color = Fixed(242); // grey const COLOR_ASCII_PRINTABLE: Color = Color::Cyan; @@ -387,4 +393,82 @@ impl<'a, Writer: Write> Printer<'a, Writer> { pub fn header_was_printed(&self) -> bool { self.header_was_printed } + + /// Loop through the given `Reader`, printing until the `Reader` buffer + /// is exhausted, or the optional `cancelled` bool is set to true. + pub fn print_all( + &mut self, + mut reader: Reader, + canceller: Option, + ) -> Result<(), Box> { + let mut buffer = [0; BUFFER_SIZE]; + 'mainloop: loop { + let size = reader.read(&mut buffer)?; + if size == 0 { + break; + } + + if let Some(cancelled) = &canceller { + if cancelled.load(Ordering::SeqCst) { + eprintln!("hexyl has been cancelled."); + std::process::exit(130); // Set exit code to 128 + SIGINT + } + } + + for b in &buffer[..size] { + let res = self.print_byte(*b); + + if res.is_err() { + // Broken pipe + break 'mainloop; + } + } + } + + // Finish last line + self.print_textline().ok(); + if !self.header_was_printed() { + self.header(); + } + self.footer(); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use std::io; + use std::str; + + use super::*; + + fn assert_print_all_output(input: Reader, expected_string: String) -> () { + let mut output = vec![]; + let mut printer = Printer::new(&mut output, false, BorderStyle::Unicode, true); + + printer.print_all(input, None).unwrap(); + + let actual_string: &str = str::from_utf8(&output).unwrap(); + assert_eq!(actual_string, expected_string) + } + + #[test] + fn empty_file_passes() { + let input = io::empty(); + let expected_string = "┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐ +└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘ +".to_owned(); + assert_print_all_output(input, expected_string); + } + + #[test] + fn short_input_passes() { + let input = io::Cursor::new(b"spam"); + let expected_string = "┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐ +│00000000│ 73 70 61 6d ┊ │spam ┊ │ +└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘ +".to_owned(); + assert_print_all_output(input, expected_string); + } }