from __future__ import annotations
import json
import pathlib
import sys
HERE = pathlib.Path(__file__).resolve().parent
OUT = HERE.parent / "testdata" / "python_oracle.json"
sys.path.insert(0, str(HERE.parent.parent / "python"))
import irgx
CASES: list[tuple[str, str, dict[str, bool], list[str]]] = [
("literal", "cat", {}, ["cat", "concatenate", "a cat and a cat", ""]),
("alternation", "cat|dog", {}, ["a cat, a dog", "catdog", "bird"]),
("class", "[0-9]+", {}, ["a1b22c333", "0", "none", "10.20.30"]),
("dot_star", "a.*b", {}, ["axxb", "ab", "ba", "aXbXaXb"]),
("star_nullable", "a*", {}, ["abc", "", "aaa", "bbb", "abc\n", "aXaXa"]),
("empty_pattern", "", {}, ["", "a", "abc", "\n"]),
("word_boundary", r"\b", {}, ["ab cd", "", " ", "a"]),
("optional", "x?", {}, ["axbxc", "xxx", ""]),
("nullable_group", "(a*)(b*)", {}, ["aabb", "ab", "", "ba"]),
("unicode_literal", "café", {}, ["le café noir", "CAFÉ", "cafe"]),
("unicode_icase", "café", {"ignore_case": True}, ["le CAFÉ noir", "Café"]),
("unicode_class", r"\w+", {}, ["naïve café", "日本語 text", "a_b-c"]),
("unicode_dot", ".", {}, ["é", "日本", "aé"]),
("ascii_class", r"\w+", {"unicode": False}, ["naïve café", "abc def"]),
("groups_numbered", r"(\w+)@(\w+)", {}, ["mail bob@host now", "no at sign"]),
("groups_named", r"(?P<user>\w+)@(?P<host>\w+)", {}, ["bob@host"]),
("groups_optional", r"(a)|(b)", {}, ["a", "b", "ab", "c"]),
("groups_nested", r"((a)(b)?)+", {}, ["abaab", "a"]),
("fixed", "a.c", {"fixed": True}, ["a.c", "abc", "xa.cx"]),
("icase", "abc", {"ignore_case": True}, ["ABC abc AbC"]),
("word", "cat", {"word": True}, ["cat concatenate the cat.", "cats"]),
("word_group", r"(c\w+)", {"word": True}, ["cat concat cow"]),
("smart_lower", "abc", {"smart_case": True}, ["ABC abc"]),
("smart_upper", "Abc", {"smart_case": True}, ["ABC abc Abc"]),
("pcre_lookahead", r"foo(?=bar)", {"pcre": True}, ["foobar foobaz"]),
("pcre_lookbehind", r"(?<=\$)\d+", {"pcre": True}, ["$42 and 43"]),
("pcre_backref", r"(\w)\1", {"pcre": True}, ["aa bb ab cc"]),
("overlapping", "aa", {}, ["aaaa", "aaa"]),
("anchored", "^a", {}, ["abc", "bac"]),
("end_anchor", "c$", {}, ["abc", "abc\n", "cab"]),
("repeat_bound", "a{2,3}", {}, ["a aa aaa aaaa"]),
("anchor_start_caret", "^a", {}, ["\nabc", "abc", "ab\nabc"]),
("anchor_start_text", r"\Aa", {}, ["\nabc", "abc", "ab\nabc"]),
("anchor_end_dollar", "b$", {}, ["ab\ncd", "ab", "cd\nab"]),
("anchor_end_text", r"b\z", {}, ["ab\ncd", "ab", "cd\nab"]),
("anchor_both_line", "^abc$", {}, ["x\nabc\ny", "abc"]),
("anchor_both_text", r"\Aabc\z", {}, ["x\nabc\ny", "abc"]),
]
def main() -> None:
out = []
for name, pattern, flags, texts in CASES:
compiled = irgx.compile(pattern.encode(), **flags)
for text in texts:
data = text.encode()
groups = [
[
list(m.span(i)) if m.span(i) != (-1, -1) else [-1, -1]
for i in range(compiled.groups + 1)
]
for m in compiled.finditer(data)
]
out.append(
{
"name": name,
"pattern": pattern,
"flags": flags,
"text": text,
"spans": [list(m.span()) for m in compiled.finditer(data)],
"groups": groups,
"is_match": compiled.is_match(data),
}
)
OUT.parent.mkdir(exist_ok=True)
OUT.write_text(
json.dumps(
{
"generator": "scripts/python_oracle.py",
"reference": "the irregex Python binding",
"engine_version": irgx.ENGINE_VERSION,
"cases": out,
},
indent=1,
ensure_ascii=False,
)
+ "\n",
encoding="utf-8",
)
print(f"{OUT}: {len(out)} cases from engine {irgx.ENGINE_VERSION}")
if __name__ == "__main__":
main()