import io import sys from unittest.mock import MagicMock, patch import pytest # Mock whisper before importing server mock_whisper = MagicMock() mock_whisper.load_model.return_value = MagicMock() sys.modules['whisper'] = mock_whisper from server import app @pytest.fixture def client(): app.config['TESTING'] = True with app.test_client() as c: yield c # --- Static file serving --- def test_index(client): resp = client.get('/') assert resp.status_code == 200 def test_allowed_static_file(client): resp = client.get('/app.js') assert resp.status_code == 200 def test_blocked_static_file(client): resp = client.get('/server.py') assert resp.status_code == 404 def test_path_traversal_blocked(client): resp = client.get('/../requirements.txt') assert resp.status_code == 404 # --- COOP/COEP headers --- def test_coop_coep_headers(client): resp = client.get('/') assert resp.headers['Cross-Origin-Opener-Policy'] == 'same-origin' assert resp.headers['Cross-Origin-Embedder-Policy'] == 'require-corp' # --- /transcribe endpoint --- def test_transcribe_no_file(client): resp = client.post('/transcribe') assert resp.status_code == 400 assert 'No file provided' in resp.get_json()['error'] def test_transcribe_empty_filename(client): data = {'file': (io.BytesIO(b'data'), '')} resp = client.post('/transcribe', data=data, content_type='multipart/form-data') assert resp.status_code == 400 assert 'No file selected' in resp.get_json()['error'] def test_transcribe_video_rejected(client): for ext in ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv', '.webm']: data = {'file': (io.BytesIO(b'data'), f'video{ext}')} resp = client.post('/transcribe', data=data, content_type='multipart/form-data') assert resp.status_code == 400 assert 'Video files not allowed' in resp.get_json()['error'] @patch('server.model') def test_transcribe_success(mock_model, client): mock_model.transcribe.return_value = {'text': 'hello world'} data = {'file': (io.BytesIO(b'audio data'), 'test.mp3')} resp = client.post('/transcribe', data=data, content_type='multipart/form-data') assert resp.status_code == 200 assert resp.get_json()['text'] == 'hello world' @patch('server.model') def test_transcribe_with_language(mock_model, client): mock_model.transcribe.return_value = {'text': 'hola'} data = {'file': (io.BytesIO(b'audio'), 'test.mp3'), 'language': 'es-ES'} resp = client.post('/transcribe', data=data, content_type='multipart/form-data') assert resp.status_code == 200 mock_model.transcribe.assert_called_once() assert mock_model.transcribe.call_args[1]['language'] == 'es' @patch('server.model') def test_transcribe_cleans_up_temp_file_on_error(mock_model, client): mock_model.transcribe.side_effect = RuntimeError('model failed') data = {'file': (io.BytesIO(b'audio'), 'test.mp3')} resp = client.post('/transcribe', data=data, content_type='multipart/form-data') assert resp.status_code == 500 assert 'model failed' in resp.get_json()['error']