""" Tests for the unified reference-number generator (apps.core.reference). Covers: hospital-token sanitization, format, per-module prefix coverage, sequence monotonicity, None-hospital fallback, and concurrent allocation uniqueness. """ import threading from datetime import datetime from unittest.mock import patch from django.test import TestCase, TransactionTestCase from apps.core.models import ReferenceSequence from apps.core.reference import generate_reference, sanitize_hospital_token from apps.organizations.models import Hospital, Organization def _make_hospital(code="TEST-HOSP"): org, _ = Organization.objects.get_or_create(code="TEST-ORG", defaults={"name": "Test Org", "status": "active"}) hospital, _ = Hospital.objects.get_or_create( code=code, defaults={"organization": org, "name": f"Test {code}", "status": "active"}, ) return hospital class SanitizeTokenTest(TestCase): def test_strips_hyphens_and_uppercases(self): class H: def __init__(self, code): self.code = code self.assertEqual(sanitize_hospital_token(H("HH-N")), "HHN") self.assertEqual(sanitize_hospital_token(H("e2e-hosp")), "E2EHOSP") self.assertEqual(sanitize_hospital_token(H("main-campus-1")), "MAINCAMPUS1") def test_none_or_empty_hospital(self): self.assertEqual(sanitize_hospital_token(None), "GEN") self.assertEqual(sanitize_hospital_token(object()), "GEN") class Empty: code = "" self.assertEqual(sanitize_hospital_token(Empty()), "GEN") def test_strips_non_alphanumeric(self): class H: def __init__(self, code): self.code = code self.assertEqual(sanitize_hospital_token(H("NUZHA@2026")), "NUZHA2026") self.assertEqual(sanitize_hospital_token(H(" spaced ")), "SPACED") class GenerateReferenceFormatTest(TestCase): def setUp(self): self.hospital = _make_hospital("HH-N") def test_format_and_prefix(self): with patch("apps.core.reference.datetime") as mock_dt: mock_dt.now.return_value = datetime(2026, 6, 14) for prefix in ("CMP", "INQ", "OBS", "APR", "SGT"): ref = generate_reference(prefix, self.hospital) self.assertRegex( ref, rf"^{prefix}-202606-HHN-0001$", f"unexpected ref {ref} for prefix {prefix}", ) def test_sequence_increments_monotonically(self): refs = [generate_reference("CMP", self.hospital) for _ in range(5)] self.assertEqual(refs, [f"CMP-202606-HHN-{i:04d}" for i in range(1, 6)]) # all unique self.assertEqual(len(set(refs)), len(refs)) def test_each_module_has_independent_sequence(self): with patch("apps.core.reference.datetime") as mock_dt: mock_dt.now.return_value = datetime(2026, 6, 14) cmp1 = generate_reference("CMP", self.hospital) inq1 = generate_reference("INQ", self.hospital) cmp2 = generate_reference("CMP", self.hospital) self.assertIn("-0001", cmp1) self.assertIn("-0001", inq1) # independent sequence self.assertIn("-0002", cmp2) def test_per_hospital_isolation(self): h2 = _make_hospital("HH-A") with patch("apps.core.reference.datetime") as mock_dt: mock_dt.now.return_value = datetime(2026, 6, 14) ref_n = generate_reference("CMP", self.hospital) # HHN ref_a = generate_reference("CMP", h2) # HHA self.assertIn("-HHN-", ref_n) self.assertIn("-HHA-", ref_a) self.assertIn("-0001", ref_n) self.assertIn("-0001", ref_a) # separate counter per hospital def test_none_hospital_fallback(self): ref = generate_reference("CMP", None) self.assertRegex(ref, r"^CMP-\d{6}-GEN-0001$") def test_sequence_resets_per_month(self): with patch("apps.core.reference.datetime") as mock_dt: mock_dt.now.return_value = datetime(2026, 6, 14) generate_reference("CMP", self.hospital) generate_reference("CMP", self.hospital) # 202606 -> 2 mock_dt.now.return_value = datetime(2026, 7, 1) july_ref = generate_reference("CMP", self.hospital) self.assertIn("-202607-HHN-0001", july_ref) class ConcurrencyTest(TransactionTestCase): """Concurrent allocation must never produce duplicate sequence numbers.""" def test_concurrent_allocations_are_unique(self): hospital = _make_hospital("HH-S") n = 40 results = [None] * n barrier = threading.Barrier(n) def worker(idx): barrier.wait() results[idx] = generate_reference("CMP", hospital) threads = [threading.Thread(target=worker, args=(i,)) for i in range(n)] for t in threads: t.start() for t in threads: t.join(timeout=30) self.assertNotIn(None, results, "a worker did not produce a reference") self.assertEqual(len(set(results)), n, "duplicate references allocated under concurrency") # numbers should be exactly 1..n numbers = sorted(int(r.split("-")[-1]) for r in results) self.assertEqual(numbers, list(range(1, n + 1))) # one sequence row for this key self.assertEqual(ReferenceSequence.objects.filter(prefix="CMP", hospital_token="HHS").count(), 1)