From efafa50c4ec342db1d4230adf2d52cc81b6f6f77 Mon Sep 17 00:00:00 2001 From: Daniel Lambert Date: Mon, 11 May 2026 15:33:26 -0500 Subject: [PATCH 1/2] document current panic in Style::from_dotted_str via test cases --- src/utils.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/utils.rs b/src/utils.rs index db182a99..ace669a0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1195,3 +1195,31 @@ fn test_attributes_many() { assert_eq!(&attrs.attrs().collect::>(), test_attrs); } } + +#[test] +// NOTE: Documenting the current panic message. Ideally this input should be silently ignored +#[should_panic = "end byte index 3 is not a char boundary; it is inside '€' (bytes 1..4 of string)"] +fn test_style_from_non_ascii_fg() { + // len() == 7, starts_with('#'), but slices [1..3] land mid-€ (3 bytes) + let fg = "#€€"; + assert_eq!(fg.len(), 7); + + let parsed_style = Style::from_dotted_str(fg); + + // silently ignores non-ascii + assert_eq!(parsed_style, Style::default()); +} + +#[test] +// NOTE: Documenting the current panic message. Ideally this input should be silently ignored +#[should_panic = "end byte index 6 is not a char boundary; it is inside '€' (bytes 4..7 of string)"] +fn test_style_from_non_ascii_bg() { + // len() == 10, starts_with("on_#"), but slices [4..6] land mid-€ + let bg = "on_#€€"; + assert_eq!(bg.len(), 10); + + let parsed_style = Style::from_dotted_str(bg); + + // silently ignores non-ascii + assert_eq!(parsed_style, Style::default()); +} From 0ebc85fbd41554617f5b5973b6e5004a74d775fe Mon Sep 17 00:00:00 2001 From: Daniel Lambert Date: Mon, 11 May 2026 15:38:51 -0500 Subject: [PATCH 2/2] ignore non-ascii input in Style::from_dotted_str --- src/utils.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index ace669a0..3a48628e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -341,7 +341,11 @@ impl Style { "reverse" => rv.reverse(), "hidden" => rv.hidden(), "strikethrough" => rv.strikethrough(), - on_true_color if on_true_color.starts_with("on_#") && on_true_color.len() == 10 => { + on_true_color + if on_true_color.starts_with("on_#") + && on_true_color.len() == 10 + && on_true_color.is_ascii() => + { if let (Ok(r), Ok(g), Ok(b)) = ( u8::from_str_radix(&on_true_color[4..6], 16), u8::from_str_radix(&on_true_color[6..8], 16), @@ -352,7 +356,11 @@ impl Style { continue; } } - true_color if true_color.starts_with('#') && true_color.len() == 7 => { + true_color + if true_color.starts_with('#') + && true_color.len() == 7 + && true_color.is_ascii() => + { if let (Ok(r), Ok(g), Ok(b)) = ( u8::from_str_radix(&true_color[1..3], 16), u8::from_str_radix(&true_color[3..5], 16), @@ -1197,8 +1205,6 @@ fn test_attributes_many() { } #[test] -// NOTE: Documenting the current panic message. Ideally this input should be silently ignored -#[should_panic = "end byte index 3 is not a char boundary; it is inside '€' (bytes 1..4 of string)"] fn test_style_from_non_ascii_fg() { // len() == 7, starts_with('#'), but slices [1..3] land mid-€ (3 bytes) let fg = "#€€"; @@ -1211,8 +1217,6 @@ fn test_style_from_non_ascii_fg() { } #[test] -// NOTE: Documenting the current panic message. Ideally this input should be silently ignored -#[should_panic = "end byte index 6 is not a char boundary; it is inside '€' (bytes 4..7 of string)"] fn test_style_from_non_ascii_bg() { // len() == 10, starts_with("on_#"), but slices [4..6] land mid-€ let bg = "on_#€€";