~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_source.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-02-23 17:00:36 UTC
  • mfrom: (4032.1.4 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090223170036-3q1v68ewdt8i0to5
(Marius Kruger) Remove all trailing whitespace and add tests to
        enforce this.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
import os
26
26
import parser
27
27
import re
28
 
from cStringIO import StringIO
29
28
import symbol
30
29
import sys
31
30
import token
32
31
 
33
32
#import bzrlib specific imports here
34
33
from bzrlib import (
35
 
    diff,
36
34
    osutils,
37
 
    patiencediff,
38
 
    textfile,
39
35
    )
40
36
import bzrlib.branch
41
37
from bzrlib.tests import (
42
 
    KnownFailure,
43
38
    TestCase,
44
39
    TestSkipped,
45
40
    )
46
 
from bzrlib.workingtree import WorkingTree
47
41
 
48
42
 
49
43
# Files which are listed here will be skipped when testing for Copyright (or
56
50
# but for compatibility with previous releases, we don't want to move it.
57
51
 
58
52
 
59
 
def check_coding_style(old_filename, oldlines, new_filename, newlines, to_file,
60
 
                  allow_binary=False, sequence_matcher=None,
61
 
                  path_encoding='utf8'):
62
 
    """text_differ to be passed to diff.DiffText, which checks code style """
63
 
    if allow_binary is False:
64
 
        textfile.check_text_lines(oldlines)
65
 
        textfile.check_text_lines(newlines)
66
 
 
67
 
    if sequence_matcher is None:
68
 
        sequence_matcher = patiencediff.PatienceSequenceMatcher
69
 
 
70
 
    started = [False] #trick to access parent scoped variable
71
 
    def start_if_needed():
72
 
        if not started[0]:
73
 
            to_file.write('+++ %s\n' % new_filename)
74
 
            started[0] = True
75
 
 
76
 
    def check_newlines(j1, j2):
77
 
        for i, line in enumerate(newlines[j1:j2]):
78
 
            bad_ws_match = re.match(r'^(([\t]*)(.*?)([\t ]*))(\r?\n)?$', line)
79
 
            if bad_ws_match:
80
 
                line_content = bad_ws_match.group(1)
81
 
                has_leading_tabs = bool(bad_ws_match.group(2))
82
 
                has_trailing_whitespace = bool(bad_ws_match.group(4))
83
 
                if has_leading_tabs:
84
 
                    start_if_needed()
85
 
                    to_file.write('line %i has leading tabs: "%s"\n'% (
86
 
                        i+1+j1, line_content))
87
 
                if has_trailing_whitespace:
88
 
                    start_if_needed()
89
 
                    to_file.write('line %i has trailing whitespace: "%s"\n'% (
90
 
                        i+1+j1, line_content))
91
 
                if len(line_content) > 79:
92
 
                    print (
93
 
                        '\nFile %s\nline %i is longer than 79 characters:'
94
 
                        '\n"%s"'% (new_filename, i+1+j1, line_content))
95
 
 
96
 
    for group in sequence_matcher(None, oldlines, newlines
97
 
            ).get_grouped_opcodes(0):
98
 
        for tag, i1, i2, j1, j2 in group:
99
 
            if tag == 'replace' or tag == 'insert':
100
 
                check_newlines(j1, j2)
101
 
 
102
 
    if len(newlines) == j2 and not newlines[j2-1].endswith('\n'):
103
 
        start_if_needed()
104
 
        to_file.write("\\ No newline at end of file\n")
105
 
 
106
 
 
107
53
class TestSourceHelper(TestCase):
108
54
 
109
55
    def source_file_name(self, package):
135
81
        # do not even think of increasing this number. If you think you need to
136
82
        # increase it, then you almost certainly are doing something wrong as
137
83
        # the relationship from working_tree to branch is one way.
138
 
        # Note that this is an exact equality so that when the number drops, 
 
84
        # Note that this is an exact equality so that when the number drops,
139
85
        #it is not given a buffer but rather has this test updated immediately.
140
86
        self.assertEqual(0, occurences)
141
87
 
165
111
 
166
112
    def get_source_files(self):
167
113
        """Yield all source files for bzr and bzrlib
168
 
        
 
114
 
169
115
        :param our_files_only: If true, exclude files from included libraries
170
116
            or plugins.
171
117
        """
316
262
 
317
263
            self.fail('\n'.join(help_text))
318
264
 
319
 
    def test_no_tabs(self):
320
 
        """bzrlib source files should not contain any tab characters."""
321
 
        incorrect = []
322
 
 
323
 
        for fname, text in self.get_source_file_contents():
324
 
            if not self.is_our_code(fname):
325
 
                continue
326
 
            if '\t' in text:
327
 
                incorrect.append(fname)
328
 
 
329
 
        if incorrect:
330
 
            self.fail('Tab characters were found in the following source files.'
331
 
              '\nThey should either be replaced by "\\t" or by spaces:'
332
 
              '\n\n    %s'
333
 
              % ('\n    '.join(incorrect)))
 
265
    def _push_file(self, dict_, fname, line_no):
 
266
        if fname not in dict_:
 
267
            dict_[fname] = [line_no]
 
268
        else:
 
269
            dict_[fname].append(line_no)
 
270
 
 
271
    def _format_message(self, dict_, message):
 
272
        files = ["%s: %s" % (f, ', '.join([str(i+1) for i in lines]))
 
273
                for f, lines in dict_.items()]
 
274
        files.sort()
 
275
        return message + '\n\n    %s' % ('\n    '.join(files))
334
276
 
335
277
    def test_coding_style(self):
336
 
        """ Check if bazaar code conforms to some coding style conventions.
 
278
        """Check if bazaar code conforms to some coding style conventions.
337
279
 
338
 
        Currently we check all .py files for:
339
 
         * new trailing white space
340
 
         * new leading tabs
341
 
         * new long lines (give warning only)
 
280
        Currently we check for:
 
281
         * any tab characters
 
282
         * trailing white space
 
283
         * non-unix newlines
342
284
         * no newline at end of files
 
285
         * lines longer than 79 chars
 
286
           (only print how many files and lines are in violation)
343
287
        """
344
 
        bzr_dir = osutils.dirname(self.get_bzrlib_dir())
345
 
        try:
346
 
            wt = WorkingTree.open(bzr_dir)
347
 
        except:
348
 
            raise TestSkipped(
349
 
                'Could not open bazaar working tree %s'
350
 
                % bzr_dir)
351
 
        diff_output = StringIO()
352
 
        wt.lock_read()
353
 
        try:
354
 
            new_tree = wt
355
 
            old_tree = new_tree.basis_tree()
356
 
 
357
 
            old_tree.lock_read()
358
 
            new_tree.lock_read()
359
 
            try:
360
 
                iterator = new_tree.iter_changes(old_tree)
361
 
                for (file_id, paths, changed_content, versioned, parent,
362
 
                    name, kind, executable) in iterator:
363
 
                    if (changed_content and paths[1].endswith('.py')):
364
 
                        if kind == ('file', 'file'):
365
 
                            diff_text = diff.DiffText(old_tree, new_tree,
366
 
                                to_file=diff_output,
367
 
                                text_differ=check_coding_style)
368
 
                            diff_text.diff(file_id, paths[0], paths[1],
369
 
                                kind[0], kind[1])
370
 
                        else:
371
 
                            check_coding_style(name[0], (), name[1],
372
 
                                new_tree.get_file(file_id).readlines(),
373
 
                                diff_output)
374
 
            finally:
375
 
                old_tree.unlock()
376
 
                new_tree.unlock()
377
 
        finally:
378
 
            wt.unlock()
379
 
        if len(diff_output.getvalue()) > 0:
380
 
            self.fail("Unacceptable coding style:\n" + diff_output.getvalue())
 
288
        tabs = {}
 
289
        trailing_ws = {}
 
290
        illegal_newlines = {}
 
291
        long_lines = {}
 
292
        no_newline_at_eof = []
 
293
        for fname, text in self.get_source_file_contents():
 
294
            if not self.is_our_code(fname):
 
295
                continue
 
296
            lines = text.splitlines(True)
 
297
            last_line_no = len(lines) - 1
 
298
            for line_no, line in enumerate(lines):
 
299
                if '\t' in line:
 
300
                    self._push_file(tabs, fname, line_no)
 
301
                if not line.endswith('\n') or line.endswith('\r\n'):
 
302
                    if line_no != last_line_no: # not no_newline_at_eof
 
303
                        self._push_file(illegal_newlines, fname, line_no)
 
304
                if line.endswith(' \n'):
 
305
                    self._push_file(trailing_ws, fname, line_no)
 
306
                if len(line) > 80:
 
307
                    self._push_file(long_lines, fname, line_no)
 
308
            if not lines[-1].endswith('\n'):
 
309
                no_newline_at_eof.append(fname)
 
310
        problems = []
 
311
        if tabs:
 
312
            problems.append(self._format_message(tabs,
 
313
                'Tab characters were found in the following source files.'
 
314
                '\nThey should either be replaced by "\\t" or by spaces:'))
 
315
        if trailing_ws:
 
316
            problems.append(self._format_message(trailing_ws,
 
317
                'Trailing white space was found in the following source files:'
 
318
                ))
 
319
        if illegal_newlines:
 
320
            problems.append(self._format_message(illegal_newlines,
 
321
                'Non-unix newlines were found in the following source files:'))
 
322
        if long_lines:
 
323
            print ("There are %i lines longer than 79 characters in %i files."
 
324
                % (sum([len(lines) for f, lines in long_lines.items()]),
 
325
                    len(long_lines)))
 
326
        if no_newline_at_eof:
 
327
            no_newline_at_eof.sort()
 
328
            problems.append("The following source files doesn't have a "
 
329
                "newline at the end:"
 
330
               '\n\n    %s'
 
331
               % ('\n    '.join(no_newline_at_eof)))
 
332
        if problems:
 
333
            self.fail('\n\n'.join(problems))
381
334
 
382
335
    def test_no_asserts(self):
383
336
        """bzr shouldn't use the 'assert' statement."""