use regexr::{Regex, Result};
fn compile(pattern: &str) -> Result<Regex> {
#[cfg(feature = "jit")]
{
regexr::RegexBuilder::new(pattern).jit(true).build()
}
#[cfg(not(feature = "jit"))]
{
Regex::new(pattern)
}
}
const MALFORMED_ESCAPES: &[&str] = &[
r"\",
r"\x",
r"\xZ",
r"\xZZ",
r"\x{",
r"\u",
r"\uZZ",
r"\u{",
r"\u{ZZZZ}",
r"\p",
r"\p{",
r"\p{L",
r"\P{",
];
#[test]
fn malformed_escape_at_pattern_start_is_rejected() {
for pattern in MALFORMED_ESCAPES {
assert!(
compile(pattern).is_err(),
"{pattern:?} must not compile: the escape is malformed"
);
}
}
#[test]
fn malformed_escape_never_compiles_to_a_match_everything_pattern() {
for pattern in MALFORMED_ESCAPES {
if let Ok(re) = compile(pattern) {
assert!(
!(re.is_match("") && re.is_match("zzz") && re.is_match("\u{1b}")),
"{pattern:?} compiled into a pattern that matches every input"
);
}
}
}
#[test]
fn escape_acceptance_does_not_depend_on_position() {
for c in ' '..='~' {
let leading = format!("\\{c}");
let trailing = format!("a\\{c}");
assert_eq!(
compile(&leading).is_ok(),
compile(&trailing).is_ok(),
"\\{c} is accepted at one position and rejected at another \
({leading:?} vs {trailing:?})"
);
}
}
#[test]
fn malformed_escape_acceptance_does_not_depend_on_position() {
for pattern in MALFORMED_ESCAPES {
let trailing = format!("a{pattern}");
assert_eq!(
compile(pattern).is_ok(),
compile(&trailing).is_ok(),
"{pattern:?} is accepted at one position and rejected at another"
);
}
}
#[test]
fn leading_invalid_escape_reports_position_zero() {
let err = compile(r"\q")
.expect_err(r"\q must be rejected")
.to_string();
assert!(
err.contains("position 0"),
"error should locate the escape at position 0: {err}"
);
}
#[test]
fn class_escape_error_names_the_offending_escape() {
for (pattern, escape) in [(r"[\b]", r"\b"), (r"[\B]", r"\B"), (r"[\z]", r"\z")] {
let err = compile(pattern)
.expect_err(&format!("{pattern} must be rejected"))
.to_string();
assert!(
err.contains(escape),
"diagnostic for {pattern} should name {escape}: {err}"
);
assert!(
!err.contains(r"\?"),
"diagnostic for {pattern} reports a placeholder instead of the escape: {err}"
);
}
}
#[test]
fn empty_pattern_is_the_only_legitimate_match_everything() {
let re = compile("").expect("the empty pattern is valid");
assert!(re.is_match(""));
assert!(re.is_match("anything"));
}