Files
claude-scripts/tests/hooks/conftest.py

268 lines
6.4 KiB
Python

"""Pytest configuration and fixtures for hook tests."""
import os
import sys
import tempfile
from collections.abc import Generator
from pathlib import Path
from typing import Any
import pytest
# Add hooks directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "hooks"))
@pytest.fixture
def temp_python_file() -> Generator[Path, None, None]:
"""Create a temporary Python file for testing."""
with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as tmp:
tmp_path = Path(tmp.name)
yield tmp_path
tmp_path.unlink(missing_ok=True)
@pytest.fixture
def mock_hook_input_pretooluse() -> dict[str, Any]:
"""Create mock PreToolUse hook input."""
return {
"tool_name": "Write",
"tool_input": {
"file_path": "test.py",
"content": "def test():\n pass",
},
}
@pytest.fixture
def mock_hook_input_posttooluse() -> dict[str, Any]:
"""Create mock PostToolUse hook input."""
return {
"tool_name": "Write",
"tool_output": {
"file_path": "test.py",
"status": "success",
},
}
@pytest.fixture
def complex_code() -> str:
"""Sample complex code for testing."""
return """
def process_data(data, config, mode, validate, transform, options):
if not data:
return None
if mode == 'simple':
if validate:
if len(data) > 100:
if transform:
if options.get('uppercase'):
return data.upper()
elif options.get('lowercase'):
return data.lower()
else:
return data
else:
return data
else:
if transform and options.get('trim'):
return data.strip()
else:
return data
else:
return data
elif mode == 'complex':
if validate and len(data) > 50:
if transform:
if options.get('reverse'):
return data[::-1]
elif options.get('double'):
return data * 2
else:
return data
else:
return data
else:
return data
else:
return None
"""
@pytest.fixture
def duplicate_code() -> str:
"""Sample code with internal duplicates."""
return """
def calculate_user_total(users):
total = 0
for user in users:
if user.active:
total += user.amount * user.tax_rate
return total
def calculate_product_total(products):
total = 0
for product in products:
if product.active:
total += product.amount * product.tax_rate
return total
def calculate_order_total(orders):
total = 0
for order in orders:
if order.active:
total += order.amount * order.tax_rate
return total
"""
@pytest.fixture
def clean_code() -> str:
"""Sample clean, modern Python code."""
return """
from typing import List, Optional, Dict
from dataclasses import dataclass
@dataclass
class User:
name: str
email: str
active: bool = True
def process_users(users: List[User]) -> Dict[str, int]:
\"\"\"Process active users and return counts.\"\"\"
active_count = sum(1 for user in users if user.active)
return {"active": active_count, "total": len(users)}
def find_user(users: List[User], email: str) -> Optional[User]:
\"\"\"Find user by email.\"\"\"
return next((u for u in users if u.email == email), None)
"""
@pytest.fixture
def non_pep8_code() -> str:
"""Code with PEP8 naming violations."""
return """
def calculateTotal(items): # Should be snake_case
return sum(items)
class user_manager: # Should be PascalCase
def GetUser(self, id): # Should be snake_case
pass
def processHTTPRequest(request): # Should be snake_case
pass
class API_handler: # Should be PascalCase
pass
"""
@pytest.fixture
def old_style_code() -> str:
"""Code with outdated Python patterns."""
return """
def process_data(items):
result = []
for i in range(len(items)): # Should use enumerate
if items[i] != None: # Should use 'is not None'
result.append(items[i])
# Old string formatting
message = "Found %d items" % len(result)
# No type hints
def add(a, b):
return a + b
return result
"""
@pytest.fixture
def test_file_code() -> str:
"""Sample test file code."""
return """
import pytest
def test_something():
assert 1 + 1 == 2
def test_another():
x = 10
y = 20
assert x < y
class TestClass:
def test_method(self):
assert True
"""
@pytest.fixture(autouse=True)
def reset_environment():
"""Reset environment variables before each test."""
# Store original environment
original_env = os.environ.copy()
# Clear quality-related environment variables
quality_vars = [k for k in os.environ if k.startswith("QUALITY_")]
for var in quality_vars:
del os.environ[var]
yield
# Restore original environment
os.environ.clear()
os.environ.update(original_env)
@pytest.fixture
def set_env_strict():
"""Set environment for strict mode."""
os.environ.update(
{
"QUALITY_ENFORCEMENT": "strict",
"QUALITY_DUP_THRESHOLD": "0.7",
"QUALITY_COMPLEXITY_THRESHOLD": "10",
"QUALITY_DUP_ENABLED": "true",
"QUALITY_COMPLEXITY_ENABLED": "true",
"QUALITY_MODERN_ENABLED": "true",
"QUALITY_REQUIRE_TYPES": "true",
},
)
@pytest.fixture
def set_env_permissive():
"""Set environment for permissive mode."""
os.environ.update(
{
"QUALITY_ENFORCEMENT": "permissive",
"QUALITY_DUP_THRESHOLD": "0.9",
"QUALITY_COMPLEXITY_THRESHOLD": "20",
"QUALITY_DUP_ENABLED": "true",
"QUALITY_COMPLEXITY_ENABLED": "true",
"QUALITY_MODERN_ENABLED": "false",
"QUALITY_REQUIRE_TYPES": "false",
},
)
@pytest.fixture
def set_env_posttooluse():
"""Set environment for PostToolUse features."""
os.environ.update(
{
"QUALITY_STATE_TRACKING": "true",
"QUALITY_CROSS_FILE_CHECK": "true",
"QUALITY_VERIFY_NAMING": "true",
"QUALITY_SHOW_SUCCESS": "true",
},
)