Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / pylint / test / unittest_lint.py @ 745

History | View | Annotate | Download (26.8 KB)

1
# Copyright (c) 2003-2014 LOGILAB S.A. (Paris, FRANCE).
2
# This program is free software; you can redistribute it and/or modify it under
3
# the terms of the GNU General Public License as published by the Free Software
4
# Foundation; either version 2 of the License, or (at your option) any later
5
# version.
6
#
7
# This program is distributed in the hope that it will be useful, but WITHOUT
8
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10
#
11
# You should have received a copy of the GNU General Public License along with
12
# this program; if not, write to the Free Software Foundation, Inc.,
13
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14

    
15
from contextlib import contextmanager
16
import sys
17
import os
18
import tempfile
19
from shutil import rmtree
20
from os import getcwd, chdir
21
from os.path import join, basename, dirname, isdir, abspath, sep
22
import unittest
23

    
24
import six
25
from six.moves import reload_module
26

    
27
from pylint import config, lint
28
from pylint.lint import PyLinter, Run, preprocess_options, \
29
     ArgumentPreprocessingError
30
from pylint.utils import MSG_STATE_SCOPE_CONFIG, MSG_STATE_SCOPE_MODULE, MSG_STATE_CONFIDENCE, \
31
    MessagesStore, PyLintASTWalker, MessageDefinition, FileState, \
32
    build_message_def, tokenize_module, UnknownMessage
33
from pylint.testutils import TestReporter
34
from pylint.reporters import text, html
35
from pylint import checkers
36
from pylint.checkers.utils import check_messages
37
from pylint import interfaces
38

    
39
if os.name == 'java':
40
    if os._name == 'nt':
41
        HOME = 'USERPROFILE'
42
    else:
43
        HOME = 'HOME'
44
else:
45
    if sys.platform == 'win32':
46
        HOME = 'USERPROFILE'
47
    else:
48
        HOME = 'HOME'
49

    
50
@contextmanager
51
def fake_home():
52
    folder = tempfile.mkdtemp('fake-home')
53
    old_home = os.environ.get(HOME)
54
    try:
55
        os.environ[HOME] = folder
56
        yield
57
    finally:
58
        os.environ.pop('PYLINTRC', '')
59
        if old_home is None:
60
            del os.environ[HOME]
61
        else:
62
            os.environ[HOME] = old_home
63
        rmtree(folder, ignore_errors=True)
64

    
65
def remove(file):
66
    try:
67
        os.remove(file)
68
    except OSError:
69
        pass
70

    
71
HERE = abspath(dirname(__file__))
72
INPUTDIR = join(HERE, 'input')
73

    
74

    
75
@contextmanager
76
def tempdir():
77
    """Create a temp directory and change the current location to it.
78

79
    This is supposed to be used with a *with* statement.
80
    """
81
    tmp = tempfile.mkdtemp()
82

    
83
    # Get real path of tempfile, otherwise test fail on mac os x
84
    current_dir = getcwd()
85
    chdir(tmp)
86
    abs_tmp = abspath('.')
87

    
88
    try:
89
        yield abs_tmp
90
    finally:
91
        chdir(current_dir)
92
        rmtree(abs_tmp)
93

    
94

    
95
def create_files(paths, chroot='.'):
96
    """Creates directories and files found in <path>.
97

98
    :param paths: list of relative paths to files or directories
99
    :param chroot: the root directory in which paths will be created
100

101
    >>> from os.path import isdir, isfile
102
    >>> isdir('/tmp/a')
103
    False
104
    >>> create_files(['a/b/foo.py', 'a/b/c/', 'a/b/c/d/e.py'], '/tmp')
105
    >>> isdir('/tmp/a')
106
    True
107
    >>> isdir('/tmp/a/b/c')
108
    True
109
    >>> isfile('/tmp/a/b/c/d/e.py')
110
    True
111
    >>> isfile('/tmp/a/b/foo.py')
112
    True
113
    """
114
    dirs, files = set(), set()
115
    for path in paths:
116
        path = join(chroot, path)
117
        filename = basename(path)
118
        # path is a directory path
119
        if filename == '':
120
            dirs.add(path)
121
        # path is a filename path
122
        else:
123
            dirs.add(dirname(path))
124
            files.add(path)
125
    for dirpath in dirs:
126
        if not isdir(dirpath):
127
            os.makedirs(dirpath)
