forked from pfalcon/re1.5
-
Notifications
You must be signed in to change notification settings - Fork 0
/
run-tests
executable file
·119 lines (102 loc) · 3.73 KB
/
run-tests
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#! /usr/bin/env python3
RE_EXEC = "./re"
test_suite = [
# basics
("search", r"abc", "abcdef"),
("search", r"cde", "abcdef"),
("search", r"abc*", "abdef"),
("search", r"abc*", "abcccdef"),
("search", r"abc+", "abdef"),
("search", r"abc+", "abcccdef"),
# match
("match", r"abc", "abcdef"),
("match", r"abc*", "abdef"),
# nested group matching
("match", r"(([0-9]*)([a-z]*)[0-9]*)", "1234hello567"),
("match", r"([0-9]*)(([a-z]*)([0-9]*))", "1234hello567"),
# non-capturing groups
("match", r"(([0-9]*)(?:[a-z]*)[0-9]*)", "1234hello568"),
("match", r"(?:[0-9]*)(([a-z]*)(?:[0-9]*))", "1234hello568"),
("match", r"([0-9]*)(?:([a-z]*)(?:[0-9]*))", "1234hello568"),
("match", r"(?:)", "1234hello568"),
("match", r"1?:", "1:"),
# named character classes
("match", r"\d+", "123abc456"),
("match", r"\s+", " \t123abc456"),
("match", r"\w+", "123abc_456 abc"),
("match", r"(\w+)\s+(\w+)", "ABC \t123hello456 abc"),
("match", r"(\S+)\s+(\D+)", "ABC \thello abc456 abc"),
("match", r"(([0-9]*)([a-z]*)\d*)", "123hello456"),
# escaped metacharacters
("match", r"(\?:)", ":"),
("match", r"\(?:", "(:"),
# errors
("search", r"?", ""),
("search", r"*", ""),
("search", r"+", ""),
("search", r"[", ""),
("search", r"(", ""),
("search", r")", ""),
]
import re
import sre_constants
import subprocess
from collections import OrderedDict
def parse_result(string, res):
name, rest = res.split(b" ", 1)
if rest == b"-no match-":
return name, None
if rest == b"REGEX ERROR":
return name, rest
assert rest.startswith(b"match ")
rest = rest[6:]
tuples = [eval(t) for t in rest.split()]
matches = tuple(string[t[0]:t[1]] for t in tuples)
return name, matches
def fit_str(string, width):
if len(string) <= width:
return string
else:
return string[:width - 2] + ".."
def main():
engine_stats = OrderedDict()
for kind, regex, string in test_suite:
# run Python re to get correct result
try:
if kind == "match":
py_res = re.match(regex, string)
else:
py_res = re.search(regex, string)
if py_res is not None:
py_res = (py_res.group(0),) + py_res.groups()
except sre_constants.error:
py_res = b"REGEX ERROR"
# run our code
try:
args = (["-m"] if kind == "match" else []) + [regex, string]
re_res = subprocess.check_output([RE_EXEC]+args, stderr=subprocess.STDOUT)
re_res = re_res.split(b'\n')[1:-1] # split lines, remove first and last
except subprocess.CalledProcessError as e:
if e.returncode == 2 and e.output == b"fatal error: Error in regexp\n":
re_res = [b"recursive REGEX ERROR", b"recursiveloop REGEX ERROR", b"backtrack REGEX ERROR", b"thompson REGEX ERROR", b"pike REGEX ERROR"]
else:
raise
# check result of each engine
for engine in re_res:
engine_name, re_res = parse_result(string, engine)
try:
stats = engine_stats[engine_name]
except KeyError:
engine_stats[engine_name] = stats = [0, 0]
if py_res == re_res:
print("pass ", end="")
stats[0] += 1
else:
print("FAIL ", end="")
stats[1] += 1
print("%-25s %-20s" % (fit_str(regex, 25), fit_str(string, 20)))
print("Ran %d tests, results:" % len(test_suite))
for name, stats in engine_stats.items():
print("%15s %2d pass %2d fail" % (str(name, encoding='utf8'), stats[0], stats[1]))
if __name__ == "__main__":
main()