Commits

Boris FELD committed 014e44b

Refactor test_func in order to extract common part for reutilization in pylint-brain

Comments (0)

Files changed (6)

test/test_format.py

 
 from pylint.checkers.format import *
 
-from utils import TestReporter
+from pylint.testutils import TestReporter
 
 REPORTER = TestReporter()
 

test/test_func.py

 import unittest
 import sys
 import re
-from os import linesep, getcwd
-from os.path import exists, abspath, dirname, join
+
+from os import getcwd
+from os.path import abspath, dirname, join
 
 from logilab.common import testlib
 
-from utils import get_tests_info, fix_path, TestReporter
-
-from logilab.astng import MANAGER
-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)
-linter.global_set_option('required-attributes', ('__revision__',))
+from pylint.testutils import (make_tests, LintTestUsingModule, LintTestUsingFile,
+    cb_test_gen, linter, test_reporter)
 
 PY26 = sys.version_info >= (2, 6)
 PY3K = sys.version_info >= (3, 0)
 
+# Configure paths
+INPUT_DIR = join(dirname(abspath(__file__)), 'input')
+MSG_DIR = join(dirname(abspath(__file__)), 'messages')
 
-if linesep != '\n':
-    LINE_RGX = re.compile(linesep)
-    def ulines(string):
-        return LINE_RGX.sub('\n', string)
-else:
-    def ulines(string):
-        return string
+# Classes
 
-INFO_TEST_RGX = re.compile('^func_i\d\d\d\d$')
+class LintTestNonExistentModuleTC(LintTestUsingModule):
+    module = 'nonexistent'
+    _get_expected = lambda self: 'F:  1: No module named nonexistent\n'
+    tags = testlib.Tags(('generated','pylint_input_%s' % module))
 
-MSG_DIR = join(dirname(abspath(__file__)), 'messages')
-INPUT_DIR = join(dirname(abspath(__file__)), 'input')
-
-def exception_str(self, ex):
-    """function used to replace default __str__ method of exception instances"""
-    return 'in %s\n:: %s' % (ex.file, ', '.join(ex.args))
-
-class LintTestUsingModule(testlib.TestCase):
-    DEFAULT_PACKAGE = 'input'
-    package = DEFAULT_PACKAGE
-    linter = linter
-    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
-
+class LintTestNonExistentFileTC(LintTestUsingFile):
+    module = join(INPUT_DIR, 'nonexistent.py')
+    _get_expected = lambda self: 'F:  1: No module named %s\n' % self.module[len(getcwd())+1 :]
+    tags = testlib.Tags(('generated', 'pylint_input_%s' % module))
     def test_functionality(self):
-        tocheck = [self.package+'.'+self.module]
-        if self.depends:
-            tocheck += [self.package+'.%s' % name.replace('.py', '')
-                        for name, file in self.depends]
-        self._test(tocheck)
-
-    def _test(self, tocheck):
-        if PY3K: # XXX remove this if block as soon as python bugs fixed
-            module = tocheck[0]
-            if module == 'input.func_unknown_encoding':
-                self.skipTest('FIXME: http://bugs.python.org/issue10588 '
-                              '(unexpected SyntaxError)')
-            elif 'func_w0613' in module:
-                self.skipTest('FIXME: http://bugs.python.org/issue10445 '
-                              '(no line number on function args)')
-        if INFO_TEST_RGX.match(self.module):
-            self.linter.enable('I')
-        else:
-            self.linter.disable('I')
-        try:
-            self.linter.check(tocheck)
-        except Exception, ex:
-            # need finalization to restore a correct state
-            self.linter.reporter.finalize()
-            ex.file = tocheck
-            print ex
-            ex.__str__ = exception_str
-            raise
-        got = self.linter.reporter.finalize()
-        self.assertMultiLineEqual(got, self._get_expected())
-
-
-    def _get_expected(self):
-        if self.module.startswith('func_noerror_'):
-            expected = ''
-        else:
-            output = open(self.output)
-            expected = output.read().strip() + '\n'
-            output.close()
-        return expected
-
-class LintTestUsingFile(LintTestUsingModule):
-
-    _TEST_TYPE = 'file'
-
-    def test_functionality(self):
-        tocheck = [join(INPUT_DIR, self.module + '.py')]
-        if self.depends:
-            tocheck += [join(INPUT_DIR, name) for name, _file in self.depends]
-        self._test(tocheck)
-
+        self._test([self.module])
 
 class TestTests(testlib.TestCase):
     """check that all testable messages have been checked"""
         else:
             self.assertEqual(todo, ['I0001'])
 
-#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
+class LintBuiltinModuleTest(LintTestUsingModule):
+    output = join(MSG_DIR, 'builtin_module.txt')
+    module = 'sys'
+    def test_functionality(self):
+        self._test(['sys'])
 