128
    for filepath in files:
129
        open(filepath, 'w').close()
130

    
131

    
132
class SysPathFixupTC(unittest.TestCase):
133
    def setUp(self):
134
        self.orig = list(sys.path)
135
        self.fake = [1, 2, 3]
136
        sys.path[:] = self.fake
137

    
138
    def tearDown(self):
139
        sys.path[:] = self.orig
140

    
141
    def test_no_args(self):
142
        with lint.fix_import_path([]):
143
            self.assertEqual(sys.path, self.fake)
144
        self.assertEqual(sys.path, self.fake)
145

    
146
    def test_one_arg(self):
147
        with tempdir() as chroot:
148
            create_files(['a/b/__init__.py'])
149
            expected = [join(chroot, 'a')] + self.fake
150

    
151
            cases = (
152
                ['a/b/'],
153
                ['a/b'],
154
                ['a/b/__init__.py'],
155
                ['a/'],
156
                ['a'],
157
            )
158

    
159
            self.assertEqual(sys.path, self.fake)
160
            for case in cases:
161
                with lint.fix_import_path(case):
162
                    self.assertEqual(sys.path, expected)
163
                self.assertEqual(sys.path, self.fake)
164

    
165
    def test_two_similar_args(self):
166
        with tempdir() as chroot:
167
            create_files(['a/b/__init__.py', 'a/c/__init__.py'])
168
            expected = [join(chroot, 'a')] + self.fake
169

    
170
            cases = (
171
                ['a/b', 'a/c'],
172
                ['a/c/', 'a/b/'],
173
                ['a/b/__init__.py', 'a/c/__init__.py'],
174
                ['a', 'a/c/__init__.py'],
175
            )
176

    
177
            self.assertEqual(sys.path, self.fake)
178
            for case in cases:
179
                with lint.fix_import_path(case):
180
                    self.assertEqual(sys.path, expected)
181
                self.assertEqual(sys.path, self.fake)
182

    
183
    def test_more_args(self):
184
        with tempdir() as chroot:
185
            create_files(['a/b/c/__init__.py', 'a/d/__init__.py', 'a/e/f.py'])
186
            expected = [
187
                join(chroot, suffix)
188
                for suffix in [sep.join(('a', 'b')), 'a', sep.join(('a', 'e'))]
189
            ] + self.fake
190

    
191
            cases = (
192
                ['a/b/c/__init__.py', 'a/d/__init__.py', 'a/e/f.py'],
193
                ['a/b/c', 'a', 'a/e'],
194
                ['a/b/c', 'a', 'a/b/c', 'a/e', 'a'],
195
            )
196

    
197
            self.assertEqual(sys.path, self.fake)
198
            for case in cases:
199
                with lint.fix_import_path(case):
200
                    self.assertEqual(sys.path, expected)
201
                self.assertEqual(sys.path, self.fake)
202

    
203

    
204
class PyLinterTC(unittest.TestCase):
205

    
206
    def setUp(self):
207
        self.linter = PyLinter()
208
        self.linter.disable('I')
209
        self.linter.config.persistent = 0
210
        # register checkers
211
        checkers.initialize(self.linter)
212
        self.linter.set_reporter(TestReporter())
213

    
214
    def init_linter(self):
215
        linter = self.linter
216
        linter.open()
217
        linter.set_current_module('toto')
218
        linter.file_state = FileState('toto')
219
        return linter
220

    
221
    def test_pylint_visit_method_taken_in_account(self):
222
        class CustomChecker(checkers.BaseChecker):
223
            __implements__ = interfaces.IAstroidChecker
224
            name = 'custom'
225
            msgs = {'W9999': ('', 'custom', '')}
226

    
227
            @check_messages('custom')
228
            def visit_class(self, _):
229
               pass
230

    
231
        self.linter.register_checker(CustomChecker(self.linter))
232
        self.linter.open()
233
        out = six.moves.StringIO()
234
        self.linter.set_reporter(text.TextReporter(out))
235
        self.linter.check('abc')
236

    
237
    def test_enable_message(self):
238
        linter = self.init_linter()
239
        self.assertTrue(linter.is_message_enabled('W0101'))
240
        self.assertTrue(linter.is_message_enabled('W0102'))
241
        linter.disable('W0101', scope='package')
242
        linter.disable('W0102', scope='module', line=1)
