From e95043467108a410a198fddc8db0d5000f4b7f12 Mon Sep 17 00:00:00 2001
From: Neda Moeini <neda.moeini@geant.org>
Date: Fri, 28 Feb 2025 11:06:54 +0100
Subject: [PATCH] Improve the tests by using a helper function for modifying
 the input file and removed the redundant code

---
 pyproject.toml                         |  2 +-
 test/conftest.py                       |  4 +-
 test/test_file_validator/test_forms.py | 89 +++++++++++++-------------
 3 files changed, 47 insertions(+), 48 deletions(-)

diff --git a/pyproject.toml b/pyproject.toml
index 981838d..4650bd8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -38,7 +38,7 @@ line-length = 120
 ban-relative-imports = "all"
 
 [tool.ruff.lint.per-file-ignores]
-"test/*" = ["S101", "ARG001",]
+"test/*" = ["ARG001", "D", "S101", "PLR2004", "PLR0917", "PLR0914", "PLC0415", "PLC2701"]
 
 [tool.pytest.ini_options]
 DJANGO_SETTINGS_MODULE = "test.settings"
diff --git a/test/conftest.py b/test/conftest.py
index 74bbc11..f91236c 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -9,7 +9,7 @@ from sage_validation.file_validator.models import MeoCostCentres, MeoValidSuppli
 
 
 @pytest.fixture
-def sample_input_file():
+def sample_input_file() -> SimpleUploadedFile:
     """Create a sample valid CSV file for testing."""
     csv_headers_list = [
         "AccountNumber",
@@ -96,7 +96,7 @@ def sample_input_file():
     return SimpleUploadedFile("test.csv", f"{csv_headers}\n{csv_content}".encode(), content_type="text/csv")
 
 @pytest.fixture
-def mock_meo_database(mocker):
+def mock_meo_database(mocker: MagicMock)-> None:
     """Mock the meo database since it's read-only."""
     fake = Faker()
 
diff --git a/test/test_file_validator/test_forms.py b/test/test_file_validator/test_forms.py
index b169538..b5df108 100644
--- a/test/test_file_validator/test_forms.py
+++ b/test/test_file_validator/test_forms.py
@@ -1,19 +1,46 @@
 """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 test_valid_csv_upload(sample_input_file, mock_meo_database):
+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():
+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})
@@ -21,7 +48,7 @@ def test_invalid_file_extension():
     assert "File must be in CSV format." in form.errors["file"]
 
 
-def test_missing_required_columns():
+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})
@@ -29,43 +56,19 @@ def test_missing_required_columns():
     assert "Missing required columns" in str(form.errors)
 
 
-def test_source_and_trader_type_validation(sample_input_file, mock_meo_database):
+def test_source_and_trader_type_validation(sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock) -> None:
     """Test validation for Source and SYSTraderTranType columns."""
-    csv_content = sample_input_file.read().decode("utf-8").splitlines()
-    reader = csv.DictReader(csv_content)
-    rows = list(reader)
-
-    # Modify the first row's "Source" and "SYSTraderTranType" values
-    rows[0]["Source"] = "90"  # Change Source from 80 to 90
-    rows[0]["SYSTraderTranType"] = "5"  # Change SYSTraderTranType from 4 to 5
-
-    # Rebuild the CSV with modified values
-    output = io.StringIO()
-    writer = csv.DictWriter(output, fieldnames=reader.fieldnames)
-    writer.writeheader()
-    writer.writerows(rows)
-    modified_file = SimpleUploadedFile("test_modified.csv", output.getvalue().encode("utf-8"), content_type="text/csv")
-
+    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, mock_meo_database):
+def test_validate_nominal_analysis_account(sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock) -> None:
     """Test validation for nominal analysis account."""
-    csv_content = sample_input_file.read().decode("utf-8").splitlines()
-    reader = csv.DictReader(csv_content)
-    rows = list(reader)
-    rows[0]["NominalAnalysisNominalAnalysisNarrative/1"] = "Invalid Name"
-
-    # Rebuild the CSV with modified values
-    output = io.StringIO()
-    writer = csv.DictWriter(output, fieldnames=reader.fieldnames)
-    writer.writeheader()
-    writer.writerows(rows)
-    modified_file = SimpleUploadedFile("test_modified.csv", output.getvalue().encode("utf-8"), content_type="text/csv")
-
+    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] == (
@@ -73,20 +76,16 @@ def test_validate_nominal_analysis_account(sample_input_file, mock_meo_database)
         ", but found 'Invalid Name'.")
 
 
-def test_validate_nc_cc_dep_combination_against_meo_sage_account(sample_input_file, mock_meo_database):
+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."""
-    csv_content = sample_input_file.read().decode("utf-8").splitlines()
-    reader = csv.DictReader(csv_content)
-    rows = list(reader)
-
-    rows[0]["NominalAnalysisNominalCostCentre/1"] = "Invalid_CC"
-    rows[0]["NominalAnalysisNominalAccountNumber/1"] = "Invalid_Account"
-
-    output = io.StringIO()
-    writer = csv.DictWriter(output, fieldnames=reader.fieldnames)
-    writer.writeheader()
-    writer.writerows(rows)
-    modified_file = SimpleUploadedFile("test_modified.csv", output.getvalue().encode("utf-8"), content_type="text/csv")
+    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()
-- 
GitLab