-class LintTestNonExistentModuleTC(LintTestUsingModule):
-    module = 'nonexistent'
-    _get_expected = lambda self: 'F:  1: No module named nonexistent\n'
-    tags = testlib.Tags(('generated','pylint_input_%s' % module))
+# Callbacks
 
-class LintTestNonExistentFileTC(LintTestUsingFile):
-    module = join(INPUT_DIR, 'nonexistent.py')
-    _get_expected = lambda self: 'F:  1: No module named %s\n' % self.module[len(getcwd())+1 :]
-    tags = testlib.Tags(('generated', 'pylint_input_%s' % module))
-    def test_functionality(self):
-        self._test([self.module])
+base_cb_file = cb_test_gen(LintTestUsingFile)
 
-def make_tests(filter_rgx):
-    """generate tests classes from test info
+def cb_file(*args):
+    if MODULES_ONLY:
+        return None
+    else:
+        return base_cb_file(*args)
 
-    return the list of generated test classes
-    """
+callbacks = [cb_test_gen(LintTestUsingModule),
+    cb_file]
+
+# Gen tests
+
+def gen_tests(filter_rgx):
+    tests = make_tests(INPUT_DIR, MSG_DIR, filter_rgx, callbacks)
+
     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('func_', '.py'):
-        if not is_to_run(module_file):
-            continue
-        base = module_file.replace('func_', '').replace('.py', '')
-
-        dependencies = get_tests_info(base, '.py')
-
-        class LintTestUsingModuleTC(LintTestUsingModule):
-            module = module_file.replace('.py', '')
-            output = messages_file
-            depends = dependencies or None
-            tags = testlib.Tags(('generated','pylint_input_%s' % module))
-        tests.append(LintTestUsingModuleTC)
-
-        if MODULES_ONLY:
-            continue
-
-        class LintTestUsingFileTC(LintTestUsingFile):
-            module = module_file.replace('.py', '')
-            output = messages_file
-            depends = dependencies or None
-            tags = testlib.Tags(('generated', 'pylint_input_%s' % module))
-        tests.append(LintTestUsingFileTC)
 
     if is_to_run('nonexistent'):
         tests.append(LintTestNonExistentModuleTC)
         if not MODULES_ONLY:
             tests.append(LintTestNonExistentFileTC)
 
-    class LintBuiltinModuleTest(LintTestUsingModule):
-        output = join(MSG_DIR, 'builtin_module.txt')
-        module = 'sys'
-        def test_functionality(self):
-            self._test(['sys'])
     tests.append(LintBuiltinModuleTest)
 
     if not filter_rgx:
 
     return tests
 
+# Create suite
+
 FILTER_RGX = None
 MODULES_ONLY = False
 
 def suite():
     return testlib.TestSuite([unittest.makeSuite(test, suiteClass=testlib.TestSuite)
-                              for test in make_tests(FILTER_RGX)])
+                              for test in gen_tests(FILTER_RGX)])
 
 if __name__=='__main__':
     if '-m' in sys.argv:
         FILTER_RGX = sys.argv[1]
         del sys.argv[1]
     testlib.unittest_main(defaultTest='suite')
-
-

test/test_import_graph.py

 from pylint.checkers import initialize, imports
 from pylint.lint import PyLinter
 
-from utils import TestReporter
+from pylint.testutils import TestReporter
 
 class DependenciesGraphTC(TestCase):
     """test the imports graph function"""

test/test_regr.py

 
 from logilab.common.testlib import TestCase, unittest_main
 
-from utils import TestReporter
-
+from pylint.testutils import TestReporter
 from pylint.lint import PyLinter
 from pylint import checkers
 
 """some pylint test utilities
 """
