File size: 13,056 Bytes
b216c95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
"""
Unit tests for common.validators module

Tests all validation functions with various inputs and edge cases.
"""

import pytest
from pathlib import Path
from datetime import datetime
from tempfile import NamedTemporaryFile, TemporaryDirectory

from common import (
    Validator,
    ValidationException,
    AudioFileException
)


class TestValidateAudioFile:
    """Test cases for validate_audio_file function"""
    
    def test_validate_audio_file_with_empty_path(self):
        """Should raise ValidationException for empty path"""
        with pytest.raises(ValidationException) as exc_info:
            Validator.validate_audio_file("")
        assert "audio_file" in str(exc_info.value)
    
    def test_validate_audio_file_nonexistent(self):
        """Should raise AudioFileException for non-existent file"""
        with pytest.raises(AudioFileException) as exc_info:
            Validator.validate_audio_file("/nonexistent/path/to/audio.wav")
        assert "does not exist" in str(exc_info.value)
    
    def test_validate_audio_file_unsupported_format(self, tmp_path):
        """Should raise AudioFileException for unsupported file format"""
        # Create a file with unsupported extension
        unsupported_file = tmp_path / "audio.xyz"
        unsupported_file.write_text("fake audio data")
        
        with pytest.raises(AudioFileException) as exc_info:
            Validator.validate_audio_file(str(unsupported_file))
        assert "Unsupported format" in str(exc_info.value)
    
    def test_validate_audio_file_empty_file(self, tmp_path):
        """Should raise AudioFileException for empty file"""
        empty_file = tmp_path / "empty.wav"
        empty_file.write_bytes(b"")
        
        with pytest.raises(AudioFileException) as exc_info:
            Validator.validate_audio_file(str(empty_file))
        assert "empty" in str(exc_info.value).lower()
    
    def test_validate_audio_file_valid_wav(self, tmp_path):
        """Should return Path object for valid WAV file"""
        valid_file = tmp_path / "audio.wav"
        valid_file.write_bytes(b"fake audio data")
        
        result = Validator.validate_audio_file(str(valid_file))
        assert isinstance(result, Path)
        assert result.exists()
        assert result.suffix.lower() == ".wav"
    
    def test_validate_audio_file_valid_mp3(self, tmp_path):
        """Should return Path object for valid MP3 file"""
        valid_file = tmp_path / "audio.mp3"
        valid_file.write_bytes(b"fake audio data")
        
        result = Validator.validate_audio_file(str(valid_file))
        assert isinstance(result, Path)
        assert result.suffix.lower() == ".mp3"
    
    def test_validate_audio_file_valid_m4a(self, tmp_path):
        """Should return Path object for valid M4A file"""
        valid_file = tmp_path / "audio.m4a"
        valid_file.write_bytes(b"fake audio data")
        
        result = Validator.validate_audio_file(str(valid_file))
        assert isinstance(result, Path)
        assert result.suffix.lower() == ".m4a"
    
    def test_validate_audio_file_is_directory(self, tmp_path):
        """Should raise AudioFileException if path is directory, not file"""
        with pytest.raises(AudioFileException) as exc_info:
            Validator.validate_audio_file(str(tmp_path))
        assert "not a file" in str(exc_info.value)


class TestValidateText:
    """Test cases for validate_text function"""
    
    def test_validate_text_empty(self):
        """Should raise ValidationException for empty text"""
        with pytest.raises(ValidationException):
            Validator.validate_text("")
    
    def test_validate_text_none(self):
        """Should raise ValidationException for None text"""
        with pytest.raises(ValidationException):
            Validator.validate_text(None)
    
    def test_validate_text_too_short(self):
        """Should raise ValidationException if text is too short"""
        with pytest.raises(ValidationException) as exc_info:
            Validator.validate_text("ab")  # MIN is 10
        assert "at least" in str(exc_info.value)
    
    def test_validate_text_valid_minimum(self):
        """Should accept text at minimum length"""
        result = Validator.validate_text("1234567890")  # 10 chars
        assert result == "1234567890"
    
    def test_validate_text_valid_normal(self):
        """Should accept normal text"""
        text = "This is a valid text"
        result = Validator.validate_text(text)
        assert result == text
    
    def test_validate_text_with_whitespace(self):
        """Should strip whitespace from text"""
        text = "  valid text  "
        result = Validator.validate_text(text)
        assert result == "valid text"
    
    def test_validate_text_custom_field_name(self):
        """Should use custom field name in error message"""
        with pytest.raises(ValidationException) as exc_info:
            Validator.validate_text("short", field_name="custom_field")
        assert "custom_field" in str(exc_info.value)


class TestValidatePatientName:
    """Test cases for validate_patient_name function"""
    
    def test_validate_patient_name_none(self):
        """Should return None for None input"""
        result = Validator.validate_patient_name(None)
        assert result is None
    
    def test_validate_patient_name_empty(self):
        """Should return None for empty string"""
        result = Validator.validate_patient_name("")
        assert result is None
    
    def test_validate_patient_name_too_short(self):
        """Should raise ValidationException for too short name"""
        with pytest.raises(ValidationException) as exc_info:
            Validator.validate_patient_name("Ab")
        assert "at least 3" in str(exc_info.value)
    
    def test_validate_patient_name_valid_cyrillic(self):
        """Should accept valid Cyrillic name"""
        name = "Иван Петров"
        result = Validator.validate_patient_name(name)
        assert result == name
    
    def test_validate_patient_name_valid_latin(self):
        """Should accept valid Latin name"""
        name = "John Smith"
        result = Validator.validate_patient_name(name)
        assert result == name
    
    def test_validate_patient_name_with_hyphen(self):
        """Should accept name with hyphen"""
        name = "Mary-Jane Watson"
        result = Validator.validate_patient_name(name)
        assert result == name
    
    def test_validate_patient_name_with_numbers(self):
        """Should reject name with numbers"""
        with pytest.raises(ValidationException):
            Validator.validate_patient_name("Ivan123 Petrov")
    
    def test_validate_patient_name_with_special_chars(self):
        """Should reject name with special characters"""
        with pytest.raises(ValidationException):
            Validator.validate_patient_name("Ivan@Petrov")
    
    def test_validate_patient_name_with_whitespace(self):
        """Should strip whitespace from name"""
        name = "  Ivan Petrov  "
        result = Validator.validate_patient_name(name)
        assert result == "Ivan Petrov"


