2008-02-07 09:50:53 +00:00
|
|
|
# Copyright (c) 2003-2008 LOGILAB S.A. (Paris, FRANCE).
|
2006-04-26 10:48:09 +00:00
|
|
|
# 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.,
|
|
|
|
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
"""functional/non regression tests for pylint"""
|
|
|
|
|
|
|
|
import unittest
|
|
|
|
import sys
|
|
|
|
import re
|
|
|
|
from os import linesep
|
|
|
|
from os.path import exists
|
|
|
|
|
|
|
|
from logilab.common import testlib
|
|
|
|
|
|
|
|
from utils import get_tests_info, fix_path, TestReporter
|
|
|
|
|
2008-02-07 09:50:53 +00:00
|
|
|
from logilab.astng import MANAGER
|
2006-04-26 10:48:09 +00:00
|
|
|
from pylint.lint import PyLinter
|
|
|
|
from pylint import checkers
|
|
|
|
|
|
|
|
test_reporter = TestReporter()
|
|
|
|
linter = PyLinter()
|
|
|
|
linter.set_reporter(test_reporter)
|
|
|
|
linter.config.persistent = 0
|
|
|
|
checkers.initialize(linter)
|
2006-09-23 11:18:15 +00:00
|
|
|
linter.global_set_option('required-attributes', ('__revision__',))
|
2006-04-26 10:48:09 +00:00
|
|
|
|
|
|
|
PY23 = sys.version_info >= (2, 3)
|
2010-05-11 09:49:21 +00:00
|
|
|
PY26 = sys.version_info >= (2, 6)
|
2006-04-26 10:48:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
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('^func_i\d\d\d\d$')
|
|
|
|
|
2010-11-02 15:32:11 +00:00
|
|
|
def exception_str(self, ex):
|
2006-04-26 10:48:09 +00:00
|
|
|
"""function used to replace default __str__ method of exception instances"""
|
|
|
|
return 'in %s\n:: %s' % (ex.file, ', '.join(ex.args))
|
|
|
|
|
2010-04-19 09:22:40 +00:00
|
|
|
class LintTestUsingModule(testlib.TestCase):
|
2009-11-25 15:30:28 +00:00
|
|
|
DEFAULT_PACKAGE = 'input'
|
|
|
|
package = DEFAULT_PACKAGE
|
2007-02-15 11:19:17 +00:00
|
|
|
linter = linter
|
2009-11-25 15:30:28 +00:00
|
|
|
module = None
|
|
|
|
depends = None
|
|
|
|
|
|
|
|
_TEST_TYPE = 'module'
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
def test_functionality(self):
|
2007-02-13 09:32:45 +00:00
|
|
|
tocheck = [self.package+'.'+self.module]
|
2006-04-26 10:48:09 +00:00
|
|
|
if self.depends:
|
2007-02-13 09:32:45 +00:00
|
|
|
tocheck += [self.package+'.%s' % name.replace('.py', '')
|
2006-04-26 10:48:09 +00:00
|
|
|
for name, file in self.depends]
|
|
|
|
self._test(tocheck)
|
2010-04-19 09:22:40 +00:00
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
def _test(self, tocheck):
|
|
|
|
if INFO_TEST_RGX.match(self.module):
|
2010-04-19 09:18:08 +00:00
|
|
|
self.linter.enable('I')
|
2006-04-26 10:48:09 +00:00
|
|
|
else:
|
2010-04-19 09:18:08 +00:00
|
|
|
self.linter.disable('I')
|
2006-04-26 10:48:09 +00:00
|
|
|
try:
|
2007-02-15 11:19:17 +00:00
|
|
|
self.linter.check(tocheck)
|
2006-04-26 10:48:09 +00:00
|
|
|
except Exception, ex:
|
|
|
|
# need finalization to restore a correct state
|
2007-02-15 11:19:17 +00:00
|
|
|
self.linter.reporter.finalize()
|
2006-04-26 10:48:09 +00:00
|
|
|
ex.file = tocheck
|
2010-11-02 15:32:11 +00:00
|
|
|
print ex
|
|
|
|
ex.__str__ = exception_str
|
2006-04-26 10:48:09 +00:00
|
|
|
raise
|
|
|
|
if self.module.startswith('func_noerror_'):
|
|
|
|
expected = ''
|
|
|
|
else:
|
|
|
|
output = open(self.output)
|
|
|
|
expected = output.read().strip()
|
|
|
|
output.close()
|
2007-02-15 11:19:17 +00:00
|
|
|
got = self.linter.reporter.finalize().strip()
|
2006-04-26 10:48:09 +00:00
|
|
|
try:
|
2010-09-28 13:02:35 +00:00
|
|
|
self.assertMultiLineEqual(got, expected)
|
2006-04-26 10:48:09 +00:00
|
|
|
except Exception, ex:
|
2010-11-02 16:38:24 +00:00
|
|
|
raise AssertionError, '%s: %s' % (self.module, ex), sys.exc_info()[-1]
|
2006-04-26 10:48:09 +00:00
|
|
|
|
2010-04-19 09:22:40 +00:00
|
|
|
class LintTestUsingFile(LintTestUsingModule):
|
|
|
|
|
2009-11-25 15:30:28 +00:00
|
|
|
_TEST_TYPE = 'file'
|
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
def test_functionality(self):
|
2007-02-13 09:32:45 +00:00
|
|
|
tocheck = [self.package+'/' + self.module + '.py']
|
2006-04-26 10:48:09 +00:00
|
|
|
if self.depends:
|
2007-02-13 09:32:45 +00:00
|
|
|
tocheck += [self.package+'/%s' % name for name, file in self.depends]
|
2006-04-26 10:48:09 +00:00
|
|
|
self._test(tocheck)
|
|
|
|
|
|
|
|
|
2007-03-09 07:46:48 +00:00
|
|
|
class TestTests(testlib.TestCase):
|
2006-04-26 10:48:09 +00:00
|
|
|
"""check that all testable messages have been checked"""
|
2009-11-25 09:50:53 +00:00
|
|
|
@testlib.tag('coverage')
|
|
|
|
def test_exhaustivity(self):
|
2009-03-18 08:02:46 +00:00
|
|
|
# skip fatal messages
|
|
|
|
todo = [msgid for msgid in linter._messages.keys() if msgid[0] != 'F']
|
2007-02-22 09:57:19 +00:00
|
|
|
for msgid in test_reporter.message_ids.keys():
|
|
|
|
try:
|
|
|
|
todo.remove(msgid)
|
|
|
|
except ValueError:
|
|
|
|
continue
|
2006-04-26 10:48:09 +00:00
|
|
|
todo.sort()
|
2010-05-11 09:49:21 +00:00
|
|
|
if PY26:
|
|
|
|
self.assertEqual(todo, ['E0503', 'E1122', 'I0001'])
|
2006-09-23 12:00:12 +00:00
|
|
|
elif PY23:
|
2007-02-22 09:57:19 +00:00
|
|
|
self.assertEqual(todo, ['E0503', 'I0001'])
|
2006-09-23 12:00:12 +00:00
|
|
|
else: # python < 2.3
|
2007-02-22 09:57:19 +00:00
|
|
|
self.assertEqual(todo, ['I0001'])
|
2007-02-18 10:36:38 +00:00
|
|
|
|
|
|
|
#bycat = {}
|
|
|
|
#for msgid in linter._messages.keys():
|
|
|
|
# bycat[msgid[0]] = bycat.setdefault(msgid[0], 0) + 1
|
|
|
|
#for cat, val in bycat.items():
|
|
|
|
# print '%s: %s' % (cat, val)
|
|
|
|
#print 'total', sum(bycat.values())
|
|
|
|
#
|
|
|
|
# on 2007/02/17:
|
|
|
|
#
|
|
|
|
# W: 48
|
|
|
|
# E: 42
|
|
|
|
# R: 15
|
|
|
|
# C: 13
|
|
|
|
# F: 7
|
|
|
|
# I: 5
|
|
|
|
# total 130
|
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
def make_tests(filter_rgx):
|
|
|
|
"""generate tests classes from test info
|
2010-04-19 09:22:40 +00:00
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
return the list of generated test classes
|
|
|
|
"""
|
|
|
|
if filter_rgx:
|
2009-03-09 18:50:07 +00:00
|
|
|
is_to_run = re.compile(filter_rgx).search
|
2006-04-26 10:48:09 +00:00
|
|
|
else:
|
|
|
|
is_to_run = lambda x: 1
|
|
|
|
tests = []
|
|
|
|
for module_file, messages_file in get_tests_info('func_', '.py') + [('nonexistant', 'messages/nonexistant.txt')]:
|
|
|
|
# skip those tests with python >= 2.3 since py2.3 detects them by itself
|
|
|
|
if PY23 and module_file == "func_unknown_encoding.py": #"func_nonascii_noencoding.py"):
|
|
|
|
continue
|
2009-03-17 10:20:27 +00:00
|
|
|
pyrestr = module_file.rsplit('_py', 1)[-1][:-3]
|
|
|
|
if pyrestr.isdigit(): # '24', '25'...
|
|
|
|
if sys.version_info < tuple([int(i) for i in pyrestr]):
|
2006-04-26 10:48:09 +00:00
|
|
|
continue
|
2010-05-11 09:49:21 +00:00
|
|
|
if pyrestr.startswith('_') and pyrestr[1:].isdigit():
|
|
|
|
# skip test for higher python versions
|
|
|
|
if sys.version_info >= ( int(pyrestr[1]), int(pyrestr[2]) ):
|
|
|
|
continue
|
2006-04-26 10:48:09 +00:00
|
|
|
if not is_to_run(module_file):
|
|
|
|
continue
|
|
|
|
base = module_file.replace('func_', '').replace('.py', '')
|
2009-11-23 14:15:26 +00:00
|
|
|
dependencies = get_tests_info(base, '.py')
|
2010-04-19 09:22:40 +00:00
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
class LintTestUsingModuleTC(LintTestUsingModule):
|
|
|
|
module = module_file.replace('.py', '')
|
|
|
|
output = messages_file
|
2009-11-23 14:15:26 +00:00
|
|
|
depends = dependencies or None
|
2009-11-25 18:07:05 +00:00
|
|
|
tags = testlib.Tags(('generated','pylint_input_%s' % module))
|
2006-04-26 10:48:09 +00:00
|
|
|
tests.append(LintTestUsingModuleTC)
|
|
|
|
|
|
|
|
if MODULES_ONLY:
|
|
|
|
continue
|
2010-04-19 09:22:40 +00:00
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
class LintTestUsingFileTC(LintTestUsingFile):
|
|
|
|
module = module_file.replace('.py', '')
|
|
|
|
output = exists(messages_file + '2') and (messages_file + '2') or messages_file
|
2009-11-23 14:15:26 +00:00
|
|
|
depends = dependencies or None
|
2009-11-25 18:07:05 +00:00
|
|
|
tags = testlib.Tags(('generated', 'pylint_input_%s' % module))
|
2006-04-26 10:48:09 +00:00
|
|
|
tests.append(LintTestUsingFileTC)
|
2010-04-19 09:22:40 +00:00
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
## # special test for f0003
|
|
|
|
## module_file, messages_file in get_tests_info('func_f0003', '.pyc')
|
|
|
|
## class LintTestSubclass(LintTest):
|
|
|
|
## module = module_file.replace('.pyc', '')
|
|
|
|
## output = messages_file
|
2009-11-23 14:15:26 +00:00
|
|
|
## depends = dependencies or None
|
2006-04-26 10:48:09 +00:00
|
|
|
## tests.append(LintTestSubclass)
|
2010-04-19 09:22:40 +00:00
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
class LintBuiltinModuleTest(LintTestUsingModule):
|
|
|
|
output = 'messages/builtin_module.txt'
|
|
|
|
module = 'sys'
|
|
|
|
def test_functionality(self):
|
|
|
|
self._test(['sys'])
|
|
|
|
tests.append(LintBuiltinModuleTest)
|
2010-04-19 09:22:40 +00:00
|
|
|
|
2006-04-26 10:48:09 +00:00
|
|
|
if not filter_rgx:
|
2010-04-19 09:22:40 +00:00
|
|
|
# test all features are tested :)
|
2006-04-26 10:48:09 +00:00
|
|
|
tests.append(TestTests)
|
|
|
|
|
|
|
|
return tests
|
|
|
|
|
|
|
|
FILTER_RGX = None
|
|
|
|
MODULES_ONLY = False
|
|
|
|
|
|
|
|
def suite():
|
2010-09-28 13:02:35 +00:00
|
|
|
return testlib.TestSuite([unittest.makeSuite(test, suiteClass=testlib.TestSuite)
|
|
|
|
for test in make_tests(FILTER_RGX)])
|
2006-04-26 10:48:09 +00:00
|
|
|
|
|
|
|
if __name__=='__main__':
|
|
|
|
if '-m' in sys.argv:
|
|
|
|
MODULES_ONLY = True
|
|
|
|
sys.argv.remove('-m')
|
2010-04-19 09:22:40 +00:00
|
|
|
|
|
|
|
if len(sys.argv) > 1:
|
2006-04-26 10:48:09 +00:00
|
|
|
FILTER_RGX = sys.argv[1]
|
|
|
|
del sys.argv[1]
|
2007-03-09 08:52:24 +00:00
|
|
|
testlib.unittest_main(defaultTest='suite')
|
2006-04-26 10:48:09 +00:00
|
|
|
|
|
|
|
|