""" Tests for file upload functionality. """ import pytest import os from io import BytesIO from app.models import load_application_data, get_attachments_path class TestFileUpload: """Tests for file upload functionality.""" def test_upload_valid_pdf(self, client, create_test_application, sample_pdf_file): """Test uploading a valid PDF file.""" session_id = 'test-upload-pdf' create_test_application(session_id=session_id, current_page=4) sample_pdf_file.seek(0) response = client.post( f'/apply/{session_id}/upload-file', data={'file': (sample_pdf_file, 'resume.pdf')}, content_type='multipart/form-data', follow_redirects=True ) assert response.status_code == 200 # Verify file was added to data loaded_data = load_application_data(session_id) assert len(loaded_data['uploaded_files']) == 1 assert loaded_data['uploaded_files'][0]['original_name'] == 'resume.pdf' def test_upload_valid_jpg(self, client, create_test_application, sample_jpg_file): """Test uploading a valid JPG image.""" session_id = 'test-upload-jpg' create_test_application(session_id=session_id, current_page=4) sample_jpg_file.seek(0) response = client.post( f'/apply/{session_id}/upload-file', data={'file': (sample_jpg_file, 'photo.jpg')}, content_type='multipart/form-data', follow_redirects=True ) assert response.status_code == 200 loaded_data = load_application_data(session_id) assert len(loaded_data['uploaded_files']) == 1 def test_upload_multiple_files(self, client, create_test_application, sample_pdf_file, sample_jpg_file): """Test uploading multiple files.""" session_id = 'test-upload-multiple' create_test_application(session_id=session_id, current_page=4) # Upload first file sample_pdf_file.seek(0) client.post( f'/apply/{session_id}/upload-file', data={'file': (sample_pdf_file, 'file1.pdf')}, content_type='multipart/form-data' ) # Upload second file sample_jpg_file.seek(0) client.post( f'/apply/{session_id}/upload-file', data={'file': (sample_jpg_file, 'file2.jpg')}, content_type='multipart/form-data' ) loaded_data = load_application_data(session_id) assert len(loaded_data['uploaded_files']) == 2 def test_upload_exceeds_max_files(self, client, create_test_application, sample_pdf_file): """Test that uploading more than 3 files is rejected.""" session_id = 'test-upload-max' create_test_application( session_id=session_id, current_page=4, uploaded_files=[ {'original_name': 'file1.pdf', 'stored_name': 'file1.pdf', 'size': 1000}, {'original_name': 'file2.pdf', 'stored_name': 'file2.pdf', 'size': 1000}, {'original_name': 'file3.pdf', 'stored_name': 'file3.pdf', 'size': 1000} ] ) sample_pdf_file.seek(0) response = client.post( f'/apply/{session_id}/upload-file', data={'file': (sample_pdf_file, 'file4.pdf')}, content_type='multipart/form-data', follow_redirects=True ) assert response.status_code == 200 # Should still have 3 files (4th was rejected) loaded_data = load_application_data(session_id) assert len(loaded_data['uploaded_files']) == 3 def test_upload_invalid_file_type(self, client, create_test_application): """Test that invalid file types are rejected.""" session_id = 'test-upload-invalid' create_test_application(session_id=session_id, current_page=4) invalid_file = BytesIO(b'executable content') response = client.post( f'/apply/{session_id}/upload-file', data={'file': (invalid_file, 'virus.exe')}, content_type='multipart/form-data', follow_redirects=True ) assert response.status_code == 200 loaded_data = load_application_data(session_id) assert len(loaded_data.get('uploaded_files', [])) == 0 def test_upload_file_too_large(self, client, create_test_application, large_file): """Test that files larger than 4MB are rejected.""" session_id = 'test-upload-large' create_test_application(session_id=session_id, current_page=4) large_file.seek(0) response = client.post( f'/apply/{session_id}/upload-file', data={'file': (large_file, 'large.pdf')}, content_type='multipart/form-data', follow_redirects=True ) assert response.status_code == 200 loaded_data = load_application_data(session_id) assert len(loaded_data.get('uploaded_files', [])) == 0 def test_upload_no_file_selected(self, client, create_test_application): """Test uploading without selecting a file.""" session_id = 'test-upload-nofile' create_test_application(session_id=session_id, current_page=4) response = client.post( f'/apply/{session_id}/upload-file', data={}, content_type='multipart/form-data', follow_redirects=True ) assert response.status_code == 200 class TestFileRemoval: """Tests for file removal functionality.""" def test_remove_uploaded_file(self, client, create_test_application, sample_pdf_file, app): """Test removing an uploaded file.""" session_id = 'test-remove-file' create_test_application(session_id=session_id, current_page=4) # Upload a file sample_pdf_file.seek(0) client.post( f'/apply/{session_id}/upload-file', data={'file': (sample_pdf_file, 'remove_me.pdf')}, content_type='multipart/form-data' ) # Verify it was uploaded loaded_data = load_application_data(session_id) assert len(loaded_data['uploaded_files']) == 1 # Remove the file response = client.post( f'/apply/{session_id}/remove-file/0', follow_redirects=True ) assert response.status_code == 200 loaded_data = load_application_data(session_id) assert len(loaded_data['uploaded_files']) == 0 def test_remove_nonexistent_file(self, client, create_test_application): """Test removing a file with invalid index.""" session_id = 'test-remove-invalid' create_test_application(session_id=session_id, current_page=4) response = client.post( f'/apply/{session_id}/remove-file/999', follow_redirects=True ) assert response.status_code == 200 class TestFileStorage: """Tests for file storage on disk.""" def test_file_saved_to_attachments_folder(self, client, create_test_application, sample_pdf_file, app): """Test that uploaded files are saved to the attachments folder.""" session_id = 'test-file-storage' create_test_application(session_id=session_id, current_page=4) sample_pdf_file.seek(0) client.post( f'/apply/{session_id}/upload-file', data={'file': (sample_pdf_file, 'stored.pdf')}, content_type='multipart/form-data' ) # Check that file exists in attachments folder attachments_path = get_attachments_path(session_id) assert os.path.exists(attachments_path) # Check that a file was created files = os.listdir(attachments_path) assert len(files) > 0 def test_filename_sanitization(self, client, create_test_application, sample_pdf_file): """Test that filenames are sanitized for security.""" session_id = 'test-sanitize' create_test_application(session_id=session_id, current_page=4) sample_pdf_file.seek(0) # Try uploading a file with potentially dangerous name client.post( f'/apply/{session_id}/upload-file', data={'file': (sample_pdf_file, '../../../etc/passwd.pdf')}, content_type='multipart/form-data' ) loaded_data = load_application_data(session_id) if len(loaded_data['uploaded_files']) > 0: # Filename should be sanitized stored_name = loaded_data['uploaded_files'][0]['stored_name'] assert '../' not in stored_name assert '/' not in stored_name.split('_')[-1] # After timestamp