Skip to content

Commit 8f00c71

Browse files
authored
Merge pull request #183 from mull-project/code-climate
CHECK regex match: fix case when there are two+ "CHECK:" in a check line
2 parents e196653 + de37c66 commit 8f00c71

File tree

9 files changed

+135
-23
lines changed

9 files changed

+135
-23
lines changed

.coverage

-52 KB
Binary file not shown.

.github/workflows/ci-linux.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ jobs:
3737
3838
- name: Run tests
3939
run: |
40-
poetry run invoke test
40+
poetry run invoke check

.github/workflows/ci-mac.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ jobs:
3737
3838
- name: Run tests
3939
run: |
40-
poetry run invoke test
40+
poetry run invoke check

.github/workflows/ci-windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,5 @@ jobs:
5050
5151
- name: Run tests
5252
run: |
53-
poetry run invoke test
53+
poetry run invoke check
5454
shell: bash

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.coverage
12
.idea
23
.venv
34
__pycache__

filecheck/filecheck.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,6 @@ class CheckResult(Enum):
180180
CHECK_NOT_WITHOUT_MATCH = 5
181181

182182

183-
# Allow check prefixes only at the beginnings of lines or
184-
# after non-word characters.
185-
BEFORE_PREFIX = "^(.*?[^\\w-])?"
186-
187-
188183
def check_line(
189184
line, current_check, match_full_lines
190185
): # pylint: disable=too-many-return-statements
@@ -323,6 +318,11 @@ def parse_checks_from_strings(
323318

324319
@staticmethod
325320
def parse_check(line: str, line_idx, config: Config) -> Optional[Check]:
321+
# Allow check prefixes only at the beginnings of lines or
322+
# after non-word characters.
323+
# /^((?!PART).)*$/ is a negative match.
324+
# https://stackoverflow.com/a/6259570/598057
325+
before_prefix = f"^(((?!{config.check_prefix}).)*?[^-\\w])?"
326326
line = line.rstrip()
327327

328328
if not config.strict_whitespace:
@@ -332,23 +332,22 @@ def parse_check(line: str, line_idx, config: Config) -> Optional[Check]:
332332
strict_whitespace_match = "" if config.strict_mode else " *"
333333

334334
check_regex = (
335-
f"{BEFORE_PREFIX}({config.check_prefix}):"
335+
f"{before_prefix}({config.check_prefix}):"
336336
f"{strict_whitespace_match}(.*)"
337337
)
338-
339338
check_match = re.search(check_regex, line)
340339
check_type = CheckType.CHECK
341340
if not check_match:
342341
check_regex = (
343-
f"{BEFORE_PREFIX}({config.check_prefix}-NEXT):"
342+
f"{before_prefix}({config.check_prefix}-NEXT):"
344343
f"{strict_whitespace_match}(.*)"
345344
)
346345
check_match = re.search(check_regex, line)
347346
check_type = CheckType.CHECK_NEXT
348347

349348
if check_match:
350-
check_keyword = check_match.group(2)
351-
check_expression = check_match.group(3)
349+
check_keyword = check_match.group(3)
350+
check_expression = check_match.group(4)
352351
if not config.strict_mode:
353352
check_expression = check_expression.strip(" ")
354353

@@ -386,20 +385,20 @@ def parse_check(line: str, line_idx, config: Config) -> Optional[Check]:
386385
expression=check_expression,
387386
source_line=line,
388387
check_line_idx=line_idx,
389-
start_index=check_match.start(3),
388+
start_index=check_match.start(4),
390389
)
391390
return check
392391

393392
check_not_regex = (
394-
f"{BEFORE_PREFIX}({config.check_prefix}-NOT):"
393+
f"{before_prefix}({config.check_prefix}-NOT):"
395394
f"{strict_whitespace_match}(.*)"
396395
)
397396
check_match = re.search(check_not_regex, line)
398397
if check_match:
399398
match_type = MatchType.SUBSTRING
400399

401-
check_keyword = check_match.group(2)
402-
check_expression = check_match.group(3)
400+
check_keyword = check_match.group(3)
401+
check_expression = check_match.group(4)
403402
if not config.strict_mode:
404403
check_expression = check_expression.strip(" ")
405404

@@ -416,14 +415,14 @@ def parse_check(line: str, line_idx, config: Config) -> Optional[Check]:
416415
expression=check_expression,
417416
source_line=line,
418417
check_line_idx=line_idx,
419-
start_index=check_match.start(3),
418+
start_index=check_match.start(4),
420419
)
421420
return check
422421

423-
check_empty_regex = f"{BEFORE_PREFIX}({config.check_prefix}-EMPTY):"
422+
check_empty_regex = f"{before_prefix}({config.check_prefix}-EMPTY):"
424423
check_match = re.search(check_empty_regex, line)
425424
if check_match:
426-
check_keyword = check_match.group(2)
425+
check_keyword = check_match.group(3)
427426

