diff --git a/flake8/engine.py b/flake8/engine.py index 9cbdf6d..0f440c1 100644 --- a/flake8/engine.py +++ b/flake8/engine.py @@ -120,7 +120,8 @@ class StyleGuide(object): ]) def __init__(self, **kwargs): - self._styleguide = NoQAStyleGuide(**kwargs) + # This allows us to inject a mocked StyleGuide in the tests. + self._styleguide = kwargs.pop('styleguide', NoQAStyleGuide(**kwargs)) @property def options(self): @@ -139,8 +140,8 @@ class StyleGuide(object): """ try: return func(*args, **kwargs) - except IOError as ioerr: - if ioerr.errno in self.serial_retry_errors: + except OSError as oserr: + if oserr.errno in self.serial_retry_errors: self.init_report(pep8.StandardReport) else: raise @@ -161,7 +162,7 @@ class StyleGuide(object): filename=filename, lines=lines, expected=expected, - line_offset=0, + line_offset=line_offset, ) diff --git a/flake8/tests/test_engine.py b/flake8/tests/test_engine.py index 60b388c..a6faab5 100644 --- a/flake8/tests/test_engine.py +++ b/flake8/tests/test_engine.py @@ -1,5 +1,6 @@ from __future__ import with_statement +import errno import unittest try: from unittest import mock @@ -7,6 +8,7 @@ except ImportError: import mock # < PY33 from flake8 import engine, util, __version__, reporter +import pep8 class TestEngine(unittest.TestCase): @@ -112,5 +114,87 @@ class TestEngine(unittest.TestCase): assert 'X' not in sg.options.ignore +def oserror_generator(error_number, message='Ominous OSError message'): + def oserror_side_effect(*args, **kwargs): + if hasattr(oserror_side_effect, 'used'): + return + + oserror_side_effect.used = True + raise OSError(error_number, message) + + return oserror_side_effect + + +class TestStyleGuide(unittest.TestCase): + def setUp(self): + mocked_styleguide = mock.Mock(spec=engine.NoQAStyleGuide) + self.styleguide = engine.StyleGuide(styleguide=mocked_styleguide) + self.mocked_sg = mocked_styleguide + + def test_proxies_excluded(self): + self.styleguide.excluded('file.py', parent='.') + + self.mocked_sg.excluded.assert_called_once_with('file.py', parent='.') + + def test_proxies_init_report(self): + reporter = object() + self.styleguide.init_report(reporter) + + self.mocked_sg.init_report.assert_called_once_with(reporter) + + def test_proxies_check_files(self): + self.styleguide.check_files(['foo', 'bar']) + + self.mocked_sg.check_files.assert_called_once_with( + paths=['foo', 'bar'] + ) + + def test_proxies_input_file(self): + self.styleguide.input_file('file.py', + lines=[9, 10], + expected='foo', + line_offset=20) + + self.mocked_sg.input_file.assert_called_once_with(filename='file.py', + lines=[9, 10], + expected='foo', + line_offset=20) + + def test_check_files_retries_on_specific_OSErrors(self): + self.mocked_sg.check_files.side_effect = oserror_generator( + errno.ENOSPC, 'No space left on device' + ) + + self.styleguide.check_files(['foo', 'bar']) + + self.mocked_sg.init_report.assert_called_once_with(pep8.StandardReport) + + def test_input_file_retries_on_specific_OSErrors(self): + self.mocked_sg.input_file.side_effect = oserror_generator( + errno.ENOSPC, 'No space left on device' + ) + + self.styleguide.input_file('file.py') + + self.mocked_sg.init_report.assert_called_once_with(pep8.StandardReport) + + def test_check_files_reraises_unknown_OSErrors(self): + self.mocked_sg.check_files.side_effect = oserror_generator( + errno.EADDRINUSE, + 'lol why are we talking about binding to sockets' + ) + + self.assertRaises(OSError, self.styleguide.check_files, + ['foo', 'bar']) + + def test_input_file_reraises_unknown_OSErrors(self): + self.mocked_sg.input_file.side_effect = oserror_generator( + errno.EADDRINUSE, + 'lol why are we talking about binding to sockets' + ) + + self.assertRaises(OSError, self.styleguide.input_file, + ['foo', 'bar']) + if __name__ == '__main__': unittest.main()