use regexr::Regex;
fn compile(pattern: &str) -> Result<Regex, regexr::Error> {
#[cfg(feature = "jit")]
{
regexr::RegexBuilder::new(pattern).jit(true).build()
}
#[cfg(not(feature = "jit"))]
{
Regex::new(pattern)
}
}
fn assert_escape_denotes(escape: &str, expected: char) {
let subject = expected.to_string();
let other = if expected == 'x' { 'y' } else { 'x' }.to_string();
for pattern in [
escape.to_string(),
format!("a{escape}"),
format!("[{escape}]"),
] {
let re = compile(&pattern).unwrap_or_else(|e| panic!("{pattern:?} should compile: {e}"));
let haystack = if pattern.starts_with('a') {
format!("a{subject}")
} else {
subject.clone()
};
assert!(
re.is_match(&haystack),
"{pattern:?} should match {haystack:?} (U+{:04X})",
expected as u32
);
assert!(
!re.is_match(&other),
"{pattern:?} matched {other:?}, so it is not anchored to U+{:04X}",
expected as u32
);
}
}
#[test]
fn control_character_escapes_denote_their_control_characters() {
assert_escape_denotes(r"\n", '\n');
assert_escape_denotes(r"\r", '\r');
assert_escape_denotes(r"\t", '\t');
assert_escape_denotes(r"\f", '\u{0c}');
assert_escape_denotes(r"\v", '\u{0b}');
assert_escape_denotes(r"\0", '\0');
}
#[test]
fn escape_character_escape_denotes_u001b() {
assert_escape_denotes(r"\e", '\u{1b}');
}
#[test]
fn alert_escape_denotes_u0007() {
assert_escape_denotes(r"\a", '\u{07}');
}
#[test]
fn escaped_ascii_punctuation_denotes_itself() {
for c in ' '..='~' {
if c.is_ascii_alphanumeric() {
continue;
}
assert_escape_denotes(&format!("\\{c}"), c);
}
}
#[test]
fn unassigned_letter_escapes_remain_errors() {
for pattern in [r"\j", r"\J", r"\m", r"\T", r"\Y", r"\g", r"\l"] {
assert!(
compile(pattern).is_err(),
"{pattern:?} has no assigned meaning and must not compile"
);
}
}