56
50
# but for compatibility with previous releases, we don't want to move it.
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)
67
if sequence_matcher is None:
68
sequence_matcher = patiencediff.PatienceSequenceMatcher
70
started = [False] #trick to access parent scoped variable
71
def start_if_needed():
73
to_file.write('+++ %s\n' % new_filename)
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)
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))
85
to_file.write('line %i has leading tabs: "%s"\n'% (
86
i+1+j1, line_content))
87
if has_trailing_whitespace:
89
to_file.write('line %i has trailing whitespace: "%s"\n'% (
90
i+1+j1, line_content))
91
if len(line_content) > 79:
93
'\nFile %s\nline %i is longer than 79 characters:'
94
'\n"%s"'% (new_filename, i+1+j1, line_content))
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)
102
if len(newlines) == j2 and not newlines[j2-1].endswith('\n'):
104
to_file.write("\\ No newline at end of file\n")
107
53
class TestSourceHelper(TestCase):
109
55
def source_file_name(self, package):
317
263
self.fail('\n'.join(help_text))
319
def test_no_tabs(self):
320
"""bzrlib source files should not contain any tab characters."""
323
for fname, text in self.get_source_file_contents():
324
if not self.is_our_code(fname):
327
incorrect.append(fname)
330
self.fail('Tab characters were found in the following source files.'
331
'\nThey should either be replaced by "\\t" or by spaces:'
333
% ('\n '.join(incorrect)))
265
def _push_file(self, dict_, fname, line_no):
266
if fname not in dict_:
267
dict_[fname] = [line_no]
269
dict_[fname].append(line_no)
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()]
275
return message + '\n\n %s' % ('\n '.join(files))
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.
338
Currently we check all .py files for:
339
* new trailing white space
341
* new long lines (give warning only)
280
Currently we check for:
282
* trailing white space
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)
344
bzr_dir = osutils.dirname(self.get_bzrlib_dir())
346
wt = WorkingTree.open(bzr_dir)
349
'Could not open bazaar working tree %s'
351
diff_output = StringIO()
355
old_tree = new_tree.basis_tree()
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,
367
text_differ=check_coding_style)
368
diff_text.diff(file_id, paths[0], paths[1],
371
check_coding_style(name[0], (), name[1],
372
new_tree.get_file(file_id).readlines(),
379
if len(diff_output.getvalue()) > 0:
380
self.fail("Unacceptable coding style:\n" + diff_output.getvalue())
290
illegal_newlines = {}
292
no_newline_at_eof = []
293
for fname, text in self.get_source_file_contents():
294
if not self.is_our_code(fname):
296
lines = text.splitlines(True)
297
last_line_no = len(lines) - 1
298
for line_no, line in enumerate(lines):
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)
307
self._push_file(long_lines, fname, line_no)
308
if not lines[-1].endswith('\n'):
309
no_newline_at_eof.append(fname)
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:'))
316
problems.append(self._format_message(trailing_ws,
317
'Trailing white space was found in the following source files:'
320
problems.append(self._format_message(illegal_newlines,
321
'Non-unix newlines were found in the following source files:'))
323
print ("There are %i lines longer than 79 characters in %i files."
324
% (sum([len(lines) for f, lines in long_lines.items()]),
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:"
331
% ('\n '.join(no_newline_at_eof)))
333
self.fail('\n\n'.join(problems))
382
335
def test_no_asserts(self):
383
336
"""bzr shouldn't use the 'assert' statement."""