-import sys
-from glob import glob
-from os.path import join, abspath, dirname, basename, exists, splitext
-from cStringIO import StringIO
-
-from pylint.interfaces import IReporter
-from pylint.reporters import BaseReporter
-
-PREFIX = abspath(dirname(__file__))
-
-def fix_path():
-    sys.path.insert(0, PREFIX)
-
-SYS_VERS_STR = '%d%d' % sys.version_info[:2]
-
-def get_tests_info(prefix, suffix):
-    """get python input examples and output messages
-    
-    We use following conventions for input files and messages:
-    for different inputs:
-        don't test for python  <   x.y    ->  input   =  <name>_pyxy.py
-        don't 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
-        higher versions                   ->  message with highest num
-    """
-    result = []
-    for fname in glob(join(PREFIX, 'input', 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(PREFIX, 'messages', 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:
-            outfile = None
-        result.append((infile, outfile))
-    return result
-
-
-TITLE_UNDERLINES = ['', '=', '-', '.']
-
-class TestReporter(BaseReporter):
-    """ store plain text messages 
-    """
-    
-    __implements____ = IReporter
-    
-    def __init__(self):
-        self.message_ids = {}
-        self.reset()
-        
-    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 """
-        fpath, module, object, line, _ = location
-        self.message_ids[msg_id] = 1
-        if object:
-            object = ':%s' % object
-        sigle = msg_id[0]
-        self.messages.append('%s:%3s%s: %s' % (sigle, line, object, msg))
-
-    def finalize(self):
-        self.messages.sort()
-        for msg in self.messages:
-            print >>self.out, msg
-        result = self.out.getvalue()
-        self.reset()
-        return result
-    
-    def display_results(self, layout):
-        """ignore layouts"""
-
 
 # # # # #  pyreverse unittest utilities  # # # # # #
 
 from logilab.common.testlib import TestCase
 import os
 import sys
-from os.path import join
+from os.path import join, dirname, abspath
 
 from logilab.astng import MANAGER
 
+# Copyright (c) 2003-2008 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.,
+# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+"""functional/non regression tests for pylint"""
+
+import unittest
+import sys
+import re
+
+from glob import glob
+from os import linesep
+from os.path import exists, abspath, dirname, join, basename, splitext
+from cStringIO import StringIO
+
+from logilab.common import testlib
+
+from logilab.astng import MANAGER
+from pylint.reporters import BaseReporter
+from pylint.interfaces import IReporter
+from pylint.lint import PyLinter
+from pylint import checkers
+
+
+# Utils
+
+SYS_VERS_STR = '%d%d' % sys.version_info[:2]
+TITLE_UNDERLINES = ['', '=', '-', '.']
+PREFIX = abspath(dirname(__file__))
+
+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:
+        don't test for python  <   x.y    ->  input   =  <name>_pyxy.py
+        don't 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
+        higher 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:
+            outfile = None
+        result.append((infile, outfile))
+    return result
+
+class TestReporter(BaseReporter):
+    """ store plain text messages
+    """
+
+    __implements____ = IReporter
+
+    def __init__(self):
+        self.message_ids = {}
+        self.reset()
+
+    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 """
+        fpath, module, object, line, _ = location
+        self.message_ids[msg_id] = 1
+        if object:
+            object = ':%s' % object
+        sigle = msg_id[0]
+        self.messages.append('%s:%3s%s: %s' % (sigle, line, object, msg))
+
+    def finalize(self):
+        self.messages.sort()
+        for msg in self.messages:
+            print >>self.out, msg
+        result = self.out.getvalue()
+        self.reset()
+        return result
+
+    def display_results(self, layout):
+        """ignore layouts"""
+
+# 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('^func_i\d\d\d\d$')
+
+def exception_str(self, ex):
+    """function used to replace default __str__ method of exception instances"""
+    return 'in %s\n:: %s' % (ex.file, ', '.join(ex.args))
+
+# Test classes
+
+class LintTestUsingModule(testlib.TestCase):
+    DEFAULT_PACKAGE = 'input'
+    package = DEFAULT_PACKAGE
+    linter = linter
+    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
+
+    def test_functionality(self):
+        tocheck = [self.package+'.'+self.module]
+        if self.depends:
+            tocheck += [self.package+'.%s' % name.replace('.py', '')
+                        for name, file in self.depends]
+        self._test(tocheck)
+
+    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, ex:
+            # need finalization to restore a correct state
+            self.linter.reporter.finalize()
+            ex.file = tocheck
+            print ex
+            ex.__str__ = exception_str
+            raise
+        got = self.linter.reporter.finalize()
+        self.assertMultiLineEqual(got, self._get_expected())
+
+
+    def _get_expected(self):
+        if self.module.startswith('func_noerror_'):
+            expected = ''
+        else:
+            output = open(self.output)
+            expected = output.read().strip() + '\n'
+            output.close()
+        return expected
+
+class LintTestUsingFile(LintTestUsingModule):
+
+    _TEST_TYPE = 'file'
+
+    def test_functionality(self):
+        tocheck = [join(self.INPUT_DIR, self.module + '.py')]
+        if self.depends:
+            tocheck += [join(self.INPUT_DIR, name) for name, _file in self.depends]
+        self._test(tocheck)
+
+# Callback
+
+def cb_test_gen(base_class):
+    def call(input_dir, msg_dir, module_file, messages_file, dependencies):
+        class LintTC(base_class):
+            module = module_file.replace('.py', '')
+            output = messages_file
+            depends = dependencies or None
+            tags = testlib.Tags(('generated', 'pylint_input_%s' % module))
+            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_', '.py'):
+        if not is_to_run(module_file):
+            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