forked from VimPlug/jedi
13
.travis.yml
13
.travis.yml
@@ -6,12 +6,11 @@ python:
|
|||||||
- 3.2
|
- 3.2
|
||||||
install:
|
install:
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.5' ]]; then
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.5' ]]; then
|
||||||
pip install --use-mirrors simplejson unittest2;
|
export PIP_INSECURE=t;
|
||||||
fi
|
fi
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then
|
- pip install --use-mirrors tox
|
||||||
pip install --use-mirrors unittest2;
|
|
||||||
fi
|
|
||||||
- pip install --use-mirrors nose
|
|
||||||
script:
|
script:
|
||||||
- cd test
|
- export TOXENV=$(echo "$TRAVIS_PYTHON_VERSION" |
|
||||||
- ./test.sh
|
sed --regexp-extended 's/([0-9])\.([0-9])/py\1\2/g')
|
||||||
|
- echo "TOXENV=$TOXENV"
|
||||||
|
- tox
|
||||||
|
|||||||
7
pytest.ini
Normal file
7
pytest.ini
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[pytest]
|
||||||
|
addopts = --assert=plain
|
||||||
|
|
||||||
|
# Activate `clean_jedi_cache` fixture for all tests. This should be
|
||||||
|
# fine as long as we are using `clean_jedi_cache` as a session scoped
|
||||||
|
# fixture.
|
||||||
|
usefixtures = clean_jedi_cache
|
||||||
82
test/base.py
82
test/base.py
@@ -1,4 +1,3 @@
|
|||||||
import time
|
|
||||||
import sys
|
import sys
|
||||||
if sys.hexversion < 0x02070000:
|
if sys.hexversion < 0x02070000:
|
||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
@@ -8,48 +7,17 @@ import os
|
|||||||
from os.path import abspath, dirname
|
from os.path import abspath, dirname
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
test_dir = dirname(abspath(__file__))
|
import pytest
|
||||||
root_dir = dirname(test_dir)
|
|
||||||
sys.path.insert(0, root_dir)
|
|
||||||
|
|
||||||
import jedi
|
import jedi
|
||||||
from jedi import debug
|
from jedi._compatibility import is_py25
|
||||||
|
|
||||||
test_sum = 0
|
|
||||||
t_start = time.time()
|
|
||||||
# Sorry I didn't use argparse here. It's because argparse is not in the
|
|
||||||
# stdlib in 2.5.
|
|
||||||
args = sys.argv[1:]
|
|
||||||
|
|
||||||
print_debug = False
|
|
||||||
try:
|
|
||||||
i = args.index('--debug')
|
|
||||||
args = args[:i] + args[i + 1:]
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
print_debug = True
|
|
||||||
jedi.set_debug_function(debug.print_to_stdout)
|
|
||||||
|
|
||||||
sys.argv = sys.argv[:1] + args
|
|
||||||
|
|
||||||
summary = []
|
|
||||||
tests_fail = 0
|
|
||||||
|
|
||||||
|
|
||||||
def get_test_list():
|
test_dir = dirname(abspath(__file__))
|
||||||
# get test list, that should be executed
|
root_dir = dirname(test_dir)
|
||||||
test_files = {}
|
|
||||||
last = None
|
|
||||||
for arg in sys.argv[1:]:
|
sample_int = 1 # This is used in completion/imports.py
|
||||||
if arg.isdigit():
|
|
||||||
if last is None:
|
|
||||||
continue
|
|
||||||
test_files[last].append(int(arg))
|
|
||||||
else:
|
|
||||||
test_files[arg] = []
|
|
||||||
last = arg
|
|
||||||
return test_files
|
|
||||||
|
|
||||||
|
|
||||||
class TestBase(unittest.TestCase):
|
class TestBase(unittest.TestCase):
|
||||||
@@ -76,13 +44,6 @@ class TestBase(unittest.TestCase):
|
|||||||
return script.function_definition()
|
return script.function_definition()
|
||||||
|
|
||||||
|
|
||||||
def print_summary():
|
|
||||||
print('\nSummary: (%s fails of %s tests) in %.3fs' % \
|
|
||||||
(tests_fail, test_sum, time.time() - t_start))
|
|
||||||
for s in summary:
|
|
||||||
print(s)
|
|
||||||
|
|
||||||
|
|
||||||
def cwd_at(path):
|
def cwd_at(path):
|
||||||
"""
|
"""
|
||||||
Decorator to run function at `path`.
|
Decorator to run function at `path`.
|
||||||
@@ -102,3 +63,32 @@ def cwd_at(path):
|
|||||||
os.chdir(oldcwd)
|
os.chdir(oldcwd)
|
||||||
return wrapper
|
return wrapper
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
_py25_fails = 0
|
||||||
|
py25_allowed_fails = 9
|
||||||
|
|
||||||
|
|
||||||
|
def skip_py25_fails(func):
|
||||||
|
"""
|
||||||
|
Skip first `py25_allowed_fails` failures in Python 2.5.
|
||||||
|
|
||||||
|
.. todo:: Remove this decorator by implementing "skip tag" for
|
||||||
|
integration tests.
|
||||||
|
"""
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapper(*args, **kwds):
|
||||||
|
global _py25_fails
|
||||||
|
try:
|
||||||
|
func(*args, **kwds)
|
||||||
|
except AssertionError:
|
||||||
|
_py25_fails += 1
|
||||||
|
if _py25_fails > py25_allowed_fails:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
pytest.skip("%d-th failure (there can be %d failures)" %
|
||||||
|
(_py25_fails, py25_allowed_fails))
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
if not is_py25:
|
||||||
|
skip_py25_fails = lambda f: f
|
||||||
|
|||||||
@@ -154,9 +154,9 @@ mod1.a
|
|||||||
|
|
||||||
from .. import base
|
from .. import base
|
||||||
#? int()
|
#? int()
|
||||||
base.tests_fail
|
base.sample_int
|
||||||
|
|
||||||
from ..base import tests_fail as f
|
from ..base import sample_int as f
|
||||||
#? int()
|
#? int()
|
||||||
f
|
f
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,23 @@
|
|||||||
from os.path import join, dirname, abspath
|
import os
|
||||||
default_base_dir = join(dirname(abspath(__file__)), 'completion')
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
import run
|
import pytest
|
||||||
|
|
||||||
|
from . import base
|
||||||
|
from . import run
|
||||||
|
from . import refactor
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--base-dir", default=default_base_dir,
|
"--integration-case-dir",
|
||||||
|
default=os.path.join(base.test_dir, 'completion'),
|
||||||
help="Directory in which integration test case files locate.")
|
help="Directory in which integration test case files locate.")
|
||||||
|
parser.addoption(
|
||||||
|
"--refactor-case-dir",
|
||||||
|
default=os.path.join(base.test_dir, 'refactor'),
|
||||||
|
help="Directory in which refactoring test case files locate.")
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--test-files", "-T", default=[], action='append',
|
"--test-files", "-T", default=[], action='append',
|
||||||
help=(
|
help=(
|
||||||
@@ -15,7 +25,7 @@ def pytest_addoption(parser):
|
|||||||
"For example: -T generators.py:10,13,19. "
|
"For example: -T generators.py:10,13,19. "
|
||||||
"Note that you can use -m to specify the test case by id."))
|
"Note that you can use -m to specify the test case by id."))
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--thirdparty",
|
"--thirdparty", action='store_true',
|
||||||
help="Include integration tests that requires third party modules.")
|
help="Include integration tests that requires third party modules.")
|
||||||
|
|
||||||
|
|
||||||
@@ -38,11 +48,40 @@ def pytest_generate_tests(metafunc):
|
|||||||
"""
|
"""
|
||||||
:type metafunc: _pytest.python.Metafunc
|
:type metafunc: _pytest.python.Metafunc
|
||||||
"""
|
"""
|
||||||
if 'case' in metafunc.fixturenames:
|
|
||||||
base_dir = metafunc.config.option.base_dir
|
|
||||||
test_files = dict(map(parse_test_files_option,
|
test_files = dict(map(parse_test_files_option,
|
||||||
metafunc.config.option.test_files))
|
metafunc.config.option.test_files))
|
||||||
|
if 'case' in metafunc.fixturenames:
|
||||||
|
base_dir = metafunc.config.option.integration_case_dir
|
||||||
thirdparty = metafunc.config.option.thirdparty
|
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))
|
||||||
|
metafunc.parametrize('case', cases)
|
||||||
|
if 'refactor_case' in metafunc.fixturenames:
|
||||||
|
base_dir = metafunc.config.option.refactor_case_dir
|
||||||
metafunc.parametrize(
|
metafunc.parametrize(
|
||||||
'case',
|
'refactor_case',
|
||||||
run.collect_dir_tests(base_dir, test_files, thirdparty))
|
refactor.collect_dir_tests(base_dir, test_files))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def clean_jedi_cache(request):
|
||||||
|
"""
|
||||||
|
Set `jedi.settings.cache_directory` to a temporary directory during test.
|
||||||
|
|
||||||
|
Note that you can't use built-in `tmpdir` and `monkeypatch`
|
||||||
|
fixture here because their scope is 'function', which is not used
|
||||||
|
in 'session' scope fixture.
|
||||||
|
|
||||||
|
This fixture is activated in ../pytest.ini.
|
||||||
|
"""
|
||||||
|
settings = base.jedi.settings
|
||||||
|
old = settings.cache_directory
|
||||||
|
tmp = tempfile.mkdtemp(prefix='jedi-test-')
|
||||||
|
settings.cache_directory = tmp
|
||||||
|
|
||||||
|
@request.addfinalizer
|
||||||
|
def restore():
|
||||||
|
settings.cache_directory = old
|
||||||
|
shutil.rmtree(tmp)
|
||||||
|
|||||||
@@ -4,13 +4,8 @@ Refactoring tests work a little bit similar to Black Box tests. But the idea is
|
|||||||
here to compare two versions of code.
|
here to compare two versions of code.
|
||||||
"""
|
"""
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import traceback
|
|
||||||
import re
|
import re
|
||||||
import itertools
|
|
||||||
|
|
||||||
import base
|
|
||||||
|
|
||||||
from jedi._compatibility import reduce
|
from jedi._compatibility import reduce
|
||||||
import jedi
|
import jedi
|
||||||
@@ -64,7 +59,7 @@ class RefactoringCase(object):
|
|||||||
self.name, self.line_nr - 1)
|
self.name, self.line_nr - 1)
|
||||||
|
|
||||||
|
|
||||||
def collect_file_tests(source, f_name, lines_to_execute):
|
def collect_file_tests(source, path, lines_to_execute):
|
||||||
r = r'^# --- ?([^\n]*)\n((?:(?!\n# \+\+\+).)*)' \
|
r = r'^# --- ?([^\n]*)\n((?:(?!\n# \+\+\+).)*)' \
|
||||||
r'\n# \+\+\+((?:(?!\n# ---).)*)'
|
r'\n# \+\+\+((?:(?!\n# ---).)*)'
|
||||||
for match in re.finditer(r, source, re.DOTALL | re.MULTILINE):
|
for match in re.finditer(r, source, re.DOTALL | re.MULTILINE):
|
||||||
@@ -86,7 +81,6 @@ def collect_file_tests(source, f_name, lines_to_execute):
|
|||||||
if lines_to_execute and line_nr - 1 not in lines_to_execute:
|
if lines_to_execute and line_nr - 1 not in lines_to_execute:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
path = os.path.join(os.path.abspath(refactoring_test_dir), f_name)
|
|
||||||
yield RefactoringCase(name, source, line_nr, index, path,
|
yield RefactoringCase(name, source, line_nr, index, path,
|
||||||
new_name, start_line_test, second)
|
new_name, start_line_test, second)
|
||||||
|
|
||||||
@@ -96,65 +90,8 @@ def collect_dir_tests(base_dir, test_files):
|
|||||||
files_to_execute = [a for a in test_files.items() if a[0] in f_name]
|
files_to_execute = [a for a in test_files.items() if a[0] in f_name]
|
||||||
lines_to_execute = reduce(lambda x, y: x + y[1], files_to_execute, [])
|
lines_to_execute = reduce(lambda x, y: x + y[1], files_to_execute, [])
|
||||||
if f_name.endswith(".py") and (not test_files or files_to_execute):
|
if f_name.endswith(".py") and (not test_files or files_to_execute):
|
||||||
path = os.path.join(refactoring_test_dir, f_name)
|
path = os.path.join(base_dir, f_name)
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
source = f.read()
|
source = f.read()
|
||||||
for case in collect_file_tests(source, f_name, lines_to_execute):
|
for case in collect_file_tests(source, path, lines_to_execute):
|
||||||
yield case
|
yield case
|
||||||
|
|
||||||
|
|
||||||
def run_test(cases):
|
|
||||||
"""
|
|
||||||
This is the completion test for some cases. The tests are not unit test
|
|
||||||
like, they are rather integration tests.
|
|
||||||
It uses comments to specify a test in the next line. The comment also says,
|
|
||||||
which results are expected. The comment always begins with `#?`. The last
|
|
||||||
row symbolizes the cursor.
|
|
||||||
|
|
||||||
For example::
|
|
||||||
|
|
||||||
#? ['ab']
|
|
||||||
ab = 3; a
|
|
||||||
|
|
||||||
#? int()
|
|
||||||
ab = 3; ab
|
|
||||||
"""
|
|
||||||
fails = 0
|
|
||||||
tests = 0
|
|
||||||
for case in cases:
|
|
||||||
try:
|
|
||||||
if not case.check():
|
|
||||||
print(case)
|
|
||||||
print(' ' + repr(str(case.result)))
|
|
||||||
print(' ' + repr(case.desired))
|
|
||||||
fails += 1
|
|
||||||
except Exception:
|
|
||||||
print(traceback.format_exc())
|
|
||||||
print(case)
|
|
||||||
fails += 1
|
|
||||||
tests += 1
|
|
||||||
return tests, fails
|
|
||||||
|
|
||||||
|
|
||||||
def test_dir(refactoring_test_dir):
|
|
||||||
for (path, cases) in itertools.groupby(
|
|
||||||
collect_dir_tests(refactoring_test_dir, test_files),
|
|
||||||
lambda case: case.path):
|
|
||||||
num_tests, fails = run_test(cases)
|
|
||||||
|
|
||||||
base.test_sum += num_tests
|
|
||||||
f_name = os.path.basename(path)
|
|
||||||
s = 'run %s tests with %s fails (%s)' % (num_tests, fails, f_name)
|
|
||||||
base.tests_fail += fails
|
|
||||||
print(s)
|
|
||||||
base.summary.append(s)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
refactoring_test_dir = os.path.join(base.test_dir, 'refactor')
|
|
||||||
test_files = base.get_test_list()
|
|
||||||
test_dir(refactoring_test_dir)
|
|
||||||
|
|
||||||
base.print_summary()
|
|
||||||
|
|
||||||
sys.exit(1 if base.tests_fail else 0)
|
|
||||||
|
|||||||
276
test/run.py
276
test/run.py
@@ -17,62 +17,40 @@ There are different kind of tests:
|
|||||||
How to run tests?
|
How to run tests?
|
||||||
+++++++++++++++++
|
+++++++++++++++++
|
||||||
|
|
||||||
Basically ``run.py`` searches the ``completion`` directory for files with lines
|
Jedi uses pytest_ to run unit and integration tests. To run tests,
|
||||||
starting with the symbol above. There is also support for third party
|
simply run ``py.test``. You can also use tox_ to run tests for
|
||||||
libraries. In a normal test run (``./run.py``) they are not being executed, you
|
multiple Python versions.
|
||||||
have to provide a ``--thirdparty`` option.
|
|
||||||
|
|
||||||
Now it's much more important, that you know how test only one file (``./run.py
|
.. _pytest: http://pytest.org
|
||||||
classes``, where ``classes`` is the name of the file to test) or even one test
|
.. _tox: http://testrun.org/tox
|
||||||
(``./run.py classes 90``, which would just execute the test on line 90).
|
|
||||||
|
|
||||||
If you want to debug a test, just use the --debug option.
|
Integration test cases are located in ``test/completion`` directory
|
||||||
|
and each test cases are indicated by the comment ``#?`` (complete /
|
||||||
|
definitions), ``#!`` (assignments) and ``#<`` (usages). There is also
|
||||||
|
support for third party libraries. In a normal test run they are not
|
||||||
|
being executed, you have to provide a ``--thirdparty`` option.
|
||||||
|
|
||||||
|
In addition to standard `-k` and `-m` options in py.test, you can use
|
||||||
|
`-T` (`--test-files`) option to specify integration test cases to run.
|
||||||
|
It takes the format of ``FILE_NAME[:LINE[,LINE[,...]]]`` where
|
||||||
|
``FILE_NAME`` is a file in ``test/completion`` and ``LINE`` is a line
|
||||||
|
number of the test comment. Here is some recipes:
|
||||||
|
|
||||||
|
Run tests only in ``basic.py`` and ``imports.py``::
|
||||||
|
|
||||||
|
py.test test/test_integration.py -T basic.py -T imports.py
|
||||||
|
|
||||||
|
Run test at line 4, 6, and 8 in ``basic.py``::
|
||||||
|
|
||||||
|
py.test test/test_integration.py -T basic.py:4,6,8
|
||||||
|
|
||||||
|
See ``py.test --help`` for more information.
|
||||||
|
|
||||||
|
If you want to debug a test, just use the --pdb option.
|
||||||
|
|
||||||
Auto-Completion
|
Auto-Completion
|
||||||
+++++++++++++++
|
+++++++++++++++
|
||||||
|
|
||||||
.. autofunction:: run_completion_test
|
|
||||||
|
|
||||||
Definition
|
|
||||||
++++++++++
|
|
||||||
|
|
||||||
.. autofunction:: run_definition_test
|
|
||||||
|
|
||||||
Goto
|
|
||||||
++++
|
|
||||||
|
|
||||||
.. autofunction:: run_goto_test
|
|
||||||
|
|
||||||
Related Names
|
|
||||||
+++++++++++++
|
|
||||||
|
|
||||||
.. autofunction:: run_related_name_test
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
import traceback
|
|
||||||
import itertools
|
|
||||||
|
|
||||||
import base
|
|
||||||
|
|
||||||
from jedi._compatibility import unicode, StringIO, reduce, literal_eval, is_py25
|
|
||||||
|
|
||||||
import jedi
|
|
||||||
from jedi import debug
|
|
||||||
|
|
||||||
|
|
||||||
sys.path.pop(0) # pop again, because it might affect the completion
|
|
||||||
|
|
||||||
|
|
||||||
TEST_COMPLETIONS = 0
|
|
||||||
TEST_DEFINITIONS = 1
|
|
||||||
TEST_ASSIGNMENTS = 2
|
|
||||||
TEST_USAGES = 3
|
|
||||||
|
|
||||||
|
|
||||||
def run_completion_test(case):
|
|
||||||
"""
|
|
||||||
Uses comments to specify a test in the next line. The comment says, which
|
Uses comments to specify a test in the next line. The comment says, which
|
||||||
results are expected. The comment always begins with `#?`. The last row
|
results are expected. The comment always begins with `#?`. The last row
|
||||||
symbolizes the cursor.
|
symbolizes the cursor.
|
||||||
@@ -85,74 +63,18 @@ def run_completion_test(case):
|
|||||||
Because it follows ``a.rea`` and a is an ``int``, which has a ``real``
|
Because it follows ``a.rea`` and a is an ``int``, which has a ``real``
|
||||||
property.
|
property.
|
||||||
|
|
||||||
Returns 1 for fail and 0 for success.
|
Definition
|
||||||
"""
|
++++++++++
|
||||||
(script, correct, line_nr) = (case.script(), case.correct, case.line_nr)
|
|
||||||
completions = script.complete()
|
|
||||||
#import cProfile; cProfile.run('script.complete()')
|
|
||||||
|
|
||||||
comp_str = set([c.word for c in completions])
|
|
||||||
if comp_str != set(literal_eval(correct)):
|
|
||||||
print('Solution @%s not right, received %s, wanted %s'\
|
|
||||||
% (line_nr - 1, comp_str, correct))
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def run_definition_test(case):
|
|
||||||
"""
|
|
||||||
Definition tests use the same symbols like completion tests. This is
|
Definition tests use the same symbols like completion tests. This is
|
||||||
possible because the completion tests are defined with a list::
|
possible because the completion tests are defined with a list::
|
||||||
|
|
||||||
#? int()
|
#? int()
|
||||||
ab = 3; ab
|
ab = 3; ab
|
||||||
|
|
||||||
Returns 1 for fail and 0 for success.
|
Goto
|
||||||
"""
|
++++
|
||||||
def definition(correct, correct_start, path):
|
|
||||||
def defs(line_nr, indent):
|
|
||||||
s = jedi.Script(script.source, line_nr, indent, path)
|
|
||||||
return set(s.definition())
|
|
||||||
|
|
||||||
should_be = set()
|
|
||||||
number = 0
|
|
||||||
for index in re.finditer('(?: +|$)', correct):
|
|
||||||
if correct == ' ':
|
|
||||||
continue
|
|
||||||
# -1 for the comment, +3 because of the comment start `#? `
|
|
||||||
start = index.start()
|
|
||||||
if base.print_debug:
|
|
||||||
jedi.set_debug_function(None)
|
|
||||||
number += 1
|
|
||||||
try:
|
|
||||||
should_be |= defs(line_nr - 1, start + correct_start)
|
|
||||||
except Exception:
|
|
||||||
print('could not resolve %s indent %s' % (line_nr - 1, start))
|
|
||||||
raise
|
|
||||||
if base.print_debug:
|
|
||||||
jedi.set_debug_function(debug.print_to_stdout)
|
|
||||||
# because the objects have different ids, `repr` it, then compare it.
|
|
||||||
should_str = set(r.desc_with_module for r in should_be)
|
|
||||||
if len(should_str) < number:
|
|
||||||
raise Exception('Solution @%s not right, too few test results: %s'
|
|
||||||
% (line_nr - 1, should_str))
|
|
||||||
return should_str
|
|
||||||
|
|
||||||
(correct, line_nr, column, start, line) = \
|
|
||||||
(case.correct, case.line_nr, case.column, case.start, case.line)
|
|
||||||
script = case.script()
|
|
||||||
should_str = definition(correct, start, script.source_path)
|
|
||||||
result = script.definition()
|
|
||||||
is_str = set(r.desc_with_module for r in result)
|
|
||||||
if is_str != should_str:
|
|
||||||
print('Solution @%s not right, received %s, wanted %s' \
|
|
||||||
% (line_nr - 1, is_str, should_str))
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def run_goto_test(case):
|
|
||||||
"""
|
|
||||||
Tests look like this::
|
Tests look like this::
|
||||||
|
|
||||||
abc = 1
|
abc = 1
|
||||||
@@ -165,51 +87,26 @@ def run_goto_test(case):
|
|||||||
#! 2 ['abc=1']
|
#! 2 ['abc=1']
|
||||||
abc
|
abc
|
||||||
|
|
||||||
Returns 1 for fail and 0 for success.
|
Related Names
|
||||||
"""
|
+++++++++++++
|
||||||
(script, correct, line_nr) = (case.script(), case.correct, case.line_nr)
|
|
||||||
result = script.goto()
|
|
||||||
comp_str = str(sorted(str(r.description) for r in result))
|
|
||||||
if comp_str != correct:
|
|
||||||
print('Solution @%s not right, received %s, wanted %s'\
|
|
||||||
% (line_nr - 1, comp_str, correct))
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def run_related_name_test(case):
|
|
||||||
"""
|
|
||||||
Tests look like this::
|
Tests look like this::
|
||||||
|
|
||||||
abc = 1
|
abc = 1
|
||||||
#< abc@1,0 abc@3,0
|
#< abc@1,0 abc@3,0
|
||||||
abc
|
abc
|
||||||
|
|
||||||
Returns 1 for fail and 0 for success.
|
|
||||||
"""
|
"""
|
||||||
(script, correct, line_nr) = (case.script(), case.correct, case.line_nr)
|
import os
|
||||||
result = script.related_names()
|
import re
|
||||||
correct = correct.strip()
|
|
||||||
compare = sorted((r.module_name, r.start_pos[0], r.start_pos[1])
|
|
||||||
for r in result)
|
|
||||||
wanted = []
|
|
||||||
if not correct:
|
|
||||||
positions = []
|
|
||||||
else:
|
|
||||||
positions = literal_eval(correct)
|
|
||||||
for pos_tup in positions:
|
|
||||||
if type(pos_tup[0]) == str:
|
|
||||||
# this means that there is a module specified
|
|
||||||
wanted.append(pos_tup)
|
|
||||||
else:
|
|
||||||
wanted.append(('renaming', line_nr + pos_tup[0], pos_tup[1]))
|
|
||||||
|
|
||||||
wanted = sorted(wanted)
|
import jedi
|
||||||
if compare != wanted:
|
from jedi._compatibility import unicode, StringIO, reduce, is_py25
|
||||||
print('Solution @%s not right, received %s, wanted %s'\
|
|
||||||
% (line_nr - 1, compare, wanted))
|
|
||||||
return 1
|
TEST_COMPLETIONS = 0
|
||||||
return 0
|
TEST_DEFINITIONS = 1
|
||||||
|
TEST_ASSIGNMENTS = 2
|
||||||
|
TEST_USAGES = 3
|
||||||
|
|
||||||
|
|
||||||
class IntegrationTestCase(object):
|
class IntegrationTestCase(object):
|
||||||
@@ -274,7 +171,7 @@ def collect_file_tests(lines, lines_to_execute):
|
|||||||
correct = None
|
correct = None
|
||||||
|
|
||||||
|
|
||||||
def collect_dir_tests(base_dir, test_files, thirdparty=False):
|
def collect_dir_tests(base_dir, test_files):
|
||||||
for f_name in os.listdir(base_dir):
|
for f_name in os.listdir(base_dir):
|
||||||
files_to_execute = [a for a in test_files.items() if a[0] in f_name]
|
files_to_execute = [a for a in test_files.items() if a[0] in f_name]
|
||||||
lines_to_execute = reduce(lambda x, y: x + y[1], files_to_execute, [])
|
lines_to_execute = reduce(lambda x, y: x + y[1], files_to_execute, [])
|
||||||
@@ -290,86 +187,3 @@ def collect_dir_tests(base_dir, test_files, thirdparty=False):
|
|||||||
case.path = path
|
case.path = path
|
||||||
case.source = source
|
case.source = source
|
||||||
yield case
|
yield case
|
||||||
|
|
||||||
|
|
||||||
def run_test(cases):
|
|
||||||
"""
|
|
||||||
This is the completion test for some cases. The tests are not unit test
|
|
||||||
like, they are rather integration tests.
|
|
||||||
"""
|
|
||||||
testers = {
|
|
||||||
TEST_COMPLETIONS: run_completion_test,
|
|
||||||
TEST_DEFINITIONS: run_definition_test,
|
|
||||||
TEST_ASSIGNMENTS: run_goto_test,
|
|
||||||
TEST_USAGES: run_related_name_test,
|
|
||||||
}
|
|
||||||
|
|
||||||
tests = 0
|
|
||||||
fails = 0
|
|
||||||
for case in cases:
|
|
||||||
tests += 1
|
|
||||||
try:
|
|
||||||
fails += testers[case.test_type](case)
|
|
||||||
except Exception:
|
|
||||||
print(traceback.format_exc())
|
|
||||||
print(case)
|
|
||||||
fails += 1
|
|
||||||
return tests, fails
|
|
||||||
|
|
||||||
|
|
||||||
def test_dir(completion_test_dir, thirdparty=False):
|
|
||||||
for (path, cases) in itertools.groupby(
|
|
||||||
collect_dir_tests(completion_test_dir, test_files, thirdparty),
|
|
||||||
lambda case: case.path):
|
|
||||||
f_name = os.path.basename(path)
|
|
||||||
|
|
||||||
if thirdparty:
|
|
||||||
lib = f_name.replace('_.py', '')
|
|
||||||
try:
|
|
||||||
# there is always an underline at the end.
|
|
||||||
# It looks like: completion/thirdparty/pylab_.py
|
|
||||||
__import__(lib)
|
|
||||||
except ImportError:
|
|
||||||
base.summary.append('Thirdparty-Library %s not found.' %
|
|
||||||
f_name)
|
|
||||||
continue
|
|
||||||
|
|
||||||
num_tests, fails = run_test(cases)
|
|
||||||
base.test_sum += num_tests
|
|
||||||
|
|
||||||
s = 'run %s tests with %s fails (%s)' % (num_tests, fails, f_name)
|
|
||||||
base.tests_fail += fails
|
|
||||||
print(s)
|
|
||||||
base.summary.append(s)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
try:
|
|
||||||
i = sys.argv.index('--thirdparty')
|
|
||||||
thirdparty = True
|
|
||||||
sys.argv = sys.argv[:i] + sys.argv[i + 1:]
|
|
||||||
except ValueError:
|
|
||||||
thirdparty = False
|
|
||||||
|
|
||||||
test_files = base.get_test_list()
|
|
||||||
|
|
||||||
# completion tests:
|
|
||||||
completion_test_dir = os.path.join(base.test_dir, 'completion')
|
|
||||||
|
|
||||||
# execute tests
|
|
||||||
test_dir(completion_test_dir)
|
|
||||||
if test_files or thirdparty:
|
|
||||||
completion_test_dir += '/thirdparty'
|
|
||||||
test_dir(completion_test_dir, thirdparty=True)
|
|
||||||
|
|
||||||
base.print_summary()
|
|
||||||
#from guppy import hpy
|
|
||||||
#hpy()
|
|
||||||
#print hpy().heap()
|
|
||||||
|
|
||||||
exit_code = 1 if base.tests_fail else 0
|
|
||||||
if sys.hexversion < 0x02060000 and base.tests_fail <= 9:
|
|
||||||
# Python 2.5 has major incompabillities (e.g. no property.setter),
|
|
||||||
# therefore it is not possible to pass all tests.
|
|
||||||
exit_code = 0
|
|
||||||
sys.exit(exit_code)
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
set -e
|
|
||||||
|
|
||||||
python regression.py
|
|
||||||
python run.py
|
|
||||||
echo
|
|
||||||
python refactor.py
|
|
||||||
echo
|
|
||||||
nosetests --with-doctest --doctest-tests ../jedi/
|
|
||||||
@@ -1,23 +1,36 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from run import \
|
from . import base
|
||||||
|
from .run import \
|
||||||
TEST_COMPLETIONS, TEST_DEFINITIONS, TEST_ASSIGNMENTS, TEST_USAGES
|
TEST_COMPLETIONS, TEST_DEFINITIONS, TEST_ASSIGNMENTS, TEST_USAGES
|
||||||
|
|
||||||
import jedi
|
import jedi
|
||||||
from jedi._compatibility import literal_eval
|
from jedi._compatibility import literal_eval
|
||||||
|
|
||||||
|
|
||||||
|
def assert_case_equal(case, actual, desired):
|
||||||
|
"""
|
||||||
|
Assert ``actual == desired`` with formatted message.
|
||||||
|
|
||||||
|
This is not needed for typical py.test use case, but as we need
|
||||||
|
``--assert=plain`` (see ../pytest.ini) to workaround some issue
|
||||||
|
due to py.test magic, let's format the message by hand.
|
||||||
|
"""
|
||||||
|
assert actual == desired, """
|
||||||
|
Test %r failed.
|
||||||
|
actual = %s
|
||||||
|
desired = %s
|
||||||
|
""" % (case, actual, desired)
|
||||||
|
|
||||||
|
|
||||||
def run_completion_test(case):
|
def run_completion_test(case):
|
||||||
(script, correct, line_nr) = (case.script(), case.correct, case.line_nr)
|
(script, correct, line_nr) = (case.script(), case.correct, case.line_nr)
|
||||||
completions = script.complete()
|
completions = script.complete()
|
||||||
#import cProfile; cProfile.run('script.complete()')
|
#import cProfile; cProfile.run('script.complete()')
|
||||||
|
|
||||||
comp_str = set([c.word for c in completions])
|
comp_str = set([c.word for c in completions])
|
||||||
if comp_str != set(literal_eval(correct)):
|
assert_case_equal(case, comp_str, set(literal_eval(correct)))
|
||||||
raise AssertionError(
|
|
||||||
'Solution @%s not right, received %s, wanted %s'\
|
|
||||||
% (line_nr - 1, comp_str, correct))
|
|
||||||
|
|
||||||
|
|
||||||
def run_definition_test(case):
|
def run_definition_test(case):
|
||||||
@@ -52,19 +65,14 @@ def run_definition_test(case):
|
|||||||
should_str = definition(correct, start, script.source_path)
|
should_str = definition(correct, start, script.source_path)
|
||||||
result = script.definition()
|
result = script.definition()
|
||||||
is_str = set(r.desc_with_module for r in result)
|
is_str = set(r.desc_with_module for r in result)
|
||||||
if is_str != should_str:
|
assert_case_equal(case, is_str, should_str)
|
||||||
raise AssertionError(
|
|
||||||
'Solution @%s not right, received %s, wanted %s'
|
|
||||||
% (line_nr - 1, is_str, should_str))
|
|
||||||
|
|
||||||
|
|
||||||
def run_goto_test(case):
|
def run_goto_test(case):
|
||||||
(script, correct, line_nr) = (case.script(), case.correct, case.line_nr)
|
(script, correct, line_nr) = (case.script(), case.correct, case.line_nr)
|
||||||
result = script.goto()
|
result = script.goto()
|
||||||
comp_str = str(sorted(str(r.description) for r in result))
|
comp_str = str(sorted(str(r.description) for r in result))
|
||||||
if comp_str != correct:
|
assert_case_equal(case, comp_str, correct)
|
||||||
raise AssertionError('Solution @%s not right, received %s, wanted %s'
|
|
||||||
% (line_nr - 1, comp_str, correct))
|
|
||||||
|
|
||||||
|
|
||||||
def run_related_name_test(case):
|
def run_related_name_test(case):
|
||||||
@@ -85,14 +93,11 @@ def run_related_name_test(case):
|
|||||||
else:
|
else:
|
||||||
wanted.append(('renaming', line_nr + pos_tup[0], pos_tup[1]))
|
wanted.append(('renaming', line_nr + pos_tup[0], pos_tup[1]))
|
||||||
|
|
||||||
wanted = sorted(wanted)
|
assert_case_equal(case, compare, sorted(wanted))
|
||||||
if compare != wanted:
|
|
||||||
raise AssertionError('Solution @%s not right, received %s, wanted %s'
|
|
||||||
% (line_nr - 1, compare, wanted))
|
|
||||||
|
|
||||||
|
|
||||||
def test_integration(case, monkeypatch, pytestconfig):
|
def test_integration(case, monkeypatch, pytestconfig):
|
||||||
repo_root = os.path.dirname(os.path.dirname(pytestconfig.option.base_dir))
|
repo_root = base.root_dir
|
||||||
monkeypatch.chdir(os.path.join(repo_root, 'jedi'))
|
monkeypatch.chdir(os.path.join(repo_root, 'jedi'))
|
||||||
testers = {
|
testers = {
|
||||||
TEST_COMPLETIONS: run_completion_test,
|
TEST_COMPLETIONS: run_completion_test,
|
||||||
@@ -100,4 +105,15 @@ def test_integration(case, monkeypatch, pytestconfig):
|
|||||||
TEST_ASSIGNMENTS: run_goto_test,
|
TEST_ASSIGNMENTS: run_goto_test,
|
||||||
TEST_USAGES: run_related_name_test,
|
TEST_USAGES: run_related_name_test,
|
||||||
}
|
}
|
||||||
testers[case.test_type](case)
|
base.skip_py25_fails(testers[case.test_type])(case)
|
||||||
|
|
||||||
|
|
||||||
|
def test_refactor(refactor_case):
|
||||||
|
"""
|
||||||
|
Run refactoring test case.
|
||||||
|
|
||||||
|
:type refactor_case: :class:`.refactor.RefactoringCase`
|
||||||
|
"""
|
||||||
|
refactor_case.run()
|
||||||
|
assert_case_equal(refactor_case,
|
||||||
|
refactor_case.result, refactor_case.desired)
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ import itertools
|
|||||||
import os
|
import os
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
from base import TestBase, unittest, cwd_at
|
import pytest
|
||||||
|
|
||||||
|
from .base import TestBase, unittest, cwd_at
|
||||||
|
|
||||||
import jedi
|
import jedi
|
||||||
from jedi._compatibility import is_py25, utf8, unicode
|
from jedi._compatibility import is_py25, utf8, unicode
|
||||||
@@ -524,5 +526,16 @@ class TestSpeed(TestBase):
|
|||||||
script.function_definition()
|
script.function_definition()
|
||||||
#print(jedi.imports.imports_processed)
|
#print(jedi.imports.imports_processed)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif("sys.version_info >= (3,0)")
|
||||||
|
def test_settings_module():
|
||||||
|
"""
|
||||||
|
jedi.settings and jedi.cache.settings must be the same module.
|
||||||
|
"""
|
||||||
|
from jedi import cache
|
||||||
|
from jedi import settings
|
||||||
|
assert cache.settings is settings
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
19
tox.ini
19
tox.ini
@@ -1,16 +1,13 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py25, py26, py27, py32
|
envlist = py25, py26, py27, py32
|
||||||
[testenv]
|
[testenv]
|
||||||
setenv =
|
|
||||||
XDG_CACHE_HOME={envtmpdir}/cache
|
|
||||||
deps =
|
deps =
|
||||||
nose
|
pytest
|
||||||
commands =
|
commands =
|
||||||
python regression.py
|
py.test []
|
||||||
python run.py
|
# Doctests can't be run with the main tests because then py.test
|
||||||
python refactor.py
|
# tries to import broken python files under test/*/.
|
||||||
nosetests --with-doctest --doctest-tests {toxinidir}/jedi
|
py.test --doctest-modules {toxinidir}/jedi
|
||||||
changedir = test
|
|
||||||
[testenv:py25]
|
[testenv:py25]
|
||||||
deps =
|
deps =
|
||||||
simplejson
|
simplejson
|
||||||
@@ -20,3 +17,9 @@ deps =
|
|||||||
deps =
|
deps =
|
||||||
unittest2
|
unittest2
|
||||||
{[testenv]deps}
|
{[testenv]deps}
|
||||||
|
[testenv:py32]
|
||||||
|
# TODO: Without this setting, test uses ~/.cache/jedi/.
|
||||||
|
# There could be a bug due to import hack.
|
||||||
|
# See test_settings_module in test/test_regression.py.
|
||||||
|
setenv =
|
||||||
|
XDG_CACHE_HOME={envtmpdir}/cache
|
||||||
|
|||||||
Reference in New Issue
Block a user