Skip to content

Commit 6aeb7a5

Browse files
Michael0x2agvanrossum
authored andcommitted
Modify incremental tests to allow initial error (#2069)
This pull request modifies the testing framework to allow us to specify the expected output during both the first and second runs of incremental mode, instead of mandating that the first run typechecks. This is useful since it lets us write tests that check whether or not incremental recovers correctly in the presence of errors.
1 parent 9e4c77f commit 6aeb7a5

File tree

4 files changed

+112
-71
lines changed

4 files changed

+112
-71
lines changed

mypy/test/data.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ def parse_test_cases(
4646
i += 1
4747

4848
files = [] # type: List[Tuple[str, str]] # path and contents
49+
tcout = [] # type: List[str] # Regular output errors
50+
tcout2 = [] # type: List[str] # Output errors for incremental, second run
4951
stale_modules = None # type: Optional[Set[str]] # module names
5052
rechecked_modules = None # type: Optional[Set[str]] # module names
51-
while i < len(p) and p[i].id not in ['out', 'case']:
53+
while i < len(p) and p[i].id != 'case':
5254
if p[i].id == 'file':
5355
# Record an extra file needed for the test case.
5456
files.append((os.path.join(base_path, p[i].arg),
@@ -74,6 +76,16 @@ def parse_test_cases(
7476
rechecked_modules = set()
7577
else:
7678
rechecked_modules = {item.strip() for item in p[i].arg.split(',')}
79+
elif p[i].id == 'out' or p[i].id == 'out1':
80+
tcout = p[i].data
81+
if native_sep and os.path.sep == '\\':
82+
tcout = [fix_win_path(line) for line in tcout]
83+
ok = True
84+
elif p[i].id == 'out2':
85+
tcout2 = p[i].data
86+
if native_sep and os.path.sep == '\\':
87+
tcout2 = [fix_win_path(line) for line in tcout2]
88+
ok = True
7789
else:
7890
raise ValueError(
7991
'Invalid section header {} in {} at line {}'.format(
@@ -88,21 +100,14 @@ def parse_test_cases(
88100
raise ValueError(
89101
'Stale modules must be a subset of rechecked modules ({})'.format(path))
90102

91-
tcout = [] # type: List[str]
92-
if i < len(p) and p[i].id == 'out':
93-
tcout = p[i].data
94-
if native_sep and os.path.sep == '\\':
95-
tcout = [fix_win_path(line) for line in tcout]
96-
ok = True
97-
i += 1
98-
elif optional_out:
103+
if optional_out:
99104
ok = True
100105

101106
if ok:
102107
input = expand_includes(p[i0].data, include_path)
103108
expand_errors(input, tcout, 'main')
104109
lastline = p[i].line if i < len(p) else p[i - 1].line + 9999
105-
tc = DataDrivenTestCase(p[i0].arg, input, tcout, path,
110+
tc = DataDrivenTestCase(p[i0].arg, input, tcout, tcout2, path,
106111
p[i0].line, lastline, perform,
107112
files, stale_modules, rechecked_modules)
108113
out.append(tc)
@@ -129,11 +134,12 @@ class DataDrivenTestCase(TestCase):
129134

130135
clean_up = None # type: List[Tuple[bool, str]]
131136

132-
def __init__(self, name, input, output, file, line, lastline,
137+
def __init__(self, name, input, output, output2, file, line, lastline,
133138
perform, files, expected_stale_modules, expected_rechecked_modules):
134139
super().__init__(name)
135140
self.input = input
136141
self.output = output
142+
self.output2 = output2
137143
self.lastline = lastline
138144
self.file = file
139145
self.line = line

mypy/test/testcheck.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,10 @@ def run_case_once(self, testcase: DataDrivenTestCase, incremental=0) -> None:
114114
options.use_builtins_fixtures = True
115115
set_show_tb(True) # Show traceback on crash.
116116

117-
output = testcase.output
118117
if incremental:
119118
options.incremental = True
120119
if incremental == 1:
121120
# In run 1, copy program text to program file.
122-
output = []
123121
for module_name, program_path, program_text in module_data:
124122
if module_name == '__main__':
125123
with open(program_path, 'w') as f:
@@ -155,16 +153,25 @@ def run_case_once(self, testcase: DataDrivenTestCase, incremental=0) -> None:
155153
a = e.messages
156154
a = normalize_error_messages(a)
157155

156+
# Make sure error messages match
157+
if incremental == 0:
158+
msg = 'Invalid type checker output ({}, line {})'
159+
output = testcase.output
160+
elif incremental == 1:
161+
msg = 'Invalid type checker output in incremental, run 1 ({}, line {})'
162+
output = testcase.output
163+
elif incremental == 2:
164+
msg = 'Invalid type checker output in incremental, run 2 ({}, line {})'
165+
output = testcase.output2
166+
else:
167+
raise AssertionError()
168+
158169
if output != a and self.update_data:
159170
update_testcase_output(testcase, a)
160-
161-
assert_string_arrays_equal(
162-
output, a,
163-
'Invalid type checker output ({}, line {})'.format(
164-
testcase.file, testcase.line))
171+
assert_string_arrays_equal(output, a, msg.format(testcase.file, testcase.line))
165172

166173
if incremental and res:
167-
if not options.silent_imports:
174+
if not options.silent_imports and testcase.output is None:
168175
self.verify_cache(module_data, a, res.manager)
169176
if incremental == 2:
170177
self.check_module_equivalence(

0 commit comments

Comments
 (0)