This commit is contained in:
HotSwapp
2025-08-18 20:20:04 -05:00
parent 89b2bc0aa2
commit bac8cc4bd5
114 changed files with 30258 additions and 1341 deletions

View File

@@ -0,0 +1,192 @@
import os
import uuid
import csv
import io
import pytest
from fastapi.testclient import TestClient
# Ensure required env vars for app import/config
os.environ.setdefault("SECRET_KEY", "x" * 32)
os.environ.setdefault("DATABASE_URL", "sqlite:////tmp/delphi_test.sqlite")
from app.main import app # noqa: E402
from app.auth.security import get_current_user # noqa: E402
@pytest.fixture(scope="module")
def client():
# Override auth to bypass JWT for these tests
class _User:
def __init__(self):
self.id = "test"
self.username = "tester"
self.is_admin = True
self.is_active = True
app.dependency_overrides[get_current_user] = lambda: _User()
try:
yield TestClient(app)
finally:
app.dependency_overrides.pop(get_current_user, None)
@pytest.fixture(scope="module")
def phone_book_data(client: TestClient):
gid1 = f"PBGRP1-{uuid.uuid4().hex[:6]}"
gid2 = f"PBGRP2-{uuid.uuid4().hex[:6]}"
def _create_customer(cid: str, last: str, first: str, group: str):
payload = {
"id": cid,
"last": last,
"first": first,
"group": group,
"email": f"{cid.lower()}@example.com",
}
resp = client.post("/api/customers/", json=payload)
assert resp.status_code == 200, resp.text
def _add_phone(cid: str, location: str, number: str):
resp = client.post(f"/api/customers/{cid}/phones", json={"location": location, "phone": number})
assert resp.status_code == 200, resp.text
# Create entries for letters A, B and non-alpha '#'
cid_a1 = f"PB-{uuid.uuid4().hex[:6]}-A1"
cid_a2 = f"PB-{uuid.uuid4().hex[:6]}-A2"
cid_b1 = f"PB-{uuid.uuid4().hex[:6]}-B1"
cid_hash = f"PB-{uuid.uuid4().hex[:6]}-H"
_create_customer(cid_a1, last="Alpha", first="Alice", group=gid1)
_add_phone(cid_a1, "Office", "111-111-1111")
_add_phone(cid_a1, "Mobile", "111-111-2222")
_create_customer(cid_a2, last="Able", first="Andy", group=gid1)
_add_phone(cid_a2, "Office", "222-222-2222")
_create_customer(cid_b1, last="Beta", first="Bob", group=gid2)
_add_phone(cid_b1, "Home", "333-333-3333")
_create_customer(cid_hash, last="123Company", first="NA", group=gid1)
_add_phone(cid_hash, "Main", "444-444-4444")
try:
yield {
"gid1": gid1,
"gid2": gid2,
"ids": [cid_a1, cid_a2, cid_b1, cid_hash],
}
finally:
# Cleanup
for cid in [cid_a1, cid_a2, cid_b1, cid_hash]:
client.delete(f"/api/customers/{cid}")
def _parse_csv(text: str):
reader = csv.reader(io.StringIO(text))
rows = list(reader)
return rows[0], rows[1:]
def test_phone_book_csv_letter_column_when_grouped_by_letter(client: TestClient, phone_book_data):
# Only include our test group gid1 to avoid interference
gid = phone_book_data["gid1"]
resp = client.get(
"/api/customers/phone-book",
params={
"format": "csv",
"mode": "numbers",
"grouping": "letter",
"groups": gid,
},
)
assert resp.status_code == 200
assert "text/csv" in resp.headers.get("content-type", "")
header, rows = _parse_csv(resp.text)
assert "Letter" in header
# Ensure letters include 'A' and '#'
letters = {r[header.index("Letter")] for r in rows}
assert "A" in letters and "#" in letters
def test_phone_book_html_sections_by_letter_with_page_break(client: TestClient, phone_book_data):
gid = phone_book_data["gid1"]
resp = client.get(
"/api/customers/phone-book",
params={
"format": "html",
"mode": "numbers",
"grouping": "letter",
"page_break": "1",
"groups": gid,
},
)
assert resp.status_code == 200
html = resp.text
# Snapshot-style checks: section headers and page-break class
assert "Letter: A" in html
assert "Letter: #" in html
assert "class=\"section-title\"" in html
assert "page-break" in html # later sections should have page-break class
def test_phone_book_html_group_then_letter_sections(client: TestClient, phone_book_data):
gid1 = phone_book_data["gid1"]
gid2 = phone_book_data["gid2"]
# Include both groups to verify group and nested letter sections
resp = client.get(
"/api/customers/phone-book",
params=[
("format", "html"),
("mode", "addresses"),
("grouping", "group_letter"),
("groups", gid1),
("groups", gid2),
],
)
assert resp.status_code == 200
html = resp.text
assert f"Group: {gid1}" in html
assert f"Group: {gid2}" in html
assert "Letter: A" in html or "Letter: #" in html
def test_phone_book_csv_no_letter_for_grouping_none(client: TestClient, phone_book_data):
gid = phone_book_data["gid1"]
resp = client.get(
"/api/customers/phone-book",
params={
"format": "csv",
"mode": "numbers",
"grouping": "none",
"groups": gid,
},
)
assert resp.status_code == 200
header, rows = _parse_csv(resp.text)
assert "Letter" not in header
# Basic sanity: names and phones are present
assert any("Alpha" in ",".join(row) or "Able" in ",".join(row) for row in rows)
def test_phone_book_respects_group_filter(client: TestClient, phone_book_data):
gid2 = phone_book_data["gid2"]
resp = client.get(
"/api/customers/phone-book",
params={
"format": "csv",
"mode": "numbers",
"grouping": "letter",
"groups": gid2,
},
)
assert resp.status_code == 200
header, rows = _parse_csv(resp.text)
# Only Beta/Bob (gid2) should be present
all_text = "\n".join([",".join(r) for r in rows])
assert "Beta" in all_text or "Bob" in all_text
# Ensure gid1 names are not present
assert "Alpha" not in all_text and "Able" not in all_text