Files
claude-skills-reference/tests/test_gdpr_compliance.py
Claude 36678cd00d feat(tests): add comprehensive test suite with 1493 tests across 4 phases
Phase 1 - Foundation:
- Add pytest, pyproject.toml, requirements-dev.txt
- 593 smoke tests (324 syntax + 269 argparse --help) for all Python scripts
- Harden CI: remove || true from compileall, expand to all 9 directories, add pytest step

Phase 2 - Calculator unit tests:
- RICE prioritizer: formula, prioritization, portfolio analysis, roadmap
- DCF valuation: WACC, cash flow projections, terminal value, sensitivity
- Financial ratios: profitability, liquidity, leverage, efficiency, valuation
- Campaign ROI: metrics, benchmarks, portfolio summary
- Funnel analyzer: stage metrics, bottleneck detection, segment comparison
- OKR tracker: numeric/percentage/milestone/boolean KR scoring, status

Phase 3 - Parser and compliance tests:
- SEO checker: HTML parsing, scoring, heading hierarchy, alt text, word count
- Commit linter: conventional commit regex, lint report, file input
- GDPR compliance: pattern detection, file scanning, project analysis

Phase 4 - Integration tests:
- 671 skill integrity tests: frontmatter, H1 headings, scripts dirs, references

Bug fixes found by tests:
- Fix duplicate --reason argparse arg in document_version_control.py

https://claude.ai/code/session_01MsVmZoAsPvLv7rAGDBGTbL
2026-03-30 19:54:00 +00:00

134 lines
5.1 KiB
Python

"""Unit tests for the GDPR Compliance Checker."""
import os
import sys
import tempfile
from pathlib import Path
import pytest
sys.path.insert(0, os.path.join(
os.path.dirname(__file__), "..", "ra-qm-team", "gdpr-dsgvo-expert", "scripts"
))
from gdpr_compliance_checker import (
PERSONAL_DATA_PATTERNS,
CODE_PATTERNS,
should_skip,
scan_file_for_patterns,
analyze_project,
)
class TestShouldSkip:
def test_skips_node_modules(self):
assert should_skip(Path("project/node_modules/package/index.js")) is True
def test_skips_venv(self):
assert should_skip(Path("project/venv/lib/site-packages/foo.py")) is True
def test_skips_git(self):
assert should_skip(Path("project/.git/objects/abc123")) is True
def test_allows_normal_path(self):
assert should_skip(Path("project/src/main.py")) is False
def test_allows_deep_path(self):
assert should_skip(Path("project/src/utils/helpers/data.py")) is False
class TestScanFileForPatterns:
def test_detects_email(self):
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write('user_email = "john@example.com"\n')
f.flush()
findings = scan_file_for_patterns(Path(f.name), PERSONAL_DATA_PATTERNS)
os.unlink(f.name)
email_findings = [f for f in findings if f["pattern"] == "email"]
assert len(email_findings) >= 1
assert email_findings[0]["category"] == "contact_data"
def test_detects_health_data(self):
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write('record = {"diagnosis": "flu", "treatment": "rest"}\n')
f.flush()
findings = scan_file_for_patterns(Path(f.name), PERSONAL_DATA_PATTERNS)
os.unlink(f.name)
health_findings = [f for f in findings if f["pattern"] == "health_data"]
assert len(health_findings) >= 1
assert health_findings[0]["risk"] == "critical"
def test_detects_code_logging_issue(self):
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write('log.info("User email: " + user.email)\n')
f.flush()
findings = scan_file_for_patterns(Path(f.name), CODE_PATTERNS)
os.unlink(f.name)
log_findings = [f for f in findings if f["pattern"] == "logging_personal_data"]
assert len(log_findings) >= 1
def test_no_findings_on_clean_file(self):
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write('x = 1 + 2\nprint("hello")\n')
f.flush()
findings = scan_file_for_patterns(Path(f.name), PERSONAL_DATA_PATTERNS)
os.unlink(f.name)
assert len(findings) == 0
def test_handles_unreadable_file(self):
findings = scan_file_for_patterns(Path("/nonexistent/file.py"), PERSONAL_DATA_PATTERNS)
assert findings == []
class TestAnalyzeProject:
def test_scores_clean_project(self):
with tempfile.TemporaryDirectory() as tmpdir:
# Create a clean Python file
src = Path(tmpdir) / "clean.py"
src.write_text("x = 1\ny = 2\nresult = x + y\n", encoding="utf-8")
result = analyze_project(Path(tmpdir))
assert result["summary"]["compliance_score"] == 100
assert result["summary"]["status"] == "compliant"
def test_detects_issues_in_project(self):
with tempfile.TemporaryDirectory() as tmpdir:
src = Path(tmpdir) / "bad.py"
src.write_text(
'user_email = "john@example.com"\n'
'log.info("Patient diagnosis: " + record.diagnosis)\n',
encoding="utf-8",
)
result = analyze_project(Path(tmpdir))
assert result["summary"]["compliance_score"] < 100
assert len(result["personal_data_findings"]) > 0
def test_returns_recommendations(self):
with tempfile.TemporaryDirectory() as tmpdir:
src = Path(tmpdir) / "issues.py"
src.write_text(
'password = "secret123"\n'
'user_email = "test@test.com"\n',
encoding="utf-8",
)
result = analyze_project(Path(tmpdir))
assert "recommendations" in result
assert isinstance(result["recommendations"], list)
class TestPersonalDataPatterns:
"""Test that the regex patterns work correctly."""
@pytest.mark.parametrize("pattern_name,test_string", [
("email", "contact: user@example.com"),
("ip_address", "server IP: 192.168.1.100"),
("phone_number", "call +1-555-123-4567"),
("credit_card", "card: 4111-1111-1111-1111"),
("date_of_birth", "field: date of birth"),
("health_data", "the patient reported symptoms"),
("biometric", "store fingerprint data"),
("religion", "religious preference recorded"),
])
def test_pattern_matches(self, pattern_name, test_string):
import re
pattern = PERSONAL_DATA_PATTERNS[pattern_name]["pattern"]
assert re.search(pattern, test_string, re.IGNORECASE) is not None