diff -Nru rust-hexyl-0.4.0/Cargo.toml rust-hexyl-0.5.1/Cargo.toml --- rust-hexyl-0.4.0/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rust-hexyl-0.5.1/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -11,8 +11,9 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "hexyl" -version = "0.4.0" +version = "0.5.1" authors = ["David Peter "] description = "A command-line hex viewer" homepage = "https://github.com/sharkdp/hexyl" diff -Nru rust-hexyl-0.4.0/Cargo.toml.orig rust-hexyl-0.5.1/Cargo.toml.orig --- rust-hexyl-0.4.0/Cargo.toml.orig 2019-01-14 09:51:24.000000000 +0000 +++ rust-hexyl-0.5.1/Cargo.toml.orig 2019-05-30 13:34:49.000000000 +0000 @@ -7,7 +7,8 @@ name = "hexyl" readme = "README.md" repository = "https://github.com/sharkdp/hexyl" -version = "0.4.0" +version = "0.5.1" +edition = "2018" [dependencies] ansi_term = "0.11" diff -Nru rust-hexyl-0.4.0/.cargo_vcs_info.json rust-hexyl-0.5.1/.cargo_vcs_info.json --- rust-hexyl-0.4.0/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 +++ rust-hexyl-0.5.1/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +1,5 @@ { "git": { - "sha1": "7e46a5d788545ff88c5bcff05717a2b14f199f1e" + "sha1": "82c34fe39ba880bd3cbea4360a35c806f5bba363" } } diff -Nru rust-hexyl-0.4.0/debian/cargo-checksum.json rust-hexyl-0.5.1/debian/cargo-checksum.json --- rust-hexyl-0.4.0/debian/cargo-checksum.json 2019-01-29 20:05:21.000000000 +0000 +++ rust-hexyl-0.5.1/debian/cargo-checksum.json 2019-07-13 05:08:43.000000000 +0000 @@ -1 +1 @@ -{"package":"97e27e1d8535147ccd4c91bf322f7d1cd3984f9346cfea70b75ed5e9156ad53f","files":{}} +{"package":"Could not get crate checksum","files":{}} diff -Nru rust-hexyl-0.4.0/debian/changelog rust-hexyl-0.5.1/debian/changelog --- rust-hexyl-0.4.0/debian/changelog 2019-01-29 20:05:21.000000000 +0000 +++ rust-hexyl-0.5.1/debian/changelog 2019-07-13 05:08:43.000000000 +0000 @@ -1,3 +1,9 @@ +rust-hexyl (0.5.1-1) unstable; urgency=medium + + * Package hexyl 0.5.1 from crates.io using debcargo 2.3.1-alpha.0 + + -- Wolfgang Silbermayr Sat, 13 Jul 2019 07:08:43 +0200 + rust-hexyl (0.4.0-1) unstable; urgency=medium * Package hexyl 0.4.0 from crates.io using debcargo 2.2.9 diff -Nru rust-hexyl-0.4.0/debian/control rust-hexyl-0.5.1/debian/control --- rust-hexyl-0.4.0/debian/control 2019-01-29 20:05:21.000000000 +0000 +++ rust-hexyl-0.5.1/debian/control 2019-07-13 05:08:43.000000000 +0000 @@ -2,7 +2,7 @@ Section: utils Priority: optional Build-Depends: debhelper (>= 11), - dh-cargo (>= 10), + dh-cargo (>= 18), cargo:native, rustc:native, libstd-rust-dev, @@ -28,7 +28,14 @@ Section: utils Depends: ${misc:Depends}, - ${shlibs:Depends} + ${shlibs:Depends}, + ${cargo:Depends} +Recommends: + ${cargo:Recommends} +Suggests: + ${cargo:Suggests} +Provides: + ${cargo:Provides} Built-Using: ${cargo:Built-Using} XB-X-Cargo-Built-Using: ${cargo:X-Cargo-Built-Using} Description: Command-line hex viewer with colored output diff -Nru rust-hexyl-0.4.0/debian/rules.debcargo.hint rust-hexyl-0.5.1/debian/rules.debcargo.hint --- rust-hexyl-0.4.0/debian/rules.debcargo.hint 2019-01-29 20:05:21.000000000 +0000 +++ rust-hexyl-0.5.1/debian/rules.debcargo.hint 2019-07-13 05:08:43.000000000 +0000 @@ -1,3 +1,6 @@ #!/usr/bin/make -f %: dh $@ --buildsystem cargo + +override_dh_auto_test: + dh_auto_test -- test --all diff -Nru rust-hexyl-0.4.0/README.md rust-hexyl-0.5.1/README.md --- rust-hexyl-0.4.0/README.md 2019-01-14 09:51:20.000000000 +0000 +++ rust-hexyl-0.5.1/README.md 2019-05-30 13:35:11.000000000 +0000 @@ -22,16 +22,16 @@ ### On Debian-based systems ``` bash -wget "https://github.com/sharkdp/hexyl/releases/download/v0.4.0/hexyl_0.4.0_amd64.deb" -sudo dpkg -i hexyl_0.4.0_amd64.deb +wget "https://github.com/sharkdp/hexyl/releases/download/v0.5.1/hexyl_0.5.1_amd64.deb" +sudo dpkg -i hexyl_0.5.1_amd64.deb ``` ### On Arch Linux -You can install `hexyl` from [this AUR package](https://aur.archlinux.org/packages/hexyl/): +You can install `hexyl` from [the official package repository](https://www.archlinux.org/packages/community/x86_64/hexyl/): ``` -yay -S hexyl +pacman -S hexyl ``` ### On macOS @@ -46,6 +46,12 @@ pkg install hexyl ``` +### Via Nix + +``` +nix-env -i hexyl +``` + ### On other distributions Check out the [release page](https://github.com/sharkdp/hexyl/releases) for binary builds. @@ -57,7 +63,7 @@ ### Via cargo -If you have Rust 1.29 or higher, you can install `hexyl` from source via `cargo`: +If you have Rust 1.31 or higher, you can install `hexyl` from source via `cargo`: ``` cargo install hexyl ``` diff -Nru rust-hexyl-0.4.0/src/main.rs rust-hexyl-0.5.1/src/main.rs --- rust-hexyl-0.4.0/src/main.rs 2019-01-14 09:40:13.000000000 +0000 +++ rust-hexyl-0.5.1/src/main.rs 2019-05-30 13:29:44.000000000 +0000 @@ -1,8 +1,10 @@ #[macro_use] extern crate clap; -extern crate ansi_term; -extern crate atty; -extern crate ctrlc; + +use atty; +use ctrlc; + +mod squeezer; use std::fs::File; use std::io::{self, prelude::*, StdoutLock}; @@ -14,6 +16,7 @@ use ansi_term::Color; use ansi_term::Color::Fixed; +use crate::squeezer::{SqueezeAction, Squeezer}; use atty::Stream; const BUFFER_SIZE: usize = 256; @@ -55,7 +58,7 @@ } fn color(self) -> &'static Color { - use ByteCategory::*; + use crate::ByteCategory::*; match self.category() { Null => &COLOR_NULL, @@ -67,7 +70,7 @@ } fn as_char(self) -> char { - use ByteCategory::*; + use crate::ByteCategory::*; match self.category() { Null => '0', @@ -80,6 +83,73 @@ } } +struct BorderElements { + left_corner: char, + horizontal_line: char, + column_separator: char, + right_corner: char, +} + +enum BorderStyle { + Unicode, + Ascii, + None, +} + +impl BorderStyle { + fn header_elems(&self) -> Option { + match self { + BorderStyle::Unicode => Some(BorderElements { + left_corner: '┌', + horizontal_line: '─', + column_separator: '┬', + right_corner: '┐', + }), + BorderStyle::Ascii => Some(BorderElements { + left_corner: '+', + horizontal_line: '-', + column_separator: '+', + right_corner: '+', + }), + BorderStyle::None => None, + } + } + + fn footer_elems(&self) -> Option { + match self { + BorderStyle::Unicode => Some(BorderElements { + left_corner: '└', + horizontal_line: '─', + column_separator: '┴', + right_corner: '┘', + }), + BorderStyle::Ascii => Some(BorderElements { + left_corner: '+', + horizontal_line: '-', + column_separator: '+', + right_corner: '+', + }), + BorderStyle::None => None, + } + } + + fn outer_sep(&self) -> char { + match self { + BorderStyle::Unicode => '│', + BorderStyle::Ascii => '|', + BorderStyle::None => ' ', + } + } + + fn inner_sep(&self) -> char { + match self { + BorderStyle::Unicode => '┊', + BorderStyle::Ascii => '|', + BorderStyle::None => ' ', + } + } +} + struct Printer<'a> { idx: usize, /// The raw bytes used as input for the current line. @@ -88,18 +158,28 @@ buffer_line: Vec, stdout: StdoutLock<'a>, show_color: bool, + border_style: BorderStyle, + header_was_printed: bool, byte_hex_table: Vec, byte_char_table: Vec, + squeezer: Squeezer, } impl<'a> Printer<'a> { - fn new(stdout: StdoutLock, show_color: bool) -> Printer { + fn new( + stdout: StdoutLock<'_>, + show_color: bool, + border_style: BorderStyle, + use_squeeze: bool, + ) -> Printer<'_> { Printer { idx: 1, raw_line: vec![], buffer_line: vec![], stdout, show_color, + border_style, + header_was_printed: false, byte_hex_table: (0u8..=u8::max_value()) .map(|i| { let byte_hex = format!("{:02x} ", i); @@ -120,47 +200,87 @@ } }) .collect(), + squeezer: Squeezer::new(use_squeeze), } } fn header(&mut self) { - writeln!( - self.stdout, - "┌{0:─<8}┬{0:─<25}┬{0:─<25}┬{0:─<8}┬{0:─<8}┐", - "" - ) - .ok(); + if let Some(border_elements) = self.border_style.header_elems() { + let h = border_elements.horizontal_line; + let h8 = h.to_string().repeat(8); + let h25 = h.to_string().repeat(25); + + writeln!( + self.stdout, + "{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}", + l = border_elements.left_corner, + c = border_elements.column_separator, + r = border_elements.right_corner, + h8 = h8, + h25 = h25 + ) + .ok(); + } } fn footer(&mut self) { - writeln!( - self.stdout, - "└{0:─<8}┴{0:─<25}┴{0:─<25}┴{0:─<8}┴{0:─<8}┘", - "" - ) - .ok(); + if let Some(border_elements) = self.border_style.footer_elems() { + let h = border_elements.horizontal_line; + let h8 = h.to_string().repeat(8); + let h25 = h.to_string().repeat(25); + + writeln!( + self.stdout, + "{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}", + l = border_elements.left_corner, + c = border_elements.column_separator, + r = border_elements.right_corner, + h8 = h8, + h25 = h25 + ) + .ok(); + } + } + + fn print_position_indicator(&mut self) { + if !self.header_was_printed { + self.header(); + self.header_was_printed = true; + } + + let style = COLOR_OFFSET.normal(); + let byte_index = format!("{:08x}", self.idx - 1); + let formatted_string = if self.show_color { + format!("{}", style.paint(byte_index)) + } else { + byte_index + }; + let _ = write!( + &mut self.buffer_line, + "{}{}{} ", + self.border_style.outer_sep(), + formatted_string, + self.border_style.outer_sep() + ); } fn print_byte(&mut self, b: u8) -> io::Result<()> { if self.idx % 16 == 1 { - let style = COLOR_OFFSET.normal(); - let byte_index = format!("{:08x}", self.idx - 1); - let formatted_string = if self.show_color { - format!("{}", style.paint(byte_index)) - } else { - byte_index - }; - let _ = write!(&mut self.buffer_line, "│{}│ ", formatted_string); + self.print_position_indicator(); } write!(&mut self.buffer_line, "{}", self.byte_hex_table[b as usize])?; self.raw_line.push(b); + self.squeezer.process(b, self.idx); + match self.idx % 16 { 8 => { - let _ = write!(&mut self.buffer_line, "┊ "); + let _ = write!(&mut self.buffer_line, "{} ", self.border_style.inner_sep()); + } + 0 => { + self.print_textline()?; } - 0 => self.print_textline()?, _ => {} } @@ -173,19 +293,41 @@ let len = self.raw_line.len(); if len == 0 { + if self.squeezer.active() { + self.print_position_indicator(); + let _ = writeln!( + &mut self.buffer_line, + "{0:1$}{4}{0:2$}{5}{0:3$}{4}{0:3$}{5}", + "", + 24, + 25, + 8, + self.border_style.inner_sep(), + self.border_style.outer_sep(), + ); + self.stdout.write_all(&self.buffer_line)?; + } return Ok(()); } if len < 8 { let _ = write!( &mut self.buffer_line, - "{0:1$}┊{0:2$}│", + "{0:1$}{3}{0:2$}{4}", "", 3 * (8 - len), - 1 + 3 * 8 + 1 + 3 * 8, + self.border_style.inner_sep(), + self.border_style.outer_sep(), ); } else { - let _ = write!(&mut self.buffer_line, "{0:1$}│", "", 3 * (16 - len)); + let _ = write!( + &mut self.buffer_line, + "{0:1$}{2}", + "", + 3 * (16 - len), + self.border_style.outer_sep() + ); } let mut idx = 1; @@ -197,17 +339,57 @@ ); if idx == 8 { - let _ = write!(&mut self.buffer_line, "┊"); + let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep()); } idx += 1; } if len < 8 { - let _ = writeln!(&mut self.buffer_line, "{0:1$}┊{0:2$}│ ", "", 8 - len, 8); + let _ = writeln!( + &mut self.buffer_line, + "{0:1$}{3}{0:2$}{4} ", + "", + 8 - len, + 8, + self.border_style.inner_sep(), + self.border_style.outer_sep(), + ); } else { - let _ = writeln!(&mut self.buffer_line, "{0:1$}│", "", 16 - len); + let _ = writeln!( + &mut self.buffer_line, + "{0:1$}{2}", + "", + 16 - len, + self.border_style.outer_sep() + ); + } + + match self.squeezer.action() { + SqueezeAction::Print => { + self.buffer_line.clear(); + let style = COLOR_OFFSET.normal(); + let asterisk = if self.show_color { + format!("{}", style.paint("*")) + } else { + String::from("*") + }; + let _ = writeln!( + &mut self.buffer_line, + "{5}{0}{1:2$}{5}{1:3$}{6}{1:3$}{5}{1:4$}{6}{1:4$}{5}", + asterisk, + "", + 7, + 25, + 8, + self.border_style.outer_sep(), + self.border_style.inner_sep(), + ); + } + SqueezeAction::Delete => self.buffer_line.clear(), + SqueezeAction::Ignore => (), } + self.stdout.write_all(&self.buffer_line)?; self.raw_line.clear(); @@ -217,7 +399,7 @@ } } -fn run() -> Result<(), Box<::std::error::Error>> { +fn run() -> Result<(), Box> { let app = App::new(crate_name!()) .setting(AppSettings::ColorAuto) .setting(AppSettings::ColoredHelp) @@ -235,6 +417,24 @@ .help("Read only N bytes from the input"), ) .arg( + Arg::with_name("bytes") + .short("c") + .long("bytes") + .takes_value(true) + .value_name("N") + .help("An alias for -n/--length"), + ) + .arg( + Arg::with_name("nosqueezing") + .short("v") + .long("no-squeezing") + .help( + "Displays all input data. Otherwise any number of groups of output \ + lines which would be identical to the preceding group of lines, are \ + replaced with a line comprised of a single asterisk.", + ), + ) + .arg( Arg::with_name("color") .long("color") .takes_value(true) @@ -245,6 +445,14 @@ "When to use colors. The auto-mode only displays colors if the output \ goes to an interactive terminal", ), + ) + .arg( + Arg::with_name("border") + .long("border") + .takes_value(true) + .possible_values(&["unicode", "ascii", "none"]) + .default_value("unicode") + .help("Whether to draw a border with unicode or ASCII characters, or none at all"), ); let matches = app.get_matches_safe()?; @@ -256,10 +464,15 @@ None => Box::new(stdin.lock()), }; - if let Some(length) = matches - .value_of("length") - .and_then(|n| n.parse::().ok()) - { + let length_arg = matches.value_of("length").or(matches.value_of("bytes")); + + if let Some(length) = length_arg.and_then(|n| { + if n.starts_with("0x") { + u64::from_str_radix(n.trim_start_matches("0x"), 16).ok() + } else { + n.parse::().ok() + } + }) { reader = Box::new(reader.take(length)); } @@ -269,6 +482,14 @@ _ => true, }; + let border_style = match matches.value_of("border") { + Some("unicode") => BorderStyle::Unicode, + Some("ascii") => BorderStyle::Ascii, + _ => BorderStyle::None, + }; + + let squeeze = !matches.is_present("nosqueezing"); + // Set up Ctrl-C handler let cancelled = Arc::new(AtomicBool::new(false)); let c = cancelled.clone(); @@ -279,8 +500,7 @@ .expect("Error setting Ctrl-C handler"); let stdout = io::stdout(); - let mut printer = Printer::new(stdout.lock(), show_color); - printer.header(); + let mut printer = Printer::new(stdout.lock(), show_color, border_style, squeeze); let mut buffer = [0; BUFFER_SIZE]; 'mainloop: loop { @@ -306,6 +526,9 @@ // Finish last line printer.print_textline().ok(); + if !printer.header_was_printed { + printer.header(); + } printer.footer(); Ok(()) diff -Nru rust-hexyl-0.4.0/src/squeezer.rs rust-hexyl-0.5.1/src/squeezer.rs --- rust-hexyl-0.4.0/src/squeezer.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-hexyl-0.5.1/src/squeezer.rs 2019-05-30 13:29:44.000000000 +0000 @@ -0,0 +1,399 @@ +#[derive(Debug, PartialEq)] +enum SqueezeState { + /// not enabled + Disabled, + /// Will be set from all states if equal condition can't be hold up. + /// Set if previous byte is not equal the current processed byte. + NoSqueeze, + /// Valid for a whole line to identify if it is candidate for squeezing + Probe, + /// Squeeze line parsing is active, but EOL is not reached yet + SqueezeActive, + /// Squeeze line, EOL is reached, will influence the action + Squeeze, + /// same as Squeeze, however this is only for the first line after + /// the squeeze candidate has been set. + SqueezeFirstLine, + /// same as SqueezeActive, however this is only for the first line after + /// the squeeze candidate has been set. + SqueezeActiveFirstLine, +} + +pub struct Squeezer { + state: SqueezeState, + byte: u8, +} + +#[derive(Debug, PartialEq)] +pub enum SqueezeAction { + Ignore, + Print, + Delete, +} + +/// line size +const LSIZE: usize = 16; + +impl Squeezer { + pub fn new(enabled: bool) -> Squeezer { + Squeezer { + state: if enabled { + SqueezeState::Probe + } else { + SqueezeState::Disabled + }, + byte: 0, + } + } + + pub fn process(&mut self, b: u8, i: usize) { + use self::SqueezeState::*; + if self.state == Disabled { + return; + } + let eq = b == self.byte; + + if i % LSIZE == 0 { + if !eq { + self.state = Probe; + } else { + self.state = match self.state { + NoSqueeze => Probe, + Probe => SqueezeActiveFirstLine, + SqueezeActiveFirstLine => SqueezeFirstLine, + SqueezeFirstLine => SqueezeActive, + SqueezeActive => Squeeze, + Squeeze => SqueezeActive, + Disabled => Disabled, + }; + } + } else if !eq { + if i % LSIZE == 1 { + self.state = Probe; + } else if i % LSIZE != 1 { + self.state = NoSqueeze; + } + } + + self.byte = b; + } + + pub fn active(&self) -> bool { + use self::SqueezeState::*; + match self.state { + Squeeze | SqueezeActive | SqueezeFirstLine | SqueezeActiveFirstLine => true, + _ => false, + } + } + + pub fn action(&mut self) -> SqueezeAction { + match self.state { + SqueezeState::SqueezeFirstLine => { + self.state = SqueezeState::SqueezeActive; + SqueezeAction::Print + } + SqueezeState::Squeeze => { + self.state = SqueezeState::SqueezeActive; + SqueezeAction::Delete + } + _ => SqueezeAction::Ignore, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn three_same_lines() { + const LINES: usize = 3; + let v = vec![0u8; LINES * LSIZE]; + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, // first line, print as is + SqueezeAction::Print, // print squeeze symbol + SqueezeAction::Delete, // delete reoccurring line + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + let action = s.action(); + assert_eq!(action, exp[line]); + line += 1; + } + } + + #[test] + fn incomplete_while_squeeze() { + // fourth line only has 12 bytes and should be printed + let v = vec![0u8; 3 * LSIZE + 12]; + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, // first line, print as is + SqueezeAction::Print, // print squeeze symbol + SqueezeAction::Delete, // delete reoccurring line + SqueezeAction::Ignore, // last line only 12 bytes, print it + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + assert_eq!(s.action(), exp[line]); + line += 1; + } + } + + #[test] + /// all three lines are different, print all + fn three_different_lines() { + let mut v: Vec = vec![]; + v.extend(vec![0u8; 16]); + v.extend(vec![1u8; 16]); + v.extend(vec![2u8; 16]); + + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, // first line, print as is + SqueezeAction::Ignore, // different + SqueezeAction::Ignore, // different + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + let action = s.action(); + assert_eq!(action, exp[line]); + line += 1; + } + } + + #[test] + /// first two lines same, hence squeeze symbol, third line diff, hence + /// print + fn one_squeeze_no_delete() { + const LINES: usize = 3; + let mut v = vec![0u8; (LINES - 1) * LSIZE]; + v.extend(vec![1u8; 16]); + + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, // first line, print as is + SqueezeAction::Print, // print squeeze symbol + SqueezeAction::Ignore, // different lines, print again + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + let action = s.action(); + assert_eq!(action, exp[line]); + line += 1; + } + } + + #[test] + /// First line all eq, 2nd half eq with first line, then change + fn second_line_different() { + const LINES: usize = 2; + let mut v = vec![0u8; (LINES - 1) * LSIZE]; + v.extend(vec![0u8; 8]); + v.extend(vec![1u8; 8]); + + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, // first line, print as is + SqueezeAction::Ignore, // print squeeze symbol + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + let action = s.action(); + assert_eq!(action, exp[line]); + line += 1; + } + } + + #[test] + /// all three lines never become squeeze candidate (diff within line) + fn never_squeeze_candidate() { + let mut v = vec![]; + v.extend(vec![0u8; 8]); + v.extend(vec![1u8; 8]); + v.extend(vec![0u8; 8]); + v.extend(vec![1u8; 8]); + v.extend(vec![0u8; 8]); + v.extend(vec![1u8; 8]); + + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, // first line, print as is + SqueezeAction::Ignore, // print squeeze symbol + SqueezeAction::Ignore, // print squeeze symbol + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + let action = s.action(); + assert_eq!(action, exp[line]); + line += 1; + } + } + + #[test] + fn mix_everything() { + let mut v = vec![]; + v.extend(vec![10u8; 16]); // print + v.extend(vec![20u8; 16]); // print + v.extend(vec![0u8; 16]); // print + v.extend(vec![0u8; 16]); // * + v.extend(vec![10u8; 16]); // print + v.extend(vec![20u8; 16]); // print + v.extend(vec![0u8; 16]); // print + v.extend(vec![0u8; 16]); // * + v.extend(vec![0u8; 16]); // delete + v.extend(vec![0u8; 16]); // delete* + v.extend(vec![20u8; 16]); // print + v.extend(vec![0u8; 12]); // print, only 12 bytes + + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, + SqueezeAction::Ignore, + SqueezeAction::Ignore, + SqueezeAction::Print, + SqueezeAction::Ignore, + SqueezeAction::Ignore, + SqueezeAction::Ignore, + SqueezeAction::Print, + SqueezeAction::Delete, + SqueezeAction::Delete, + SqueezeAction::Ignore, + SqueezeAction::Ignore, + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + let action = s.action(); + assert_eq!(action, exp[line]); + line += 1; + } + } + + #[test] + fn last_char_diff() { + // see issue #62 + let mut v = vec![]; + v.extend(vec![20u8; 16]); + v.extend(vec![20u8; 15]); + v.push(61); + v.extend(vec![20u8; 16]); + v.extend(vec![20u8; 16]); + + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, // print as is + SqueezeAction::Ignore, // print as is + SqueezeAction::Ignore, // print as is + SqueezeAction::Print, // print '*' char + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + assert_eq!(s.action(), exp[line]); + line += 1; + } + } + + #[test] + fn first_char_diff() { + // see issue #62 + let mut v = vec![]; + v.extend(vec![20u8; 16]); + v.push(61); + v.extend(vec![20u8; 15]); + v.extend(vec![20u8; 16]); + + let mut s = Squeezer::new(true); + // just initialized + assert_eq!(s.action(), SqueezeAction::Ignore); + + let exp = vec![ + SqueezeAction::Ignore, // print as is + SqueezeAction::Ignore, // print as is + SqueezeAction::Ignore, // print as is + ]; + + let mut line = 0; + let mut idx = 1; + for z in v.chunks(LSIZE) { + for i in z { + s.process(*i, idx); + idx += 1; + } + assert_eq!(s.action(), exp[line]); + line += 1; + } + } +} diff -Nru rust-hexyl-0.4.0/.travis.yml rust-hexyl-0.5.1/.travis.yml --- rust-hexyl-0.4.0/.travis.yml 2019-01-09 19:53:04.000000000 +0000 +++ rust-hexyl-0.5.1/.travis.yml 2019-04-13 16:27:17.000000000 +0000 @@ -18,7 +18,7 @@ # Minimum Rust supported channel. - os: linux - rust: 1.29.0 + rust: 1.31.0 env: TARGET=x86_64-unknown-linux-gnu