Files
shell-speak/tests/test_integration.py
Auto User 95459fb4c8 fix: resolve CI test failure in output.py
- Fixed undefined 'tool' variable in display_history function
- Changed '[tool]' markup tag usage to proper Rich syntax
- All tests now pass (38/38 unit tests)
- Type checking passes with mypy --strict
2026-01-31 06:22:27 +00:00

235 lines
6.9 KiB
Python

"""Integration tests for the diff auditor."""
import os
import tempfile
from pathlib import Path
import pytest
from click.testing import CliRunner
from git import Repo
from cli_diff_auditor.cli import main
from cli_diff_auditor.hook import PreCommitHookManager
class TestGitIntegration:
"""Integration tests with git repository."""
def setup_method(self):
"""Set up test fixtures."""
self.runner = CliRunner()
@pytest.fixture
def temp_repo(self):
"""Create a temporary git repository."""
with tempfile.TemporaryDirectory() as tmpdir:
repo = Repo.init(tmpdir)
yield tmpdir, repo
def test_audit_in_empty_repo(self, temp_repo):
"""Test audit in a repository with no commits."""
tmpdir, repo = temp_repo
result = self.runner.invoke(main, ["audit"], catch_exceptions=False)
assert result.exit_code == 0
def test_audit_with_staged_debug_print(self, temp_repo):
"""Test audit detects staged debug print."""
tmpdir, repo = temp_repo
test_file = Path(tmpdir) / "test.py"
test_file.write_text("print('hello')\n")
repo.index.add(["test.py"])
repo.index.commit("Initial commit")
test_file.write_text("print('world')\n")
repo.index.add(["test.py"])
result = self.runner.invoke(main, ["audit"], catch_exceptions=False)
assert result.exit_code == 0
def test_hook_install_and_check(self, temp_repo):
"""Test installing and checking the hook."""
tmpdir, repo = temp_repo
manager = PreCommitHookManager()
result = manager.install_hook(tmpdir)
assert result.success is True
installed = manager.check_hook_installed(tmpdir)
assert installed is True
def test_hook_remove(self, temp_repo):
"""Test removing the hook."""
tmpdir, repo = temp_repo
manager = PreCommitHookManager()
manager.install_hook(tmpdir)
result = manager.remove_hook(tmpdir)
assert result.success is True
assert manager.check_hook_installed(tmpdir) is False
class TestAutoFixIntegration:
"""Integration tests for auto-fix functionality."""
def setup_method(self):
"""Set up test fixtures."""
self.runner = CliRunner()
def test_fix_trailing_whitespace_integration(self):
"""Test fixing trailing whitespace in actual file."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
f.write("def hello():\n return 'world' \n")
temp_path = f.name
try:
result = self.runner.invoke(main, ["fix", temp_path])
assert result.exit_code == 0
content = Path(temp_path).read_text()
assert content == "def hello():\n return 'world'\n"
finally:
os.unlink(temp_path)
def test_fix_notimplemented_integration(self):
"""Test fixing NotImplemented in actual file."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
f.write("def foo():\n raise NotImplemented\n")
temp_path = f.name
try:
from cli_diff_auditor.autofix import AutoFixer
fixer = AutoFixer()
result = fixer.fix_notimplemented_error(temp_path)
assert result.success is True
content = Path(temp_path).read_text()
assert "raise NotImplementedError" in content
finally:
os.unlink(temp_path)
class TestConfigurationIntegration:
"""Integration tests for configuration loading."""
def setup_method(self):
"""Set up test fixtures."""
self.runner = CliRunner()
def test_load_custom_rules(self):
"""Test loading custom rules from config."""
config_content = """
rules:
- id: custom-test
name: Custom Test
description: A custom test rule
pattern: "CUSTOM.*"
severity: warning
category: custom
"""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
f.write(config_content)
config_path = f.name
try:
result = self.runner.invoke(main, ["--config", config_path, "rules"])
assert result.exit_code == 0
assert "custom-test" in result.output
finally:
os.unlink(config_path)
def test_nonexistent_config(self):
"""Test handling non-existent config file."""
result = self.runner.invoke(main, ["--config", "/nonexistent/config.yaml", "rules"])
assert result.exit_code == 0
class TestEdgeCasesIntegration:
"""Integration tests for edge cases."""
def setup_method(self):
"""Set up test fixtures."""
self.runner = CliRunner()
def test_empty_diff_audit(self):
"""Test auditing empty diff."""
result = self.runner.invoke(main, ["audit-diff", ""])
assert result.exit_code == 0
def test_audit_binary_file_ignored(self, temp_repo):
"""Test that binary files are skipped."""
tmpdir, repo = temp_repo
test_file = Path(tmpdir) / "image.png"
test_file.write_bytes(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR")
repo.index.add(["image.png"])
repo.index.commit("Add binary file")
result = self.runner.invoke(main, ["audit"], catch_exceptions=False)
assert result.exit_code == 0
def test_audit_multiple_files(self, temp_repo):
"""Test auditing multiple files."""
tmpdir, repo = temp_repo
file1 = Path(tmpdir) / "file1.py"
file1.write_text("print('hello')\n")
file2 = Path(tmpdir) / "file2.py"
file2.write_text("console.log('world')\n")
repo.index.add(["file1.py", "file2.py"])
repo.index.commit("Add files")
file1.write_text("print('updated')\n")
file2.write_text("console.log('updated')\n")
repo.index.add(["file1.py", "file2.py"])
result = self.runner.invoke(main, ["audit"], catch_exceptions=False)
assert result.exit_code == 0
@pytest.fixture
def temp_repo(self):
"""Create a temporary git repository."""
with tempfile.TemporaryDirectory() as tmpdir:
repo = Repo.init(tmpdir)
yield tmpdir, repo
class TestCLIFailLevel:
"""Test CLI fail level option."""
def setup_method(self):
"""Set up test fixtures."""
self.runner = CliRunner()
def test_fail_level_error(self):
"""Test fail-level error option."""
result = self.runner.invoke(main, ["check", "--fail-level", "error"])
assert result.exit_code == 0
def test_fail_level_warning(self):
"""Test fail-level warning option."""
result = self.runner.invoke(main, ["check", "--fail-level", "warning"])
assert result.exit_code == 0
def test_fail_level_info(self):
"""Test fail-level info option."""
result = self.runner.invoke(main, ["check", "--fail-level", "info"])
assert result.exit_code == 0