243
        self.assertFalse(linter.is_message_enabled('W0101'))
244
        self.assertFalse(linter.is_message_enabled('W0102', 1))
245
        linter.set_current_module('tutu')
246
        self.assertFalse(linter.is_message_enabled('W0101'))
247
        self.assertTrue(linter.is_message_enabled('W0102'))
248
        linter.enable('W0101', scope='package')
249
        linter.enable('W0102', scope='module', line=1)
250
        self.assertTrue(linter.is_message_enabled('W0101'))
251
        self.assertTrue(linter.is_message_enabled('W0102', 1))
252

    
253
    def test_enable_message_category(self):
254
        linter = self.init_linter()
255
        self.assertTrue(linter.is_message_enabled('W0101'))
256
        self.assertTrue(linter.is_message_enabled('C0202'))
257
        linter.disable('W', scope='package')
258
        linter.disable('C', scope='module', line=1)
259
        self.assertFalse(linter.is_message_enabled('W0101'))
260
        self.assertTrue(linter.is_message_enabled('C0202'))
261
        self.assertFalse(linter.is_message_enabled('C0202', line=1))
262
        linter.set_current_module('tutu')
263
        self.assertFalse(linter.is_message_enabled('W0101'))
264
        self.assertTrue(linter.is_message_enabled('C0202'))
265
        linter.enable('W', scope='package')
266
        linter.enable('C', scope='module', line=1)
267
        self.assertTrue(linter.is_message_enabled('W0101'))
268
        self.assertTrue(linter.is_message_enabled('C0202'))
269
        self.assertTrue(linter.is_message_enabled('C0202', line=1))
270

    
271
    def test_message_state_scope(self):
272
        class FakeConfig(object):
273
            confidence = ['HIGH']
274

    
275
        linter = self.init_linter()
276
        linter.disable('C0202')
277
        self.assertEqual(MSG_STATE_SCOPE_CONFIG,
278
                         linter.get_message_state_scope('C0202'))
279
        linter.disable('W0101', scope='module', line=3)
280
        self.assertEqual(MSG_STATE_SCOPE_CONFIG,
281
                         linter.get_message_state_scope('C0202'))
282
        self.assertEqual(MSG_STATE_SCOPE_MODULE,
283
                         linter.get_message_state_scope('W0101', 3))
284
        linter.enable('W0102', scope='module', line=3)
285
        self.assertEqual(MSG_STATE_SCOPE_MODULE,
286
                         linter.get_message_state_scope('W0102', 3))
287
        linter.config = FakeConfig()
288
        self.assertEqual(
289
            MSG_STATE_CONFIDENCE,
290
            linter.get_message_state_scope('this-is-bad',
291
                                           confidence=interfaces.INFERENCE))
292

    
293
    def test_enable_message_block(self):
294
        linter = self.init_linter()
295
        linter.open()
296
        filepath = join(INPUTDIR, 'func_block_disable_msg.py')
297
        linter.set_current_module('func_block_disable_msg')
298
        astroid = linter.get_ast(filepath, 'func_block_disable_msg')
299
        linter.process_tokens(tokenize_module(astroid))
300
        fs = linter.file_state
301
        fs.collect_block_lines(linter.msgs_store, astroid)
302
        # global (module level)
303
        self.assertTrue(linter.is_message_enabled('W0613'))
304
        self.assertTrue(linter.is_message_enabled('E1101'))
305
        # meth1
306
        self.assertTrue(linter.is_message_enabled('W0613', 13))
307
        # meth2
308
        self.assertFalse(linter.is_message_enabled('W0613', 18))
309
        # meth3
310
        self.assertFalse(linter.is_message_enabled('E1101', 24))
311
        self.assertTrue(linter.is_message_enabled('E1101', 26))
312
        # meth4
313
        self.assertFalse(linter.is_message_enabled('E1101', 32))
314
        self.assertTrue(linter.is_message_enabled('E1101', 36))
315
        # meth5
316
        self.assertFalse(linter.is_message_enabled('E1101', 42))
317
        self.assertFalse(linter.is_message_enabled('E1101', 43))
318
        self.assertTrue(linter.is_message_enabled('E1101', 46))
319
        self.assertFalse(linter.is_message_enabled('E1101', 49))
320
        self.assertFalse(linter.is_message_enabled('E1101', 51))
321
        # meth6
322
        self.assertFalse(linter.is_message_enabled('E1101', 57))
