"""INDL-37 Service Detail Page & PDF Export — pure-unit tests for the
XML-escape / formula-injection guard used by the single-service PDF builder.

``_xml_escape_and_neutralize`` (src/apps/scheduling/services/scheduling_pdf.py)
is a module-level pure function with no reportlab/DB import at module scope,
so it can be exercised directly without Postgres/Redis/reportlab being
installed.

Run in isolation from the DB-backed suite (the top-level ``tests/conftest.py``
imports ``src.main`` / SQLAlchemy at collection time, which requires a live
DB dependency stack to even import):

    python3 -m pytest --confcutdir=tests/apps/scheduling \
        tests/apps/scheduling/test_scheduling_pdf.py -v
"""
import pytest

from src.apps.scheduling.services.scheduling_pdf import _xml_escape_and_neutralize


def test_escapes_xml_metacharacters():
    assert _xml_escape_and_neutralize("<b>test</b>") == "&lt;b&gt;test&lt;/b&gt;"


def test_escapes_ampersand_before_other_entities():
    # Ampersand must be escaped first so "<" -> "&lt;" isn't double-escaped.
    assert _xml_escape_and_neutralize("<a&b>") == "&lt;a&amp;b&gt;"


@pytest.mark.parametrize("prefix", ["=", "+", "-", "@", "\t", "\r"])
def test_neutralizes_formula_injection_prefixes(prefix):
    value = f"{prefix}SUM(1+1)"
    out = _xml_escape_and_neutralize(value)
    assert out.startswith(" " + prefix)


def test_formula_prefix_example_sum():
    assert _xml_escape_and_neutralize("=SUM(1+1)") == " =SUM(1+1)"


def test_none_returns_empty_string():
    assert _xml_escape_and_neutralize(None) == ""


def test_plain_safe_string_passes_through_unchanged():
    assert _xml_escape_and_neutralize("John Smith") == "John Smith"


def test_non_string_is_coerced_to_string():
    assert _xml_escape_and_neutralize(42) == "42"


def test_safe_string_with_no_metachars_and_no_formula_prefix_unchanged():
    assert _xml_escape_and_neutralize("Riverside Cemetery, Section B") == (
        "Riverside Cemetery, Section B"
    )
