Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Unified Diff: third_party/pylint/pylint/testutils.py

Issue 1920403002: [content/test/gpu] Run pylint check of gpu tests in unittest instead of PRESUBMIT (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update path to LICENSE.txt of logilab/README.chromium Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/pylint/pylint/reporters/text.py ('k') | third_party/pylint/pylint/utils.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/pylint/pylint/testutils.py
diff --git a/third_party/pylint/pylint/testutils.py b/third_party/pylint/pylint/testutils.py
new file mode 100644
index 0000000000000000000000000000000000000000..2f9af4d102a9f7aebce6a86d7f2afd510393650f
--- /dev/null
+++ b/third_party/pylint/pylint/testutils.py
@@ -0,0 +1,412 @@
+# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
+# http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+"""functional/non regression tests for pylint"""
+from __future__ import print_function
+
+import collections
+import contextlib
+import functools
+import os
+import sys
+import re
+import unittest
+import tempfile
+import tokenize
+
+from glob import glob
+from os import linesep, getcwd, sep
+from os.path import abspath, basename, dirname, isdir, join, splitext
+
+from astroid import test_utils
+
+from pylint import checkers
+from pylint.utils import PyLintASTWalker
+from pylint.reporters import BaseReporter
+from pylint.interfaces import IReporter
+from pylint.lint import PyLinter
+
+import six
+from six.moves import StringIO
+
+
+# Utils
+
+SYS_VERS_STR = '%d%d%d' % sys.version_info[:3]
+TITLE_UNDERLINES = ['', '=', '-', '.']
+PREFIX = abspath(dirname(__file__))
+PY3K = sys.version_info[0] == 3
+
+def fix_path():
+ sys.path.insert(0, PREFIX)
+
+def get_tests_info(input_dir, msg_dir, prefix, suffix):
+ """get python input examples and output messages
+
+ We use following conventions for input files and messages:
+ for different inputs:
+ test for python >= x.y -> input = <name>_pyxy.py
+ test for python < x.y -> input = <name>_py_xy.py
+ for one input and different messages:
+ message for python >= x.y -> message = <name>_pyxy.txt
+ lower versions -> message with highest num
+ """
+ result = []
+ for fname in glob(join(input_dir, prefix + '*' + suffix)):
+ infile = basename(fname)
+ fbase = splitext(infile)[0]
+ # filter input files :
+ pyrestr = fbase.rsplit('_py', 1)[-1] # like _26 or 26
+ if pyrestr.isdigit(): # '24', '25'...
+ if SYS_VERS_STR < pyrestr:
+ continue
+ if pyrestr.startswith('_') and pyrestr[1:].isdigit():
+ # skip test for higher python versions
+ if SYS_VERS_STR >= pyrestr[1:]:
+ continue
+ messages = glob(join(msg_dir, fbase + '*.txt'))
+ # the last one will be without ext, i.e. for all or upper versions:
+ if messages:
+ for outfile in sorted(messages, reverse=True):
+ py_rest = outfile.rsplit('_py', 1)[-1][:-4]
+ if py_rest.isdigit() and SYS_VERS_STR >= py_rest:
+ break
+ else:
+ # This will provide an error message indicating the missing filename.
+ outfile = join(msg_dir, fbase + '.txt')
+ result.append((infile, outfile))
+ return result
+
+
+class TestReporter(BaseReporter):
+ """reporter storing plain text messages"""
+
+ __implements____ = IReporter
+
+ def __init__(self): # pylint: disable=super-init-not-called
+
+ self.message_ids = {}
+ self.reset()
+ self.path_strip_prefix = getcwd() + sep
+
+ def reset(self):
+ self.out = StringIO()
+ self.messages = []
+
+ def add_message(self, msg_id, location, msg):
+ """manage message of different type and in the context of path """
+ _, _, obj, line, _ = location
+ self.message_ids[msg_id] = 1
+ if obj:
+ obj = ':%s' % obj
+ sigle = msg_id[0]
+ if PY3K and linesep != '\n':
+ # 2to3 writes os.linesep instead of using
+ # the previosly used line separators
+ msg = msg.replace('\r\n', '\n')
+ self.messages.append('%s:%3s%s: %s' % (sigle, line, obj, msg))
+
+ def finalize(self):
+ self.messages.sort()
+ for msg in self.messages:
+ print(msg, file=self.out)
+ result = self.out.getvalue()
+ self.reset()
+ return result
+
+ def display_results(self, layout):
+ """ignore layouts"""
+
+
+class Message(collections.namedtuple('Message',
+ ['msg_id', 'line', 'node', 'args'])):
+ def __new__(cls, msg_id, line=None, node=None, args=None):
+ return tuple.__new__(cls, (msg_id, line, node, args))
+
+
+class UnittestLinter(object):
+ """A fake linter class to capture checker messages."""
+ # pylint: disable=unused-argument, no-self-use
+
+ def __init__(self):
+ self._messages = []
+ self.stats = {}
+
+ def release_messages(self):
+ try:
+ return self._messages
+ finally:
+ self._messages = []
+
+ def add_message(self, msg_id, line=None, node=None, args=None,
+ confidence=None):
+ self._messages.append(Message(msg_id, line, node, args))
+
+ def is_message_enabled(self, *unused_args):
+ return True
+
+ def add_stats(self, **kwargs):
+ for name, value in six.iteritems(kwargs):
+ self.stats[name] = value
+ return self.stats
+
+ @property
+ def options_providers(self):
+ return linter.options_providers
+
+def set_config(**kwargs):
+ """Decorator for setting config values on a checker."""
+ def _Wrapper(fun):
+ @functools.wraps(fun)
+ def _Forward(self):
+ for key, value in six.iteritems(kwargs):
+ setattr(self.checker.config, key, value)
+ if isinstance(self, CheckerTestCase):
+ # reopen checker in case, it may be interested in configuration change
+ self.checker.open()
+ fun(self)
+
+ return _Forward
+ return _Wrapper
+
+
+class CheckerTestCase(unittest.TestCase):
+ """A base testcase class for unittesting individual checker classes."""
+ CHECKER_CLASS = None
+ CONFIG = {}
+
+ def setUp(self):
+ self.linter = UnittestLinter()
+ self.checker = self.CHECKER_CLASS(self.linter) # pylint: disable=not-callable
+ for key, value in six.iteritems(self.CONFIG):
+ setattr(self.checker.config, key, value)
+ self.checker.open()
+
+ @contextlib.contextmanager
+ def assertNoMessages(self):
+ """Assert that no messages are added by the given method."""
+ with self.assertAddsMessages():
+ yield
+
+ @contextlib.contextmanager
+ def assertAddsMessages(self, *messages):
+ """Assert that exactly the given method adds the given messages.
+
+ The list of messages must exactly match *all* the messages added by the
+ method. Additionally, we check to see whether the args in each message can
+ actually be substituted into the message string.
+ """
+ yield
+ got = self.linter.release_messages()
+ msg = ('Expected messages did not match actual.\n'
+ 'Expected:\n%s\nGot:\n%s' % ('\n'.join(repr(m) for m in messages),
+ '\n'.join(repr(m) for m in got)))
+ self.assertEqual(list(messages), got, msg)
+
+ def walk(self, node):
+ """recursive walk on the given node"""
+ walker = PyLintASTWalker(linter)
+ walker.add_checker(self.checker)
+ walker.walk(node)
+
+
+# Init
+test_reporter = TestReporter()
+linter = PyLinter()
+linter.set_reporter(test_reporter)
+linter.config.persistent = 0
+checkers.initialize(linter)
+linter.global_set_option('required-attributes', ('__revision__',))
+
+if linesep != '\n':
+ LINE_RGX = re.compile(linesep)
+ def ulines(string):
+ return LINE_RGX.sub('\n', string)
+else:
+ def ulines(string):
+ return string
+
+INFO_TEST_RGX = re.compile(r'^func_i\d\d\d\d$')
+
+def exception_str(self, ex): # pylint: disable=unused-argument
+ """function used to replace default __str__ method of exception instances"""
+ return 'in %s\n:: %s' % (ex.file, ', '.join(ex.args))
+
+# Test classes
+
+class LintTestUsingModule(unittest.TestCase):
+ INPUT_DIR = None
+ DEFAULT_PACKAGE = 'input'
+ package = DEFAULT_PACKAGE
+ linter = linter
+ module = None
+ depends = None
+ output = None
+ _TEST_TYPE = 'module'
+ maxDiff = None
+
+ def shortDescription(self):
+ values = {'mode' : self._TEST_TYPE,
+ 'input': self.module,
+ 'pkg': self.package,
+ 'cls': self.__class__.__name__}
+
+ if self.package == self.DEFAULT_PACKAGE:
+ msg = '%(mode)s test of input file "%(input)s" (%(cls)s)'
+ else:
+ msg = '%(mode)s test of input file "%(input)s" in "%(pkg)s" (%(cls)s)'
+ return msg % values
+
+ def test_functionality(self):
+ tocheck = [self.package+'.'+self.module]
+ if self.depends:
+ tocheck += [self.package+'.%s' % name.replace('.py', '')
+ for name, _ in self.depends]
+ self._test(tocheck)
+
+ def _check_result(self, got):
+ self.assertMultiLineEqual(self._get_expected().strip()+'\n',
+ got.strip()+'\n')
+
+ def _test(self, tocheck):
+ if INFO_TEST_RGX.match(self.module):
+ self.linter.enable('I')
+ else:
+ self.linter.disable('I')
+ try:
+ self.linter.check(tocheck)
+ except Exception as ex:
+ # need finalization to restore a correct state
+ self.linter.reporter.finalize()
+ ex.file = tocheck
+ print(ex)
+ ex.__str__ = exception_str
+ raise
+ self._check_result(self.linter.reporter.finalize())
+
+ def _has_output(self):
+ return not self.module.startswith('func_noerror_')
+
+ def _get_expected(self):
+ if self._has_output() and self.output:
+ with open(self.output, 'U') as fobj:
+ return fobj.read().strip() + '\n'
+ else:
+ return ''
+
+class LintTestUsingFile(LintTestUsingModule):
+
+ _TEST_TYPE = 'file'
+
+ def test_functionality(self):
+ importable = join(self.INPUT_DIR, self.module)
+ # python also prefers packages over simple modules.
+ if not isdir(importable):
+ importable += '.py'
+ tocheck = [importable]
+ if self.depends:
+ tocheck += [join(self.INPUT_DIR, name) for name, _file in self.depends]
+ self._test(tocheck)
+
+class LintTestUpdate(LintTestUsingModule):
+
+ _TEST_TYPE = 'update'
+
+ def _check_result(self, got):
+ if self._has_output():
+ try:
+ expected = self._get_expected()
+ except IOError:
+ expected = ''
+ if got != expected:
+ with open(self.output, 'w') as fobj:
+ fobj.write(got)
+
+# Callback
+
+def cb_test_gen(base_class):
+ def call(input_dir, msg_dir, module_file, messages_file, dependencies):
+ # pylint: disable=no-init
+ class LintTC(base_class):
+ module = module_file.replace('.py', '')
+ output = messages_file
+ depends = dependencies or None
+ INPUT_DIR = input_dir
+ MSG_DIR = msg_dir
+ return LintTC
+ return call
+
+# Main function
+
+def make_tests(input_dir, msg_dir, filter_rgx, callbacks):
+ """generate tests classes from test info
+
+ return the list of generated test classes
+ """
+ if filter_rgx:
+ is_to_run = re.compile(filter_rgx).search
+ else:
+ is_to_run = lambda x: 1
+ tests = []
+ for module_file, messages_file in (
+ get_tests_info(input_dir, msg_dir, 'func_', '')
+ ):
+ if not is_to_run(module_file) or module_file.endswith('.pyc'):
+ continue
+ base = module_file.replace('func_', '').replace('.py', '')
+
+ dependencies = get_tests_info(input_dir, msg_dir, base, '.py')
+
+ for callback in callbacks:
+ test = callback(input_dir, msg_dir, module_file, messages_file,
+ dependencies)
+ if test:
+ tests.append(test)
+ return tests
+
+def tokenize_str(code):
+ return list(tokenize.generate_tokens(StringIO(code).readline))
+
+@contextlib.contextmanager
+def create_tempfile(content=None):
+ """Create a new temporary file.
+
+ If *content* parameter is given, then it will be written
+ in the temporary file, before passing it back.
+ This is a context manager and should be used with a *with* statement.
+ """
+ # Can't use tempfile.NamedTemporaryFile here
+ # because on Windows the file must be closed before writing to it,
+ # see http://bugs.python.org/issue14243
+ fd, tmp = tempfile.mkstemp()
+ if content:
+ if sys.version_info >= (3, 0):
+ # erff
+ os.write(fd, bytes(content, 'ascii'))
+ else:
+ os.write(fd, content)
+ try:
+ yield tmp
+ finally:
+ os.close(fd)
+ os.remove(tmp)
+
+@contextlib.contextmanager
+def create_file_backed_module(code):
+ """Create an astroid module for the given code, backed by a real file."""
+ with create_tempfile() as temp:
+ module = test_utils.build_module(code)
+ module.file = temp
+ yield module
« no previous file with comments | « third_party/pylint/pylint/reporters/text.py ('k') | third_party/pylint/pylint/utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698