Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions cpp_linter_hooks/clang_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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:
Expand All @@ -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__":
Expand Down
31 changes: 16 additions & 15 deletions tests/test_clang_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down