| #!/usr/bin/env python3 |
| # Copyright 2023 The Pigweed Authors |
| # |
| # 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 |
| # |
| # https://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. |
| """Tests for cpp_checks.""" |
| |
| import os |
| from pathlib import Path |
| import unittest |
| from unittest.mock import MagicMock, mock_open, patch |
| |
| from pw_presubmit import cpp_checks |
| |
| # pylint: disable=attribute-defined-outside-init |
| |
| |
| def _temproot(): |
| root = Path(os.environ['_PW_ACTUAL_ENVIRONMENT_ROOT']) / 'temp' |
| root.mkdir(exist_ok=True) |
| return root |
| |
| |
| class TestPragmaOnce(unittest.TestCase): |
| """Test pragma_once check.""" |
| |
| def _run(self, contents: str) -> None: |
| self.ctx = MagicMock() |
| self.ctx.fail = MagicMock() |
| self.ctx.format_options.filter_paths = lambda x: x |
| path = MagicMock(spec=Path('include/foo.h')) |
| |
| def mocked_open_read(*args, **kwargs): |
| return mock_open(read_data=contents)(*args, **kwargs) |
| |
| with patch.object(path, 'open', mocked_open_read): |
| self.ctx.paths = [path] |
| cpp_checks.pragma_once(self.ctx) |
| |
| def test_empty(self) -> None: |
| self._run('') |
| self.ctx.fail.assert_called() |
| |
| def test_simple(self) -> None: |
| self._run('#pragma once') |
| self.ctx.fail.assert_not_called() |
| |
| def test_not_first(self) -> None: |
| self._run('1\n2\n3\n#pragma once') |
| self.ctx.fail.assert_not_called() |
| |
| def test_different_pragma(self) -> None: |
| self._run('#pragma thrice') |
| self.ctx.fail.assert_called() |
| |
| |
| def guard(path: Path) -> str: |
| return str(path.name).replace('.', '_').upper() |
| |
| |
| class TestIncludeGuard(unittest.TestCase): |
| """Test pragma_once check.""" |
| |
| def _run(self, contents: str, **kwargs) -> None: |
| self.ctx = MagicMock() |
| self.ctx.format_options.filter_paths = lambda x: x |
| self.ctx.fail = MagicMock() |
| path = MagicMock(spec=Path('abc/def/foo.h')) |
| path.name = 'foo.h' |
| |
| def mocked_open_read(*args, **kwargs): |
| return mock_open(read_data=contents)(*args, **kwargs) |
| |
| with patch.object(path, 'open', mocked_open_read): |
| self.ctx.paths = [path] |
| check = cpp_checks.include_guard_check(**kwargs) |
| check(self.ctx) |
| |
| def test_empty(self) -> None: |
| self._run('') |
| self.ctx.fail.assert_called() |
| |
| def test_simple(self) -> None: |
| self._run('#ifndef FOO_H\n#define FOO_H', guard=guard) |
| self.ctx.fail.assert_not_called() |
| |
| def test_simple_any(self) -> None: |
| self._run('#ifndef BAR_H\n#define BAR_H') |
| self.ctx.fail.assert_not_called() |
| |
| def test_simple_comments(self) -> None: |
| self._run('// abc\n#ifndef BAR_H\n// def\n#define BAR_H\n// ghi') |
| self.ctx.fail.assert_not_called() |
| |
| def test_simple_whitespace(self) -> None: |
| self._run( |
| ' // abc\n #ifndef BAR_H\n// def\n' |
| ' #define BAR_H\n// ghi\n #endif' |
| ) |
| self.ctx.fail.assert_not_called() |
| |
| def test_simple_not_expected(self) -> None: |
| self._run('#ifnef BAR_H\n#define BAR_H', guard=guard) |
| self.ctx.fail.assert_called() |
| |
| def test_no_define(self) -> None: |
| self._run('#ifndef FOO_H') |
| self.ctx.fail.assert_called() |
| |
| def test_non_matching_define(self) -> None: |
| self._run('#ifndef FOO_H\n#define BAR_H') |
| self.ctx.fail.assert_called() |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |