"""Test cases for AST diff (used for fine-grained incremental checking)"""
from __future__ import annotations
import os
import sys
import pytest
from mypy import build
from mypy.errors import CompileError
from mypy.modulefinder import BuildSource
from mypy.nodes import MypyFile
from mypy.options import Options
from mypy.server.astdiff import compare_symbol_table_snapshots, snapshot_symbol_table
from mypy.test.config import test_temp_dir
from mypy.test.data import DataDrivenTestCase, DataSuite
from mypy.test.helpers import assert_string_arrays_equal, parse_options
class ASTDiffSuite(DataSuite):
files = ["diff.test"]
def run_case(self, testcase: DataDrivenTestCase) -> None:
first_src = "\n".join(testcase.input)
files_dict = dict(testcase.files)
second_src = files_dict["tmp/next.py"]
options = parse_options(first_src, testcase, 1)
if options.python_version > sys.version_info:
pytest.skip("Test case requires a newer Python version")
messages1, files1 = self.build(first_src, options)
messages2, files2 = self.build(second_src, options)
a = []
if messages1:
a.extend(messages1)
if messages2:
a.append("== next ==")
a.extend(messages2)
assert (
files1 is not None and files2 is not None
), "cases where CompileError occurred should not be run"
prefix = "__main__"
snapshot1 = snapshot_symbol_table(prefix, files1["__main__"].names)
snapshot2 = snapshot_symbol_table(prefix, files2["__main__"].names)
diff = compare_symbol_table_snapshots(prefix, snapshot1, snapshot2)
for trigger in sorted(diff):
a.append(trigger)
assert_string_arrays_equal(
testcase.output, a, f"Invalid output ({testcase.file}, line {testcase.line})"
)
def build(self, source: str, options: Options) -> tuple[list[str], dict[str, MypyFile] | None]:
options.use_builtins_fixtures = True
options.show_traceback = True
options.cache_dir = os.devnull
options.allow_empty_bodies = True
try:
result = build.build(
sources=[BuildSource("main", None, source)],
options=options,
alt_lib_path=test_temp_dir,
)
except CompileError as e:
# TODO: Is it okay to return None?
return e.messages, None
return result.errors, result.files