- Implemented a new function to detect usage of typing.Any in code, which raises warnings during pre-tool use. - Updated the pretooluse_hook to handle quality issues related to typing.Any and integrate it with existing quality checks. - Modified the response structure to include permissionDecision instead of decision for consistency across hooks. - Enhanced test coverage for typing.Any usage detection in both single and multi-edit scenarios. - Adjusted existing tests to reflect changes in response structure and ensure proper validation of quality checks.
197 lines
7.2 KiB
Python
197 lines
7.2 KiB
Python
"""Test QualityConfig class and configuration loading."""
|
|
|
|
import os
|
|
|
|
import pytest
|
|
from code_quality_guard import QualityConfig
|
|
|
|
|
|
class TestQualityConfig:
|
|
"""Test QualityConfig dataclass and environment loading."""
|
|
|
|
def test_default_config(self):
|
|
"""Test default configuration values."""
|
|
config = QualityConfig()
|
|
|
|
# Core settings
|
|
assert config.duplicate_threshold == 0.7
|
|
assert config.duplicate_enabled is True
|
|
assert config.complexity_threshold == 10
|
|
assert config.complexity_enabled is True
|
|
assert config.modernization_enabled is True
|
|
assert config.require_type_hints is True
|
|
assert config.enforcement_mode == "strict"
|
|
|
|
# PostToolUse features
|
|
assert config.state_tracking_enabled is False
|
|
assert config.cross_file_check_enabled is False
|
|
assert config.verify_naming is True
|
|
assert config.show_success is False
|
|
|
|
# Skip patterns
|
|
assert "test_" in config.skip_patterns
|
|
assert "_test.py" in config.skip_patterns
|
|
assert "/tests/" in config.skip_patterns
|
|
assert "/fixtures/" in config.skip_patterns
|
|
|
|
def test_from_env_with_defaults(self):
|
|
"""Test loading config from environment with defaults."""
|
|
config = QualityConfig.from_env()
|
|
|
|
# Should use defaults when env vars not set
|
|
assert config.duplicate_threshold == 0.7
|
|
assert config.complexity_threshold == 10
|
|
assert config.enforcement_mode == "strict"
|
|
|
|
def test_from_env_with_custom_values(self):
|
|
"""Test loading config from environment with custom values."""
|
|
os.environ.update(
|
|
{
|
|
"QUALITY_DUP_THRESHOLD": "0.8",
|
|
"QUALITY_DUP_ENABLED": "false",
|
|
"QUALITY_COMPLEXITY_THRESHOLD": "15",
|
|
"QUALITY_COMPLEXITY_ENABLED": "false",
|
|
"QUALITY_MODERN_ENABLED": "false",
|
|
"QUALITY_REQUIRE_TYPES": "false",
|
|
"QUALITY_ENFORCEMENT": "permissive",
|
|
"QUALITY_STATE_TRACKING": "true",
|
|
"QUALITY_CROSS_FILE_CHECK": "true",
|
|
"QUALITY_VERIFY_NAMING": "false",
|
|
"QUALITY_SHOW_SUCCESS": "true",
|
|
},
|
|
)
|
|
|
|
config = QualityConfig.from_env()
|
|
|
|
assert config.duplicate_threshold == 0.8
|
|
assert config.duplicate_enabled is False
|
|
assert config.complexity_threshold == 15
|
|
assert config.complexity_enabled is False
|
|
assert config.modernization_enabled is False
|
|
assert config.require_type_hints is False
|
|
assert config.enforcement_mode == "permissive"
|
|
assert config.state_tracking_enabled is True
|
|
assert config.cross_file_check_enabled is True
|
|
assert config.verify_naming is False
|
|
assert config.show_success is True
|
|
|
|
def test_from_env_with_invalid_boolean(self):
|
|
"""Test loading config with invalid boolean values."""
|
|
os.environ["QUALITY_DUP_ENABLED"] = "invalid"
|
|
config = QualityConfig.from_env()
|
|
|
|
# Should default to False for invalid boolean
|
|
assert config.duplicate_enabled is False
|
|
|
|
def test_from_env_with_invalid_float(self):
|
|
"""Test loading config with invalid float values."""
|
|
os.environ["QUALITY_DUP_THRESHOLD"] = "not_a_float"
|
|
|
|
with pytest.raises(ValueError, match="could not convert string to float"):
|
|
QualityConfig.from_env()
|
|
|
|
def test_from_env_with_invalid_int(self):
|
|
"""Test loading config with invalid int values."""
|
|
os.environ["QUALITY_COMPLEXITY_THRESHOLD"] = "not_an_int"
|
|
|
|
with pytest.raises(ValueError, match="invalid literal"):
|
|
QualityConfig.from_env()
|
|
|
|
def test_enforcement_modes(self):
|
|
"""Test different enforcement modes."""
|
|
modes = ["strict", "warn", "permissive"]
|
|
|
|
for mode in modes:
|
|
os.environ["QUALITY_ENFORCEMENT"] = mode
|
|
config = QualityConfig.from_env()
|
|
assert config.enforcement_mode == mode
|
|
|
|
def test_skip_patterns_initialization(self):
|
|
"""Test skip patterns initialization."""
|
|
config = QualityConfig(skip_patterns=None)
|
|
assert config.skip_patterns is not None
|
|
assert len(config.skip_patterns) > 0
|
|
|
|
custom_patterns = ["custom_test_", "/custom/"]
|
|
config = QualityConfig(skip_patterns=custom_patterns)
|
|
assert config.skip_patterns == custom_patterns
|
|
|
|
def test_threshold_boundaries(self):
|
|
"""Test threshold boundary values."""
|
|
# Test minimum threshold
|
|
os.environ["QUALITY_DUP_THRESHOLD"] = "0.0"
|
|
config = QualityConfig.from_env()
|
|
assert config.duplicate_threshold == 0.0
|
|
|
|
# Test maximum threshold
|
|
os.environ["QUALITY_DUP_THRESHOLD"] = "1.0"
|
|
config = QualityConfig.from_env()
|
|
assert config.duplicate_threshold == 1.0
|
|
|
|
# Test complexity threshold
|
|
os.environ["QUALITY_COMPLEXITY_THRESHOLD"] = "1"
|
|
config = QualityConfig.from_env()
|
|
assert config.complexity_threshold == 1
|
|
|
|
def test_config_combinations(self):
|
|
"""Test various configuration combinations."""
|
|
test_cases = [
|
|
# All checks disabled
|
|
{
|
|
"env": {
|
|
"QUALITY_DUP_ENABLED": "false",
|
|
"QUALITY_COMPLEXITY_ENABLED": "false",
|
|
"QUALITY_MODERN_ENABLED": "false",
|
|
},
|
|
"expected": {
|
|
"duplicate_enabled": False,
|
|
"complexity_enabled": False,
|
|
"modernization_enabled": False,
|
|
},
|
|
},
|
|
# Only duplicate checking
|
|
{
|
|
"env": {
|
|
"QUALITY_DUP_ENABLED": "true",
|
|
"QUALITY_COMPLEXITY_ENABLED": "false",
|
|
"QUALITY_MODERN_ENABLED": "false",
|
|
},
|
|
"expected": {
|
|
"duplicate_enabled": True,
|
|
"complexity_enabled": False,
|
|
"modernization_enabled": False,
|
|
},
|
|
},
|
|
# PostToolUse only
|
|
{
|
|
"env": {
|
|
"QUALITY_DUP_ENABLED": "false",
|
|
"QUALITY_STATE_TRACKING": "true",
|
|
"QUALITY_VERIFY_NAMING": "true",
|
|
},
|
|
"expected": {
|
|
"duplicate_enabled": False,
|
|
"state_tracking_enabled": True,
|
|
"verify_naming": True,
|
|
},
|
|
},
|
|
]
|
|
|
|
for test_case in test_cases:
|
|
os.environ.clear()
|
|
os.environ.update(test_case["env"])
|
|
config = QualityConfig.from_env()
|
|
|
|
for key, expected_value in test_case["expected"].items():
|
|
assert getattr(config, key) == expected_value
|
|
|
|
def test_case_insensitive_boolean(self):
|
|
"""Test case-insensitive boolean parsing."""
|
|
test_values = ["TRUE", "True", "true", "FALSE", "False", "false"]
|
|
expected = [True, True, True, False, False, False]
|
|
|
|
for value, expected_bool in zip(test_values, expected, strict=False):
|
|
os.environ["QUALITY_DUP_ENABLED"] = value
|
|
config = QualityConfig.from_env()
|
|
assert config.duplicate_enabled == expected_bool
|