323
        self.assertTrue(linter.is_message_enabled('E1101', 61))
324
        self.assertFalse(linter.is_message_enabled('E1101', 64))
325
        self.assertFalse(linter.is_message_enabled('E1101', 66))
326

    
327
        self.assertTrue(linter.is_message_enabled('E0602', 57))
328
        self.assertTrue(linter.is_message_enabled('E0602', 61))
329
        self.assertFalse(linter.is_message_enabled('E0602', 62))
330
        self.assertTrue(linter.is_message_enabled('E0602', 64))
331
        self.assertTrue(linter.is_message_enabled('E0602', 66))
332
        # meth7
333
        self.assertFalse(linter.is_message_enabled('E1101', 70))
334
        self.assertTrue(linter.is_message_enabled('E1101', 72))
335
        self.assertTrue(linter.is_message_enabled('E1101', 75))
336
        self.assertTrue(linter.is_message_enabled('E1101', 77))
337

    
338
        fs = linter.file_state
339
        self.assertEqual(17, fs._suppression_mapping['W0613', 18])
340
        self.assertEqual(30, fs._suppression_mapping['E1101', 33])
341
        self.assertTrue(('E1101', 46) not in fs._suppression_mapping)
342
        self.assertEqual(1, fs._suppression_mapping['C0302', 18])
343
        self.assertEqual(1, fs._suppression_mapping['C0302', 50])
344
        # This is tricky. While the disable in line 106 is disabling
345
        # both 108 and 110, this is usually not what the user wanted.
346
        # Therefore, we report the closest previous disable comment.
347
        self.assertEqual(106, fs._suppression_mapping['E1101', 108])
348
        self.assertEqual(109, fs._suppression_mapping['E1101', 110])
349

    
350
    def test_enable_by_symbol(self):
351
        """messages can be controlled by symbolic names.
352

353
        The state is consistent across symbols and numbers.
354
        """
355
        linter = self.init_linter()
356
        self.assertTrue(linter.is_message_enabled('W0101'))
357
        self.assertTrue(linter.is_message_enabled('unreachable'))
358
        self.assertTrue(linter.is_message_enabled('W0102'))
359
        self.assertTrue(linter.is_message_enabled('dangerous-default-value'))
360
        linter.disable('unreachable', scope='package')
361
        linter.disable('dangerous-default-value', scope='module', line=1)
362
        self.assertFalse(linter.is_message_enabled('W0101'))
363
        self.assertFalse(linter.is_message_enabled('unreachable'))
364
        self.assertFalse(linter.is_message_enabled('W0102', 1))
365
        self.assertFalse(linter.is_message_enabled('dangerous-default-value', 1))
366
        linter.set_current_module('tutu')
367
        self.assertFalse(linter.is_message_enabled('W0101'))
368
        self.assertFalse(linter.is_message_enabled('unreachable'))
369
        self.assertTrue(linter.is_message_enabled('W0102'))
370
        self.assertTrue(linter.is_message_enabled('dangerous-default-value'))
371
        linter.enable('unreachable', scope='package')
372
        linter.enable('dangerous-default-value', scope='module', line=1)
373
        self.assertTrue(linter.is_message_enabled('W0101'))
374
        self.assertTrue(linter.is_message_enabled('unreachable'))
375
        self.assertTrue(linter.is_message_enabled('W0102', 1))
376
        self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1))
377

    
378
    def test_lint_ext_module_with_file_output(self):
379
        self.linter.set_reporter(text.TextReporter())
380
        if sys.version_info < (3, 0):
381
            strio = 'StringIO'
382
        else:
383
            strio = 'io'
384
        self.linter.config.files_output = True
385
        pylint_strio = 'pylint_%s.txt' % strio
386
        files = [pylint_strio, 'pylint_global.txt']
387
        for file in files:
388
            self.addCleanup(remove, file)
389

    
390
        self.linter.check(strio)
391
        self.linter.generate_reports()
392
        for f in files:
393
            self.assertTrue(os.path.exists(f))
394

    
395
    def test_enable_report(self):
396
        self.assertEqual(self.linter.report_is_enabled('RP0001'), True)
397
        self.linter.disable('RP0001')
398
        self.assertEqual(self.linter.report_is_enabled('RP0001'), False)
399
        self.linter.enable('RP0001')
400
        self.assertEqual(self.linter.report_is_enabled('RP0001'), True)
