Files
ai-tax-agent/tests/unit/test_forms.py
harkon b324ff09ef
Some checks failed
CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
CI/CD Pipeline / Policy Validation (push) Has been cancelled
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-firm-connectors) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-forms) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-hmrc) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ingestion) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-normalize-map) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ocr) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-indexer) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-reason) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rpa) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (ui-review) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (ui-review) (push) Has been cancelled
CI/CD Pipeline / Generate SBOM (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Notifications (push) Has been cancelled
Initial commit
2025-10-11 08:41:36 +01:00

815 lines
29 KiB
Python

"""
Unit tests for svc-forms service
Tests actual business logic: PDF form filling, evidence pack generation,
currency formatting, and field mapping
"""
import os
import sys
from unittest.mock import AsyncMock, Mock, patch
import pytest
# Add the project root to the path so we can import from apps
sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
# Import the actual service code
from apps.svc_forms.main import FormsSettings
# pylint: disable=wrong-import-position,import-error,too-few-public-methods
# pylint: disable=global-statement,raise-missing-from,unused-argument
# pylint: disable=too-many-arguments,too-many-positional-arguments
# pylint: disable=too-many-locals,import-outside-toplevel
# mypy: disable-error-code=union-attr
class TestFormsSettings:
"""Test FormsSettings configuration"""
def test_default_settings(self) -> None:
"""Test default FormsSettings values"""
settings = FormsSettings()
# Test service configuration
assert settings.service_name == "svc-forms"
# Test form templates configuration
assert settings.forms_template_dir == "forms/templates"
assert settings.output_bucket == "filled-forms"
assert settings.evidence_packs_bucket == "evidence-packs"
# Test supported forms
expected_forms = ["SA100", "SA103", "SA105", "SA106"]
assert settings.supported_forms == expected_forms
# Test PDF configuration
assert settings.pdf_quality == "high"
assert settings.flatten_forms is True
def test_custom_settings(self) -> None:
"""Test custom FormsSettings values"""
custom_settings = FormsSettings(
forms_template_dir="custom/templates",
output_bucket="custom-forms",
evidence_packs_bucket="custom-evidence",
supported_forms=["SA100", "SA103"],
pdf_quality="medium",
flatten_forms=False,
)
assert custom_settings.forms_template_dir == "custom/templates"
assert custom_settings.output_bucket == "custom-forms"
assert custom_settings.evidence_packs_bucket == "custom-evidence"
assert custom_settings.supported_forms == ["SA100", "SA103"]
assert custom_settings.pdf_quality == "medium"
assert custom_settings.flatten_forms is False
class TestFormSupport:
"""Test form support validation"""
def test_supported_forms_list(self) -> None:
"""Test supported forms list"""
settings = FormsSettings()
supported_forms = settings.supported_forms
# Test that key UK tax forms are supported
assert "SA100" in supported_forms # Main self-assessment form
assert "SA103" in supported_forms # Self-employment
assert "SA105" in supported_forms # Property income
assert "SA106" in supported_forms # Foreign income
def test_form_validation(self) -> None:
"""Test form ID validation logic"""
settings = FormsSettings()
valid_forms = settings.supported_forms
# Test valid form IDs
for form_id in valid_forms:
assert form_id in valid_forms
assert form_id.startswith("SA") # UK self-assessment forms
assert len(form_id) >= 5 # Minimum length
# Test invalid form IDs
invalid_forms = ["INVALID", "CT600", "VAT100", ""]
for invalid_form in invalid_forms:
assert invalid_form not in valid_forms
class TestPDFConfiguration:
"""Test PDF configuration and quality settings"""
def test_pdf_quality_options(self) -> None:
"""Test PDF quality configuration"""
# Test different quality settings
quality_options = ["low", "medium", "high", "maximum"]
for quality in quality_options:
settings = FormsSettings(pdf_quality=quality)
assert settings.pdf_quality == quality
def test_flatten_forms_option(self) -> None:
"""Test form flattening configuration"""
# Test flattening enabled (default)
settings_flat = FormsSettings(flatten_forms=True)
assert settings_flat.flatten_forms is True
# Test flattening disabled
settings_editable = FormsSettings(flatten_forms=False)
assert settings_editable.flatten_forms is False
def test_pdf_configuration_validation(self) -> None:
"""Test PDF configuration validation"""
settings = FormsSettings()
# Test that quality is a string
assert isinstance(settings.pdf_quality, str)
assert len(settings.pdf_quality) > 0
# Test that flatten_forms is boolean
assert isinstance(settings.flatten_forms, bool)
class TestFormFieldMapping:
"""Test form field mapping concepts"""
def test_sa100_field_mapping(self) -> None:
"""Test SA100 form field mapping structure"""
# Test the concept of SA100 field mapping
# In a real implementation, this would test actual field mapping logic
sa100_fields = {
# Personal details
"1.1": "forename",
"1.2": "surname",
"1.3": "date_of_birth",
"1.4": "national_insurance_number",
# Income summary
"2.1": "total_income_from_employment",
"2.2": "total_income_from_self_employment",
"2.3": "total_income_from_property",
"2.4": "total_income_from_savings",
# Tax calculation
"3.1": "total_income_tax_due",
"3.2": "total_national_insurance_due",
"3.3": "total_tax_and_ni_due",
}
# Test field mapping structure
for box_number, field_name in sa100_fields.items():
assert isinstance(box_number, str)
assert "." in box_number # Box numbers have section.item format
assert isinstance(field_name, str)
assert len(field_name) > 0
def test_sa103_field_mapping(self) -> None:
"""Test SA103 (self-employment) field mapping structure"""
sa103_fields = {
# Business details
"3.1": "business_name",
"3.2": "business_description",
"3.3": "business_address",
"3.4": "accounting_period_start",
"3.5": "accounting_period_end",
# Income
"3.11": "turnover",
"3.12": "other_business_income",
# Expenses
"3.13": "cost_of_goods_sold",
"3.14": "construction_industry_subcontractor_costs",
"3.15": "other_direct_costs",
"3.16": "employee_costs",
"3.17": "premises_costs",
"3.18": "repairs_and_renewals",
"3.19": "general_administrative_expenses",
"3.20": "motor_expenses",
"3.21": "travel_and_subsistence",
"3.22": "advertising_and_entertainment",
"3.23": "legal_and_professional_costs",
"3.24": "bad_debts",
"3.25": "interest_and_alternative_finance_payments",
"3.26": "other_finance_charges",
"3.27": "depreciation_and_loss_on_disposal",
"3.28": "other_business_expenses",
# Profit calculation
"3.29": "total_expenses",
"3.30": "net_profit_or_loss",
}
# Test field mapping structure
for box_number, field_name in sa103_fields.items():
assert isinstance(box_number, str)
assert box_number.startswith("3.") # SA103 fields start with 3.
assert isinstance(field_name, str)
assert len(field_name) > 0
def test_currency_formatting(self) -> None:
"""Test currency formatting for form fields"""
# Test currency formatting concepts
test_amounts = [
(1234.56, "1,234.56"),
(1000000.00, "1,000,000.00"),
(0.50, "0.50"),
(0.00, "0.00"),
(999.99, "999.99"),
]
for amount, expected_format in test_amounts:
# Test that amounts can be formatted correctly
formatted = f"{amount:,.2f}"
assert formatted == expected_format
def test_date_formatting(self) -> None:
"""Test date formatting for form fields"""
# Test date formatting concepts
test_dates = [
("2024-04-05", "05/04/2024"), # UK date format
("2023-12-31", "31/12/2023"),
("2024-01-01", "01/01/2024"),
]
for iso_date, expected_format in test_dates:
# Test that dates can be formatted correctly for UK forms
from datetime import datetime
date_obj = datetime.fromisoformat(iso_date)
formatted = date_obj.strftime("%d/%m/%Y")
assert formatted == expected_format
class TestEvidencePackGeneration:
"""Test evidence pack generation concepts"""
def test_evidence_pack_structure(self) -> None:
"""Test evidence pack structure"""
# Test the concept of evidence pack structure
evidence_pack = {
"taxpayer_id": "taxpayer_123",
"tax_year": "2023-24",
"generated_at": "2024-01-15T10:30:00Z",
"documents": [
{
"type": "filled_form",
"form_id": "SA100",
"filename": "SA100_2023-24_taxpayer_123.pdf",
"size_bytes": 245760,
},
{
"type": "supporting_document",
"document_type": "bank_statement",
"filename": "bank_statement_jan_2024.pdf",
"size_bytes": 512000,
},
{
"type": "supporting_document",
"document_type": "receipt",
"filename": "office_supplies_receipt.pdf",
"size_bytes": 128000,
},
],
"total_size_bytes": 885760,
"checksum": "sha256:abc123def456...",
}
# Test evidence pack structure
assert "taxpayer_id" in evidence_pack
assert "tax_year" in evidence_pack
assert "generated_at" in evidence_pack
assert "documents" in evidence_pack
assert "total_size_bytes" in evidence_pack
assert "checksum" in evidence_pack
# Test documents structure
for document in evidence_pack["documents"]:
assert "type" in document
assert "filename" in document
assert "size_bytes" in document
def test_evidence_pack_validation(self) -> None:
"""Test evidence pack validation concepts"""
# Test validation rules for evidence packs
validation_rules = {
"max_total_size_mb": 100, # 100MB limit
"max_documents": 50, # Maximum 50 documents
"allowed_document_types": [
"filled_form",
"supporting_document",
"calculation_summary",
"audit_trail",
],
"required_forms": ["SA100"], # SA100 is always required
"supported_file_formats": [".pdf", ".jpg", ".png"],
}
# Test validation rule structure
assert isinstance(validation_rules["max_total_size_mb"], int)
assert isinstance(validation_rules["max_documents"], int)
assert isinstance(validation_rules["allowed_document_types"], list)
assert isinstance(validation_rules["required_forms"], list)
assert isinstance(validation_rules["supported_file_formats"], list)
# Test that SA100 is required
assert "SA100" in validation_rules["required_forms"]
# Test that PDF is supported
assert ".pdf" in validation_rules["supported_file_formats"]
class TestHealthEndpoint:
"""Test health check endpoint"""
@pytest.mark.asyncio
async def test_health_check_endpoint(self) -> None:
"""Test health check endpoint returns correct data"""
from apps.svc_forms.main import health_check
result = await health_check()
assert result["status"] == "healthy"
assert result["service"] == "svc-forms"
assert "timestamp" in result
assert "supported_forms" in result
assert isinstance(result["supported_forms"], list)
class TestFormFilling:
"""Test form filling functionality"""
@pytest.mark.asyncio
async def test_fill_form_async_sa100(self) -> None:
"""Test async form filling for SA100"""
from apps.svc_forms.main import _fill_form_async
form_id = "SA100"
field_values = {
"taxpayer_name": "John Smith",
"nino": "AB123456C",
"total_income": "50000.00",
}
tenant_id = "tenant1"
filling_id = "FILL123"
actor = "user1"
with (
patch("apps.svc_forms.main.pdf_form_filler") as mock_pdf_filler,
patch("apps.svc_forms.main.storage_client") as mock_storage,
patch("apps.svc_forms.main.event_bus") as mock_event_bus,
patch("apps.svc_forms.main.metrics") as mock_metrics,
):
# Mock PDF form filler
mock_pdf_filler.fill_form.return_value = b"mock_filled_pdf_content"
# Mock storage operations (async)
mock_storage.put_object = AsyncMock(return_value=True)
mock_event_bus.publish = AsyncMock(return_value=None)
# Mock metrics
mock_counter = Mock()
mock_counter.labels.return_value = mock_counter
mock_counter.inc.return_value = None
mock_metrics.counter.return_value = mock_counter
# Call the function
await _fill_form_async(form_id, field_values, tenant_id, filling_id, actor)
# Verify operations were called
mock_pdf_filler.fill_form.assert_called_once_with(form_id, field_values)
mock_storage.put_object.assert_called()
mock_event_bus.publish.assert_called()
@pytest.mark.asyncio
async def test_fill_form_async_error_handling(self) -> None:
"""Test error handling in async form filling"""
from apps.svc_forms.main import _fill_form_async
form_id = "SA100"
field_values = {"taxpayer_name": "John Smith"}
tenant_id = "tenant1"
filling_id = "FILL123"
actor = "user1"
with (
patch("apps.svc_forms.main.pdf_form_filler") as mock_pdf_filler,
patch("apps.svc_forms.main.event_bus") as mock_event_bus,
patch("apps.svc_forms.main.metrics") as mock_metrics,
):
# Mock PDF processing to raise an error
mock_pdf_filler.fill_form.side_effect = Exception("PDF processing failed")
mock_event_bus.publish = AsyncMock(return_value=None)
# Mock metrics
mock_counter = Mock()
mock_counter.labels.return_value = mock_counter
mock_counter.inc.return_value = None
mock_metrics.counter.return_value = mock_counter
# Call the function - should not raise but log error and update metrics
await _fill_form_async(form_id, field_values, tenant_id, filling_id, actor)
# Verify error metrics were updated
mock_metrics.counter.assert_called_with("form_filling_errors_total")
mock_counter.labels.assert_called_with(
tenant_id=tenant_id, form_id=form_id, error_type="Exception"
)
mock_counter.inc.assert_called()
class TestEvidencePackCreation:
"""Test evidence pack creation functionality"""
@pytest.mark.asyncio
async def test_create_evidence_pack_async(self) -> None:
"""Test async evidence pack creation"""
from apps.svc_forms.main import _create_evidence_pack_async
taxpayer_id = "TP123456"
tax_year = "2023-24"
scope = "full_submission"
evidence_items = [
{
"type": "calculation",
"calculation_id": "CALC123",
"description": "Tax calculation for 2023-24",
},
{
"type": "document",
"document_id": "DOC456",
"description": "P60 for 2023-24",
},
]
tenant_id = "tenant1"
pack_id = "PACK123"
actor = "user1"
with (
patch("apps.svc_forms.main.evidence_pack_generator") as mock_evidence_gen,
patch("apps.svc_forms.main.storage_client") as mock_storage,
patch("apps.svc_forms.main.event_bus") as mock_event_bus,
patch("apps.svc_forms.main.metrics") as mock_metrics,
):
# Mock evidence pack generator
mock_evidence_gen.create_evidence_pack = AsyncMock(
return_value={
"pack_size": 1024,
"evidence_count": 2,
"pack_data": b"mock_pack_data",
}
)
# Mock metrics
mock_counter = Mock()
mock_counter.labels.return_value = mock_counter
mock_counter.inc.return_value = None
mock_metrics.counter.return_value = mock_counter
# Call the function
await _create_evidence_pack_async(
taxpayer_id, tax_year, scope, evidence_items, tenant_id, pack_id, actor
)
# Verify operations were called
mock_evidence_gen.create_evidence_pack.assert_called_once_with(
taxpayer_id=taxpayer_id,
tax_year=tax_year,
scope=scope,
evidence_items=evidence_items,
)
mock_metrics.counter.assert_called_with("evidence_packs_created_total")
mock_counter.labels.assert_called_with(tenant_id=tenant_id, scope=scope)
mock_counter.inc.assert_called()
@pytest.mark.asyncio
async def test_create_evidence_pack_async_error_handling(self) -> None:
"""Test error handling in async evidence pack creation"""
from apps.svc_forms.main import _create_evidence_pack_async
taxpayer_id = "TP123456"
tax_year = "2023-24"
scope = "full_submission"
evidence_items = [{"type": "calculation", "calculation_id": "CALC123"}]
tenant_id = "tenant1"
pack_id = "PACK123"
actor = "user1"
with (
patch("apps.svc_forms.main.evidence_pack_generator") as mock_evidence_gen,
patch("apps.svc_forms.main.event_bus") as mock_event_bus,
):
# Mock evidence pack generator to raise an error
mock_evidence_gen.create_evidence_pack = AsyncMock(
side_effect=Exception("Evidence pack creation failed")
)
mock_event_bus.publish = AsyncMock(return_value=None)
# Call the function - should not raise but log error
await _create_evidence_pack_async(
taxpayer_id, tax_year, scope, evidence_items, tenant_id, pack_id, actor
)
# Verify evidence pack generator was called and failed
mock_evidence_gen.create_evidence_pack.assert_called_once_with(
taxpayer_id=taxpayer_id,
tax_year=tax_year,
scope=scope,
evidence_items=evidence_items,
)
class TestEventHandling:
"""Test event handling functionality"""
@pytest.mark.asyncio
async def test_handle_calculation_ready(self) -> None:
"""Test handling calculation ready events"""
from apps.svc_forms.main import _handle_calculation_ready
from libs.events import EventPayload
# Create mock event payload
payload = EventPayload(
actor="user1",
tenant_id="tenant1",
data={
"calculation_id": "CALC123",
"schedule": "SA100",
"taxpayer_id": "TP123",
"tenant_id": "tenant1",
"actor": "user1",
},
)
with patch("apps.svc_forms.main.BackgroundTasks") as mock_bg_tasks:
mock_bg_tasks.return_value = Mock()
# Call the function
await _handle_calculation_ready("calculation_ready", payload)
# Should not raise an error
assert True # If we get here, the function completed successfully
@pytest.mark.asyncio
async def test_handle_calculation_ready_missing_data(self) -> None:
"""Test handling calculation ready events with missing data"""
from apps.svc_forms.main import _handle_calculation_ready
from libs.events import EventPayload
# Create mock event payload with missing data
payload = EventPayload(
data={}, # Missing required fields
actor="test_user",
tenant_id="tenant1",
)
# Call the function - should handle gracefully
await _handle_calculation_ready("calculation_ready", payload)
# Should not raise an error
assert True
class TestHealthEndpoints:
"""Test health check endpoints"""
@pytest.mark.asyncio
async def test_health_check_endpoint(self) -> None:
"""Test health check endpoint"""
from apps.svc_forms.main import health_check
result = await health_check()
assert result["status"] == "healthy"
assert result["service"] == "svc-forms"
assert "version" in result
assert "timestamp" in result
assert "supported_forms" in result
@pytest.mark.asyncio
async def test_list_supported_forms_endpoint(self) -> None:
"""Test list supported forms endpoint"""
from apps.svc_forms.main import list_supported_forms
# Mock dependencies
current_user = {"user_id": "test_user"}
tenant_id = "test_tenant"
result = await list_supported_forms(current_user, tenant_id)
assert isinstance(result, dict)
assert "supported_forms" in result
assert isinstance(result["supported_forms"], list)
assert "total_forms" in result
class TestFormValidation:
"""Test form validation business logic"""
def test_supported_form_validation_sa100(self) -> None:
"""Test validation of supported SA100 form"""
from apps.svc_forms.main import settings
form_id = "SA100"
# Test that SA100 is in supported forms
assert form_id in settings.supported_forms
# Test form validation logic
is_supported = form_id in settings.supported_forms
assert is_supported is True
def test_supported_form_validation_invalid(self) -> None:
"""Test validation of unsupported form"""
from apps.svc_forms.main import settings
form_id = "INVALID_FORM"
# Test that invalid form is not supported
is_supported = form_id in settings.supported_forms
assert is_supported is False
def test_field_values_processing_basic(self) -> None:
"""Test basic field values processing"""
field_values = {
"taxpayer_name": "John Smith",
"nino": "AB123456C",
"total_income": "50000.00",
"box_1": "25000",
"box_2": "15000",
}
# Test field count
assert len(field_values) == 5
# Test field types
assert isinstance(field_values["taxpayer_name"], str)
assert isinstance(field_values["total_income"], str)
# Test box field processing
box_fields = {k: v for k, v in field_values.items() if k.startswith("box_")}
assert len(box_fields) == 2
assert "box_1" in box_fields
assert "box_2" in box_fields
def test_form_boxes_to_field_values_conversion(self) -> None:
"""Test conversion from form boxes to field values"""
form_boxes = {
"1": {"value": 50000, "description": "Total income"},
"2": {"value": 5000, "description": "Tax deducted"},
"3": {"value": 2000, "description": "Other income"},
}
# Convert to field values format
field_values = {}
for box_id, box_data in form_boxes.items():
field_values[f"box_{box_id}"] = box_data["value"]
# Test conversion
assert len(field_values) == 3
assert field_values["box_1"] == 50000
assert field_values["box_2"] == 5000
assert field_values["box_3"] == 2000
class TestEvidencePackLogic:
"""Test evidence pack business logic"""
def test_evidence_items_validation_basic(self) -> None:
"""Test basic evidence items validation"""
evidence_items = [
{
"type": "calculation",
"calculation_id": "CALC123",
"description": "Tax calculation for 2023-24",
},
{
"type": "document",
"document_id": "DOC456",
"description": "P60 for 2023-24",
},
]
# Test evidence items structure
assert len(evidence_items) == 2
# Test first item
calc_item = evidence_items[0]
assert calc_item["type"] == "calculation"
assert "calculation_id" in calc_item
assert "description" in calc_item
# Test second item
doc_item = evidence_items[1]
assert doc_item["type"] == "document"
assert "document_id" in doc_item
assert "description" in doc_item
def test_evidence_pack_scope_validation(self) -> None:
"""Test evidence pack scope validation"""
valid_scopes = ["full_submission", "partial_submission", "supporting_docs"]
for scope in valid_scopes:
# Test that scope is a valid string
assert isinstance(scope, str)
assert len(scope) > 0
# Test invalid scope
invalid_scope = ""
assert len(invalid_scope) == 0
def test_taxpayer_id_validation(self) -> None:
"""Test taxpayer ID validation"""
valid_taxpayer_ids = ["TP123456", "TAXPAYER_001", "12345678"]
for taxpayer_id in valid_taxpayer_ids:
# Test basic validation
assert isinstance(taxpayer_id, str)
assert len(taxpayer_id) > 0
assert taxpayer_id.strip() == taxpayer_id # No leading/trailing spaces
def test_tax_year_format_validation(self) -> None:
"""Test tax year format validation"""
valid_tax_years = ["2023-24", "2022-23", "2021-22"]
for tax_year in valid_tax_years:
# Test format
assert isinstance(tax_year, str)
assert len(tax_year) == 7 # Format: YYYY-YY
assert "-" in tax_year
# Test year parts
parts = tax_year.split("-")
assert len(parts) == 2
assert len(parts[0]) == 4 # Full year
assert len(parts[1]) == 2 # Short year
class TestFormFillingLogic:
"""Test form filling business logic"""
def test_filling_id_generation_format(self) -> None:
"""Test filling ID generation format"""
import ulid
# Generate filling ID like the service does
filling_id = str(ulid.new())
# Test format
assert isinstance(filling_id, str)
assert len(filling_id) == 26 # ULID length
# Test uniqueness
filling_id2 = str(ulid.new())
assert filling_id != filling_id2
def test_object_key_generation(self) -> None:
"""Test S3 object key generation"""
tenant_id = "tenant123"
filling_id = "01HKQM7XQZX8QZQZQZQZQZQZQZ"
# Generate object key like the service does
object_key = f"tenants/{tenant_id}/filled/{filling_id}.pdf"
# Test format
assert object_key == "tenants/tenant123/filled/01HKQM7XQZX8QZQZQZQZQZQZQZ.pdf"
assert object_key.startswith("tenants/")
assert object_key.endswith(".pdf")
assert tenant_id in object_key
assert filling_id in object_key
def test_form_metadata_generation(self) -> None:
"""Test form metadata generation"""
from datetime import datetime
form_id = "SA100"
filling_id = "FILL123"
tenant_id = "tenant1"
calculation_id = "CALC456"
# Generate metadata like the service does
metadata = {
"form_id": form_id,
"filling_id": filling_id,
"tenant_id": tenant_id,
"calculation_id": calculation_id or "",
"filled_at": datetime.utcnow().isoformat(),
}
# Test metadata structure
assert "form_id" in metadata
assert "filling_id" in metadata
assert "tenant_id" in metadata
assert "calculation_id" in metadata
assert "filled_at" in metadata
# Test values
assert metadata["form_id"] == form_id
assert metadata["filling_id"] == filling_id
assert metadata["tenant_id"] == tenant_id
assert metadata["calculation_id"] == calculation_id
if __name__ == "__main__":
pytest.main([__file__])