extern crate fwdansi; extern crate proptest; extern crate termcolor; use fwdansi::write_ansi; use proptest::prelude::*; use std::io; use termcolor::{Ansi, Color, ColorSpec, WriteColor}; proptest! { #[test] fn check_no_crash(ref ansi_string in any::>()) { let mut ansi = Ansi::new(Vec::with_capacity(ansi_string.len())); prop_assert!(write_ansi(&mut ansi, &ansi_string).is_ok()); } #[test] fn ansi_idempotent(ref elements in prop::collection::vec(Element::any(), 0..100)) { // first, write the test string into an ANSI buffer. let mut original = Ansi::new(Vec::new()); for e in elements { e.write(&mut original).unwrap(); } // recover the original string, and forward it using `write_ansi`. let original = original.into_inner(); let mut forwarded = Ansi::new(Vec::with_capacity(original.len())); prop_assert!(write_ansi(&mut forwarded, &original).is_ok()); prop_assert_eq!(original, forwarded.into_inner()); } } #[derive(Debug, Clone)] enum Element { ColorSpec(ColorSpec), Reset, Text(Vec), } fn any_opt_color() -> impl Strategy> { let color = prop_oneof![ Just(Color::Black), Just(Color::Red), Just(Color::Green), Just(Color::Yellow), Just(Color::Blue), Just(Color::Magenta), Just(Color::Cyan), Just(Color::White), any::().prop_map(Color::Ansi256), any::<[u8; 3]>().prop_map(|[r, g, b]| Color::Rgb(r, g, b)), ]; prop::option::weighted(0.9, color) } prop_compose! { fn any_color_spec()( bold in any::(), underline in any::(), intense in any::(), fg_color in any_opt_color(), bg_color in any_opt_color(), ) -> ColorSpec { let mut spec = ColorSpec::new(); spec.set_bold(bold) .set_underline(underline) .set_intense(intense) .set_fg(fg_color) .set_bg(bg_color); spec } } impl Element { fn any() -> impl Strategy { prop_oneof![ Just(Element::Reset), any_color_spec().prop_map(Element::ColorSpec), any::>().prop_filter_map("ignored empty SGR", |v| { if v.windows(3).find(|w| w == b"\x1b[m").is_some() { None } else { Some(Element::Text(v)) } }), ] } fn write(&self, mut w: W) -> io::Result<()> { w.write_all(b"~")?; match self { Element::ColorSpec(cs) => w.set_color(cs), Element::Reset => w.reset(), Element::Text(text) => w.write_all(text), } } }