56
51
# 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
54
class TestSourceHelper(TestCase):
109
56
def source_file_name(self, package):
317
264
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)))
266
def _push_file(self, dict_, fname, line_no):
267
if fname not in dict_:
268
dict_[fname] = [line_no]
270
dict_[fname].append(line_no)
272
def _format_message(self, dict_, message):
273
files = ["%s: %s" % (f, ', '.join([str(i+1) for i in lines]))
274
for f, lines in dict_.items()]
276
return message + '\n\n %s' % ('\n '.join(files))
335
278
def test_coding_style(self):
336
""" Check if bazaar code conforms to some coding style conventions.
279
"""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)
281
Currently we check for:
283
* trailing white space
342
285
* no newline at end of files
286
* lines longer than 79 chars
287
(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())
291
illegal_newlines = {}
293
no_newline_at_eof = []
294
for fname, text in self.get_source_file_contents():
295
if not self.is_our_code(fname):
297
lines = text.splitlines(True)
298
last_line_no = len(lines) - 1
299
for line_no, line in enumerate(lines):
301
self._push_file(tabs, fname, line_no)
302
if not line.endswith('\n') or line.endswith('\r\n'):
303
if line_no != last_line_no: # not no_newline_at_eof
304
self._push_file(illegal_newlines, fname, line_no)
305
if line.endswith(' \n'):
306
self._push_file(trailing_ws, fname, line_no)
308
self._push_file(long_lines, fname, line_no)
309
if not lines[-1].endswith('\n'):
310
no_newline_at_eof.append(fname)
313
problems.append(self._format_message(tabs,
314
'Tab characters were found in the following source files.'
315
'\nThey should either be replaced by "\\t" or by spaces:'))
317
problems.append(self._format_message(trailing_ws,
318
'Trailing white space was found in the following source files:'
321
problems.append(self._format_message(illegal_newlines,
322
'Non-unix newlines were found in the following source files:'))
324
print ("There are %i lines longer than 79 characters in %i files."
325
% (sum([len(lines) for f, lines in long_lines.items()]),
327
if no_newline_at_eof:
328
no_newline_at_eof.sort()
329
problems.append("The following source files doesn't have a "
330
"newline at the end:"
332
% ('\n '.join(no_newline_at_eof)))
334
raise KnownFailure("test_coding_style has failed")
335
self.fail('\n\n'.join(problems))
382
337
def test_no_asserts(self):
383
338
"""bzr shouldn't use the 'assert' statement."""