use super::*;
fn parsed(pattern: &str) -> SubPattern {
parse_pattern(pattern, 0)
.unwrap_or_else(|e| panic!("parse {:?} failed: {}", pattern, e))
.pattern
}
fn lit(cp: u32) -> OpCode {
OpCode::Literal(cp)
}
#[test]
fn literal_single_char() {
assert_eq!(parsed("a").data, vec![lit(97)]);
}
#[test]
fn literal_multi_char_concat() {
assert_eq!(parsed("ab").data, vec![lit(97), lit(98)]);
}
#[test]
fn literal_escape() {
assert_eq!(parsed("\\n").data, vec![lit(10)]);
assert_eq!(parsed("\\t").data, vec![lit(9)]);
assert_eq!(parsed("\\\\").data, vec![lit(92)]);
}
#[test]
fn literal_hex_escape() {
assert_eq!(parsed("\\x41").data, vec![lit(0x41)]);
}
#[test]
fn literal_unicode_u_escape() {
assert_eq!(parsed("\\u00e9").data, vec![lit(0xe9)]);
}
#[test]
fn literal_octal_escape() {
assert_eq!(parsed("\\0").data, vec![lit(0)]);
}
#[test]
fn any_dot() {
assert_eq!(parsed(".").data, vec![OpCode::Any]);
}
#[test]
fn at_beginning_end() {
assert_eq!(
parsed("^abc$").data,
vec![
OpCode::At(AtCode::Beginning),
lit(97),
lit(98),
lit(99),
OpCode::At(AtCode::End),
]
);
}
#[test]
fn at_beginning_end_string() {
assert_eq!(
parsed("\\A\\Z").data,
vec![
OpCode::At(AtCode::BeginningString),
OpCode::At(AtCode::EndString),
]
);
}
#[test]
fn at_boundary() {
assert_eq!(
parsed("\\b\\B").data,
vec![
OpCode::At(AtCode::Boundary),
OpCode::At(AtCode::NonBoundary),
]
);
}
#[test]
fn char_class_literal_set() {
assert_eq!(
parsed("[abc]").data,
vec![OpCode::In(vec![
SetItem::Literal(97),
SetItem::Literal(98),
SetItem::Literal(99),
])]
);
}
#[test]
fn char_class_range() {
assert_eq!(
parsed("[a-z]").data,
vec![OpCode::In(vec![SetItem::Range(97, 122)])]
);
}
#[test]
fn char_class_negate() {
assert_eq!(
parsed("[^abc]").data,
vec![OpCode::In(vec![
SetItem::Negate,
SetItem::Literal(97),
SetItem::Literal(98),
SetItem::Literal(99),
])]
);
}
#[test]
fn char_class_mixed_ranges() {
assert_eq!(
parsed("[a-zA-Z0-9]").data,
vec![OpCode::In(vec![
SetItem::Range(97, 122),
SetItem::Range(65, 90),
SetItem::Range(48, 57),
])]
);
}
#[test]
fn char_class_with_category() {
assert_eq!(
parsed("[\\d\\s]").data,
vec![OpCode::In(vec![
SetItem::Category(ChCode::Digit),
SetItem::Category(ChCode::Space),
])]
);
}
#[test]
fn char_class_leading_dash_literal() {
assert_eq!(
parsed("[-abc]").data,
vec![OpCode::In(vec![
SetItem::Literal(45),
SetItem::Literal(97),
SetItem::Literal(98),
SetItem::Literal(99),
])]
);
}
#[test]
fn char_class_escaped_dash() {
assert_eq!(
parsed("[a\\-z]").data,
vec![OpCode::In(vec![
SetItem::Literal(97),
SetItem::Literal(45),
SetItem::Literal(122),
])]
);
}
#[test]
fn char_class_closing_bracket_as_first_char() {
assert_eq!(parsed("[]]").data, vec![lit(93)]);
}
#[test]
fn char_class_single_literal_unwraps() {
assert_eq!(parsed("[a]").data, vec![lit(97)]);
}
#[test]
fn char_class_single_literal_negated() {
assert_eq!(parsed("[^a]").data, vec![OpCode::NotLiteral(97)]);
}
#[test]
fn digit_shortcut() {
assert_eq!(
parsed("\\d").data,
vec![OpCode::In(vec![SetItem::Category(ChCode::Digit)])]
);
}
#[test]
fn word_and_space_shortcuts() {
assert_eq!(
parsed("\\w").data,
vec![OpCode::In(vec![SetItem::Category(ChCode::Word)])]
);
assert_eq!(
parsed("\\s\\S").data,
vec![
OpCode::In(vec![SetItem::Category(ChCode::Space)]),
OpCode::In(vec![SetItem::Category(ChCode::NotSpace)]),
]
);
}
#[test]
fn max_repeat_plus() {
assert_eq!(
parsed("a+").data,
vec![OpCode::MaxRepeat {
min: 1,
max: u32::MAX,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn max_repeat_star() {
assert_eq!(
parsed("a*").data,
vec![OpCode::MaxRepeat {
min: 0,
max: u32::MAX,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn max_repeat_question() {
assert_eq!(
parsed("a?").data,
vec![OpCode::MaxRepeat {
min: 0,
max: 1,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn max_repeat_braces_fixed() {
assert_eq!(
parsed("a{3}").data,
vec![OpCode::MaxRepeat {
min: 3,
max: 3,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn max_repeat_braces_range() {
assert_eq!(
parsed("a{2,5}").data,
vec![OpCode::MaxRepeat {
min: 2,
max: 5,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn max_repeat_braces_open_upper() {
assert_eq!(
parsed("a{3,}").data,
vec![OpCode::MaxRepeat {
min: 3,
max: u32::MAX,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn max_repeat_braces_open_lower() {
assert_eq!(
parsed("a{,5}").data,
vec![OpCode::MaxRepeat {
min: 0,
max: 5,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn min_repeat_plus_question() {
assert_eq!(
parsed("a+?").data,
vec![OpCode::MinRepeat {
min: 1,
max: u32::MAX,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn possessive_repeat_double_plus() {
assert_eq!(
parsed("a++").data,
vec![OpCode::PossessiveRepeat {
min: 1,
max: u32::MAX,
item: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn repeat_overflow_is_error() {
assert!(parse_pattern("a{4294967296}", 0).is_err());
}
#[test]
fn subpattern_capturing() {
assert_eq!(
parsed("(a)").data,
vec![OpCode::Subpattern {
group: Some(1),
add_flags: 0,
del_flags: 0,
p: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn subpattern_non_capturing_unwrapped() {
assert_eq!(parsed("(?:a)").data, vec![lit(97)]);
}
#[test]
fn subpattern_named_group() {
let parsed_full = parse_pattern("(?P<foo>a)", 0).unwrap();
assert_eq!(
parsed_full.pattern.data,
vec![OpCode::Subpattern {
group: Some(1),
add_flags: 0,
del_flags: 0,
p: SubPattern {
data: vec![lit(97)]
},
}]
);
}
#[test]
fn subpattern_inline_flags_scoped() {
assert_eq!(
parsed("(?i:abc)").data,
vec![OpCode::Subpattern {
group: None,
add_flags: 2,
del_flags: 0,
p: SubPattern {
data: vec![lit(97), lit(98), lit(99)]
},
}]
);
}
#[test]
fn subpattern_inline_flags_add_and_del() {
assert_eq!(
parsed("(?i-s:abc)").data,
vec![OpCode::Subpattern {
group: None,
add_flags: 2,
del_flags: 16,
p: SubPattern {
data: vec![lit(97), lit(98), lit(99)]
},
}]
);
}
#[test]
fn global_inline_flags() {
let parsed_full = parse_pattern("(?i)abc", 0).unwrap();
assert_eq!(parsed_full.pattern.data, vec![lit(97), lit(98), lit(99)]);
assert!(parsed_full.flags & 2 != 0);
}
#[test]
fn groupref_decimal() {
assert_eq!(
parsed("(a)\\1").data,
vec![
OpCode::Subpattern {
group: Some(1),
add_flags: 0,
del_flags: 0,
p: SubPattern {
data: vec![lit(97)]
},
},
OpCode::GroupRef(1),
]
);
}
#[test]
fn groupref_named() {
assert_eq!(
parsed("(?P<n>a)(?P=n)").data,
vec![
OpCode::Subpattern {
group: Some(1),
add_flags: 0,
del_flags: 0,
p: SubPattern {
data: vec![lit(97)]
},
},
OpCode::GroupRef(1),
]
);
}
#[test]
fn groupref_invalid_is_error() {
assert!(parse_pattern("a\\1", 0).is_err());
assert!(parse_pattern("\\10", 0).is_err());
}
#[test]
fn groupref_exists() {
assert_eq!(
parsed("(a)(?(1)b|c)").data,
vec![
OpCode::Subpattern {
group: Some(1),
add_flags: 0,
del_flags: 0,
p: SubPattern {
data: vec![lit(97)]
},
},
OpCode::GroupRefExists {
cond_group: 1,
yes: SubPattern {
data: vec![lit(98)]
},
no: Some(SubPattern {
data: vec![lit(99)]
}),
},
]
);
}
#[test]
fn assert_lookahead() {
assert_eq!(
parsed("(?=a)b").data,
vec![
OpCode::Assert {
direction: 1,
p: SubPattern {
data: vec![lit(97)]
},
},
lit(98),
]
);
}
#[test]
fn assert_not_lookahead() {
assert_eq!(
parsed("(?!a)b").data,
vec![
OpCode::AssertNot {
direction: 1,
p: SubPattern {
data: vec![lit(97)]
},
},
lit(98),
]
);
}
#[test]
fn assert_lookbehind() {
assert_eq!(
parsed("(?<=a)b").data,
vec![
OpCode::Assert {
direction: -1,
p: SubPattern {
data: vec![lit(97)]
},
},
lit(98),
]
);
}
#[test]
fn assert_not_lookbehind() {
assert_eq!(
parsed("(?<!a)b").data,
vec![
OpCode::AssertNot {
direction: -1,
p: SubPattern {
data: vec![lit(97)]
},
},
lit(98),
]
);
}
#[test]
fn atomic_group() {
assert_eq!(
parsed("(?>a)").data,
vec![OpCode::AtomicGroup(SubPattern {
data: vec![lit(97)]
})]
);
}
#[test]
fn branch_three_way() {
assert_eq!(
parsed("ab|cd|ef").data,
vec![OpCode::Branch(vec![
SubPattern {
data: vec![lit(97), lit(98)]
},
SubPattern {
data: vec![lit(99), lit(100)]
},
SubPattern {
data: vec![lit(101), lit(102)]
},
])]
);
}
#[test]
fn branch_single_letters_collapse_to_set() {
assert_eq!(
parsed("a|b|c").data,
vec![OpCode::In(vec![
SetItem::Literal(97),
SetItem::Literal(98),
SetItem::Literal(99),
])]
);
}
#[test]
fn branch_shared_prefix_moved_out() {
assert_eq!(
parsed("abc|abd").data,
vec![
lit(97),
lit(98),
OpCode::In(vec![SetItem::Literal(99), SetItem::Literal(100),]),
]
);
}
#[test]
fn comment_is_discarded() {
assert_eq!(parsed("a(?#comment)b").data, vec![lit(97), lit(98)]);
}
#[test]
fn named_unicode_escape_errors() {
assert!(parse_pattern(r"\N{LATIN SMALL LETTER A}", 0).is_err());
}
#[test]
fn full_complex_pattern() {
parse_pattern(r"https?://(?P<host>[\w.-]+)(:\d+)?(/\S*)?", 0).unwrap();
}
fn parse_err(pattern: &str) -> ParseError {
parse_pattern(pattern, 0).expect_err("expected parse error")
}
#[test]
fn parse_error_display_includes_position() {
let err = parse_err("(");
let s = format!("{}", err);
assert!(s.contains("at position"), "{}", s);
}
#[test]
fn err_bad_escape_at_end_of_pattern() {
let err = parse_err(r"abc\");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn err_unterminated_subpattern() {
let err = parse_err("(abc");
assert!(err.msg.contains("missing )"), "{}", err.msg);
}
#[test]
fn err_unbalanced_close_paren() {
let err = parse_err("abc)");
assert!(err.msg.contains("unbalanced parenthesis"), "{}", err.msg);
}
#[test]
fn err_unterminated_character_set() {
let err = parse_err("[abc");
assert!(
err.msg.contains("unterminated character set"),
"{}",
err.msg
);
}
#[test]
fn err_bad_character_range() {
let err = parse_err("[z-a]");
assert!(err.msg.contains("bad character range"), "{}", err.msg);
}
#[test]
fn err_min_repeat_greater_than_max() {
let err = parse_err("a{5,2}");
assert!(
err.msg.contains("min repeat greater than max repeat"),
"{}",
err.msg
);
}
#[test]
fn err_multiple_repeat() {
let err = parse_err("a*?+");
assert!(err.msg.contains("multiple repeat"), "{}", err.msg);
}
#[test]
fn err_invalid_group_reference() {
let err = parse_err(r"(a)\7");
assert!(err.msg.contains("invalid group reference"), "{}", err.msg);
}
#[test]
fn err_unknown_named_group() {
let err = parse_err(r"(?P=foo)");
assert!(err.msg.contains("unknown group name"), "{}", err.msg);
}
#[test]
fn err_redefinition_of_group_name() {
let err = parse_err("(?P<foo>a)(?P<foo>b)");
assert!(
err.msg.contains("redefinition of group name"),
"{}",
err.msg
);
}
#[test]
fn err_bad_character_in_group_name() {
let err = parse_err("(?P<1foo>a)");
assert!(
err.msg.contains("bad character in group name"),
"{}",
err.msg
);
}
#[test]
fn err_missing_group_name() {
let err = parse_err("(?P<>a)");
assert!(err.msg.contains("missing group name"), "{}", err.msg);
}
#[test]
fn err_unknown_extension() {
let err = parse_err("(?Z)");
assert!(err.msg.contains("unknown extension"), "{}", err.msg);
}
#[test]
fn err_unknown_p_extension() {
let err = parse_err("(?PZ)");
assert!(err.msg.contains("unknown extension"), "{}", err.msg);
}
#[test]
fn err_unknown_lookaround() {
let err = parse_err("(?<X)");
assert!(err.msg.contains("unknown extension"), "{}", err.msg);
}
#[test]
fn err_unterminated_comment() {
let err = parse_err("(?#unterminated");
assert!(err.msg.contains("unterminated comment"), "{}", err.msg);
}
#[test]
fn err_global_flags_not_at_start() {
let err = parse_err("a(?i)b");
assert!(
err.msg.contains("global flags not at the start"),
"{}",
err.msg
);
}
#[test]
fn err_unknown_inline_flag() {
let err = parse_err("(?Q:abc)");
assert!(err.msg.contains("unknown flag") || err.msg.contains("unknown extension"));
}
#[test]
fn err_flag_turned_on_and_off() {
let err = parse_err("(?i-i:abc)");
assert!(err.msg.contains("flag turned on and off"), "{}", err.msg);
}
#[test]
fn err_cannot_turn_off_ascii() {
let err = parse_err("(?-a:abc)");
assert!(err.msg.contains("cannot turn off"), "{}", err.msg);
}
#[test]
fn err_inline_locale_flag_str() {
let err = parse_err("(?L:abc)");
assert!(err.msg.contains("'L' flag with a str pattern") || err.msg.contains("LOCALE"));
}
#[test]
fn err_unknown_p_extension_eof() {
let err = parse_err("(?P");
assert!(err.msg.contains("unexpected end of pattern"), "{}", err.msg);
}
#[test]
fn err_conditional_too_many_branches() {
let err = parse_err("(?(1)a|b|c)");
assert!(
err.msg
.contains("conditional backref with more than two branches"),
"{}",
err.msg
);
}
#[test]
fn err_too_many_groups() {
let many_groups = "(?:".to_string() + &"(a)".repeat(501) + ")";
let err = parse_err(&many_groups);
assert!(err.msg.contains("too many groups"), "{}", err.msg);
}
#[test]
fn err_open_group_self_reference() {
let err = parse_err(r"(a\1)");
assert!(
err.msg.contains("cannot refer to an open group"),
"{}",
err.msg
);
}
#[test]
fn err_repeat_overflow() {
let err = parse_err("a{99999999999}");
assert!(
err.msg.contains("the repetition number is too large"),
"{}",
err.msg
);
}
#[test]
fn err_incomplete_unicode_escape() {
let err = parse_err(r"\u00");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_incomplete_long_unicode_escape() {
let err = parse_err(r"\U0000");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_long_unicode_escape_out_of_range() {
let err = parse_err(r"\U00FFFFFF");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn err_octal_escape_out_of_range() {
let err = parse_err(r"\400");
assert!(err.msg.contains("octal escape value"), "{}", err.msg);
}
#[test]
fn err_class_incomplete_unicode_escape() {
let err = parse_err(r"[\u00]");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_class_octal_escape_out_of_range() {
let err = parse_err(r"[\400]");
assert!(err.msg.contains("octal escape value"), "{}", err.msg);
}
#[test]
fn err_class_bad_escape() {
let err = parse_err(r"[\p]");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn err_class_named_unicode_escape_not_supported() {
let err = parse_err(r"[\N{LATIN SMALL LETTER A}]");
assert!(
err.msg.contains("named unicode escapes not yet supported"),
"{}",
err.msg
);
}
#[test]
fn parses_inline_locale_flag_bytes() {
parse_pattern("(?L)abc", SRE_FLAG_LOCALE).unwrap_err(); }
#[test]
fn parses_ascii_flag_inline() {
parse_pattern("(?a)abc", 0).unwrap();
}
#[test]
fn parses_unicode_flag_inline() {
parse_pattern("(?u)abc", 0).unwrap();
}
#[test]
fn parses_hex_escape_in_class() {
parse_pattern(r"[\x41]", 0).unwrap();
}
#[test]
fn parses_short_unicode_escape_in_class() {
parse_pattern(r"[A]", 0).unwrap();
}
#[test]
fn parses_long_unicode_escape_in_class() {
parse_pattern(r"[\U00000041]", 0).unwrap();
}
#[test]
fn parses_octal_escape_in_class() {
parse_pattern(r"[\101]", 0).unwrap();
}
#[test]
fn parses_short_unicode_escape() {
parse_pattern(r"A", 0).unwrap();
}
#[test]
fn parses_long_unicode_escape() {
parse_pattern(r"\U00000041", 0).unwrap();
}
#[test]
fn parses_octal_escape_three_digits() {
parse_pattern(r"\077", 0).unwrap();
}
#[test]
fn parses_hex_escape() {
parse_pattern(r"\x41", 0).unwrap();
}
#[test]
fn parses_class_leading_dash() {
parse_pattern("[-]", 0).unwrap();
}
#[test]
fn parses_class_trailing_dash() {
parse_pattern("[a-]", 0).unwrap();
}
#[test]
fn parses_class_dash_escape_range() {
parse_pattern(r"[\d-a]", 0).unwrap_err();
}
#[test]
fn parses_class_nested_class_union() {
parse_pattern(r"[[:alpha:]]", 0).unwrap();
}
#[test]
fn parses_atomic_group_nested() {
parse_pattern("(?>(?>a))", 0).unwrap();
}
#[test]
fn parses_possessive_question() {
parse_pattern("a?+", 0).unwrap();
}
#[test]
fn parses_min_repeat_braces() {
parse_pattern("a{3,5}?", 0).unwrap();
}
#[test]
fn parses_open_lower_bound_min() {
parse_pattern("a{,5}?", 0).unwrap();
}
#[test]
fn parses_inline_global_flag_at_start_only() {
parse_pattern("(?im)abc", 0).unwrap();
}
#[test]
fn parses_lookbehind_positive() {
parse_pattern("(?<=abc)", 0).unwrap();
}
#[test]
fn parses_lookbehind_negative() {
parse_pattern("(?<!abc)", 0).unwrap();
}
#[test]
fn parses_conditional_backref_yes_only() {
parse_pattern("(a)?(?(1)b)", 0).unwrap();
}
#[test]
fn parses_conditional_named_backref() {
parse_pattern("(?P<foo>a)?(?(foo)b|c)", 0).unwrap();
}
#[test]
fn parses_empty_pattern() {
parse_pattern("", 0).unwrap();
}
#[test]
fn parses_verbose_mode() {
parse_pattern("(?x) a # comment\n b", 0).unwrap();
}
#[test]
fn err_lookbehind_refers_to_group_in_same_lookbehind() {
let err = parse_err(r"(?<=(a)\1)");
assert!(
err.msg
.contains("cannot refer to group defined in the same lookbehind"),
"{}",
err.msg
);
}
#[test]
fn err_unterminated_named_backref() {
let err = parse_err("(?P=foo");
assert!(err.msg.contains("missing )"), "{}", err.msg);
}
#[test]
fn err_unterminated_named_group_name() {
let err = parse_err("(?P<foo");
assert!(err.msg.contains("missing >"), "{}", err.msg);
}
#[test]
fn err_empty_named_backref() {
let err = parse_err("(?P=)");
assert!(err.msg.contains("missing group name"), "{}", err.msg);
}
#[test]
fn err_unicode_escape_bad_hex() {
let err = parse_err(r"\u00gg");
assert!(err.msg.contains("incomplete escape") || err.msg.contains("bad escape"));
}
#[test]
fn err_class_long_unicode_escape_out_of_range() {
let err = parse_err(r"[\U00FFFFFF]");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn err_class_hex_escape_incomplete() {
let err = parse_err(r"[\x4]");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_unterminated_class_bracket_only() {
let err = parse_err("[");
assert!(
err.msg.contains("unterminated character set"),
"{}",
err.msg
);
}
#[test]
fn err_unterminated_class_after_dash() {
let err = parse_err("[a-");
assert!(
err.msg.contains("unterminated character set"),
"{}",
err.msg
);
}
#[test]
fn err_unterminated_class_in_escape() {
let err = parse_err(r"[\");
assert!(err.msg.contains("bad escape") || err.msg.contains("unterminated"));
}
#[test]
fn err_unterminated_group_after_subname() {
let err = parse_err("(?P<foo>");
assert!(err.msg.contains("missing )"), "{}", err.msg);
}
#[test]
fn err_empty_failure_subpattern_inline_no_close() {
let err = parse_err("(?!");
assert!(err.msg.contains("missing )"), "{}", err.msg);
}
#[test]
fn err_conditional_unknown_named_group() {
let err = parse_err("(?(missing)a|b)");
assert!(err.msg.contains("unknown group name"), "{}", err.msg);
}
#[test]
fn err_conditional_bad_group_number() {
let err = parse_err("(?(0)a|b)");
assert!(err.msg.contains("bad group number"), "{}", err.msg);
}
#[test]
fn err_conditional_invalid_group_reference() {
let err = parse_err("(?(99)a|b)");
assert!(err.msg.contains("invalid group reference"), "{}", err.msg);
}
#[test]
fn err_conditional_unterminated() {
let err = parse_err("(?(1)a|b");
assert!(err.msg.contains("missing )"), "{}", err.msg);
}
#[test]
fn err_named_unicode_escape_in_set_not_supported() {
let err = parse_err(r"[\N{LATIN SMALL LETTER A}]");
assert!(err.msg.contains("named unicode escapes not yet supported"));
}
#[test]
fn err_decimal_backref_to_open_group() {
let err = parse_err(r"(\1)");
assert!(
err.msg.contains("cannot refer to an open group"),
"{}",
err.msg
);
}
#[test]
fn parses_empty_negative_lookahead_explicit_failure() {
let p = parse_pattern("(?!)", 0).unwrap();
assert_eq!(p.pattern.data, vec![OpCode::Failure]);
}
#[test]
fn parses_complex_class_flattening() {
parse_pattern(r"[[abc][def]]", 0).unwrap();
}
#[test]
fn parses_long_unicode_escape_in_set() {
parse_pattern(r"[\U00000041]", 0).unwrap();
}
#[test]
fn parses_global_inline_flag_unicode() {
parse_pattern("(?u)abc", 0).unwrap();
}
#[test]
fn parses_global_inline_flag_ascii() {
parse_pattern("(?a)abc", 0).unwrap();
}
#[test]
fn parses_multiple_inline_flags() {
parse_pattern("(?ims)abc", 0).unwrap();
}
#[test]
fn err_inline_flag_unknown_after_dash() {
let err = parse_err("(?-Z:abc)");
assert!(err.msg.contains("unknown flag") || err.msg.contains("missing :"));
}
#[test]
fn err_inline_flag_empty_after_dash() {
let err = parse_err("(?-:abc)");
assert!(err.msg.contains("missing flag"));
}
#[test]
fn parses_inline_flag_only_negative() {
parse_pattern("(?-i:abc)", 0).unwrap();
}
#[test]
fn parses_brace_empty_as_literal() {
parse_pattern("a{}b", 0).unwrap();
}
#[test]
fn parses_brace_no_close_as_literal() {
parse_pattern("a{5", 0).unwrap();
}
#[test]
fn parses_brace_with_comma_no_close() {
parse_pattern("a{5,", 0).unwrap();
}
#[test]
fn parses_brace_no_digits_no_close() {
parse_pattern("a{abc", 0).unwrap();
}
#[test]
fn parses_class_escape_short_unicode() {
parse_pattern(r"[A]", 0).unwrap();
}
#[test]
fn err_class_decimal_escape_8_or_9() {
let err = parse_err(r"[\8]");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn parses_class_with_non_letter_escape() {
parse_pattern(r"[\!]", 0).unwrap();
}
#[test]
fn err_class_escape_unknown_letter() {
let err = parse_err(r"[\p]");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn parses_class_octal_escape_three_digits() {
parse_pattern(r"[\077]", 0).unwrap();
}
#[test]
fn parses_outer_escape_non_letter() {
parse_pattern(r"\!", 0).unwrap();
}
#[test]
fn err_outer_escape_unknown_letter() {
let err = parse_err(r"\p");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn parses_outer_octal_three_digits() {
parse_pattern(r"\077", 0).unwrap();
}
#[test]
fn err_outer_two_digit_backref_invalid_group() {
let many_groups = "(a)".repeat(7) + r"\77";
let err = parse_pattern(&many_groups, 0).unwrap_err();
assert!(err.msg.contains("invalid group reference"), "{}", err.msg);
}
#[test]
fn err_subpattern_eof_after_qmark() {
let err = parse_err("(?");
assert!(err.msg.contains("unexpected end of pattern"), "{}", err.msg);
}
#[test]
fn err_subpattern_eof_after_lookbehind_qmark() {
let err = parse_err("(?<");
assert!(err.msg.contains("unexpected end of pattern"), "{}", err.msg);
}
#[test]
fn err_inline_flag_unknown_in_dash_group() {
let err = parse_err("(?i-Z:abc)");
assert!(err.msg.contains("unknown flag"), "{}", err.msg);
}
#[test]
fn err_inline_flag_missing_colon_after_minus() {
let err = parse_err("(?-i)");
assert!(
err.msg.contains("missing :") || err.msg.contains("missing -, : or )"),
"{}",
err.msg
);
}
#[test]
fn err_inline_flag_eof_after_qmark() {
let err = parse_err("(?-");
assert!(err.msg.contains("missing flag"), "{}", err.msg);
}
#[test]
fn err_global_flag_cannot_disable_global() {
let err = parse_err("(?-i)abc");
assert!(err.msg.contains("missing :"), "{}", err.msg);
}
#[test]
fn err_external_flag_locale_with_str() {
use crate::native::re::constants::SRE_FLAG_LOCALE;
let err = parse_pattern("abc", SRE_FLAG_LOCALE).unwrap_err();
assert!(
err.msg.contains("LOCALE flag with a str pattern"),
"{}",
err.msg
);
}
#[test]
fn err_external_flag_ascii_and_unicode() {
use crate::native::re::constants::{SRE_FLAG_ASCII, SRE_FLAG_UNICODE};
let err = parse_pattern("abc", SRE_FLAG_ASCII | SRE_FLAG_UNICODE).unwrap_err();
assert!(
err.msg.contains("ASCII and UNICODE flags are incompatible"),
"{}",
err.msg
);
}
#[test]
fn err_inline_flag_type_flag_conflict_global() {
let err = parse_err("(?au)abc");
assert!(
err.msg.contains("flags 'a', 'u' and 'L' are incompatible"),
"{}",
err.msg
);
}
#[test]
fn err_inline_flag_type_flag_conflict_scoped() {
let err = parse_err("(?au:abc)");
assert!(
err.msg.contains("flags 'a', 'u' and 'L' are incompatible"),
"{}",
err.msg
);
}
#[test]
fn err_inline_flag_non_letter_after_first() {
let err = parse_err("(?i9)");
assert!(err.msg.contains("missing -, : or )"), "{}", err.msg);
}
#[test]
fn err_lookbehind_conditional_open_group() {
let err = parse_err("((?<=(?(1)a|b)))");
assert!(
err.msg.contains("cannot refer to an open group"),
"{}",
err.msg
);
}
#[test]
fn err_outer_hex_escape_breaks_on_multichar_token() {
let err = parse_err(r"\x4\n");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_conditional_groupref_overflow_u32() {
let err = parse_err("(?(99999999999)a|b)");
assert!(err.msg.contains("invalid group reference"), "{}", err.msg);
}
#[test]
fn parses_short_unicode_escape_in_class_form() {
parse_pattern(r"[A]", 0).unwrap();
}
#[test]
fn err_class_short_unicode_escape_incomplete() {
let err = parse_err(r"[\u00]");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_class_long_unicode_escape_incomplete() {
let err = parse_err(r"[\U0000]");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_class_bad_letter_escape() {
let err = parse_err(r"[\q]");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn err_outer_unicode_escape_incomplete() {
let err = parse_err(r"\u00");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn parses_class_escape_lookup_category() {
parse_pattern(r"[\w]", 0).unwrap();
}
#[test]
fn err_groupref_decimal_overflow() {
let err = parse_err(r"\9999999999999");
assert!(err.msg.contains("bad escape") || err.msg.contains("invalid group reference"));
}
#[test]
fn err_decimal_backref_to_open_group_from_named() {
let err = parse_err(r"(?P<foo>(?P=foo))");
assert!(
err.msg.contains("cannot refer to an open group"),
"{}",
err.msg
);
}
#[test]
fn err_subpattern_lookbehind_unterminated_lt() {
let err = parse_err(r"(?<");
assert!(err.msg.contains("unexpected end of pattern"), "{}", err.msg);
}
#[test]
fn err_subpattern_extension_unterminated_p() {
let err = parse_err(r"(?P");
assert!(err.msg.contains("unexpected end of pattern"), "{}", err.msg);
}
#[test]
fn err_inline_flag_no_terminator() {
let err = parse_err(r"(?i");
assert!(err.msg.contains("missing -, : or )"), "{}", err.msg);
}
#[test]
fn err_inline_flag_unknown_after_initial() {
let err = parse_err(r"(?Z)");
assert!(err.msg.contains("unknown flag") || err.msg.contains("unknown extension"));
}
#[test]
fn err_inline_flag_missing_after_dash() {
let err = parse_err(r"(?i-");
assert!(err.msg.contains("missing flag"), "{}", err.msg);
}
#[test]
fn err_inline_flag_disable_no_colon() {
let err = parse_err(r"(?i-i:");
assert!(err.msg.contains("flag turned on and off"), "{}", err.msg);
}
#[test]
fn err_inline_flag_disable_unknown() {
let err = parse_err(r"(?-Z:abc)");
assert!(err.msg.contains("unknown flag"), "{}", err.msg);
}
#[test]
fn err_repetition_too_large_braces() {
let err = parse_err("a{9999999999999999999999}");
assert!(
err.msg.contains("repetition number is too large"),
"{}",
err.msg
);
}
#[test]
fn parses_max_repeat_with_only_lower_bound() {
parse_pattern("a{3}", 0).unwrap();
}
#[test]
fn err_repetition_with_repeat_after() {
let err = parse_err(r"a{3}+?");
assert!(err.msg.contains("multiple repeat"), "{}", err.msg);
}
#[test]
fn err_named_group_empty_at_open() {
let err = parse_err("(?P<>x)");
assert!(err.msg.contains("missing group name"), "{}", err.msg);
}
#[test]
fn err_named_group_eof_with_content() {
let err = parse_err("(?P<foo");
assert!(err.msg.contains("missing >"), "{}", err.msg);
}
#[test]
fn err_named_backref_no_chars() {
let err = parse_err("(?P=");
assert!(err.msg.contains("missing group name"), "{}", err.msg);
}
#[test]
fn err_named_group_bad_char_at_open_via_getuntil() {
let err = parse_err("(?P<1>x)");
assert!(
err.msg.contains("bad character in group name"),
"{}",
err.msg
);
}
#[test]
fn parses_class_with_long_unicode_escape() {
parse_pattern(r"[A]", 0).unwrap();
}
#[test]
fn err_class_escape_two_char_unknown_letter() {
let err = parse_err(r"[\h]");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn err_outer_octal_overflow() {
let err = parse_err(r"\99999999999");
assert!(err.msg.contains("bad escape") || err.msg.contains("invalid group reference"));
}
#[test]
fn parses_class_unicode_short_escape_in_set() {
parse_pattern(r"[A]", 0).unwrap();
}
#[test]
fn parses_two_class_alternation_flatten() {
parse_pattern(r"[a[b]]", 0).unwrap();
}
#[test]
fn parses_class_with_inner_class_that_blocks_flatten() {
parse_pattern(r"[a[^b]c]", 0).unwrap();
}
#[test]
fn err_conditional_unknown_number_too_large() {
let many = "(?(99999)a|b)";
let err = parse_err(many);
assert!(err.msg.contains("invalid group reference"), "{}", err.msg);
}
#[test]
fn err_inline_flag_global_unknown() {
let err = parse_err("(?xZ)");
assert!(err.msg.contains("unknown flag") || err.msg.contains("missing"));
}
#[test]
fn err_inline_flag_disable_global() {
let err = parse_err("(?-u:abc)");
assert!(
err.msg.contains("cannot turn off flags 'a', 'u' and 'L'"),
"{}",
err.msg
);
}
#[test]
fn err_brace_repeat_overflow_lower() {
let err = parse_err("a{99999999999999999999,5}");
assert!(
err.msg.contains("repetition number is too large"),
"{}",
err.msg
);
}
#[test]
fn err_inline_flag_eof_no_minus_colon_close() {
let err = parse_err("(?i:");
assert!(err.msg.contains("missing )"), "{}", err.msg);
}
#[test]
fn parses_atomic_group_simple() {
parse_pattern(r"(?>abc)", 0).unwrap();
}
#[test]
fn parses_verbose_global_flag_in_subpattern() {
parse_pattern("(?x:a # comment\n b)", 0).unwrap();
}
#[test]
fn err_brace_repeat_max_overflow() {
let err = parse_err("a{1,99999999999999999999}");
assert!(
err.msg.contains("repetition number is too large"),
"{}",
err.msg
);
}
#[test]
fn err_repeat_at_start_of_pattern() {
let err = parse_err("+abc");
assert!(err.msg.contains("nothing to repeat"), "{}", err.msg);
}
#[test]
fn err_repeat_after_anchor() {
let err = parse_err(r"\A?");
assert!(err.msg.contains("nothing to repeat"), "{}", err.msg);
}
#[test]
fn parses_quantifier_on_noncapturing_group() {
parse_pattern("(?:abc){3}", 0).unwrap();
}
#[test]
fn parses_quantifier_on_noncapturing_group_optional() {
parse_pattern("(?:abc)?", 0).unwrap();
}
#[test]
fn parses_quantifier_on_noncapturing_group_lazy() {
parse_pattern("(?:abc)*?", 0).unwrap();
}
#[test]
fn err_class_long_unicode_escape_unreachable_hex() {
let err = parse_err(r"[\U7FFFFFFF]");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn parses_class_with_class_escape_category() {
parse_pattern(r"[\d]", 0).unwrap();
}
#[test]
fn parses_class_short_unicode_escape_hex() {
parse_pattern("[\\u0041]", 0).unwrap();
}
#[test]
fn parses_outer_short_unicode_escape_hex() {
parse_pattern("\\u0041", 0).unwrap();
}
#[test]
fn parses_class_category_then_literal() {
parse_pattern(r"[\db]", 0).unwrap();
}
#[test]
fn err_repeat_brace_max_exact_maxrepeat() {
let err = parse_err("a{1,4294967295}");
assert!(
err.msg.contains("repetition number is too large"),
"{}",
err.msg
);
}
#[test]
fn parses_nested_class_flatten_at_position_one() {
parse_pattern("[[abc]]", 0).unwrap();
}
#[test]
fn parses_class_literal_escape() {
parse_pattern(r"[\n]", 0).unwrap();
}
#[test]
fn parses_outer_octal_three_digit_padded() {
parse_pattern(r"\077", 0).unwrap();
}
#[test]
fn err_outer_decimal_groupref_overflow_long() {
let err = parse_err(r"\99999999999");
assert!(err.msg.contains("bad escape") || err.msg.contains("invalid group reference"));
}
#[test]
fn err_outer_escape_letter_unknown() {
let err = parse_err(r"\h");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn err_outer_unicode_short_incomplete_explicit() {
let err = parse_err(r"\u123");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn parses_conditional_referencing_first_group() {
parse_pattern("(a)(?(1)b)", 0).unwrap();
}
#[test]
fn err_conditional_named_unterminated() {
let err = parse_err("(?(foo");
assert!(err.msg.contains("missing )") || err.msg.contains("unknown group name"));
}
#[test]
fn err_inline_flag_global_then_invalid_letter() {
let err = parse_err("(?xZ");
assert!(err.msg.contains("unknown flag"), "{}", err.msg);
}
#[test]
fn err_inline_flag_after_minus_unknown() {
let err = parse_err("(?-Z");
assert!(err.msg.contains("unknown flag") || err.msg.contains("missing"));
}
#[test]
fn err_inline_flag_disable_no_colon_close_paren() {
let err = parse_err("(?i-i)");
assert!(
err.msg.contains("missing :") || err.msg.contains("flag turned on"),
"{}",
err.msg
);
}
#[test]
fn err_inline_flag_global_unicode_then_dash() {
let err = parse_err("(?u-i)");
assert!(
err.msg.contains("cannot turn on global flag") || err.msg.contains("missing :"),
"{}",
err.msg
);
}
#[test]
fn parses_class_with_class_escape_literal() {
parse_pattern(r"[\t]", 0).unwrap();
}
#[test]
fn err_class_unicode_short_incomplete_explicit() {
let err = parse_err(r"[\u12]");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_outer_hex_escape_incomplete() {
let err = parse_err(r"\x4");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_class_hex_escape_no_digits() {
let err = parse_err(r"[\xz]");
assert!(err.msg.contains("incomplete escape"), "{}", err.msg);
}
#[test]
fn err_outer_escape_punct_unknown() {
parse_pattern(r"\#", 0).unwrap();
}
#[test]
fn err_unknown_outer_escape_letter() {
let err = parse_err(r"\Q");
assert!(err.msg.contains("bad escape"), "{}", err.msg);
}
#[test]
fn parses_outer_octal_three_digits_returns() {
parse_pattern(r"\077", 0).unwrap();
}
#[test]
fn parses_nested_class_flatten_inner_negated() {
parse_pattern("[a[^b]]", 0).unwrap();
}
#[test]
fn parses_nested_class_with_inner_class_and_more() {
parse_pattern("[a[bc]de]", 0).unwrap();
}
#[test]
fn err_class_range_with_class_escape_endpoint_invalid() {
let err = parse_err(r"[\d-z]");
assert!(err.msg.contains("bad character range"), "{}", err.msg);
}
#[test]
fn err_conditional_named_unknown() {
let err = parse_err("(?(abc)x|y)");
assert!(err.msg.contains("unknown group name"), "{}", err.msg);
}
#[test]
fn err_inline_flag_unknown_first_char() {
let err = parse_err("(?-Q)");
assert!(err.msg.contains("missing flag") || err.msg.contains("unknown flag"));
}
#[test]
fn err_inline_flag_negate_global_in_subgroup() {
let err = parse_err("(?u-i)abc");
assert!(
err.msg.contains("cannot turn on global flag") || err.msg.contains("missing :"),
"{}",
err.msg
);
}
#[test]
fn err_inline_flag_eof_after_dash_letter() {
let err = parse_err("(?-i");
assert!(err.msg.contains("missing :"), "{}", err.msg);
}
#[test]
fn err_inline_flag_disable_global_at_end() {
let err = parse_err("(?-u)abc");
assert!(
err.msg.contains("cannot turn off") || err.msg.contains("missing :"),
"{}",
err.msg
);
}
#[test]
fn err_class_range_right_endpoint_is_class_escape() {
let err = parse_err(r"[a-\d]");
assert!(err.msg.contains("bad character range"), "{}", err.msg);
}
#[test]
fn parses_branch_flatten_with_set() {
parse_pattern("a|[bc]|d", 0).unwrap();
}
#[test]
fn parses_branch_no_flatten_with_anchor() {
parse_pattern(r"a|\b|c", 0).unwrap();
}
#[test]
fn err_groupref_in_lookbehind_open_via_named_path() {
let err = parse_err(r"(?<=(?P<foo>(?P=foo)))");
assert!(
err.msg.contains("cannot refer to an open group")
|| err
.msg
.contains("cannot refer to group defined in the same lookbehind"),
"{}",
err.msg
);
}
#[test]
fn parses_outer_octal_three_digit_non_zero_lead() {
parse_pattern(r"\107", 0).unwrap();
}
#[test]
fn err_outer_octal_three_digit_out_of_range() {
let err = parse_err(r"\477");
assert!(err.msg.contains("octal escape value"), "{}", err.msg);
}
#[test]
fn err_conditional_named_unknown_named_after_first_group() {
let err = parse_err("(a)(?(unknown)x|y)");
assert!(err.msg.contains("unknown group name"), "{}", err.msg);
}
#[test]
fn err_inline_flag_global_in_subgroup_via_partial_parse() {
let err = parse_err("(?u)abc(?i)def");
assert!(
err.msg.contains("global flags not at the start"),
"{}",
err.msg
);
}
#[test]
fn err_inline_flag_eof_after_qmark_letter() {
let err = parse_err("(?i");
assert!(err.msg.contains("missing -, : or )"), "{}", err.msg);
}
#[test]
fn err_inline_flag_disable_then_eof_after_letter() {
let err = parse_err("(?i-i");
assert!(err.msg.contains("missing :"), "{}", err.msg);
}
#[test]
fn err_inline_flag_after_enable_unknown_letter() {
let err = parse_err("(?-iZ");
assert!(err.msg.contains("unknown flag"), "{}", err.msg);
}
#[test]
fn err_inline_flag_disable_global_specifically() {
let err = parse_err("(?i-u:abc)");
assert!(
err.msg.contains("cannot turn off") || err.msg.contains("global flag"),
"{}",
err.msg
);
}
#[test]
fn err_named_group_starts_with_digit() {
let err = parse_err("(?P<1abc>x)");
assert!(err.msg.contains("bad character in group name"));
}
#[test]
fn err_named_backref_starts_with_digit() {
let err = parse_err(r"(?P<foo>a)(?P=1foo)");
assert!(
err.msg.contains("bad character in group name") || err.msg.contains("unknown group name")
);
}
#[test]
fn err_named_unterminated_no_terminator_char() {
let err = parse_err("(?P<foo");
assert!(err.msg.contains("missing >"));
}
#[test]
fn parses_nested_negated_class_disables_flatten() {
parse_pattern("[a[^b]]", 0).unwrap();
}
#[test]
fn err_class_range_with_category_endpoint() {
let err = parse_err(r"[\d-z]");
assert!(err.msg.contains("bad character range"), "{}", err.msg);
}