401

    
402
    def test_report_output_format_aliased(self):
403
        text.register(self.linter)
404
        self.linter.set_option('output-format', 'text')
405
        self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter')
406

    
407
    def test_report_output_format_custom(self):
408
        this_module = sys.modules[__name__]
409
        class TestReporter(object):
410
            pass
411
        this_module.TestReporter = TestReporter
412
        class_name = ".".join((this_module.__name__, 'TestReporter'))
413
        self.linter.set_option('output-format', class_name)
414
        self.assertEqual(self.linter.reporter.__class__.__name__, 'TestReporter')
415

    
416
    def test_set_option_1(self):
417
        linter = self.linter
418
        linter.set_option('disable', 'C0111,W0234')
419
        self.assertFalse(linter.is_message_enabled('C0111'))
420
        self.assertFalse(linter.is_message_enabled('W0234'))
421
        self.assertTrue(linter.is_message_enabled('W0113'))
422
        self.assertFalse(linter.is_message_enabled('missing-docstring'))
423
        self.assertFalse(linter.is_message_enabled('non-iterator-returned'))
424

    
425
    def test_set_option_2(self):
426
        linter = self.linter
427
        linter.set_option('disable', ('C0111', 'W0234') )
428
        self.assertFalse(linter.is_message_enabled('C0111'))
429
        self.assertFalse(linter.is_message_enabled('W0234'))
430
        self.assertTrue(linter.is_message_enabled('W0113'))
431
        self.assertFalse(linter.is_message_enabled('missing-docstring'))
432
        self.assertFalse(linter.is_message_enabled('non-iterator-returned'))
433

    
434
    def test_enable_checkers(self):
435
        self.linter.disable('design')
436
        self.assertFalse('design' in [c.name for c in self.linter.prepare_checkers()])
437
        self.linter.enable('design')
438
        self.assertTrue('design' in [c.name for c in self.linter.prepare_checkers()])
439

    
440
    def test_errors_only(self):
441
        linter = self.linter
442
        self.linter.error_mode()
443
        checkers = self.linter.prepare_checkers()
444
        checker_names = set(c.name for c in checkers)
445
        should_not = set(('design', 'format', 'metrics',
446
                      'miscellaneous', 'similarities'))
447
        self.assertSetEqual(set(), should_not & checker_names)
448

    
449
    def test_disable_similar(self):
450
        self.linter.set_option('disable', 'RP0801')
451
        self.linter.set_option('disable', 'R0801')
452
        self.assertFalse('similarities' in [c.name for c in self.linter.prepare_checkers()])
453

    
454
    def test_disable_alot(self):
455
        """check that we disabled a lot of checkers"""
456
        self.linter.set_option('reports', False)
457
        self.linter.set_option('disable', 'R,C,W')
458
        checker_names = [c.name for c in self.linter.prepare_checkers()]
459
        for cname in  ('design', 'metrics', 'similarities'):
460
            self.assertFalse(cname in checker_names, cname)
461

    
462
    def test_addmessage(self):
463
        self.linter.set_reporter(TestReporter())
464
        self.linter.open()
465
        self.linter.set_current_module('0123')
466
        self.linter.add_message('C0301', line=1, args=(1, 2))
467
        self.linter.add_message('line-too-long', line=2, args=(3, 4))
468
        self.assertEqual(
469
            ['C:  1: Line too long (1/2)', 'C:  2: Line too long (3/4)'],
470
            self.linter.reporter.messages)
471

    
472
    def test_init_hooks_called_before_load_plugins(self):
473
        self.assertRaises(RuntimeError,
474
                          Run, ['--load-plugins', 'unexistant', '--init-hook', 'raise RuntimeError'])
475
        self.assertRaises(RuntimeError,
476
                          Run, ['--init-hook', 'raise RuntimeError', '--load-plugins', 'unexistant'])
477

    
478

    
479
    def test_analyze_explicit_script(self):
480
        self.linter.set_reporter(TestReporter())
481
        self.linter.check(os.path.join(os.path.dirname(__file__), 'data', 'ascript'))
482
        self.assertEqual(
483
            ['C:  2: Line too long (175/100)'],
484
            self.linter.reporter.messages)
485

    
486
    def test_html_reporter_missing_files(self):
487
        output = six.StringIO()
488
        self.linter.set_reporter(html.HTMLReporter(output))
