# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ test_bashate ---------------------------------- Tests for `bashate` module. """ import mock from bashate import bashate from bashate import messages from bashate.tests import base MESSAGES = messages.MESSAGES class TestBashate(base.TestCase): def setUp(self): super(TestBashate, self).setUp() self.run = bashate.BashateRun() @mock.patch('bashate.bashate.BashateRun') @mock.patch('sys.argv') def test_main_no_files(self, m_bashaterun, m_argv): m_run_obj = mock.MagicMock() m_run_obj.error_count = 0 m_bashaterun.return_value = m_run_obj result = bashate.main() expected_return = 1 self.assertEqual(expected_return, result) @mock.patch('bashate.bashate.BashateRun') @mock.patch('sys.argv') def test_main_return_one_on_errors(self, m_bashaterun, m_argv): m_run_obj = mock.MagicMock() m_run_obj.warning_count = 1 m_run_obj.error_count = 1 m_bashaterun.return_value = m_run_obj result = bashate.main() expected_return = 1 self.assertEqual(expected_return, result) @mock.patch('bashate.bashate.BashateRun') @mock.patch('sys.argv') def test_main_return_one_on_ioerror(self, m_bashaterun, m_argv): m_run_obj = mock.MagicMock() m_run_obj.error_count = 0 m_run_obj.check_files = mock.Mock(side_effect=IOError) m_bashaterun.return_value = m_run_obj result = bashate.main() expected_return = 1 self.assertEqual(expected_return, result) def test_multi_ignore_with_slash(self): self.run.register_ignores('E001|E011') bashate.check_no_trailing_whitespace("if ", self.run) bashate.check_if_then("if ", self.run) self.assertEqual(0, self.run.error_count) def test_multi_ignore_with_comma(self): self.run.register_ignores('E001,E011') bashate.check_no_trailing_whitespace("if ", self.run) bashate.check_if_then("if ", self.run) self.assertEqual(0, self.run.error_count) def test_multi_ignore_mixed(self): self.run.register_ignores('E001|E002,E003|E011') bashate.check_no_trailing_whitespace("if ", self.run) bashate.check_if_then("if ", self.run) bashate.check_indents(" echo", self.run) self.assertEqual(0, self.run.error_count) def test_ignore(self): self.run.register_ignores('E001') bashate.check_no_trailing_whitespace("if ", self.run) self.assertEqual(0, self.run.error_count) @mock.patch('bashate.bashate.BashateRun.print_error') def test_while_check_for_do(self, m_print_error): test_line = 'while `do something args`' bashate.check_for_do(test_line, self.run) m_print_error.assert_called_once_with( MESSAGES['E010'].msg % 'while', test_line) class TestBashateSamples(base.TestCase): """End to end regression testing of bashate against script samples.""" def setUp(self): super(TestBashateSamples, self).setUp() log_error_patcher = mock.patch( 'bashate.bashate.BashateRun.log_error') self.m_log_error = log_error_patcher.start() self.run = bashate.BashateRun() self.addCleanup(log_error_patcher.stop) def assert_error_found(self, error, lineno): error_found = False for call in self.m_log_error.call_args_list: # unwrap args args = call[0] if (args[0].startswith(error) and lineno == args[3]): error_found = True if not error_found: self.fail('Error %s expected at line %d not found!' % (error, lineno)) def test_sample_E001(self): test_files = ['bashate/tests/samples/E001_bad.sh'] self.run.check_files(test_files, False) self.assert_error_found('E001', 4) def test_sample_E002(self): test_files = ['bashate/tests/samples/E002_bad.sh'] self.run.check_files(test_files, False) self.assert_error_found('E002', 3) def test_sample_E006_bad(self): test_files = ['bashate/tests/samples/E006_bad.sh'] self.run.check_files(test_files, False) self.assertEqual(self.run.warning_count, 3) self.assert_error_found('E006', 5) self.assert_error_found('E006', 6) self.assert_error_found('E006', 8) def test_sample_E006_bad_ignore_trailing_ws(self): self.run.register_ignores('E001') test_files = ['bashate/tests/samples/E006_bad.sh'] self.run.check_files(test_files, False) self.assertEqual(self.run.warning_count, 3) self.assert_error_found('E006', 5) self.assert_error_found('E006', 6) self.assert_error_found('E006', 8) def test_sample_E006_good(self): test_files = ['bashate/tests/samples/E006_good.sh'] self.run.check_files(test_files, False) self.assertEqual(self.run.warning_count, 0) def test_sample_E010_good(self): test_files = ['bashate/tests/samples/E010_good.sh'] self.run.check_files(test_files, False) self.assertEqual(self.run.error_count, 0) def test_sample_E010(self): test_files = ['bashate/tests/samples/E010_bad.sh'] self.run.check_files(test_files, False) self.assert_error_found('E010', 3) self.assert_error_found('E010', 9) def test_sample_E011_good(self): test_files = ['bashate/tests/samples/E011_good.sh'] self.run.check_files(test_files, False) self.assertEqual(self.run.error_count, 0) def test_sample_E011(self): test_files = ['bashate/tests/samples/E011_bad.sh'] self.run.check_files(test_files, False) self.assert_error_found('E011', 3) self.assert_error_found('E011', 6) def test_sample_E012(self): test_files = ['bashate/tests/samples/E012_bad.sh'] self.run.check_files(test_files, False) self.assert_error_found('E012', 9) self.assert_error_found('E040', 10) def test_sample_E041(self): test_files = ['bashate/tests/samples/E041_bad.sh'] self.run.check_files(test_files, False) self.assert_error_found('E041', 4) def test_sample_E042(self): test_files = ['bashate/tests/samples/E042_bad.sh'] self.run.register_errors('E042') self.run.check_files(test_files, False) self.assert_error_found('E042', 2) self.assert_error_found('E042', 6) def test_sample_for_loops(self): test_files = ['bashate/tests/samples/for_loops.sh'] self.run.check_files(test_files, False) self.assert_error_found('E010', 14) self.assert_error_found('E010', 20) def test_sample_comments(self): test_files = ['bashate/tests/samples/comments.sh'] self.run.check_files(test_files, False) self.assertEqual(0, self.run.error_count) def test_sample_E005(self): test_files = ['bashate/tests/samples/E005_bad'] self.run.register_errors('E005') self.run.check_files(test_files, False) self.assert_error_found('E005', 1) def test_sample_E040(self): test_files = ['bashate/tests/samples/E040_syntax_error.sh'] self.run.register_errors('E040') self.run.check_files(test_files, False) self.assert_error_found('E040', 7) def test_sample_warning(self): # reuse a couple of the above files to make sure we turn # errors down to warnings if requested test_files = ['bashate/tests/samples/E011_bad.sh', 'bashate/tests/samples/E041_bad.sh'] self.run.register_warnings('E011,E041') self.run.check_files(test_files, False) self.assertEqual(0, self.run.error_count) self.assertEqual(4, self.run.warning_count) def test_ignore_heredoc(self): test_files = ['bashate/tests/samples/heredoc_ignore.sh'] self.run.check_files(test_files, False) self.assertEqual(0, self.run.error_count) def test_pre_zero_dot_one_sample_file(self): """Test the sample file with all pre 0.1.0 release checks. This is a legacy compatibility check to make sure we still catch the same errors as we did before the first 0.1.0 release of the bashate pypi package. There were no tests before this, so it is our baseline regression check. New checks shouldn't need to be added here, and should have their own separate unit test and/or sample file checks. """ test_files = ['bashate/tests/samples/legacy_sample.sh'] self.run.check_files(test_files, False) expected_errors = [ ('E002', 4), ('E003', 6), ('E001', 10), ('E010', 13), ('E010', 18), ('E010', 23), ('E011', 29), ('E020', 3) ] for error in expected_errors: self.assert_error_found(*error)