Spaces:
Configuration error
Configuration error
DeWitt Gibson
commited on
Commit
·
d122202
1
Parent(s):
0deccde
Upload test package
Browse files- .circleci/config.yml +27 -38
- tests/conftest.py +105 -0
- tests/data/test_privacy_guard.py +259 -0
- tests/utils/test_utils.py +25 -0
.circleci/config.yml
CHANGED
@@ -1,51 +1,40 @@
|
|
1 |
-
#
|
2 |
-
# Stacks detected: deps:python:.,file:setup.py:.
|
3 |
version: 2.1
|
|
|
4 |
orbs:
|
5 |
-
python: circleci/python@2
|
|
|
6 |
jobs:
|
7 |
-
test
|
8 |
-
# Install dependencies and run tests
|
9 |
docker:
|
10 |
-
- image: cimg/python:3.
|
11 |
steps:
|
12 |
- checkout
|
|
|
|
|
13 |
- python/install-packages:
|
14 |
-
pkg-manager: pip
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
- run:
|
16 |
name: Run tests
|
17 |
-
command:
|
|
|
|
|
|
|
18 |
- store_test_results:
|
19 |
-
path:
|
20 |
-
|
21 |
-
|
22 |
-
docker:
|
23 |
-
- image: cimg/python:3.8-node
|
24 |
-
steps:
|
25 |
-
- checkout
|
26 |
-
- run:
|
27 |
-
name: Create the ~/artifacts directory if it doesn't exist
|
28 |
-
command: mkdir -p ~/artifacts
|
29 |
-
- python/dist
|
30 |
- store_artifacts:
|
31 |
-
path:
|
32 |
-
destination:
|
33 |
-
|
34 |
-
# This is an example deploy job, not actually used by the workflow
|
35 |
-
docker:
|
36 |
-
- image: cimg/base:stable
|
37 |
-
steps:
|
38 |
-
# Replace this with steps to deploy to users
|
39 |
-
- run:
|
40 |
-
name: deploy
|
41 |
-
command: '#e.g. ./deploy.sh'
|
42 |
workflows:
|
43 |
-
|
44 |
jobs:
|
45 |
-
- test
|
46 |
-
- build-package:
|
47 |
-
requires:
|
48 |
-
- test-python
|
49 |
-
# - deploy:
|
50 |
-
# requires:
|
51 |
-
# - build-package
|
|
|
1 |
+
# .circleci/config.yml
|
|
|
2 |
version: 2.1
|
3 |
+
|
4 |
orbs:
|
5 |
+
python: circleci/python@2.1
|
6 |
+
|
7 |
jobs:
|
8 |
+
build-and-test:
|
|
|
9 |
docker:
|
10 |
+
- image: cimg/python:3.9
|
11 |
steps:
|
12 |
- checkout
|
13 |
+
|
14 |
+
# Create and activate virtual environment
|
15 |
- python/install-packages:
|
16 |
+
pkg-manager: pip
|
17 |
+
# Create a virtual environment
|
18 |
+
venv-create: true
|
19 |
+
# Use requirements.txt for dependencies
|
20 |
+
pip-dependency-file: requirements/dev.txt
|
21 |
+
|
22 |
+
# Run tests
|
23 |
- run:
|
24 |
name: Run tests
|
25 |
+
command: |
|
26 |
+
python -m pytest tests/ -v
|
27 |
+
|
28 |
+
# Store test results
|
29 |
- store_test_results:
|
30 |
+
path: test-results
|
31 |
+
|
32 |
+
# Store test reports
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
- store_artifacts:
|
34 |
+
path: test-results
|
35 |
+
destination: tr1
|
36 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
workflows:
|
38 |
+
main:
|
39 |
jobs:
|
40 |
+
- build-and-test
|
|
|
|
|
|
|
|
|
|
|
|
tests/conftest.py
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
tests/conftest.py - Pytest configuration and shared fixtures
|
3 |
+
"""
|
4 |
+
|
5 |
+
import pytest
|
6 |
+
import os
|
7 |
+
import json
|
8 |
+
from pathlib import Path
|
9 |
+
from typing import Dict, Any
|
10 |
+
from llmguardian.core.logger import SecurityLogger
|
11 |
+
from llmguardian.core.config import Config
|
12 |
+
|
13 |
+
@pytest.fixture(scope="session")
|
14 |
+
def test_data_dir() -> Path:
|
15 |
+
"""Get test data directory"""
|
16 |
+
return Path(__file__).parent / "data"
|
17 |
+
|
18 |
+
@pytest.fixture(scope="session")
|
19 |
+
def test_config() -> Dict[str, Any]:
|
20 |
+
"""Load test configuration"""
|
21 |
+
config_path = Path(__file__).parent / "config" / "test_config.json"
|
22 |
+
with open(config_path) as f:
|
23 |
+
return json.load(f)
|
24 |
+
|
25 |
+
@pytest.fixture
|
26 |
+
def security_logger():
|
27 |
+
"""Create a security logger for testing"""
|
28 |
+
return SecurityLogger(log_path=str(Path(__file__).parent / "logs"))
|
29 |
+
|
30 |
+
@pytest.fixture
|
31 |
+
def config(test_config):
|
32 |
+
"""Create a configuration instance for testing"""
|
33 |
+
return Config(config_data=test_config)
|
34 |
+
|
35 |
+
@pytest.fixture
|
36 |
+
def temp_dir(tmpdir):
|
37 |
+
"""Create a temporary directory for test files"""
|
38 |
+
return Path(tmpdir)
|
39 |
+
|
40 |
+
@pytest.fixture
|
41 |
+
def sample_text_data():
|
42 |
+
"""Sample text data for testing"""
|
43 |
+
return {
|
44 |
+
"clean": "This is a clean text without sensitive information.",
|
45 |
+
"with_pii": "Contact john.doe@example.com or call 123-456-7890",
|
46 |
+
"with_phi": "Patient medical record #12345: Diagnosis notes",
|
47 |
+
"with_financial": "Credit card: 4111-1111-1111-1111",
|
48 |
+
"with_credentials": "API key: xyz123abc",
|
49 |
+
"with_location": "IP: 192.168.1.1, GPS: 37.7749, -122.4194",
|
50 |
+
"mixed": """
|
51 |
+
Name: John Doe
|
52 |
+
Email: john.doe@example.com
|
53 |
+
SSN: 123-45-6789
|
54 |
+
Credit Card: 4111-1111-1111-1111
|
55 |
+
Medical ID: PHI123456
|
56 |
+
Password: secret123
|
57 |
+
"""
|
58 |
+
}
|
59 |
+
|
60 |
+
@pytest.fixture
|
61 |
+
def sample_vectors():
|
62 |
+
"""Sample vector data for testing"""
|
63 |
+
return {
|
64 |
+
"clean": [0.1, 0.2, 0.3],
|
65 |
+
"suspicious": [0.9, 0.8, 0.7],
|
66 |
+
"anomalous": [10.0, -10.0, 5.0]
|
67 |
+
}
|
68 |
+
|
69 |
+
@pytest.fixture
|
70 |
+
def test_rules():
|
71 |
+
"""Test privacy rules"""
|
72 |
+
return {
|
73 |
+
"test_rule_1": {
|
74 |
+
"name": "Test Rule 1",
|
75 |
+
"category": "PII",
|
76 |
+
"level": "CONFIDENTIAL",
|
77 |
+
"patterns": [r"\b\w+@\w+\.\w+\b"],
|
78 |
+
"actions": ["mask"]
|
79 |
+
},
|
80 |
+
"test_rule_2": {
|
81 |
+
"name": "Test Rule 2",
|
82 |
+
"category": "PHI",
|
83 |
+
"level": "RESTRICTED",
|
84 |
+
"patterns": [r"medical.*\d+"],
|
85 |
+
"actions": ["block", "alert"]
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
@pytest.fixture(autouse=True)
|
90 |
+
def setup_teardown():
|
91 |
+
"""Setup and teardown for each test"""
|
92 |
+
# Setup
|
93 |
+
test_log_dir = Path(__file__).parent / "logs"
|
94 |
+
test_log_dir.mkdir(exist_ok=True)
|
95 |
+
|
96 |
+
yield
|
97 |
+
|
98 |
+
# Teardown
|
99 |
+
for f in test_log_dir.glob("*.log"):
|
100 |
+
f.unlink()
|
101 |
+
|
102 |
+
@pytest.fixture
|
103 |
+
def mock_security_logger(mocker):
|
104 |
+
"""Create a mocked security logger"""
|
105 |
+
return mocker.patch("llmguardian.core.logger.SecurityLogger")
|
tests/data/test_privacy_guard.py
ADDED
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
tests/data/test_privacy_guard.py - Test cases for privacy protection functionality
|
3 |
+
"""
|
4 |
+
|
5 |
+
import pytest
|
6 |
+
from datetime import datetime
|
7 |
+
from unittest.mock import Mock, patch
|
8 |
+
from llmguardian.data.privacy_guard import (
|
9 |
+
PrivacyGuard,
|
10 |
+
PrivacyRule,
|
11 |
+
PrivacyLevel,
|
12 |
+
DataCategory,
|
13 |
+
PrivacyCheck
|
14 |
+
)
|
15 |
+
from llmguardian.core.exceptions import SecurityError
|
16 |
+
|
17 |
+
@pytest.fixture
|
18 |
+
def security_logger():
|
19 |
+
return Mock()
|
20 |
+
|
21 |
+
@pytest.fixture
|
22 |
+
def privacy_guard(security_logger):
|
23 |
+
return PrivacyGuard(security_logger=security_logger)
|
24 |
+
|
25 |
+
@pytest.fixture
|
26 |
+
def test_data():
|
27 |
+
return {
|
28 |
+
"pii": {
|
29 |
+
"email": "test@example.com",
|
30 |
+
"ssn": "123-45-6789",
|
31 |
+
"phone": "123-456-7890"
|
32 |
+
},
|
33 |
+
"phi": {
|
34 |
+
"medical_record": "Patient health record #12345",
|
35 |
+
"diagnosis": "Test diagnosis for patient"
|
36 |
+
},
|
37 |
+
"financial": {
|
38 |
+
"credit_card": "4111-1111-1111-1111",
|
39 |
+
"bank_account": "123456789"
|
40 |
+
},
|
41 |
+
"credentials": {
|
42 |
+
"password": "password=secret123",
|
43 |
+
"api_key": "api_key=abc123xyz"
|
44 |
+
},
|
45 |
+
"location": {
|
46 |
+
"ip": "192.168.1.1",
|
47 |
+
"coords": "latitude: 37.7749, longitude: -122.4194"
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
class TestPrivacyGuard:
|
52 |
+
def test_initialization(self, privacy_guard):
|
53 |
+
"""Test privacy guard initialization"""
|
54 |
+
assert privacy_guard.rules is not None
|
55 |
+
assert privacy_guard.compiled_patterns is not None
|
56 |
+
assert len(privacy_guard.check_history) == 0
|
57 |
+
|
58 |
+
def test_basic_pii_detection(self, privacy_guard, test_data):
|
59 |
+
"""Test detection of basic PII"""
|
60 |
+
result = privacy_guard.check_privacy(test_data["pii"])
|
61 |
+
assert not result.compliant
|
62 |
+
assert any(v["category"] == DataCategory.PII.value for v in result.violations)
|
63 |
+
assert result.risk_level in ["medium", "high"]
|
64 |
+
|
65 |
+
def test_phi_detection(self, privacy_guard, test_data):
|
66 |
+
"""Test detection of PHI"""
|
67 |
+
result = privacy_guard.check_privacy(test_data["phi"])
|
68 |
+
assert not result.compliant
|
69 |
+
assert any(v["category"] == DataCategory.PHI.value for v in result.violations)
|
70 |
+
assert result.risk_level in ["high", "critical"]
|
71 |
+
|
72 |
+
def test_financial_data_detection(self, privacy_guard, test_data):
|
73 |
+
"""Test detection of financial data"""
|
74 |
+
result = privacy_guard.check_privacy(test_data["financial"])
|
75 |
+
assert not result.compliant
|
76 |
+
assert any(v["category"] == DataCategory.FINANCIAL.value for v in result.violations)
|
77 |
+
|
78 |
+
def test_credential_detection(self, privacy_guard, test_data):
|
79 |
+
"""Test detection of credentials"""
|
80 |
+
result = privacy_guard.check_privacy(test_data["credentials"])
|
81 |
+
assert not result.compliant
|
82 |
+
assert any(v["category"] == DataCategory.CREDENTIALS.value for v in result.violations)
|
83 |
+
assert result.risk_level == "critical"
|
84 |
+
|
85 |
+
def test_location_data_detection(self, privacy_guard, test_data):
|
86 |
+
"""Test detection of location data"""
|
87 |
+
result = privacy_guard.check_privacy(test_data["location"])
|
88 |
+
assert not result.compliant
|
89 |
+
assert any(v["category"] == DataCategory.LOCATION.value for v in result.violations)
|
90 |
+
|
91 |
+
def test_privacy_enforcement(self, privacy_guard, test_data):
|
92 |
+
"""Test privacy enforcement"""
|
93 |
+
enforced = privacy_guard.enforce_privacy(
|
94 |
+
test_data["pii"],
|
95 |
+
PrivacyLevel.CONFIDENTIAL
|
96 |
+
)
|
97 |
+
assert test_data["pii"]["email"] not in enforced
|
98 |
+
assert test_data["pii"]["ssn"] not in enforced
|
99 |
+
assert "***" in enforced
|
100 |
+
|
101 |
+
def test_custom_rule_addition(self, privacy_guard):
|
102 |
+
"""Test adding custom privacy rule"""
|
103 |
+
custom_rule = PrivacyRule(
|
104 |
+
name="custom_test",
|
105 |
+
category=DataCategory.PII,
|
106 |
+
level=PrivacyLevel.CONFIDENTIAL,
|
107 |
+
patterns=[r"test\d{3}"],
|
108 |
+
actions=["mask"]
|
109 |
+
)
|
110 |
+
privacy_guard.add_rule(custom_rule)
|
111 |
+
|
112 |
+
test_content = "test123 is a test string"
|
113 |
+
result = privacy_guard.check_privacy(test_content)
|
114 |
+
assert not result.compliant
|
115 |
+
assert any(v["rule"] == "custom_test" for v in result.violations)
|
116 |
+
|
117 |
+
def test_rule_removal(self, privacy_guard):
|
118 |
+
"""Test rule removal"""
|
119 |
+
initial_rule_count = len(privacy_guard.rules)
|
120 |
+
privacy_guard.remove_rule("pii_basic")
|
121 |
+
assert len(privacy_guard.rules) == initial_rule_count - 1
|
122 |
+
assert "pii_basic" not in privacy_guard.rules
|
123 |
+
|
124 |
+
def test_rule_update(self, privacy_guard):
|
125 |
+
"""Test rule update"""
|
126 |
+
updates = {
|
127 |
+
"patterns": [r"updated\d+"],
|
128 |
+
"actions": ["log"]
|
129 |
+
}
|
130 |
+
privacy_guard.update_rule("pii_basic", updates)
|
131 |
+
assert privacy_guard.rules["pii_basic"].patterns == updates["patterns"]
|
132 |
+
assert privacy_guard.rules["pii_basic"].actions == updates["actions"]
|
133 |
+
|
134 |
+
def test_privacy_stats(self, privacy_guard, test_data):
|
135 |
+
"""Test privacy statistics generation"""
|
136 |
+
# Generate some violations
|
137 |
+
privacy_guard.check_privacy(test_data["pii"])
|
138 |
+
privacy_guard.check_privacy(test_data["phi"])
|
139 |
+
|
140 |
+
stats = privacy_guard.get_privacy_stats()
|
141 |
+
assert stats["total_checks"] == 2
|
142 |
+
assert stats["violation_count"] > 0
|
143 |
+
assert len(stats["risk_levels"]) > 0
|
144 |
+
assert len(stats["categories"]) > 0
|
145 |
+
|
146 |
+
def test_trend_analysis(self, privacy_guard, test_data):
|
147 |
+
"""Test trend analysis"""
|
148 |
+
# Generate historical data
|
149 |
+
for _ in range(3):
|
150 |
+
privacy_guard.check_privacy(test_data["pii"])
|
151 |
+
privacy_guard.check_privacy(test_data["phi"])
|
152 |
+
|
153 |
+
trends = privacy_guard.analyze_trends()
|
154 |
+
assert "violation_frequency" in trends
|
155 |
+
assert "risk_distribution" in trends
|
156 |
+
assert "category_trends" in trends
|
157 |
+
|
158 |
+
def test_configuration_validation(self, privacy_guard):
|
159 |
+
"""Test configuration validation"""
|
160 |
+
validation = privacy_guard.validate_configuration()
|
161 |
+
assert validation["valid"]
|
162 |
+
assert "statistics" in validation
|
163 |
+
assert validation["statistics"]["total_rules"] > 0
|
164 |
+
|
165 |
+
def test_privacy_report(self, privacy_guard, test_data):
|
166 |
+
"""Test privacy report generation"""
|
167 |
+
# Generate some data
|
168 |
+
privacy_guard.check_privacy(test_data["pii"])
|
169 |
+
privacy_guard.check_privacy(test_data["phi"])
|
170 |
+
|
171 |
+
report = privacy_guard.generate_privacy_report()
|
172 |
+
assert "summary" in report
|
173 |
+
assert "risk_analysis" in report
|
174 |
+
assert "category_analysis" in report
|
175 |
+
assert "recommendations" in report
|
176 |
+
|
177 |
+
def test_error_handling(self, privacy_guard):
|
178 |
+
"""Test error handling"""
|
179 |
+
with pytest.raises(SecurityError):
|
180 |
+
privacy_guard.check_privacy(None)
|
181 |
+
|
182 |
+
def test_batch_processing(self, privacy_guard, test_data):
|
183 |
+
"""Test batch privacy checking"""
|
184 |
+
items = [
|
185 |
+
test_data["pii"],
|
186 |
+
test_data["phi"],
|
187 |
+
test_data["financial"]
|
188 |
+
]
|
189 |
+
results = privacy_guard.batch_check_privacy(items)
|
190 |
+
assert results["compliant_items"] >= 0
|
191 |
+
assert results["non_compliant_items"] > 0
|
192 |
+
assert "overall_risk_level" in results
|
193 |
+
|
194 |
+
def test_privacy_impact_simulation(self, privacy_guard, test_data):
|
195 |
+
"""Test privacy impact simulation"""
|
196 |
+
simulation_config = {
|
197 |
+
"scenarios": [
|
198 |
+
{
|
199 |
+
"name": "add_pii",
|
200 |
+
"type": "add_data",
|
201 |
+
"data": "email: new@example.com"
|
202 |
+
}
|
203 |
+
]
|
204 |
+
}
|
205 |
+
results = privacy_guard.simulate_privacy_impact(
|
206 |
+
test_data["pii"],
|
207 |
+
simulation_config
|
208 |
+
)
|
209 |
+
assert "baseline" in results
|
210 |
+
assert "simulations" in results
|
211 |
+
|
212 |
+
@pytest.mark.asyncio
|
213 |
+
async def test_monitoring(self, privacy_guard):
|
214 |
+
"""Test privacy monitoring"""
|
215 |
+
callback_called = False
|
216 |
+
|
217 |
+
def test_callback(issues):
|
218 |
+
nonlocal callback_called
|
219 |
+
callback_called = True
|
220 |
+
|
221 |
+
# Start monitoring
|
222 |
+
privacy_guard.monitor_privacy_compliance(
|
223 |
+
interval=1,
|
224 |
+
callback=test_callback
|
225 |
+
)
|
226 |
+
|
227 |
+
# Generate some violations
|
228 |
+
privacy_guard.check_privacy({"sensitive": "test@example.com"})
|
229 |
+
|
230 |
+
# Wait for monitoring cycle
|
231 |
+
await asyncio.sleep(2)
|
232 |
+
|
233 |
+
privacy_guard.stop_monitoring()
|
234 |
+
assert callback_called
|
235 |
+
|
236 |
+
def test_context_handling(self, privacy_guard, test_data):
|
237 |
+
"""Test context-aware privacy checking"""
|
238 |
+
context = {
|
239 |
+
"source": "test",
|
240 |
+
"environment": "development",
|
241 |
+
"exceptions": ["verified_public_email"]
|
242 |
+
}
|
243 |
+
result = privacy_guard.check_privacy(test_data["pii"], context)
|
244 |
+
assert "context" in result.metadata
|
245 |
+
|
246 |
+
@pytest.mark.parametrize("risk_level,expected", [
|
247 |
+
("low", "low"),
|
248 |
+
("medium", "medium"),
|
249 |
+
("high", "high"),
|
250 |
+
("critical", "critical")
|
251 |
+
])
|
252 |
+
def test_risk_level_comparison(self, privacy_guard, risk_level, expected):
|
253 |
+
"""Test risk level comparison"""
|
254 |
+
other_level = "low"
|
255 |
+
comparison = privacy_guard._compare_risk_levels(risk_level, other_level)
|
256 |
+
assert comparison >= 0 if risk_level != "low" else comparison == 0
|
257 |
+
|
258 |
+
if __name__ == "__main__":
|
259 |
+
pytest.main([__file__])
|
tests/utils/test_utils.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
tests/utils/test_utils.py - Testing utilities and helpers
|
3 |
+
"""
|
4 |
+
|
5 |
+
import json
|
6 |
+
from pathlib import Path
|
7 |
+
from typing import Dict, Any, Optional
|
8 |
+
import numpy as np
|
9 |
+
|
10 |
+
def load_test_data(filename: str) -> Dict[str, Any]:
|
11 |
+
"""Load test data from JSON file"""
|
12 |
+
data_path = Path(__file__).parent.parent / "data" / filename
|
13 |
+
with open(data_path) as f:
|
14 |
+
return json.load(f)
|
15 |
+
|
16 |
+
def compare_privacy_results(result1: Dict[str, Any],
|
17 |
+
result2: Dict[str, Any]) -> bool:
|
18 |
+
"""Compare two privacy check results"""
|
19 |
+
# Compare basic fields
|
20 |
+
if result1["compliant"] != result2["compliant"]:
|
21 |
+
return False
|
22 |
+
if result1["risk_level"] != result2["risk_level"]:
|
23 |
+
return False
|
24 |
+
|
25 |
+
#
|