mcp-security-framework 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_security_framework/__init__.py +96 -0
- mcp_security_framework/cli/__init__.py +18 -0
- mcp_security_framework/cli/cert_cli.py +511 -0
- mcp_security_framework/cli/security_cli.py +791 -0
- mcp_security_framework/constants.py +209 -0
- mcp_security_framework/core/__init__.py +61 -0
- mcp_security_framework/core/auth_manager.py +1011 -0
- mcp_security_framework/core/cert_manager.py +1663 -0
- mcp_security_framework/core/permission_manager.py +735 -0
- mcp_security_framework/core/rate_limiter.py +602 -0
- mcp_security_framework/core/security_manager.py +943 -0
- mcp_security_framework/core/ssl_manager.py +735 -0
- mcp_security_framework/examples/__init__.py +75 -0
- mcp_security_framework/examples/django_example.py +615 -0
- mcp_security_framework/examples/fastapi_example.py +472 -0
- mcp_security_framework/examples/flask_example.py +506 -0
- mcp_security_framework/examples/gateway_example.py +803 -0
- mcp_security_framework/examples/microservice_example.py +690 -0
- mcp_security_framework/examples/standalone_example.py +576 -0
- mcp_security_framework/middleware/__init__.py +250 -0
- mcp_security_framework/middleware/auth_middleware.py +292 -0
- mcp_security_framework/middleware/fastapi_auth_middleware.py +447 -0
- mcp_security_framework/middleware/fastapi_middleware.py +757 -0
- mcp_security_framework/middleware/flask_auth_middleware.py +465 -0
- mcp_security_framework/middleware/flask_middleware.py +591 -0
- mcp_security_framework/middleware/mtls_middleware.py +439 -0
- mcp_security_framework/middleware/rate_limit_middleware.py +403 -0
- mcp_security_framework/middleware/security_middleware.py +507 -0
- mcp_security_framework/schemas/__init__.py +109 -0
- mcp_security_framework/schemas/config.py +694 -0
- mcp_security_framework/schemas/models.py +709 -0
- mcp_security_framework/schemas/responses.py +686 -0
- mcp_security_framework/tests/__init__.py +0 -0
- mcp_security_framework/utils/__init__.py +121 -0
- mcp_security_framework/utils/cert_utils.py +525 -0
- mcp_security_framework/utils/crypto_utils.py +475 -0
- mcp_security_framework/utils/validation_utils.py +571 -0
- mcp_security_framework-0.1.0.dist-info/METADATA +411 -0
- mcp_security_framework-0.1.0.dist-info/RECORD +76 -0
- mcp_security_framework-0.1.0.dist-info/WHEEL +5 -0
- mcp_security_framework-0.1.0.dist-info/entry_points.txt +3 -0
- mcp_security_framework-0.1.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/test_cli/__init__.py +0 -0
- tests/test_cli/test_cert_cli.py +379 -0
- tests/test_cli/test_security_cli.py +657 -0
- tests/test_core/__init__.py +0 -0
- tests/test_core/test_auth_manager.py +582 -0
- tests/test_core/test_cert_manager.py +795 -0
- tests/test_core/test_permission_manager.py +395 -0
- tests/test_core/test_rate_limiter.py +626 -0
- tests/test_core/test_security_manager.py +841 -0
- tests/test_core/test_ssl_manager.py +532 -0
- tests/test_examples/__init__.py +8 -0
- tests/test_examples/test_fastapi_example.py +264 -0
- tests/test_examples/test_flask_example.py +238 -0
- tests/test_examples/test_standalone_example.py +292 -0
- tests/test_integration/__init__.py +0 -0
- tests/test_integration/test_auth_flow.py +502 -0
- tests/test_integration/test_certificate_flow.py +527 -0
- tests/test_integration/test_fastapi_integration.py +341 -0
- tests/test_integration/test_flask_integration.py +398 -0
- tests/test_integration/test_standalone_integration.py +493 -0
- tests/test_middleware/__init__.py +0 -0
- tests/test_middleware/test_fastapi_middleware.py +523 -0
- tests/test_middleware/test_flask_middleware.py +582 -0
- tests/test_middleware/test_security_middleware.py +493 -0
- tests/test_schemas/__init__.py +0 -0
- tests/test_schemas/test_config.py +811 -0
- tests/test_schemas/test_models.py +879 -0
- tests/test_schemas/test_responses.py +1054 -0
- tests/test_schemas/test_serialization.py +493 -0
- tests/test_utils/__init__.py +0 -0
- tests/test_utils/test_cert_utils.py +510 -0
- tests/test_utils/test_crypto_utils.py +603 -0
- tests/test_utils/test_validation_utils.py +477 -0
@@ -0,0 +1,477 @@
|
|
1
|
+
"""
|
2
|
+
Validation Utilities Test Module
|
3
|
+
|
4
|
+
This module provides comprehensive unit tests for all validation
|
5
|
+
utilities in the MCP Security Framework.
|
6
|
+
|
7
|
+
Test Classes:
|
8
|
+
TestInputValidation: Tests for input data validation
|
9
|
+
TestFormatValidation: Tests for format validation
|
10
|
+
TestDataNormalization: Tests for data normalization
|
11
|
+
TestFileValidation: Tests for file validation
|
12
|
+
|
13
|
+
Author: MCP Security Team
|
14
|
+
Version: 1.0.0
|
15
|
+
License: MIT
|
16
|
+
"""
|
17
|
+
|
18
|
+
import pytest
|
19
|
+
|
20
|
+
from mcp_security_framework.utils.validation_utils import (
|
21
|
+
ValidationError,
|
22
|
+
normalize_data,
|
23
|
+
sanitize_string,
|
24
|
+
validate_configuration_file,
|
25
|
+
validate_directory_structure,
|
26
|
+
validate_email,
|
27
|
+
validate_file_extension,
|
28
|
+
validate_file_path,
|
29
|
+
validate_input_data,
|
30
|
+
validate_ip_address,
|
31
|
+
validate_json_schema,
|
32
|
+
validate_list_content,
|
33
|
+
validate_numeric_range,
|
34
|
+
validate_string_length,
|
35
|
+
validate_url,
|
36
|
+
)
|
37
|
+
|
38
|
+
|
39
|
+
class TestInputValidation:
|
40
|
+
"""Test suite for input data validation."""
|
41
|
+
|
42
|
+
def test_validate_input_data_dict_success(self):
|
43
|
+
"""Test successful dictionary validation."""
|
44
|
+
data = {"name": "test", "age": 25}
|
45
|
+
result = validate_input_data(data, required_fields=["name"], data_type=dict)
|
46
|
+
assert result is True
|
47
|
+
|
48
|
+
def test_validate_input_data_missing_required_fields(self):
|
49
|
+
"""Test validation with missing required fields."""
|
50
|
+
data = {"name": "test"}
|
51
|
+
with pytest.raises(ValidationError) as exc_info:
|
52
|
+
validate_input_data(data, required_fields=["name", "age"])
|
53
|
+
|
54
|
+
assert "Missing required fields" in str(exc_info.value)
|
55
|
+
|
56
|
+
def test_validate_input_data_invalid_fields(self):
|
57
|
+
"""Test validation with invalid fields."""
|
58
|
+
data = {"name": "test", "invalid_field": "value"}
|
59
|
+
with pytest.raises(ValidationError) as exc_info:
|
60
|
+
validate_input_data(data, allowed_fields=["name"])
|
61
|
+
|
62
|
+
assert "Invalid fields" in str(exc_info.value)
|
63
|
+
|
64
|
+
def test_validate_input_data_wrong_type(self):
|
65
|
+
"""Test validation with wrong data type."""
|
66
|
+
data = "not_a_dict"
|
67
|
+
with pytest.raises(ValidationError) as exc_info:
|
68
|
+
validate_input_data(data, data_type=dict)
|
69
|
+
|
70
|
+
assert "Expected dict" in str(exc_info.value)
|
71
|
+
|
72
|
+
def test_validate_input_data_no_constraints(self):
|
73
|
+
"""Test validation without any constraints."""
|
74
|
+
data = {"name": "test", "age": 25}
|
75
|
+
result = validate_input_data(data)
|
76
|
+
assert result is True
|
77
|
+
|
78
|
+
def test_validate_input_data_list_type(self):
|
79
|
+
"""Test validation with list data type."""
|
80
|
+
data = [1, 2, 3]
|
81
|
+
result = validate_input_data(data, data_type=list)
|
82
|
+
assert result is True
|
83
|
+
|
84
|
+
def test_validate_input_data_string_type(self):
|
85
|
+
"""Test validation with string data type."""
|
86
|
+
data = "test_string"
|
87
|
+
result = validate_input_data(data, data_type=str)
|
88
|
+
assert result is True
|
89
|
+
|
90
|
+
|
91
|
+
class TestFormatValidation:
|
92
|
+
"""Test suite for format validation."""
|
93
|
+
|
94
|
+
def test_validate_email_valid(self):
|
95
|
+
"""Test valid email validation."""
|
96
|
+
valid_emails = [
|
97
|
+
"test@example.com",
|
98
|
+
"user.name@domain.co.uk",
|
99
|
+
"user+tag@example.org",
|
100
|
+
]
|
101
|
+
|
102
|
+
for email in valid_emails:
|
103
|
+
assert validate_email(email) is True
|
104
|
+
|
105
|
+
def test_validate_email_invalid(self):
|
106
|
+
"""Test invalid email validation."""
|
107
|
+
invalid_emails = [
|
108
|
+
"",
|
109
|
+
"invalid_email",
|
110
|
+
"@example.com",
|
111
|
+
"test@",
|
112
|
+
"test..test@example.com",
|
113
|
+
]
|
114
|
+
|
115
|
+
for email in invalid_emails:
|
116
|
+
assert validate_email(email) is False
|
117
|
+
|
118
|
+
def test_validate_email_none_input(self):
|
119
|
+
"""Test email validation with None input."""
|
120
|
+
assert validate_email(None) is False
|
121
|
+
|
122
|
+
def test_validate_email_non_string_input(self):
|
123
|
+
"""Test email validation with non-string input."""
|
124
|
+
assert validate_email(123) is False
|
125
|
+
|
126
|
+
def test_validate_url_valid(self):
|
127
|
+
"""Test valid URL validation."""
|
128
|
+
valid_urls = [
|
129
|
+
"https://example.com",
|
130
|
+
"http://subdomain.example.org/path",
|
131
|
+
"ftp://ftp.example.net",
|
132
|
+
]
|
133
|
+
|
134
|
+
for url in valid_urls:
|
135
|
+
assert validate_url(url) is True
|
136
|
+
|
137
|
+
def test_validate_url_invalid(self):
|
138
|
+
"""Test invalid URL validation."""
|
139
|
+
invalid_urls = ["", "not_a_url", "http://", "https://"]
|
140
|
+
|
141
|
+
for url in invalid_urls:
|
142
|
+
assert validate_url(url) is False
|
143
|
+
|
144
|
+
def test_validate_url_allowed_schemes(self):
|
145
|
+
"""Test URL validation with allowed schemes."""
|
146
|
+
url = "https://example.com"
|
147
|
+
assert validate_url(url, allowed_schemes=["https"]) is True
|
148
|
+
assert validate_url(url, allowed_schemes=["http"]) is False
|
149
|
+
|
150
|
+
def test_validate_url_none_input(self):
|
151
|
+
"""Test URL validation with None input."""
|
152
|
+
assert validate_url(None) is False
|
153
|
+
|
154
|
+
def test_validate_url_non_string_input(self):
|
155
|
+
"""Test URL validation with non-string input."""
|
156
|
+
assert validate_url(123) is False
|
157
|
+
|
158
|
+
def test_validate_ip_address_valid(self):
|
159
|
+
"""Test valid IP address validation."""
|
160
|
+
valid_ips = ["192.168.1.1", "10.0.0.1", "127.0.0.1", "::1", "2001:db8::1"]
|
161
|
+
|
162
|
+
for ip in valid_ips:
|
163
|
+
assert validate_ip_address(ip) is True
|
164
|
+
|
165
|
+
def test_validate_ip_address_invalid(self):
|
166
|
+
"""Test invalid IP address validation."""
|
167
|
+
invalid_ips = ["", "256.256.256.256", "192.168.1.256", "not_an_ip"]
|
168
|
+
|
169
|
+
for ip in invalid_ips:
|
170
|
+
assert validate_ip_address(ip) is False
|
171
|
+
|
172
|
+
def test_validate_ip_address_specific_version(self):
|
173
|
+
"""Test IP address validation with specific version."""
|
174
|
+
assert validate_ip_address("192.168.1.1", "ipv4") is True
|
175
|
+
assert validate_ip_address("::1", "ipv6") is True
|
176
|
+
assert validate_ip_address("192.168.1.1", "ipv6") is False
|
177
|
+
|
178
|
+
def test_validate_ip_address_none_input(self):
|
179
|
+
"""Test IP address validation with None input."""
|
180
|
+
assert validate_ip_address(None) is False
|
181
|
+
|
182
|
+
def test_validate_ip_address_non_string_input(self):
|
183
|
+
"""Test IP address validation with non-string input."""
|
184
|
+
assert validate_ip_address(123) is False
|
185
|
+
|
186
|
+
|
187
|
+
class TestDataNormalization:
|
188
|
+
"""Test suite for data normalization."""
|
189
|
+
|
190
|
+
def test_normalize_data_string(self):
|
191
|
+
"""Test string normalization."""
|
192
|
+
assert normalize_data(" test ", "string") == "test"
|
193
|
+
assert normalize_data(None, "string") == ""
|
194
|
+
assert normalize_data(123, "string") == "123"
|
195
|
+
|
196
|
+
def test_normalize_data_integer(self):
|
197
|
+
"""Test integer normalization."""
|
198
|
+
assert normalize_data("123", "integer") == 123
|
199
|
+
assert normalize_data(123.45, "integer") == 123
|
200
|
+
assert normalize_data(None, "integer") == 0
|
201
|
+
|
202
|
+
def test_normalize_data_float(self):
|
203
|
+
"""Test float normalization."""
|
204
|
+
assert normalize_data("123.45", "float") == 123.45
|
205
|
+
assert normalize_data(123, "float") == 123.0
|
206
|
+
assert normalize_data(None, "float") == 0.0
|
207
|
+
|
208
|
+
def test_normalize_data_boolean(self):
|
209
|
+
"""Test boolean normalization."""
|
210
|
+
assert normalize_data("true", "boolean") is True
|
211
|
+
assert normalize_data("false", "boolean") is False
|
212
|
+
assert normalize_data("1", "boolean") is True
|
213
|
+
assert normalize_data("0", "boolean") is False
|
214
|
+
assert normalize_data(None, "boolean") is False
|
215
|
+
|
216
|
+
def test_normalize_data_boolean_true_values(self):
|
217
|
+
"""Test boolean normalization with various true values."""
|
218
|
+
assert normalize_data(True, "boolean") is True
|
219
|
+
assert normalize_data(1, "boolean") is True
|
220
|
+
assert normalize_data("yes", "boolean") is True
|
221
|
+
assert normalize_data("on", "boolean") is True
|
222
|
+
|
223
|
+
def test_normalize_data_boolean_false_values(self):
|
224
|
+
"""Test boolean normalization with various false values."""
|
225
|
+
assert normalize_data(False, "boolean") is False
|
226
|
+
assert normalize_data(0, "boolean") is False
|
227
|
+
assert normalize_data("", "boolean") is False
|
228
|
+
|
229
|
+
def test_normalize_data_unsupported_type(self):
|
230
|
+
"""Test normalization with unsupported type."""
|
231
|
+
with pytest.raises(ValidationError) as exc_info:
|
232
|
+
normalize_data("test", "unsupported")
|
233
|
+
|
234
|
+
assert "Unsupported data type" in str(exc_info.value)
|
235
|
+
|
236
|
+
def test_sanitize_string(self):
|
237
|
+
"""Test string sanitization."""
|
238
|
+
assert sanitize_string(" test ") == "test"
|
239
|
+
assert (
|
240
|
+
sanitize_string("test<script>alert('xss')</script>") == "testalert('xss')"
|
241
|
+
)
|
242
|
+
assert sanitize_string("test\n\t\r") == "test"
|
243
|
+
|
244
|
+
def test_sanitize_string_custom_chars(self):
|
245
|
+
"""Test string sanitization with custom allowed characters."""
|
246
|
+
result = sanitize_string("test123", r"[a-z]")
|
247
|
+
assert result == "test123"
|
248
|
+
|
249
|
+
def test_sanitize_string_none_input(self):
|
250
|
+
"""Test string sanitization with None input."""
|
251
|
+
assert sanitize_string(None) == ""
|
252
|
+
|
253
|
+
def test_sanitize_string_non_string_input(self):
|
254
|
+
"""Test string sanitization with non-string input."""
|
255
|
+
assert sanitize_string(123) == ""
|
256
|
+
|
257
|
+
|
258
|
+
class TestValidationFunctions:
|
259
|
+
"""Test suite for validation functions."""
|
260
|
+
|
261
|
+
def test_validate_string_length(self):
|
262
|
+
"""Test string length validation."""
|
263
|
+
assert validate_string_length("test", min_length=3, max_length=5) is True
|
264
|
+
assert validate_string_length("test", min_length=5) is False
|
265
|
+
assert validate_string_length("test", max_length=3) is False
|
266
|
+
|
267
|
+
def test_validate_string_length_none_input(self):
|
268
|
+
"""Test string length validation with None input."""
|
269
|
+
assert validate_string_length(None, min_length=3) is False
|
270
|
+
|
271
|
+
def test_validate_string_length_non_string_input(self):
|
272
|
+
"""Test string length validation with non-string input."""
|
273
|
+
assert validate_string_length(123, min_length=3) is False
|
274
|
+
|
275
|
+
def test_validate_numeric_range(self):
|
276
|
+
"""Test numeric value range validation."""
|
277
|
+
assert validate_numeric_range(5, min_value=1, max_value=10) is True
|
278
|
+
assert validate_numeric_range(5, min_value=10) is False
|
279
|
+
assert validate_numeric_range(5, max_value=3) is False
|
280
|
+
|
281
|
+
def test_validate_numeric_range_none_input(self):
|
282
|
+
"""Test numeric range validation with None input."""
|
283
|
+
assert validate_numeric_range(None, min_value=1) is False
|
284
|
+
|
285
|
+
def test_validate_numeric_range_non_numeric_input(self):
|
286
|
+
"""Test numeric range validation with non-numeric input."""
|
287
|
+
assert validate_numeric_range("not_a_number", min_value=1) is False
|
288
|
+
|
289
|
+
def test_validate_list_content(self):
|
290
|
+
"""Test list content and structure validation."""
|
291
|
+
assert validate_list_content([1, 2, 3], min_items=2, max_items=5) is True
|
292
|
+
assert validate_list_content([1, 2, 3], allowed_values=[1, 2, 3, 4]) is True
|
293
|
+
assert validate_list_content([1, 2, 3], allowed_values=[1, 2]) is False
|
294
|
+
|
295
|
+
def test_validate_list_content_none_input(self):
|
296
|
+
"""Test list content validation with None input."""
|
297
|
+
assert validate_list_content(None, min_items=2) is False
|
298
|
+
|
299
|
+
def test_validate_list_content_non_list_input(self):
|
300
|
+
"""Test list content validation with non-list input."""
|
301
|
+
assert validate_list_content("not_a_list", min_items=2) is False
|
302
|
+
|
303
|
+
def test_validate_list_content_too_few_items(self):
|
304
|
+
"""Test list content validation with too few items."""
|
305
|
+
assert validate_list_content([1], min_items=2) is False
|
306
|
+
|
307
|
+
def test_validate_list_content_too_many_items(self):
|
308
|
+
"""Test list content validation with too many items."""
|
309
|
+
assert validate_list_content([1, 2, 3], max_items=2) is False
|
310
|
+
|
311
|
+
def test_validate_json_schema_success(self):
|
312
|
+
"""Test successful JSON schema validation."""
|
313
|
+
data = {"name": "test", "age": 25}
|
314
|
+
schema = {
|
315
|
+
"type": "object",
|
316
|
+
"properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
|
317
|
+
"required": ["name"],
|
318
|
+
}
|
319
|
+
|
320
|
+
assert validate_json_schema(data, schema) is True
|
321
|
+
|
322
|
+
def test_validate_json_schema_missing_required(self):
|
323
|
+
"""Test JSON schema validation with missing required field."""
|
324
|
+
data = {"age": 25}
|
325
|
+
schema = {
|
326
|
+
"type": "object",
|
327
|
+
"properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
|
328
|
+
"required": ["name"],
|
329
|
+
}
|
330
|
+
|
331
|
+
with pytest.raises(ValidationError) as exc_info:
|
332
|
+
validate_json_schema(data, schema)
|
333
|
+
|
334
|
+
assert "Missing required field" in str(exc_info.value)
|
335
|
+
|
336
|
+
def test_validate_json_schema_wrong_type(self):
|
337
|
+
"""Test JSON schema validation with wrong type."""
|
338
|
+
data = {"name": 123}
|
339
|
+
schema = {"type": "object", "properties": {"name": {"type": "string"}}}
|
340
|
+
|
341
|
+
with pytest.raises(ValidationError) as exc_info:
|
342
|
+
validate_json_schema(data, schema)
|
343
|
+
|
344
|
+
assert "must be a string" in str(exc_info.value)
|
345
|
+
|
346
|
+
def test_validate_json_schema_not_dict(self):
|
347
|
+
"""Test JSON schema validation with non-dict data."""
|
348
|
+
data = "not_a_dict"
|
349
|
+
schema = {"type": "object"}
|
350
|
+
|
351
|
+
with pytest.raises(ValidationError) as exc_info:
|
352
|
+
validate_json_schema(data, schema)
|
353
|
+
|
354
|
+
assert "Data must be a dictionary" in str(exc_info.value)
|
355
|
+
|
356
|
+
def test_validate_json_schema_integer_type(self):
|
357
|
+
"""Test JSON schema validation with integer type."""
|
358
|
+
data = {"age": 25}
|
359
|
+
schema = {"type": "object", "properties": {"age": {"type": "integer"}}}
|
360
|
+
|
361
|
+
assert validate_json_schema(data, schema) is True
|
362
|
+
|
363
|
+
def test_validate_json_schema_number_type(self):
|
364
|
+
"""Test JSON schema validation with number type."""
|
365
|
+
data = {"price": 25.50}
|
366
|
+
schema = {"type": "object", "properties": {"price": {"type": "number"}}}
|
367
|
+
|
368
|
+
assert validate_json_schema(data, schema) is True
|
369
|
+
|
370
|
+
def test_validate_json_schema_boolean_type(self):
|
371
|
+
"""Test JSON schema validation with boolean type."""
|
372
|
+
data = {"active": True}
|
373
|
+
schema = {"type": "object", "properties": {"active": {"type": "boolean"}}}
|
374
|
+
|
375
|
+
assert validate_json_schema(data, schema) is True
|
376
|
+
|
377
|
+
def test_validate_json_schema_array_type(self):
|
378
|
+
"""Test JSON schema validation with array type."""
|
379
|
+
data = {"items": [1, 2, 3]}
|
380
|
+
schema = {"type": "object", "properties": {"items": {"type": "array"}}}
|
381
|
+
|
382
|
+
assert validate_json_schema(data, schema) is True
|
383
|
+
|
384
|
+
def test_validate_json_schema_object_type(self):
|
385
|
+
"""Test JSON schema validation with object type."""
|
386
|
+
data = {"user": {"name": "test"}}
|
387
|
+
schema = {"type": "object", "properties": {"user": {"type": "object"}}}
|
388
|
+
|
389
|
+
assert validate_json_schema(data, schema) is True
|
390
|
+
|
391
|
+
|
392
|
+
class TestFileValidation:
|
393
|
+
"""Test suite for file validation."""
|
394
|
+
|
395
|
+
def test_validate_file_extension(self):
|
396
|
+
"""Test file extension validation."""
|
397
|
+
assert validate_file_extension("test.txt", [".txt", ".pdf"]) is True
|
398
|
+
assert validate_file_extension("test.txt", [".pdf", ".doc"]) is False
|
399
|
+
|
400
|
+
def test_validate_file_extension_case_insensitive(self):
|
401
|
+
"""Test file extension validation with case insensitive."""
|
402
|
+
assert validate_file_extension("test.TXT", [".txt", ".pdf"]) is True
|
403
|
+
assert validate_file_extension("test.txt", [".TXT", ".PDF"]) is True
|
404
|
+
|
405
|
+
def test_validate_file_extension_without_dot(self):
|
406
|
+
"""Test file extension validation without leading dot."""
|
407
|
+
assert validate_file_extension("test.txt", ["txt", "pdf"]) is True
|
408
|
+
assert validate_file_extension("test.txt", ["pdf", "doc"]) is False
|
409
|
+
|
410
|
+
def test_validate_file_extension_exception_handling(self):
|
411
|
+
"""Test file extension validation with exception handling."""
|
412
|
+
assert validate_file_extension(None, [".txt"]) is False
|
413
|
+
assert validate_file_extension(123, [".txt"]) is False
|
414
|
+
|
415
|
+
def test_validate_file_path(self):
|
416
|
+
"""Test file path validation."""
|
417
|
+
# Test with non-existent path
|
418
|
+
assert validate_file_path("/non/existent/path", must_exist=False) is True
|
419
|
+
assert validate_file_path("/non/existent/path", must_exist=True) is False
|
420
|
+
|
421
|
+
def test_validate_file_path_exception_handling(self):
|
422
|
+
"""Test file path validation with exception handling."""
|
423
|
+
assert validate_file_path(None) is False
|
424
|
+
assert validate_file_path(123) is False
|
425
|
+
|
426
|
+
def test_validate_directory_structure(self):
|
427
|
+
"""Test directory structure validation."""
|
428
|
+
# Test with non-existent directory
|
429
|
+
assert validate_directory_structure("/non/existent/dir") is False
|
430
|
+
|
431
|
+
def test_validate_directory_structure_exception_handling(self):
|
432
|
+
"""Test directory structure validation with exception handling."""
|
433
|
+
assert validate_directory_structure(None) is False
|
434
|
+
assert validate_directory_structure(123) is False
|
435
|
+
|
436
|
+
|
437
|
+
class TestConfigurationValidation:
|
438
|
+
"""Test suite for configuration file validation."""
|
439
|
+
|
440
|
+
def test_validate_configuration_file_not_found(self, tmp_path):
|
441
|
+
"""Test configuration file validation with non-existent file."""
|
442
|
+
config_path = tmp_path / "nonexistent.json"
|
443
|
+
|
444
|
+
with pytest.raises(ValidationError) as exc_info:
|
445
|
+
validate_configuration_file(config_path, None)
|
446
|
+
|
447
|
+
assert "Configuration file not found" in str(exc_info.value)
|
448
|
+
|
449
|
+
def test_validate_configuration_file_not_file(self, tmp_path):
|
450
|
+
"""Test configuration file validation with directory instead of file."""
|
451
|
+
config_dir = tmp_path / "config"
|
452
|
+
config_dir.mkdir()
|
453
|
+
|
454
|
+
with pytest.raises(ValidationError) as exc_info:
|
455
|
+
validate_configuration_file(config_dir, None)
|
456
|
+
|
457
|
+
assert "Path is not a file" in str(exc_info.value)
|
458
|
+
|
459
|
+
def test_validate_configuration_file_unsupported_format(self, tmp_path):
|
460
|
+
"""Test configuration file validation with unsupported format."""
|
461
|
+
config_path = tmp_path / "config.yaml"
|
462
|
+
config_path.write_text("test: data")
|
463
|
+
|
464
|
+
with pytest.raises(ValidationError) as exc_info:
|
465
|
+
validate_configuration_file(config_path, None)
|
466
|
+
|
467
|
+
assert "Unsupported configuration file format" in str(exc_info.value)
|
468
|
+
|
469
|
+
def test_validate_configuration_file_invalid_json(self, tmp_path):
|
470
|
+
"""Test configuration file validation with invalid JSON."""
|
471
|
+
config_path = tmp_path / "config.json"
|
472
|
+
config_path.write_text("{ invalid json }")
|
473
|
+
|
474
|
+
with pytest.raises(ValidationError) as exc_info:
|
475
|
+
validate_configuration_file(config_path, None)
|
476
|
+
|
477
|
+
assert "Invalid JSON in configuration file" in str(exc_info.value)
|