428427
check = Check(
429428
check_type=CheckType.CHECK_EMPTY,
@@ -432,7 +431,7 @@ def parse_check(line: str, line_idx, config: Config) -> Optional[Check]:
432431
expression=None,
433432
source_line=line,
434433
check_line_idx=line_idx,
435-
start_index=check_match.start(2),
434+
start_index=check_match.start(3),
436435
)
437436
return check
438437

tasks.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,22 @@ def test_filecheck_py_using_filecheck_py_tester(context, focus=None):
187187
run_lit_tests(context, filecheck_exec, filecheck_tester_exec, focus, False)
188188

189189

190-
@task(lint, test_unit)
191-
def test(context, focus=None):
190+
@task
191+
def test_integration(context, focus=None):
192192
test_filecheck_llvm(context, focus)
193193
test_filecheck_py_using_file_check_llvm_tester(context, focus)
194194

195195

196+
@task(test_unit, test_integration)
197+
def test(_):
198+
pass
199+
200+
201+
@task(lint, test)
202+
def check(_):
203+
pass
204+
205+
196206
@task
197207
def clean(context):
198208
find_command = one_line_command(

tests/unit/test_check_parser.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from filecheck.filecheck import CheckParser, Config, MatchType, CheckType
2+
3+
4+
def create_default_config(check_file):
5+
return Config(
6+
check_file=check_file,
7+
match_full_lines=False,
8+
strict_whitespace=False,
9+
check_prefix=None,
10+
implicit_check_not=None,
11+
dump_input=None,
12+
)
13+
14+
15+
def test_01_most_basic():
16+
config = create_default_config("fake.filecheck")
17+
input_string = "CHECK: String 1"
18+
check = CheckParser.parse_check(input_string, 0, config)
19+
assert check.check_type == CheckType.CHECK
20+
assert check.match_type == MatchType.SUBSTRING
21+
assert check.check_keyword == "CHECK"
22+
assert check.expression == "String 1"
23+
assert check.source_line == input_string
24+
assert check.check_line_idx == 0
25+
assert check.start_index == 7
26+
27+
28+
def test_02_two_check_words():
29+
config = create_default_config("fake.filecheck")
30+
input_string = "CHECK: CHECK: String 1"
31+
check = CheckParser.parse_check(input_string, 0, config)
32+
assert check.match_type == MatchType.SUBSTRING
33+
assert check.check_keyword == "CHECK"
34+
assert check.expression == "CHECK: String 1"
35+
assert check.source_line == input_string
36+
assert check.check_line_idx == 0
37+
assert check.start_index == 7
38+
39+
40+
def test_10_regex_basic():
41+
config = create_default_config("fake.filecheck")
42+
input_string = "CHECK: {{String 1}}"
43+
check = CheckParser.parse_check(input_string, 0, config)
44+
assert check.match_type == MatchType.REGEX
45+
assert check.check_keyword == "CHECK"
46+
assert check.expression == "String 1"
47+
assert check.source_line == input_string
48+
assert check.check_line_idx == 0
49+
assert check.start_index == 7
50+
51+
52+
def test_11_regex_two_check_words():
53+
config = create_default_config("fake.filecheck")
54+
input_string = "CHECK: CHECK: {{String 1}}"
55+
check = CheckParser.parse_check(input_string, 0, config)
56+
assert check.match_type == MatchType.REGEX
57+
assert check.check_keyword == "CHECK"
58+
assert check.source_line == input_string
59+
assert check.check_line_idx == 0
60+
assert check.start_index == 7
61+
62+
# The behavior seems to be different across Python 3.6 - 3.9.
63+
assert (
64+
check.expression == r"CHECK\:\ String 1"
65+
or check.expression == r"CHECK:\ String 1"
66+
)
67+
68+
69+
def test_90_check_two_times_no_offset():
70+
config = create_default_config("fake.filecheck")
71+
input_string = (
72+
"CHECK:{{^.*filecheck.check:1:(9|10): "
73+
"error: CHECK: expected string not found in input$}}"
74+
)
75+
check = CheckParser.parse_check(input_string, 0, config)
76+
assert check.match_type == MatchType.REGEX
77+
assert check.expression == (
78+
"^.*filecheck.check:1:(9|10): "
79+
"error: CHECK: expected string not found in input$"
80+
)
81+
assert check.check_keyword == "CHECK"
82+
assert check.source_line == input_string
83+
assert check.check_line_idx == 0
84+
assert check.start_index == 6
85+
86+
87+
def test_91_check_two_times_with_offset():
88+
config = create_default_config("fake.filecheck")
89+
input_string = (
90+
"; CHECK:{{^.*filecheck.check:1:(9|10): "
91+
"error: CHECK: expected string not found in input$}}"
92+
)
93+
check = CheckParser.parse_check(input_string, 0, config)
94+
assert check.match_type == MatchType.REGEX
95+
assert check.expression == (
96+
"^.*filecheck.check:1:(9|10): "
97+
"error: CHECK: expected string not found in input$"
98+
)
99+
assert check.check_keyword == "CHECK"
100+
assert check.source_line == input_string
101+
assert check.check_line_idx == 0
102+
assert check.start_index == 8

0 commit comments

Comments
 (0)