Files
stack/tests/ccw/test_table.py
kert 8b33613910
All checks were successful
ci/woodpecker/push/infra-ci Pipeline was successful
ci/woodpecker/push/deploy Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
add test coverage for CMS table models, CMS logging, and CCW tables/docs
3946 new tests covering:
- cms.table: all 150 SQLTable models (schema, tablename, qualified_name,
  column_names, nullable fields, construction, uniqueness)
- cms.log: JsonlHandler, setup() idempotency, custom attrs, exceptions
- ccw.table: all 41 claim tables across 7 types (IP, SNF, Hospice, HHA,
  HOP, Carrier, DME) with structural validation
- ccw.docs: all 308 variable documentation modules (importability,
  required attrs, type validation)
2026-02-28 20:44:53 -05:00

222 lines
7.6 KiB
Python

"""Tests for CCW FFS Claims table models.
Validates that all 41 auto-generated Pydantic table models across
7 claim types (IP, SNF, Hospice, HHA, HOP, Carrier, DME) follow
the SQLTable contract.
"""
from __future__ import annotations
import inspect
from datetime import date
import pytest
from aco.table.base import SQLTable
from ccw.table import carrier, dme, hha, hop, hospice, ip, snf
def _all_ccw_classes():
"""Collect all SQLTable subclasses from all CCW table modules."""
classes = []
for mod in [carrier, dme, hha, hop, hospice, ip, snf]:
for name, cls in inspect.getmembers(mod, inspect.isclass):
if issubclass(cls, SQLTable) and cls is not SQLTable:
classes.append(cls)
return classes
ALL_CCW_CLASSES = _all_ccw_classes()
ALL_CCW_IDS = [cls.__name__ for cls in ALL_CCW_CLASSES]
# ── Module importability ─────────────────────────────────────────
class TestImports:
def test_all_seven_modules_import(self) -> None:
pass
def test_total_class_count(self) -> None:
assert len(ALL_CCW_CLASSES) == 41
# ── Schema metadata (parametrized across all 41 classes) ─────────
class TestSchemaMetadata:
@pytest.fixture(params=ALL_CCW_CLASSES, ids=ALL_CCW_IDS)
def table_cls(self, request):
return request.param
def test_schema_is_ccw(self, table_cls) -> None:
assert table_cls.__schema__ == "ccw"
def test_tablename_set(self, table_cls) -> None:
assert table_cls.__tablename__, f"{table_cls.__name__} empty tablename"
def test_qualified_name(self, table_cls) -> None:
assert table_cls.qualified_name() == f"ccw.{table_cls.__tablename__}"
def test_column_names_non_empty(self, table_cls) -> None:
assert len(table_cls.column_names()) > 0
def test_all_fields_nullable(self, table_cls) -> None:
for field_name, field_info in table_cls.model_fields.items():
assert field_info.default is None, (
f"{table_cls.__name__}.{field_name} not nullable"
)
# ── Claim type structure ─────────────────────────────────────────
class TestClaimTypeStructure:
"""Institutional claim types (IP, SNF, Hospice, HHA, HOP) have 7
sub-tables each; professional types (Carrier, DME) have 3 each."""
@pytest.mark.parametrize(
"mod,expected",
[
(ip, 7),
(snf, 7),
(hospice, 7),
(hha, 7),
(hop, 7),
(carrier, 3),
(dme, 3),
],
)
def test_subtable_count(self, mod, expected) -> None:
classes = [
c
for _, c in inspect.getmembers(mod, inspect.isclass)
if issubclass(c, SQLTable) and c is not SQLTable
]
assert len(classes) == expected
@pytest.mark.parametrize(
"mod,prefix",
[
(ip, "Ip"),
(snf, "Snf"),
(hospice, "Hospice"),
(hha, "Hha"),
(hop, "Hop"),
],
)
def test_institutional_subtable_names(self, mod, prefix) -> None:
"""Each institutional claim type has Base, RevenueCenter,
ConditionCode, OccurrenceCode, SpanCode, ValueCode, Demo."""
expected = {
f"{prefix}Base",
f"{prefix}RevenueCenter",
f"{prefix}ConditionCode",
f"{prefix}OccurrenceCode",
f"{prefix}SpanCode",
f"{prefix}ValueCode",
f"{prefix}Demo",
}
actual = {
name
for name, cls in inspect.getmembers(mod, inspect.isclass)
if issubclass(cls, SQLTable) and cls is not SQLTable
}
assert actual == expected
@pytest.mark.parametrize("mod,prefix", [(carrier, "Carrier"), (dme, "Dme")])
def test_professional_subtable_names(self, mod, prefix) -> None:
expected = {f"{prefix}Base", f"{prefix}Line", f"{prefix}Demo"}
actual = {
name
for name, cls in inspect.getmembers(mod, inspect.isclass)
if issubclass(cls, SQLTable) and cls is not SQLTable
}
assert actual == expected
# ── Tablename uniqueness ─────────────────────────────────────────
class TestUniqueness:
def test_no_duplicate_tablenames(self) -> None:
names = [cls.__tablename__ for cls in ALL_CCW_CLASSES]
assert len(names) == len(set(names))
# ── Field type correctness ───────────────────────────────────────
class TestFieldTypes:
"""CCW tables use str, float, and date field types."""
def test_field_types_are_expected(self) -> None:
allowed = {str, float, date}
for cls in ALL_CCW_CLASSES:
for field_name, field_info in cls.model_fields.items():
annotation = field_info.annotation
# Annotation is `T | None` — extract the base type
# For union types, __args__ gives (T, NoneType)
if hasattr(annotation, "__args__"):
base_types = {t for t in annotation.__args__ if t is not type(None)}
assert base_types.issubset(allowed), (
f"{cls.__name__}.{field_name}: {base_types} not in {allowed}"
)
# ── Construction ─────────────────────────────────────────────────
class TestConstruction:
def test_empty_construction(self) -> None:
obj = ip.IpBase()
assert obj.bene_id is None
assert obj.clm_id is None
def test_construction_with_kwargs(self) -> None:
obj = carrier.CarrierBase(
bene_id="BEN123",
clm_id="CLM456",
clm_pmt_amt=1234.56,
)
assert obj.bene_id == "BEN123"
assert obj.clm_pmt_amt == 1234.56
def test_date_field(self) -> None:
obj = carrier.CarrierBase(clm_from_dt=date(2024, 3, 15))
assert obj.clm_from_dt == date(2024, 3, 15)
def test_from_attributes_config(self) -> None:
assert ip.IpBase.model_config.get("from_attributes") is True
# ── Spot checks — largest tables ─────────────────────────────────
class TestSpotChecks:
def test_ip_base_is_largest(self) -> None:
assert len(ip.IpBase.column_names()) == 252
def test_snf_base_field_count(self) -> None:
assert len(snf.SnfBase.column_names()) == 180
def test_hop_base_field_count(self) -> None:
assert len(hop.HopBase.column_names()) == 167
def test_carrier_line_field_count(self) -> None:
assert len(carrier.CarrierLine.column_names()) == 89
def test_common_key_fields(self) -> None:
"""All Base tables should have bene_id and clm_id."""
for cls in ALL_CCW_CLASSES:
if cls.__name__.endswith("Base"):
cols = cls.column_names()
assert "bene_id" in cols, f"{cls.__name__} missing bene_id"
assert "clm_id" in cols, f"{cls.__name__} missing clm_id"
def test_demo_tables_have_demo_fields(self) -> None:
for cls in ALL_CCW_CLASSES:
if cls.__name__.endswith("Demo"):
cols = cls.column_names()
assert "demo_id_num" in cols, f"{cls.__name__} missing demo_id_num"