"""Tests for the file_validator forms.""" import csv import io from unittest.mock import MagicMock from django.core.files.uploadedfile import SimpleUploadedFile from sage_validation.file_validator.forms import CSVUploadForm def create_modified_csv(sample_file: SimpleUploadedFile, modifications: dict[str, str]) -> SimpleUploadedFile: """ Modify specific fields in the first row of a CSV file and return a new SimpleUploadedFile. Args: sample_file (SimpleUploadedFile): The original CSV file. modifications (dict): Dictionary of column names to modified values. Returns: SimpleUploadedFile: The modified CSV file. """ csv_content = sample_file.read().decode("utf-8").splitlines() reader = csv.DictReader(csv_content) rows = list(reader) for key, value in modifications.items(): rows[0][key] = value output = io.StringIO() writer = csv.DictWriter(output, fieldnames=reader.fieldnames or []) writer.writeheader() writer.writerows(rows) return SimpleUploadedFile("test_modified.csv", output.getvalue().encode("utf-8"), content_type="text/csv") def test_valid_csv_upload(sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock) -> None: """Test CSV upload with valid data.""" form = CSVUploadForm(files={"file": sample_input_file}) assert form.is_valid(), f"Form errors: {form.errors}" def test_invalid_file_extension() -> None: """Test form rejects non-CSV files.""" bad_file = SimpleUploadedFile("test.txt", b"Some text content", content_type="text/plain") form = CSVUploadForm(files={"file": bad_file}) assert not form.is_valid() assert "File must be in CSV format." in form.errors["file"] def test_missing_required_columns() -> None: """Test form rejects CSV missing required headers.""" invalid_csv = SimpleUploadedFile("test.csv", b"AccountNumber,CBAccountNumber\n12345,54321", content_type="text/csv") form = CSVUploadForm(files={"file": invalid_csv}) assert not form.is_valid() assert "Missing required columns" in str(form.errors) def test_source_and_trader_type_validation(sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock) -> None: """Test validation for Source and SYSTraderTranType columns.""" modified_file = create_modified_csv(sample_input_file, {"Source": "90", "SYSTraderTranType": "5"}) form = CSVUploadForm(files={"file": modified_file}) assert not form.is_valid() assert "Row 1: 'Source' must be 80" in form.errors["file"][0] assert "Row 1: 'SYSTraderTranType' must be 4" in form.errors["file"][1] def test_validate_nominal_analysis_account(sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock) -> None: """Test validation for nominal analysis account.""" modified_file = create_modified_csv(sample_input_file, {"NominalAnalysisNominalAnalysisNarrative/1": "Invalid Name"}) form = CSVUploadForm(files={"file": modified_file}) assert not form.is_valid() assert form.errors["file"][0] == ( "Row 1: 'AccountNumber' must match 'Sample Narrative' in 'NominalAnalysisNominalAnalysisNarrative/1'" ", but found 'Invalid Name'.") def test_validate_nc_cc_dep_combination_against_meo_sage_account( sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock ) -> None: """Test validation for nominal analysis fields against MEO valid Sage accounts.""" modified_file = create_modified_csv( sample_input_file, { "NominalAnalysisNominalCostCentre/1": "Invalid_CC", "NominalAnalysisNominalAccountNumber/1": "Invalid_Account" }) form = CSVUploadForm(files={"file": modified_file}) assert not form.is_valid() assert ("Row 1: 'NominalAnalysisNominalCostCentre/1' (Invalid_CC) is not a valid cost centre." in str(form.errors["file"][0]))