#[cfg(test)] #[allow(clippy::module_inception)] pub mod ansi_test_utils { use ansi_term; use crate::ansi; use crate::config::Config; use crate::delta::State; use crate::paint; use crate::style::Style; // Check if `output[line_number]` start with `expected_prefix` // Then check if the first style in the line is the `expected_style` pub fn assert_line_has_style( output: &str, line_number: usize, expected_prefix: &str, expected_style: &str, config: &Config, ) { assert!(_line_has_style( output, line_number, expected_prefix, expected_style, config, false, )); } // Check if `output[line_number]` start with `expected_prefix` // Then check if it contains the `expected_substring` with the corresponding `expected_style` // If the line contains multiples times the `expected_style`, will only compare with the first // item found pub fn assert_line_contain_substring_style( output: &str, line_number: usize, expected_prefix: &str, expected_substring: &str, expected_style: &str, config: &Config, ) { assert_eq!( expected_substring, _line_get_substring_matching_style( output, line_number, expected_prefix, expected_style, config, ) .unwrap() ); } // Check if `output[line_number]` start with `expected_prefix` // Then check if the line does not contains the `expected_style` pub fn assert_line_does_not_contain_substring_style( output: &str, line_number: usize, expected_prefix: &str, expected_style: &str, config: &Config, ) { assert!(_line_get_substring_matching_style( output, line_number, expected_prefix, expected_style, config, ) .is_none()); } pub fn assert_line_does_not_have_style( output: &str, line_number: usize, expected_prefix: &str, expected_style: &str, config: &Config, ) { assert!(!_line_has_style( output, line_number, expected_prefix, expected_style, config, false, )); } pub fn assert_line_has_4_bit_color_style( output: &str, line_number: usize, expected_prefix: &str, expected_style: &str, config: &Config, ) { assert!(_line_has_style( output, line_number, expected_prefix, expected_style, config, true, )); } pub fn assert_line_has_no_color(output: &str, line_number: usize, expected_prefix: &str) { let line = output.lines().nth(line_number).unwrap(); let stripped_line = ansi::strip_ansi_codes(line); assert!(stripped_line.starts_with(expected_prefix)); assert_eq!(line, stripped_line); } /// Assert that the specified line number of output (a) has, after stripping ANSI codes, a /// substring starting at `substring_begin` equal to `expected_substring` and (b) in its raw /// form contains a version of that substring syntax-highlighted according to /// `language_extension`. pub fn assert_line_has_syntax_highlighted_substring( output: &str, line_number: usize, substring_begin: usize, expected_substring: &str, filename_for_highlighting: &str, state: State, config: &Config, ) { assert!( filename_for_highlighting.contains('.'), "expecting filename, not just a file extension" ); let line = output.lines().nth(line_number).unwrap(); let substring_end = substring_begin + expected_substring.len(); let substring = &ansi::strip_ansi_codes(line)[substring_begin..substring_end]; assert_eq!(substring, expected_substring); let painted_substring = paint_line(substring, filename_for_highlighting, state, config); // remove trailing newline appended by paint::paint_lines. assert!(line.contains(painted_substring.trim_end())); } pub fn assert_has_color_other_than_plus_color(string: &str, config: &Config) { let (string_without_any_color, string_with_plus_color_only) = get_color_variants(string, config); assert_ne!(string, string_without_any_color); assert_ne!(string, string_with_plus_color_only); } pub fn assert_has_plus_color_only(string: &str, config: &Config) { let (string_without_any_color, string_with_plus_color_only) = get_color_variants(string, config); assert_ne!(string, string_without_any_color); assert_eq!(string, string_with_plus_color_only); } pub fn get_color_variants(string: &str, config: &Config) -> (String, String) { let string_without_any_color = ansi::strip_ansi_codes(string); let string_with_plus_color_only = config .plus_style .ansi_term_style .paint(&string_without_any_color); ( string_without_any_color.to_string(), string_with_plus_color_only.to_string(), ) } pub fn paint_line( line: &str, filename_for_highlighting: &str, state: State, config: &Config, ) -> String { let mut output_buffer = String::new(); let mut unused_writer = Vec::::new(); let mut painter = paint::Painter::new(&mut unused_writer, config); let syntax_highlighted_style = Style { is_syntax_highlighted: true, ..Style::new() }; painter.set_syntax(Some(filename_for_highlighting)); painter.set_highlighter(); let lines = vec![(line.to_string(), state)]; let syntax_style_sections = paint::get_syntax_style_sections_for_lines( &lines, painter.highlighter.as_mut(), config, ); let diff_style_sections = vec![vec![(syntax_highlighted_style, lines[0].0.as_str())]]; paint::Painter::paint_lines( &lines, &syntax_style_sections, &diff_style_sections, &[false], &mut output_buffer, config, &mut None, None, paint::BgShouldFill::default(), ); output_buffer } fn _line_extract<'a>(output: &'a str, line_number: usize, expected_prefix: &str) -> &'a str { let line = output.lines().nth(line_number).unwrap(); assert!(ansi::strip_ansi_codes(line).starts_with(expected_prefix)); line } fn _line_get_substring_matching_style<'a>( output: &'a str, line_number: usize, expected_prefix: &str, expected_style: &str, config: &Config, ) -> Option<&'a str> { let line = _line_extract(output, line_number, expected_prefix); let style = Style::from_str( expected_style, None, None, config.true_color, config.git_config.as_ref(), ); style.get_matching_substring(line) } fn _line_has_style( output: &str, line_number: usize, expected_prefix: &str, expected_style: &str, config: &Config, _4_bit_color: bool, ) -> bool { let line = _line_extract(output, line_number, expected_prefix); let mut style = Style::from_str( expected_style, None, None, config.true_color, config.git_config(), ); if _4_bit_color { style.ansi_term_style.foreground = style .ansi_term_style .foreground .map(ansi_term_fixed_foreground_to_4_bit_color); } style.is_applied_to(line) } fn ansi_term_fixed_foreground_to_4_bit_color(color: ansi_term::Color) -> ansi_term::Color { match color { ansi_term::Color::Fixed(30) => ansi_term::Color::Black, ansi_term::Color::Fixed(31) => ansi_term::Color::Red, ansi_term::Color::Fixed(32) => ansi_term::Color::Green, ansi_term::Color::Fixed(33) => ansi_term::Color::Yellow, ansi_term::Color::Fixed(34) => ansi_term::Color::Blue, ansi_term::Color::Fixed(35) => ansi_term::Color::Purple, ansi_term::Color::Fixed(36) => ansi_term::Color::Cyan, ansi_term::Color::Fixed(37) => ansi_term::Color::White, color => panic!( "Invalid 4-bit color: {:?}. \ (Add bright color entries to this map if needed for tests.", color ), } } }