2019-07-19 18:56:29 +03:00
|
|
|
from __future__ import absolute_import, print_function
|
|
|
|
|
2019-09-23 16:19:25 +03:00
|
|
|
import logging
|
2018-03-23 00:24:15 +03:00
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
from collections import defaultdict
|
|
|
|
|
|
|
|
from mozbuild.base import MozbuildObject
|
|
|
|
from mozlint.pathutils import findobject
|
|
|
|
from mozlint.parser import Parser
|
2019-07-31 02:30:15 +03:00
|
|
|
from mozlint.result import ResultSummary
|
2018-03-23 00:24:15 +03:00
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
here = os.path.abspath(os.path.dirname(__file__))
|
|
|
|
build = MozbuildObject.from_environment(cwd=here)
|
|
|
|
|
|
|
|
lintdir = os.path.dirname(here)
|
|
|
|
sys.path.insert(0, lintdir)
|
2019-09-23 16:19:25 +03:00
|
|
|
logger = logging.getLogger("mozlint")
|
2018-03-23 00:24:15 +03:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
|
|
def root(request):
|
|
|
|
"""Return the root directory for the files of the linter under test.
|
|
|
|
|
|
|
|
For example, with LINTER=flake8 this would be tools/lint/test/files/flake8.
|
|
|
|
"""
|
|
|
|
if not hasattr(request.module, 'LINTER'):
|
|
|
|
pytest.fail("'root' fixture used from a module that didn't set the LINTER variable")
|
|
|
|
return os.path.join(here, 'files', request.module.LINTER)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
|
|
def paths(root):
|
|
|
|
"""Return a function that can resolve file paths relative to the linter
|
|
|
|
under test.
|
|
|
|
|
|
|
|
Can be used like `paths('foo.py', 'bar/baz')`. This will return a list of
|
|
|
|
absolute paths under the `root` files directory.
|
|
|
|
"""
|
|
|
|
def _inner(*paths):
|
|
|
|
if not paths:
|
|
|
|
return [root]
|
|
|
|
return [os.path.normpath(os.path.join(root, p)) for p in paths]
|
|
|
|
return _inner
|
|
|
|
|
|
|
|
|
2019-03-12 18:08:41 +03:00
|
|
|
@pytest.fixture
|
2018-03-23 00:24:15 +03:00
|
|
|
def config(request):
|
|
|
|
"""Finds, loads and returns the config for the linter name specified by the
|
|
|
|
LINTER global variable in the calling module.
|
|
|
|
|
|
|
|
This implies that each test file (that uses this fixture) should only be
|
|
|
|
used to test a single linter. If no LINTER variable is defined, the test
|
|
|
|
will fail.
|
|
|
|
"""
|
|
|
|
if not hasattr(request.module, 'LINTER'):
|
|
|
|
pytest.fail("'config' fixture used from a module that didn't set the LINTER variable")
|
|
|
|
|
|
|
|
name = request.module.LINTER
|
|
|
|
config_path = os.path.join(lintdir, '{}.yml'.format(name))
|
2018-03-29 21:50:17 +03:00
|
|
|
parser = Parser(build.topsrcdir)
|
2018-03-23 00:24:15 +03:00
|
|
|
# TODO Don't assume one linter per yaml file
|
|
|
|
return parser.parse(config_path)[0]
|
|
|
|
|
|
|
|
|
2019-03-12 18:08:41 +03:00
|
|
|
@pytest.fixture(autouse=True)
|
2018-03-23 00:24:15 +03:00
|
|
|
def run_setup(config):
|
|
|
|
"""Make sure that if the linter named in the LINTER global variable has a
|
|
|
|
setup function, it gets called before running the tests.
|
|
|
|
"""
|
|
|
|
if 'setup' not in config:
|
|
|
|
return
|
|
|
|
|
|
|
|
func = findobject(config['setup'])
|
|
|
|
func(build.topsrcdir)
|
|
|
|
|
|
|
|
|
2019-03-12 18:08:41 +03:00
|
|
|
@pytest.fixture
|
2018-03-23 00:24:15 +03:00
|
|
|
def lint(config, root):
|
|
|
|
"""Find and return the 'lint' function for the external linter named in the
|
|
|
|
LINTER global variable.
|
|
|
|
|
|
|
|
This will automatically pass in the 'config' and 'root' arguments if not
|
|
|
|
specified.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
func = findobject(config['payload'])
|
|
|
|
except (ImportError, ValueError):
|
|
|
|
pytest.fail("could not resolve a lint function from '{}'".format(config['payload']))
|
|
|
|
|
2019-07-31 02:30:15 +03:00
|
|
|
ResultSummary.root = root
|
|
|
|
|
2018-03-23 00:24:15 +03:00
|
|
|
def wrapper(paths, config=config, root=root, collapse_results=False, **lintargs):
|
2019-09-23 16:19:25 +03:00
|
|
|
lintargs['log'] = logging.LoggerAdapter(logger, {
|
|
|
|
"lintname": config.get("name"),
|
|
|
|
"pid": os.getpid()
|
|
|
|
})
|
2018-03-23 00:24:15 +03:00
|
|
|
results = func(paths, config, root=root, **lintargs)
|
|
|
|
if not collapse_results:
|
|
|
|
return results
|
|
|
|
|
|
|
|
ret = defaultdict(list)
|
|
|
|
for r in results:
|
|
|
|
ret[r.path].append(r)
|
|
|
|
return ret
|
|
|
|
|
|
|
|
return wrapper
|
2018-05-26 00:02:43 +03:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def create_temp_file(tmpdir):
|
|
|
|
def inner(contents, name=None):
|
|
|
|
name = name or 'temp.py'
|
|
|
|
path = tmpdir.join(name)
|
|
|
|
path.write(contents)
|
|
|
|
return path.strpath
|
|
|
|
return inner
|