diff --git a/tests/rules/test_empty_lines.py b/tests/rules/test_empty_lines.py index b44a8a5..ab17d71 100644 --- a/tests/rules/test_empty_lines.py +++ b/tests/rules/test_empty_lines.py @@ -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)) diff --git a/tests/rules/test_line_length.py b/tests/rules/test_line_length.py index 216317c..c1865f1 100644 --- a/tests/rules/test_line_length.py +++ b/tests/rules/test_line_length.py @@ -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)) diff --git a/tests/rules/test_new_lines.py b/tests/rules/test_new_lines.py index c77a5d7..a76d608 100644 --- a/tests/rules/test_new_lines.py +++ b/tests/rules/test_new_lines.py @@ -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)) diff --git a/yamllint/parser.py b/yamllint/parser.py index ae1ed5f..de331f4 100644 --- a/yamllint/parser.py +++ b/yamllint/parser.py @@ -77,7 +77,10 @@ def line_generator(buffer): cur = 0 next = buffer.find('\n') while next != -1: - yield Line(line_no, buffer, start=cur, end=next) + 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) line_no += 1 diff --git a/yamllint/rules/empty_lines.py b/yamllint/rules/empty_lines.py index 335b125..d9a8c4d 100644 --- a/yamllint/rules/empty_lines.py +++ b/yamllint/rules/empty_lines.py @@ -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 diff --git a/yamllint/rules/new_lines.py b/yamllint/rules/new_lines.py index 3aae90f..686bac2 100644 --- a/yamllint/rules/new_lines.py +++ b/yamllint/rules/new_lines.py @@ -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')