use proptest::prelude::*;
use regast::{PtKind, Regast};
use regex::Regex;
const PATTERNS: &[&str] = &[
"",
"a",
"a|b",
"ab",
"a?",
"a*",
"a+",
"a{0,3}",
"a{2,}",
"(a|b)*c?",
"(?:ab|b)+",
"[a-c]+",
"[^a]*",
r"\d{1,3}",
r"[\w-]+",
"(a?)*",
];
proptest! {
#![proptest_config(ProptestConfig::with_cases(256))]
#[test]
fn agrees_with_regex_and_reconstructs_deterministically(
pattern_index in 0..PATTERNS.len(),
chars in prop::collection::vec(prop::sample::select(vec!['a', 'b', 'c', '0', '-', 'é']), 0..7),
) {
let pattern = PATTERNS[pattern_index];
let input: String = chars.into_iter().collect();
let regast = Regast::new(pattern).unwrap();
let reference = Regex::new(&format!(r"\A(?:{pattern})\z")).unwrap();
prop_assert_eq!(regast.is_match(&input), reference.is_match(&input));
if let Ok(first) = regast.parse(&input) {
prop_assert_eq!(first.flatten(), input.as_str());
let second = regast.parse(&input).unwrap();
prop_assert_eq!(first.to_json(), second.to_json());
for node in first.walk() {
if let PtKind::Repeat { .. } = node.kind {
for iteration in &node.children {
prop_assert!(!first.flatten()[iteration.span.start as usize..iteration.span.end as usize].is_empty());
}
}
}
}
}
}
#[test]
fn unicode_spans_are_utf8_byte_offsets() {
let regex = Regast::new("(?<letter>[é日])+").unwrap();
let tree = regex.parse("é日").unwrap();
let groups = tree.group_by_name_all("letter");
assert_eq!(groups.len(), 2);
assert_eq!(groups[0].span.start, 0);
assert_eq!(groups[0].span.end, 2);
assert_eq!(groups[1].span.start, 2);
assert_eq!(groups[1].span.end, 5);
}