class TestValidateDate:
    """Test cases for validate_date function"""
    
    def test_validate_date_none(self):
        """Should return None for None input"""
        result = Validator.validate_date(None)
        assert result is None
    
    def test_validate_date_empty(self):
        """Should return None for empty string"""
        result = Validator.validate_date("")
        assert result is None
    
    def test_validate_date_valid_format(self):
        """Should accept valid date in DD.MM.YYYY format"""
        date_str = "15.01.2026"
        result = Validator.validate_date(date_str)
        assert result == date_str
    
    def test_validate_date_invalid_format(self):
        """Should reject invalid date format"""
        with pytest.raises(ValidationException) as exc_info:
            Validator.validate_date("2026-01-15")  # Wrong format
        assert "Invalid date format" in str(exc_info.value)
    
    def test_validate_date_invalid_day(self):
        """Should reject invalid day"""
        with pytest.raises(ValidationException):
            Validator.validate_date("32.01.2026")
    
    def test_validate_date_invalid_month(self):
        """Should reject invalid month"""
        with pytest.raises(ValidationException):
            Validator.validate_date("15.13.2026")
    
    def test_validate_date_custom_format(self):
        """Should accept custom date format"""
        date_str = "2026-01-15"
        result = Validator.validate_date(date_str, date_format="%Y-%m-%d")
        assert result == date_str
    
    def test_validate_date_with_whitespace(self):
        """Should strip whitespace from date"""
        date_str = "  15.01.2026  "
        result = Validator.validate_date(date_str)
        assert result == "15.01.2026"


class TestValidateApiKey:
    """Test cases for validate_api_key function"""
    
    def test_validate_api_key_none(self):
        """Should return None for None input"""
        result = Validator.validate_api_key(None)
        assert result is None
    
    def test_validate_api_key_empty(self):
        """Should return None for empty string"""
        result = Validator.validate_api_key("")
        assert result is None
    
    def test_validate_api_key_too_short(self):
        """Should raise ValidationException for too short key"""
        with pytest.raises(ValidationException) as exc_info:
            Validator.validate_api_key("short")
        assert "too short" in str(exc_info.value)
    
    def test_validate_api_key_valid(self):
        """Should accept valid API key"""
        api_key = "sk_test_1234567890"
        result = Validator.validate_api_key(api_key)
        assert result == api_key
    
    def test_validate_api_key_with_whitespace(self):
        """Should strip whitespace from API key"""
        api_key = "  sk_test_1234567890  "
        result = Validator.validate_api_key(api_key)
        assert result == "sk_test_1234567890"


class TestValidateFilePath:
    """Test cases for validate_file_path function"""
    
    def test_validate_file_path_empty(self):
        """Should raise ValidationException for empty path"""
        with pytest.raises(ValidationException):
            Validator.validate_file_path("")
    
    def test_validate_file_path_nonexistent_not_required(self):
        """Should accept non-existent path if must_exist=False"""
        result = Validator.validate_file_path("/nonexistent/path.txt", must_exist=False)
        assert isinstance(result, Path)
    
    def test_validate_file_path_nonexistent_required(self):
        """Should reject non-existent path if must_exist=True"""
        with pytest.raises(ValidationException) as exc_info:
            Validator.validate_file_path("/nonexistent/path.txt", must_exist=True)
        assert "does not exist" in str(exc_info.value)
    
    def test_validate_file_path_existing_file(self, tmp_path):
        """Should accept existing file path"""
        file_path = tmp_path / "test.txt"
        file_path.write_text("test content")
        
        result = Validator.validate_file_path(str(file_path), must_exist=True)
        assert isinstance(result, Path)
        assert result.exists()
    
    def test_validate_file_path_existing_directory(self, tmp_path):
        """Should accept existing directory path"""
        result = Validator.validate_file_path(str(tmp_path), must_exist=True)
        assert isinstance(result, Path)
        assert result.exists()
    
    def test_validate_file_path_resolves_relative(self):
        """Should resolve relative paths"""
        result = Validator.validate_file_path(".", must_exist=False)
        assert isinstance(result, Path)
        assert result.is_absolute()


class TestValidatorIntegration:
    """Integration tests for validators"""
    
    def test_full_patient_validation_flow(self):
        """Test complete patient data validation"""
        # Valid data
        name = Validator.validate_patient_name("Ivan Petrov")
        date = Validator.validate_date("15.01.1990")
        
        assert name == "Ivan Petrov"
        assert date == "15.01.1990"
    
    def test_full_audio_file_validation(self, tmp_path):
        """Test complete audio file validation flow"""
        # Create a valid audio file
        audio_file = tmp_path / "recording.wav"
        audio_file.write_bytes(b"fake audio data")
        
        # Validate
        result = Validator.validate_audio_file(str(audio_file))
        assert result.exists()
        assert result.suffix.lower() == ".wav"
    
    def test_validation_error_handling(self):
        """Test that validation errors have proper context"""
        with pytest.raises(ValidationException) as exc_info:
            Validator.validate_patient_name("X")
        
        exc = exc_info.value
        assert exc.field == "patient_name"
        assert "3" in str(exc)