fix(parser): Correctly handle DOS new lines in 'line' rules
Do not consider the trailing `\r` of a line a part of it.
This commit is contained in:
@@ -78,3 +78,22 @@ class EmptyLinesTestCase(RuleTestCase):
|
||||
'document-start: disable\n')
|
||||
self.check('non empty\n', conf)
|
||||
self.check('non empty\n\n', conf, problem=(2, 1))
|
||||
|
||||
def test_with_dos_newlines(self):
|
||||
conf = ('empty-lines: {max: 2, max-start: 0, max-end: 0}\n'
|
||||
'new-lines: {type: dos}\n'
|
||||
'document-start: disable\n')
|
||||
self.check('---\r\n', conf)
|
||||
self.check('---\r\ntext\r\n\r\ntext\r\n', conf)
|
||||
self.check('\r\n---\r\ntext\r\n\r\ntext\r\n', conf,
|
||||
problem=(1, 1))
|
||||
self.check('\r\n\r\n\r\n---\r\ntext\r\n\r\ntext\r\n', conf,
|
||||
problem=(3, 1))
|
||||
self.check('---\r\ntext\r\n\r\n\r\n\r\ntext\r\n', conf,
|
||||
problem=(5, 1))
|
||||
self.check('---\r\ntext\r\n\r\n\r\n\r\n\r\n\r\n\r\ntext\r\n', conf,
|
||||
problem=(8, 1))
|
||||
self.check('---\r\ntext\r\n\r\ntext\r\n\r\n', conf,
|
||||
problem=(5, 1))
|
||||
self.check('---\r\ntext\r\n\r\ntext\r\n\r\n\r\n\r\n', conf,
|
||||
problem=(7, 1))
|
||||
|
||||
@@ -171,3 +171,12 @@ class LineLengthTestCase(RuleTestCase):
|
||||
'# This is a test to check if “line-length” works nice\n'
|
||||
'with: “unicode characters” that span accross bytes! ↺\n',
|
||||
conf, problem1=(2, 53), problem2=(3, 53))
|
||||
|
||||
def test_with_dos_newlines(self):
|
||||
conf = ('line-length: {max: 10}\n'
|
||||
'new-lines: {type: dos}\n'
|
||||
'new-line-at-end-of-file: disable\n')
|
||||
self.check('---\r\nABCD EFGHI', conf)
|
||||
self.check('---\r\nABCD EFGHI\r\n', conf)
|
||||
self.check('---\r\nABCD EFGHIJ', conf, problem=(2, 11))
|
||||
self.check('---\r\nABCD EFGHIJ\r\n', conf, problem=(2, 11))
|
||||
|
||||
@@ -31,16 +31,20 @@ class NewLinesTestCase(RuleTestCase):
|
||||
self.check('---\r\ntext\r\n', conf)
|
||||
|
||||
def test_unix_type(self):
|
||||
conf = 'new-lines: {type: unix}'
|
||||
conf = ('new-line-at-end-of-file: disable\n'
|
||||
'new-lines: {type: unix}\n')
|
||||
self.check('', conf)
|
||||
self.check('\r', conf)
|
||||
self.check('\n', conf)
|
||||
self.check('\r\n', conf, problem=(1, 1))
|
||||
self.check('---\ntext\n', conf)
|
||||
self.check('---\r\ntext\r\n', conf, problem=(1, 4))
|
||||
|
||||
def test_dos_type(self):
|
||||
conf = 'new-lines: {type: dos}\n'
|
||||
conf = ('new-line-at-end-of-file: disable\n'
|
||||
'new-lines: {type: dos}\n')
|
||||
self.check('', conf)
|
||||
self.check('\r', conf)
|
||||
self.check('\n', conf, problem=(1, 1))
|
||||
self.check('\r\n', conf)
|
||||
self.check('---\ntext\n', conf, problem=(1, 4))
|
||||
|
||||
@@ -77,6 +77,9 @@ def line_generator(buffer):
|
||||
cur = 0
|
||||
next = buffer.find('\n')
|
||||
while next != -1:
|
||||
if next > 0 and buffer[next - 1] == '\r':
|
||||
yield Line(line_no, buffer, start=cur, end=next - 1)
|
||||
else:
|
||||
yield Line(line_no, buffer, start=cur, end=next)
|
||||
cur = next + 1
|
||||
next = buffer.find('\n', cur)
|
||||
|
||||
@@ -66,27 +66,37 @@ DEFAULT = {'max': 2,
|
||||
def check(conf, line):
|
||||
if line.start == line.end and line.end < len(line.buffer):
|
||||
# Only alert on the last blank line of a series
|
||||
if (line.end < len(line.buffer) - 1 and
|
||||
line.buffer[line.end + 1] == '\n'):
|
||||
if (line.end + 2 <= len(line.buffer) and
|
||||
line.buffer[line.end:line.end + 2] == '\n\n'):
|
||||
return
|
||||
elif (line.end + 4 <= len(line.buffer) and
|
||||
line.buffer[line.end:line.end + 4] == '\r\n\r\n'):
|
||||
return
|
||||
|
||||
blank_lines = 0
|
||||
|
||||
while (line.start > blank_lines and
|
||||
line.buffer[line.start - blank_lines - 1] == '\n'):
|
||||
start = line.start
|
||||
while start >= 2 and line.buffer[start - 2:start] == '\r\n':
|
||||
blank_lines += 1
|
||||
start -= 2
|
||||
while start >= 1 and line.buffer[start - 1] == '\n':
|
||||
blank_lines += 1
|
||||
start -= 1
|
||||
|
||||
max = conf['max']
|
||||
|
||||
# Special case: start of document
|
||||
if line.start - blank_lines == 0:
|
||||
if start == 0:
|
||||
blank_lines += 1 # first line doesn't have a preceding \n
|
||||
max = conf['max-start']
|
||||
|
||||
# Special case: end of document
|
||||
# NOTE: The last line of a file is always supposed to end with a new
|
||||
# line. See POSIX definition of a line at:
|
||||
if line.end == len(line.buffer) - 1 and line.buffer[line.end] == '\n':
|
||||
if ((line.end == len(line.buffer) - 1 and
|
||||
line.buffer[line.end] == '\n') or
|
||||
(line.end == len(line.buffer) - 2 and
|
||||
line.buffer[line.end:line.end + 2] == '\r\n')):
|
||||
# Allow the exception of the one-byte file containing '\n'
|
||||
if line.end == 0:
|
||||
return
|
||||
|
||||
@@ -36,10 +36,11 @@ DEFAULT = {'type': 'unix'}
|
||||
def check(conf, line):
|
||||
if line.start == 0 and len(line.buffer) > line.end:
|
||||
if conf['type'] == 'dos':
|
||||
if line.buffer[line.end - 1:line.end + 1] != '\r\n':
|
||||
if (line.end + 2 > len(line.buffer) or
|
||||
line.buffer[line.end:line.end + 2] != '\r\n'):
|
||||
yield LintProblem(1, line.end - line.start + 1,
|
||||
'wrong new line character: expected \\r\\n')
|
||||
else:
|
||||
if line.end > 0 and line.buffer[line.end - 1] == '\r':
|
||||
yield LintProblem(1, line.end - line.start,
|
||||
if line.buffer[line.end] == '\r':
|
||||
yield LintProblem(1, line.end - line.start + 1,
|
||||
'wrong new line character: expected \\n')
|
||||
|
||||
Reference in New Issue
Block a user