#!/usr/bin/env python3 # Copyright 2022 The Android Open Source Project # # 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. """Unittests for clang-format.""" import contextlib from pathlib import Path import sys import tempfile import unittest DIR = Path(__file__).resolve().parent sys.path.insert(0, str(DIR.parent)) # We have to import our local modules after the sys.path tweak. We can't use # relative imports because this is an executable program, not a module. # pylint: disable=wrong-import-position,import-error import rh.utils CLANG_FORMAT = DIR / 'clang-format.py' @contextlib.contextmanager def git_clang_format(data: str): """Create a fake git-clang-format script.""" with tempfile.TemporaryDirectory(prefix='repohooks-tests') as tempdir: tempdir = Path(tempdir) script = tempdir / 'git-clang-format-fake.sh' script.write_text(f'#!/bin/sh\n{data}', encoding='utf-8') script.chmod(0o755) yield script def run_clang_format(script, args, **kwargs): """Helper to run clang-format.py with fake git-clang-format script.""" kwargs.setdefault('capture_output', True) return rh.utils.run( [CLANG_FORMAT, '--git-clang-format', script] + args, **kwargs) class GitClangFormatExit(unittest.TestCase): """Test git-clang-format parsing.""" def test_diff_exit_0_no_output(self): """Test exit 0 w/no output.""" with git_clang_format('exit 0') as script: result = run_clang_format(script, ['--working-tree']) self.assertEqual(result.stdout, '') def test_diff_exit_0_stderr(self): """Test exit 0 w/stderr output.""" with git_clang_format('echo bad >&2; exit 0') as script: with self.assertRaises(rh.utils.CalledProcessError) as e: run_clang_format(script, ['--working-tree']) self.assertIn('clang-format failed', e.exception.stderr) def test_diff_exit_1_no_output(self): """Test exit 1 w/no output.""" with git_clang_format('exit 1') as script: result = run_clang_format(script, ['--working-tree']) self.assertEqual(result.stdout, '') def test_diff_exit_1_output(self): """Test exit 1 with output.""" with git_clang_format('echo bad; exit 1') as script: with self.assertRaises(rh.utils.CalledProcessError) as e: run_clang_format(script, ['--working-tree']) self.assertIn('clang-format failed', e.exception.stderr) def test_diff_exit_1_stderr(self): """Test exit 1 w/stderr.""" with git_clang_format('echo bad >&2; exit 1') as script: with self.assertRaises(rh.utils.CalledProcessError) as e: run_clang_format(script, ['--working-tree']) self.assertIn('clang-format failed', e.exception.stderr) def test_diff_exit_2(self): """Test exit 2.""" with git_clang_format('exit 2') as script: with self.assertRaises(rh.utils.CalledProcessError) as e: run_clang_format(script, ['--working-tree']) self.assertIn('clang-format failed', e.exception.stderr) def test_fix_exit_1_output(self): """Test fix with incorrect patch syntax.""" with git_clang_format('echo bad patch; exit 1') as script: with self.assertRaises(rh.utils.CalledProcessError) as e: run_clang_format(script, ['--working-tree', '--fix']) self.assertIn('Error: Unable to automatically fix things', e.exception.stderr) if __name__ == '__main__': unittest.main()