489
        self.linter.set_option('output-format', 'html')
490
        self.linter.check('troppoptop.py')
491
        self.linter.generate_reports()
492
        value = output.getvalue()
493
        self.assertIn('troppoptop.py', value)
494
        self.assertIn('fatal', value)
495

    
496
    def test_python3_checker_disabled(self):
497
        checker_names = [c.name for c in self.linter.prepare_checkers()]
498
        self.assertNotIn('python3', checker_names)
499

    
500
        self.linter.set_option('enable', 'python3')
501
        checker_names = [c.name for c in self.linter.prepare_checkers()]
502
        self.assertIn('python3', checker_names)
503

    
504

    
505
class ConfigTC(unittest.TestCase):
506

    
507
    def setUp(self):
508
        os.environ.pop('PYLINTRC', None)
509

    
510
    def test_pylint_home(self):
511
        uhome = os.path.expanduser('~')
512
        if uhome == '~':
513
            expected = '.pylint.d'
514
        else:
515
            expected = os.path.join(uhome, '.pylint.d')
516
        self.assertEqual(config.PYLINT_HOME, expected)
517

    
518
        try:
519
            pylintd = join(tempfile.gettempdir(), '.pylint.d')
520
            os.environ['PYLINTHOME'] = pylintd
521
            try:
522
                reload_module(config)
523
                self.assertEqual(config.PYLINT_HOME, pylintd)
524
            finally:
525
                try:
526
                    os.remove(pylintd)
527
                except:
528
                    pass
529
        finally:
530
            del os.environ['PYLINTHOME']
531

    
532
    def test_pylintrc(self):
533
        with fake_home():
534
            try:
535
                self.assertEqual(config.find_pylintrc(), None)
536
                os.environ['PYLINTRC'] = join(tempfile.gettempdir(),
537
                                              '.pylintrc')
538
                self.assertEqual(config.find_pylintrc(), None)
539
                os.environ['PYLINTRC'] = '.'
540
                self.assertEqual(config.find_pylintrc(), None)
541
            finally:
542
                reload_module(config)
543

    
544
    def test_pylintrc_parentdir(self):
545
        with tempdir() as chroot:
546

    
547
            create_files(['a/pylintrc', 'a/b/__init__.py', 'a/b/pylintrc',
548
                          'a/b/c/__init__.py', 'a/b/c/d/__init__.py',
549
                          'a/b/c/d/e/.pylintrc'])
550
            with fake_home():
551
                self.assertEqual(config.find_pylintrc(), None)
552
            results = {'a'       : join(chroot, 'a', 'pylintrc'),
553
                       'a/b'     : join(chroot, 'a', 'b', 'pylintrc'),
554
                       'a/b/c'   : join(chroot, 'a', 'b', 'pylintrc'),
555
                       'a/b/c/d' : join(chroot, 'a', 'b', 'pylintrc'),
556
                       'a/b/c/d/e' : join(chroot, 'a', 'b', 'c', 'd', 'e', '.pylintrc'),
557
                       }
558
            for basedir, expected in results.items():
559
                os.chdir(join(chroot, basedir))
560
                self.assertEqual(config.find_pylintrc(), expected)
561

    
562
    def test_pylintrc_parentdir_no_package(self):
563
        with tempdir() as chroot:
564
            with fake_home():
565
                create_files(['a/pylintrc', 'a/b/pylintrc', 'a/b/c/d/__init__.py'])
566
                self.assertEqual(config.find_pylintrc(), None)
567
                results = {'a'       : join(chroot, 'a', 'pylintrc'),
568
                           'a/b'     : join(chroot, 'a', 'b', 'pylintrc'),
569
                           'a/b/c'   : None,
570
                           'a/b/c/d' : None,
571
                           }
572
                for basedir, expected in results.items():
573
                    os.chdir(join(chroot, basedir))
574
                    self.assertEqual(config.find_pylintrc(), expected)
575

    
576

    
577
class PreprocessOptionsTC(unittest.TestCase):
578
    def _callback(self, name, value):
579
        self.args.append((name, value))
580

    
581
    def test_value_equal(self):
582
        self.args = []
583
        preprocess_options(['--foo', '--bar=baz', '--qu=ux'],
584
                           {'foo' : (self._callback, False),
585
                            'qu' : (self._callback, True)})
586
        self.assertEqual(
587
            [('foo', None), ('qu', 'ux')], self.args)
