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)
This commit is contained in:
0
tests/ccw/__init__.py
Normal file
0
tests/ccw/__init__.py
Normal file
109
tests/ccw/test_docs.py
Normal file
109
tests/ccw/test_docs.py
Normal file
@@ -0,0 +1,109 @@
|
||||
"""Tests for CCW FFS Claims Codebook variable documentation.
|
||||
|
||||
Validates that all 308 auto-generated variable modules have
|
||||
consistent structure and required attributes.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
|
||||
import pytest
|
||||
|
||||
from ccw.docs import VARIABLES
|
||||
|
||||
# ── VARIABLES registry ───────────────────────────────────────────
|
||||
|
||||
|
||||
class TestVariablesRegistry:
|
||||
def test_variables_is_list(self) -> None:
|
||||
assert isinstance(VARIABLES, list)
|
||||
|
||||
def test_variables_count(self) -> None:
|
||||
assert len(VARIABLES) == 308
|
||||
|
||||
def test_at_most_one_duplicate(self) -> None:
|
||||
# rndrng_physn_upin appears twice in the PDF codebook
|
||||
unique = set(VARIABLES)
|
||||
assert len(VARIABLES) - len(unique) <= 1
|
||||
|
||||
def test_all_lowercase(self) -> None:
|
||||
for v in VARIABLES:
|
||||
assert v == v.lower(), f"{v} is not lowercase"
|
||||
|
||||
|
||||
# ── Module importability ─────────────────────────────────────────
|
||||
|
||||
|
||||
class TestImportability:
|
||||
@pytest.fixture(params=VARIABLES)
|
||||
def var_module(self, request):
|
||||
return importlib.import_module(f"ccw.docs.{request.param}")
|
||||
|
||||
def test_importable(self, var_module) -> None:
|
||||
assert var_module is not None
|
||||
|
||||
|
||||
# ── Required attributes ──────────────────────────────────────────
|
||||
|
||||
|
||||
REQUIRED_ATTRS = ["name", "label", "type", "length", "source"]
|
||||
VALID_TYPES = {"CHAR", "NUM", "DATE"}
|
||||
|
||||
|
||||
class TestAttributes:
|
||||
@pytest.fixture(params=VARIABLES)
|
||||
def var_module(self, request):
|
||||
return importlib.import_module(f"ccw.docs.{request.param}")
|
||||
|
||||
@pytest.mark.parametrize("attr", REQUIRED_ATTRS)
|
||||
def test_has_required_attr(self, var_module, attr) -> None:
|
||||
assert hasattr(var_module, attr), f"{var_module.__name__} missing '{attr}'"
|
||||
|
||||
def test_name_starts_uppercase(self, var_module) -> None:
|
||||
# Most names are fully uppercase; a few have mixed-case
|
||||
# parenthetical qualifiers (e.g. "PRVDR_NUM (Institutional claim)")
|
||||
base = var_module.name.split("(")[0].strip()
|
||||
assert base == base.upper()
|
||||
|
||||
def test_type_is_valid(self, var_module) -> None:
|
||||
assert var_module.type in VALID_TYPES, (
|
||||
f"{var_module.__name__}: type={var_module.type!r} not in {VALID_TYPES}"
|
||||
)
|
||||
|
||||
def test_label_non_empty(self, var_module) -> None:
|
||||
assert len(var_module.label) > 0
|
||||
|
||||
def test_length_is_numeric_string(self, var_module) -> None:
|
||||
assert var_module.length.isdigit(), (
|
||||
f"{var_module.__name__}: length={var_module.length!r} not numeric"
|
||||
)
|
||||
|
||||
|
||||
# ── Spot checks ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestSpotChecks:
|
||||
def test_bene_id(self) -> None:
|
||||
mod = importlib.import_module("ccw.docs.bene_id")
|
||||
assert mod.name == "BENE_ID"
|
||||
assert mod.label == "Encrypted CCW Beneficiary ID"
|
||||
assert mod.type == "CHAR"
|
||||
assert mod.length == "15"
|
||||
assert mod.source == "CCW"
|
||||
|
||||
def test_numeric_variable(self) -> None:
|
||||
mod = importlib.import_module("ccw.docs.nch_prmry_pyr_clm_pd_amt")
|
||||
assert mod.name == "NCH_PRMRY_PYR_CLM_PD_AMT"
|
||||
assert mod.type == "NUM"
|
||||
assert mod.short_name == "PRPAYAMT"
|
||||
|
||||
def test_has_short_and_long_name(self) -> None:
|
||||
mod = importlib.import_module("ccw.docs.bene_id")
|
||||
assert hasattr(mod, "short_name")
|
||||
assert hasattr(mod, "long_name")
|
||||
|
||||
def test_docstring_present(self) -> None:
|
||||
mod = importlib.import_module("ccw.docs.bene_id")
|
||||
assert mod.__doc__ is not None
|
||||
assert "BENE_ID" in mod.__doc__
|
||||
221
tests/ccw/test_table.py
Normal file
221
tests/ccw/test_table.py
Normal file
@@ -0,0 +1,221 @@
|
||||
"""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"
|
||||
144
tests/cms/test_log.py
Normal file
144
tests/cms/test_log.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""Tests for cms.log — JSONL structured logging."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from cms.log import JsonlHandler, setup
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def log_path(tmp_path):
|
||||
return tmp_path / "test.jsonl"
|
||||
|
||||
|
||||
class TestJsonlHandler:
|
||||
def test_creates_parent_dirs(self, tmp_path) -> None:
|
||||
path = tmp_path / "nested" / "dir" / "log.jsonl"
|
||||
handler = JsonlHandler(path)
|
||||
assert path.parent.exists()
|
||||
handler.close()
|
||||
|
||||
def test_writes_json_line(self, log_path) -> None:
|
||||
handler = JsonlHandler(log_path)
|
||||
logger = logging.getLogger("test.jsonl")
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.info("hello world")
|
||||
handler.close()
|
||||
|
||||
lines = log_path.read_text().strip().split("\n")
|
||||
assert len(lines) == 1
|
||||
entry = json.loads(lines[0])
|
||||
assert entry["message"] == "hello world"
|
||||
assert entry["level"] == "INFO"
|
||||
assert entry["logger"] == "test.jsonl"
|
||||
assert "ts" in entry
|
||||
logger.removeHandler(handler)
|
||||
|
||||
def test_multiple_records(self, log_path) -> None:
|
||||
handler = JsonlHandler(log_path)
|
||||
logger = logging.getLogger("test.multi")
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.info("first")
|
||||
logger.warning("second")
|
||||
logger.debug("third")
|
||||
handler.close()
|
||||
|
||||
lines = log_path.read_text().strip().split("\n")
|
||||
assert len(lines) == 3
|
||||
levels = [json.loads(l)["level"] for l in lines]
|
||||
assert levels == ["INFO", "WARNING", "DEBUG"]
|
||||
logger.removeHandler(handler)
|
||||
|
||||
def test_custom_attrs(self, log_path) -> None:
|
||||
handler = JsonlHandler(log_path)
|
||||
logger = logging.getLogger("test.custom")
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.info("with extra", extra={"job_id": "abc123", "count": 42})
|
||||
handler.close()
|
||||
|
||||
entry = json.loads(log_path.read_text().strip())
|
||||
assert entry["job_id"] == "abc123"
|
||||
assert entry["count"] == 42
|
||||
logger.removeHandler(handler)
|
||||
|
||||
def test_exception_info(self, log_path) -> None:
|
||||
handler = JsonlHandler(log_path)
|
||||
logger = logging.getLogger("test.exc")
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
try:
|
||||
raise ValueError("test error")
|
||||
except ValueError:
|
||||
logger.exception("caught error")
|
||||
handler.close()
|
||||
|
||||
entry = json.loads(log_path.read_text().strip())
|
||||
assert entry["message"] == "caught error"
|
||||
assert "exception" in entry
|
||||
assert any("ValueError" in line for line in entry["exception"])
|
||||
logger.removeHandler(handler)
|
||||
|
||||
def test_append_mode(self, log_path) -> None:
|
||||
log_path.write_text('{"existing": true}\n')
|
||||
handler = JsonlHandler(log_path)
|
||||
logger = logging.getLogger("test.append")
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.info("appended")
|
||||
handler.close()
|
||||
|
||||
lines = log_path.read_text().strip().split("\n")
|
||||
assert len(lines) == 2
|
||||
logger.removeHandler(handler)
|
||||
|
||||
|
||||
class TestSetup:
|
||||
def test_returns_logger(self, log_path) -> None:
|
||||
logger = setup(log_path)
|
||||
assert isinstance(logger, logging.Logger)
|
||||
assert logger.name == "cms"
|
||||
# Cleanup
|
||||
for h in logger.handlers[:]:
|
||||
if isinstance(h, JsonlHandler):
|
||||
h.close()
|
||||
logger.removeHandler(h)
|
||||
|
||||
def test_sets_level(self, log_path) -> None:
|
||||
logger = setup(log_path, level=logging.WARNING)
|
||||
assert logger.level <= logging.WARNING
|
||||
for h in logger.handlers[:]:
|
||||
if isinstance(h, JsonlHandler):
|
||||
h.close()
|
||||
logger.removeHandler(h)
|
||||
|
||||
def test_idempotent_same_path(self, log_path) -> None:
|
||||
logger1 = setup(log_path)
|
||||
count_before = sum(1 for h in logger1.handlers if isinstance(h, JsonlHandler))
|
||||
logger2 = setup(log_path)
|
||||
count_after = sum(1 for h in logger2.handlers if isinstance(h, JsonlHandler))
|
||||
assert count_before == count_after
|
||||
assert logger1 is logger2
|
||||
for h in logger1.handlers[:]:
|
||||
if isinstance(h, JsonlHandler):
|
||||
h.close()
|
||||
logger1.removeHandler(h)
|
||||
|
||||
def test_different_paths_add_handlers(self, tmp_path) -> None:
|
||||
p1 = tmp_path / "a.jsonl"
|
||||
p2 = tmp_path / "b.jsonl"
|
||||
logger = setup(p1)
|
||||
before = sum(1 for h in logger.handlers if isinstance(h, JsonlHandler))
|
||||
setup(p2)
|
||||
after = sum(1 for h in logger.handlers if isinstance(h, JsonlHandler))
|
||||
assert after == before + 1
|
||||
for h in logger.handlers[:]:
|
||||
if isinstance(h, JsonlHandler):
|
||||
h.close()
|
||||
logger.removeHandler(h)
|
||||
157
tests/cms/test_table.py
Normal file
157
tests/cms/test_table.py
Normal file
@@ -0,0 +1,157 @@
|
||||
"""Tests for CMS table models (SQLTable subclasses).
|
||||
|
||||
Validates that all 150 auto-generated Pydantic table models:
|
||||
- Are importable from ``cms.table``
|
||||
- Have correct schema/tablename metadata
|
||||
- Expose ``qualified_name()`` and ``column_names()``
|
||||
- Can be constructed with nullable fields
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from datetime import date
|
||||
|
||||
import pytest
|
||||
|
||||
import cms.table
|
||||
from aco.table.base import SQLTable
|
||||
|
||||
# ── __init__.py completeness ─────────────────────────────────────
|
||||
|
||||
|
||||
class TestInit:
|
||||
"""cms.table __init__.py re-exports all models."""
|
||||
|
||||
def test_all_list_populated(self) -> None:
|
||||
assert len(cms.table.__all__) == 150
|
||||
|
||||
def test_all_names_resolve(self) -> None:
|
||||
for name in cms.table.__all__:
|
||||
cls = getattr(cms.table, name)
|
||||
assert inspect.isclass(cls), f"{name} is not a class"
|
||||
|
||||
def test_all_are_sqltable_subclasses(self) -> None:
|
||||
for name in cms.table.__all__:
|
||||
cls = getattr(cms.table, name)
|
||||
assert issubclass(cls, SQLTable), f"{name} not a SQLTable"
|
||||
|
||||
|
||||
# ── Schema metadata ──────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestSchemaMetadata:
|
||||
"""Every CMS table has __schema__='cms' and a non-empty __tablename__."""
|
||||
|
||||
@pytest.fixture(params=cms.table.__all__)
|
||||
def table_cls(self, request):
|
||||
return getattr(cms.table, request.param)
|
||||
|
||||
def test_schema_is_cms(self, table_cls) -> None:
|
||||
assert table_cls.__schema__ == "cms"
|
||||
|
||||
def test_tablename_set(self, table_cls) -> None:
|
||||
assert table_cls.__tablename__, f"{table_cls.__name__} has empty tablename"
|
||||
|
||||
def test_qualified_name(self, table_cls) -> None:
|
||||
qn = table_cls.qualified_name()
|
||||
assert qn == f"cms.{table_cls.__tablename__}"
|
||||
|
||||
def test_column_names_non_empty(self, table_cls) -> None:
|
||||
cols = table_cls.column_names()
|
||||
assert len(cols) > 0, f"{table_cls.__name__} has no columns"
|
||||
|
||||
|
||||
# ── Tablename uniqueness ─────────────────────────────────────────
|
||||
|
||||
|
||||
class TestUniqueness:
|
||||
def test_no_duplicate_tablenames(self) -> None:
|
||||
names = [getattr(cms.table, n).__tablename__ for n in cms.table.__all__]
|
||||
assert len(names) == len(set(names))
|
||||
|
||||
def test_no_duplicate_class_names(self) -> None:
|
||||
assert len(cms.table.__all__) == len(set(cms.table.__all__))
|
||||
|
||||
|
||||
# ── Field types ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestFieldTypes:
|
||||
"""All fields should be nullable (Optional)."""
|
||||
|
||||
def test_all_fields_have_defaults(self) -> None:
|
||||
"""Every field should have a default of None."""
|
||||
for name in cms.table.__all__:
|
||||
cls = getattr(cms.table, name)
|
||||
for field_name, field_info in cls.model_fields.items():
|
||||
assert field_info.default is None, (
|
||||
f"{cls.__name__}.{field_name} has no None default"
|
||||
)
|
||||
|
||||
|
||||
# ── Construction ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestConstruction:
|
||||
"""Models can be constructed empty or with kwargs."""
|
||||
|
||||
def test_empty_construction(self) -> None:
|
||||
cls = cms.table.AccountableCareOrganizations
|
||||
obj = cls()
|
||||
assert obj.aco_id is None
|
||||
assert obj.aco_name is None
|
||||
|
||||
def test_construction_with_kwargs(self) -> None:
|
||||
obj = cms.table.AccountableCareOrganizations(
|
||||
aco_id="A1234",
|
||||
aco_name="Test ACO",
|
||||
)
|
||||
assert obj.aco_id == "A1234"
|
||||
assert obj.aco_name == "Test ACO"
|
||||
|
||||
def test_date_field_construction(self) -> None:
|
||||
obj = cms.table.AccountableCareOrganizations(
|
||||
current_start_date=date(2024, 1, 1),
|
||||
)
|
||||
assert obj.current_start_date == date(2024, 1, 1)
|
||||
|
||||
def test_from_attributes_config(self) -> None:
|
||||
cls = cms.table.AccountableCareOrganizations
|
||||
assert cls.model_config.get("from_attributes") is True
|
||||
|
||||
def test_large_model_construction(self) -> None:
|
||||
"""The largest table (AcoReachFinancialQualityResults, 131 fields)."""
|
||||
cls = cms.table.AcoReachFinancialQualityResults
|
||||
obj = cls()
|
||||
assert len(cls.column_names()) == 131
|
||||
for col in cls.column_names():
|
||||
assert getattr(obj, col) is None
|
||||
|
||||
|
||||
# ── Representative spot-checks ───────────────────────────────────
|
||||
|
||||
|
||||
class TestSpotChecks:
|
||||
"""Verify specific tables have expected columns."""
|
||||
|
||||
def test_medicare_monthly_enrollment(self) -> None:
|
||||
cls = cms.table.MedicareMonthlyEnrollment
|
||||
cols = cls.column_names()
|
||||
assert "tot_benes" in cols
|
||||
assert "bene_state_abrvtn" in cols
|
||||
assert len(cols) == 60
|
||||
|
||||
def test_hospital_service_area(self) -> None:
|
||||
cls = cms.table.HospitalServiceArea
|
||||
assert cls.__tablename__ == "hospital_service_area"
|
||||
assert len(cls.column_names()) > 0
|
||||
|
||||
def test_opt_out_affidavits(self) -> None:
|
||||
cls = cms.table.OptOutAffidavits
|
||||
assert cls.qualified_name() == "cms.opt_out_affidavits"
|
||||
|
||||
def test_medicaid_spending_by_drug(self) -> None:
|
||||
cls = cms.table.MedicaidSpendingByDrug
|
||||
assert cls.__schema__ == "cms"
|
||||
assert "drug_name" in cls.column_names() or len(cls.column_names()) > 0
|
||||
Reference in New Issue
Block a user