-
-
Notifications
You must be signed in to change notification settings - Fork 499
/
conftest.py
165 lines (136 loc) · 5.63 KB
/
conftest.py
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import os
import re
import subprocess
import pytest
from . import helpers
from . import run
from . import refactor
import jedi
from jedi.evaluate.analysis import Warning
def pytest_addoption(parser):
parser.addoption(
"--integration-case-dir",
default=os.path.join(helpers.test_dir, 'completion'),
help="Directory in which integration test case files locate.")
parser.addoption(
"--refactor-case-dir",
default=os.path.join(helpers.test_dir, 'refactor'),
help="Directory in which refactoring test case files locate.")
parser.addoption(
"--test-files", "-T", default=[], action='append',
help=(
"Specify test files using FILE_NAME[:LINE[,LINE[,...]]]. "
"For example: -T generators.py:10,13,19. "
"Note that you can use -m to specify the test case by id."))
parser.addoption(
"--thirdparty", action='store_true',
help="Include integration tests that requires third party modules.")
def parse_test_files_option(opt):
"""
Parse option passed to --test-files into a key-value pair.
>>> parse_test_files_option('generators.py:10,13,19')
('generators.py', [10, 13, 19])
"""
opt = str(opt)
if ':' in opt:
(f_name, rest) = opt.split(':', 1)
return f_name, list(map(int, rest.split(',')))
else:
return opt, []
def pytest_generate_tests(metafunc):
"""
:type metafunc: _pytest.python.Metafunc
"""
test_files = dict(map(parse_test_files_option,
metafunc.config.option.test_files))
if 'case' in metafunc.fixturenames:
base_dir = metafunc.config.option.integration_case_dir
thirdparty = metafunc.config.option.thirdparty
cases = list(run.collect_dir_tests(base_dir, test_files))
if thirdparty:
cases.extend(run.collect_dir_tests(
os.path.join(base_dir, 'thirdparty'), test_files, True))
ids = ["%s:%s" % (c.module_name, c.line_nr_test) for c in cases]
metafunc.parametrize('case', cases, ids=ids)
if 'refactor_case' in metafunc.fixturenames:
base_dir = metafunc.config.option.refactor_case_dir
metafunc.parametrize(
'refactor_case',
refactor.collect_dir_tests(base_dir, test_files))
if 'static_analysis_case' in metafunc.fixturenames:
base_dir = os.path.join(os.path.dirname(__file__), 'static_analysis')
cases = list(collect_static_analysis_tests(base_dir, test_files))
metafunc.parametrize(
'static_analysis_case',
cases,
ids=[c.name for c in cases]
)
def collect_static_analysis_tests(base_dir, test_files):
for f_name in os.listdir(base_dir):
files_to_execute = [a for a in test_files.items() if a[0] in f_name]
if f_name.endswith(".py") and (not test_files or files_to_execute):
path = os.path.join(base_dir, f_name)
yield StaticAnalysisCase(path)
class StaticAnalysisCase(object):
"""
Static Analysis cases lie in the static_analysis folder.
The tests also start with `#!`, like the goto_definition tests.
"""
def __init__(self, path):
self._path = path
self.name = os.path.basename(path)
with open(path) as f:
self._source = f.read()
self.skip = False
for line in self._source.splitlines():
self.skip = self.skip or run.skip_python_version(line)
def collect_comparison(self):
cases = []
for line_nr, line in enumerate(self._source.splitlines(), 1):
match = re.match(r'(\s*)#! (\d+ )?(.*)$', line)
if match is not None:
column = int(match.group(2) or 0) + len(match.group(1))
cases.append((line_nr + 1, column, match.group(3)))
return cases
def run(self, compare_cb, environment):
analysis = jedi.Script(
self._source,
path=self._path,
environment=environment,
)._analysis()
typ_str = lambda inst: 'warning ' if isinstance(inst, Warning) else ''
analysis = [(r.line, r.column, typ_str(r) + r.name)
for r in analysis]
compare_cb(self, analysis, self.collect_comparison())
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, os.path.basename(self._path))
@pytest.fixture(scope='session')
def venv_path(tmpdir_factory, environment):
if environment.version_info.major < 3:
pytest.skip("python -m venv does not exist in Python 2")
tmpdir = tmpdir_factory.mktemp('venv_path')
dirname = os.path.join(tmpdir.dirname, 'venv')
# We cannot use the Python from tox because tox creates virtualenvs and
# they have different site.py files that work differently than the default
# ones. Instead, we find the real Python executable by printing the value
# of sys.base_prefix or sys.real_prefix if we are in a virtualenv.
output = subprocess.check_output([
environment.executable, "-c",
"import sys; "
"print(sys.real_prefix if hasattr(sys, 'real_prefix') else sys.base_prefix)"
])
prefix = output.rstrip().decode('utf8')
if os.name == 'nt':
executable_path = os.path.join(prefix, 'python')
else:
executable_name = os.path.basename(environment.executable)
executable_path = os.path.join(prefix, 'bin', executable_name)
subprocess.call([executable_path, '-m', 'venv', dirname])
return dirname
@pytest.fixture()
def cwd_tmpdir(monkeypatch, tmpdir):
with helpers.set_cwd(tmpdir.strpath):
yield tmpdir
@pytest.fixture
def evaluator(Script):
return Script('')._evaluator