588

    
589
    def test_value_space(self):
590
        self.args = []
591
        preprocess_options(['--qu', 'ux'],
592
                           {'qu' : (self._callback, True)})
593
        self.assertEqual(
594
            [('qu', 'ux')], self.args)
595

    
596
    def test_error_missing_expected_value(self):
597
        self.assertRaises(
598
            ArgumentPreprocessingError,
599
            preprocess_options,
600
            ['--foo', '--bar', '--qu=ux'],
601
            {'bar' : (None, True)})
602
        self.assertRaises(
603
            ArgumentPreprocessingError,
604
            preprocess_options,
605
            ['--foo', '--bar'],
606
            {'bar' : (None, True)})
607

    
608
    def test_error_unexpected_value(self):
609
        self.assertRaises(
610
            ArgumentPreprocessingError,
611
            preprocess_options,
612
            ['--foo', '--bar=spam', '--qu=ux'],
613
            {'bar' : (None, False)})
614

    
615

    
616
class MessagesStoreTC(unittest.TestCase):
617
    def setUp(self):
618
        self.store = MessagesStore()
619
        class Checker(object):
620
            name = 'achecker'
621
            msgs = {
622
                'W1234': ('message', 'msg-symbol', 'msg description.',
623
                          {'old_names': [('W0001', 'old-symbol')]}),
624
                'E1234': ('Duplicate keyword argument %r in %s call',
625
                          'duplicate-keyword-arg',
626
                          'Used when a function call passes the same keyword argument multiple times.',
627
                          {'maxversion': (2, 6)}),
628
                }
629
        self.store.register_messages(Checker())
630

    
631
    def _compare_messages(self, desc, msg, checkerref=False):
632
        self.assertMultiLineEqual(desc, msg.format_help(checkerref=checkerref))
633

    
634
    def test_check_message_id(self):
635
        self.assertIsInstance(self.store.check_message_id('W1234'),
636
                              MessageDefinition)
637
        self.assertRaises(UnknownMessage,
638
                          self.store.check_message_id, 'YB12')
639

    
640
    def test_message_help(self):
641
        msg = self.store.check_message_id('W1234')
642
        self._compare_messages(
643
            ''':msg-symbol (W1234): *message*
644
  msg description. This message belongs to the achecker checker.''',
645
            msg, checkerref=True)
646
        self._compare_messages(
647
            ''':msg-symbol (W1234): *message*
648
  msg description.''',
649
            msg, checkerref=False)
650

    
651
    def test_message_help_minmax(self):
652
        # build the message manually to be python version independant
653
        msg = self.store.check_message_id('E1234')
654
        self._compare_messages(
655
            ''':duplicate-keyword-arg (E1234): *Duplicate keyword argument %r in %s call*
656
  Used when a function call passes the same keyword argument multiple times.
657
  This message belongs to the achecker checker. It can't be emitted when using
658
  Python >= 2.6.''',
659
            msg, checkerref=True)
660
        self._compare_messages(
661
            ''':duplicate-keyword-arg (E1234): *Duplicate keyword argument %r in %s call*
662
  Used when a function call passes the same keyword argument multiple times.
663
  This message can't be emitted when using Python >= 2.6.''',
664
            msg, checkerref=False)
665

    
666
    def test_list_messages(self):
667
        sys.stdout = six.StringIO()
668
        try:
669
            self.store.list_messages()
670
            output = sys.stdout.getvalue()
671
        finally:
672
            sys.stdout = sys.__stdout__
673
        # cursory examination of the output: we're mostly testing it completes
674
        self.assertIn(':msg-symbol (W1234): *message*', output)
675

    
676
    def test_add_renamed_message(self):
677
        self.store.add_renamed_message('W1234', 'old-bad-name', 'msg-symbol')
678
        self.assertEqual('msg-symbol',
679
                         self.store.check_message_id('W1234').symbol)
680
        self.assertEqual('msg-symbol',
681
                         self.store.check_message_id('old-bad-name').symbol)
682

    
683
    def test_renamed_message_register(self):
684
        self.assertEqual('msg-symbol',
685
                         self.store.check_message_id('W0001').symbol)
686
        self.assertEqual('msg-symbol',
687
                         self.store.check_message_id('old-symbol').symbol)
688

    
689
   
690
if __name__ == '__main__':
691
    unittest.main()