diff --git a/cpp_linter_hooks/clang_format.py b/cpp_linter_hooks/clang_format.py index 7378524..ab74086 100644 --- a/cpp_linter_hooks/clang_format.py +++ b/cpp_linter_hooks/clang_format.py @@ -31,6 +31,11 @@ def run_clang_format(args=None) -> Tuple[int, str]: command.extend(other_args) + # Auto-inject --Werror when --dry-run is used, so clang-format returns + # non-zero when formatting changes are needed (mirrors-clang-format behavior). + if "--dry-run" in command and "--Werror" not in command: + command.append("--Werror") + try: # Run the clang-format command with captured output sp = subprocess.run( @@ -43,11 +48,7 @@ def run_clang_format(args=None) -> Tuple[int, str]: # Combine stdout and stderr for complete output output = (sp.stdout or "") + (sp.stderr or "") - # Handle special case for dry-run mode - if "--dry-run" in command: - retval = -1 # Special code to identify dry-run mode - else: - retval = sp.returncode + retval = sp.returncode # Print verbose information if requested if hook_args.verbose: @@ -71,12 +72,10 @@ def main() -> int: """Run clang-format as a command-line entry point.""" retval, output = run_clang_format() # pragma: no cover - # Print output for errors, but not for dry-run mode - if retval != 0 and retval != -1 and output.strip(): # pragma: no cover + if retval != 0 and output.strip(): # pragma: no cover print(output) - # Convert dry-run special code to success - return 0 if retval == -1 else retval # pragma: no cover + return retval # pragma: no cover if __name__ == "__main__": diff --git a/tests/test_clang_format.py b/tests/test_clang_format.py index 9eb8901..215f60b 100644 --- a/tests/test_clang_format.py +++ b/tests/test_clang_format.py @@ -54,22 +54,23 @@ def test_run_clang_format_invalid(args, expected_retval, tmp_path): @pytest.mark.benchmark -@pytest.mark.parametrize( - ("args", "expected_retval"), - ( - ( - [ - "--style=Google", - ], - 1, - ), - ), -) -def test_run_clang_format_dry_run(args, expected_retval, tmp_path): - # copy test file to tmp_path to prevent modifying repo data +def test_run_clang_format_dry_run_unformatted(tmp_path): + """Dry-run detects unformatted files and returns non-zero.""" test_file = tmp_path / "main.c" - ret, _ = run_clang_format(["--dry-run", str(test_file)]) - assert ret == -1 # Dry run should not fail + test_file.write_bytes(Path("testing/main.c").read_bytes()) + ret, output = run_clang_format(["--dry-run", "--style=Google", str(test_file)]) + assert ret == 1 # Should report failure (unformatted) + assert output.strip() # Should report which file needs formatting + + +@pytest.mark.benchmark +def test_run_clang_format_dry_run_formatted(tmp_path): + """Dry-run on already-formatted files returns success.""" + test_file = tmp_path / "good.c" + test_file.write_bytes(Path("testing/good.c").read_bytes()) + ret, output = run_clang_format(["--dry-run", "--style=Google", str(test_file)]) + assert ret == 0 # Already formatted + assert not output.strip() # No diff output @pytest.mark.benchmark