Skip to content

Commit 986f1d4

Browse files
committed
test: Speed up Swift feature usage verification script
* The set of files that enable features and the set of files that require features are expected to have a very small, if any, difference. Don't compute and check each set separately. * Find RUN and REQUIRES lines in a file in one go.
1 parent 7f8de34 commit 986f1d4

File tree

1 file changed

+48
-144
lines changed

1 file changed

+48
-144
lines changed

test/Misc/verify-swift-feature-testing.test-sh

Lines changed: 48 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,27 @@ EXCEPTIONAL_FILES = [
2727
pathlib.Path("test/IDE/complete_decl_attribute_feature_requirement.swift"),
2828
]
2929

30-
FEATURE_USAGE_RE = re.compile(
30+
ENABLE_FEATURE_RE = re.compile(
3131
r"-enable-(?:experimental|upcoming)-feature (?:-Xfrontend )?([A-Za-z0-9]*)"
3232
)
33-
# Be careful of not using REQUIRES or RUN with a colon after them or Lit will
34-
# pick them up.
3533
FEATURE_LIT_MARKER_RE = re.compile(r"swift_feature_([A-Za-z0-9]*)")
3634

3735

38-
def find_test_files_with_features_usage(swift_src_root):
36+
def find_test_files(swift_src_root):
37+
# Look for every test file in the test directories with `REQUIRES` lines
38+
# that mention `swift_feature_`.
3939
# Look for every test file in the test directories with `RUN` lines that
4040
# mention `-enable-experimental-feature` or `-enable-upcoming-feature`.
41-
# Be careful of not using REQUIRES or RUN with a colon after them or Lit will
41+
# Be careful to not use RUN or REQUIRES with a colon after them or Lit will
4242
# pick them up.
4343
output = subprocess.check_output(
4444
[
4545
"grep",
4646
"--extended-regexp",
4747
"--recursive",
4848
"-e",
49+
"REQUIRES[:].*swift_feature_",
50+
"-e",
4951
"RUN[:].*-enable-(experimental|upcoming)-feature",
5052
"--files-with-matches",
5153
str(swift_src_root / "test"),
@@ -56,154 +58,68 @@ def find_test_files_with_features_usage(swift_src_root):
5658
return output.splitlines()
5759

5860

59-
def find_test_files_with_marker_usage(swift_src_root):
60-
# Look for every test file in the test directories with `REQUIRES` lines
61-
# that mention `swift_feature_`.
62-
# Be careful of not using REQUIRES with a colon after them or Lit will
61+
def find_run_and_requires_lines(test_file):
62+
# Be careful to not use RUN or REQUIRES with a colon after them or Lit will
6363
# pick them up.
64-
output = subprocess.check_output(
65-
[
66-
"grep",
67-
"--extended-regexp",
68-
"--recursive",
69-
"-e",
70-
"REQUIRES[:].*swift_feature_",
71-
"--files-with-matches",
72-
str(swift_src_root / "test"),
73-
str(swift_src_root / "validation-test"),
74-
],
75-
text=True,
76-
)
77-
return output.splitlines()
78-
79-
80-
def find_run_lines(test_file):
8164
output = subprocess.check_output(
8265
[
8366
"grep",
8467
"--extended-regexp",
8568
"--no-filename",
8669
"-e",
8770
"RUN[:]",
88-
str(test_file),
89-
],
90-
text=True,
91-
)
92-
return output.splitlines()
93-
94-
95-
def find_requires_lines(test_file):
96-
output = subprocess.check_output(
97-
[
98-
"grep",
99-
"--extended-regexp",
100-
"--no-filename",
10171
"-e",
10272
"REQUIRES[:]",
103-
str(test_file),
73+
test_file,
10474
],
10575
text=True,
10676
)
10777
return output.splitlines()
10878

10979

110-
def check_existing_requires(test_file, feature):
111-
returncode = subprocess.call(
112-
[
113-
"grep",
114-
"--extended-regexp",
115-
"--quiet",
116-
"-e",
117-
"REQUIRES[:].*swift_feature_" + feature,
118-
str(test_file),
119-
]
120-
)
121-
return returncode != 0
80+
def check_test_file(test_file, existing_swift_features):
81+
enabled_features = set()
82+
required_features = set()
12283

84+
for line in find_run_and_requires_lines(test_file):
85+
enabled_features.update(feature for feature in ENABLE_FEATURE_RE.findall(line))
86+
required_features.update(
87+
feature for feature in FEATURE_LIT_MARKER_RE.findall(line)
88+
)
12389

124-
def check_existing_feature_usage(test_file, feature):
125-
returncode = subprocess.call(
126-
[
127-
"grep",
128-
"--extended-regexp",
129-
"--quiet",
130-
"-e",
131-
(
132-
"RUN[:].*-enable-(experimental|upcoming)-feature (-Xfrontend )?"
133-
+ re.escape(feature)
134-
),
135-
str(test_file),
136-
]
137-
)
138-
return returncode != 0
90+
had_error = False
13991

92+
# First check for unknown features.
14093

141-
def check_existing_error_message_checks(test_file, feature):
142-
returncode = subprocess.call(
143-
[
144-
"grep",
145-
"--extended-regexp",
146-
"--quiet",
147-
"-e",
148-
"requires '-enable-(experimental|upcoming)-feature " + feature + "'",
149-
str(test_file),
150-
]
151-
)
152-
return returncode != 0
94+
for feature in enabled_features.difference(existing_swift_features):
95+
enabled_features.remove(feature)
96+
print(f"error: {test_file}: Unknown feature in RUN line: {feature}")
97+
had_error = True
15398

99+
for feature in required_features.difference(existing_swift_features):
100+
required_features.remove(feature)
101+
print(f"error: {test_file}: Unknown feature in REQUIRES line: {feature}")
102+
had_error = True
154103

155-
def check_test_file_feature_usage(test_file, existing_swift_features):
156-
run_lines = find_run_lines(test_file)
157-
features = set(
158-
feature for line in run_lines for feature in FEATURE_USAGE_RE.findall(line)
159-
)
160-
num_failures = 0
161-
for feature in features:
162-
# First, check this is a valid feature
163-
if feature not in existing_swift_features:
164-
print("error: {}: Unknown feature: {}".format(str(test_file), feature))
165-
num_failures += 1
166-
continue
104+
# If the sets are equal, we're fine.
105+
if enabled_features == required_features:
106+
return had_error
167107

168-
# No warning if the necessary `REQUIRES` is already there
169-
if not check_existing_requires(test_file, feature):
170-
continue
108+
# Then check for imbalances between required and enabled features.
171109

172-
# Some tests check for the errors themselves, so we can skip them as well
173-
if not check_existing_error_message_checks(test_file, feature):
174-
continue
110+
for feature in enabled_features.difference(required_features):
111+
# Be careful to not use REQUIRES with a colon after it or Lit will pick
112+
# it up.
113+
print(f"error: {test_file}: Missing 'REQUIRES" + f": swift_feature_{feature}'")
114+
had_error = True
175115

176-
# For everything else, print a warning and add to the invalid exit code
116+
for feature in required_features.difference(enabled_features):
177117
print(
178-
"error: {}: Missing '{}: swift_feature_{}'".format(
179-
str(test_file), "REQUIRES", feature
180-
)
118+
f"error: {test_file}: Missing '-enable-(experimental|upcoming)-feature: {feature}'"
181119
)
182-
num_failures += 1
183-
return num_failures == 0
120+
had_error = True
184121

185-
186-
def check_test_file_marker_usage(test_file):
187-
require_lines = find_requires_lines(test_file)
188-
features = set(
189-
feature
190-
for line in require_lines
191-
for feature in FEATURE_LIT_MARKER_RE.findall(line)
192-
)
193-
num_failures = 0
194-
for feature in features:
195-
# No warning if -enable-experimental/upcoming-feature is there
196-
if not check_existing_feature_usage(test_file, feature):
197-
continue
198-
199-
# For everything else, print a warning and add to the invalid exit code
200-
print(
201-
"error: {}: Missing '-enable-experimental/upcoming-feature: {}'".format(
202-
str(test_file), feature
203-
)
204-
)
205-
num_failures += 1
206-
return num_failures == 0
122+
return had_error
207123

208124

209125
def main():
@@ -214,29 +130,17 @@ def main():
214130
swift_src_root = pathlib.Path(sys.argv[1])
215131
existing_swift_features = set(json.loads(sys.argv[2]))
216132

217-
num_failures = 0
218-
test_files_with_features_usage = find_test_files_with_features_usage(swift_src_root)
219-
for test_file in test_files_with_features_usage:
220-
test_file = pathlib.Path(test_file)
221-
# First lets check this is not one of the exceptional files
222-
if test_file.relative_to(swift_src_root) in EXCEPTIONAL_FILES:
223-
continue
224-
225-
if not check_test_file_feature_usage(test_file, existing_swift_features):
226-
num_failures += 1
227-
228-
test_files_with_marker_usage = find_test_files_with_marker_usage(swift_src_root)
229-
for test_file in test_files_with_marker_usage:
230-
test_file = pathlib.Path(test_file)
133+
had_error = False
231134

232-
# First lets check this is not one of the exceptional files
233-
if test_file.relative_to(swift_src_root) in EXCEPTIONAL_FILES:
135+
for test_file in find_test_files(swift_src_root):
136+
# Skip if this is one of the exceptional files.
137+
if pathlib.Path(test_file).relative_to(swift_src_root) in EXCEPTIONAL_FILES:
234138
continue
235139

236-
if not check_test_file_marker_usage(test_file):
237-
num_failures += 1
140+
if check_test_file(test_file, existing_swift_features):
141+
had_error = True
238142

239-
if num_failures > 0:
143+
if had_error:
240144
sys.exit(1)
241145

242146

0 commit comments

Comments
 (0)