Files
stack/tests/cli/test_rec_deep.py
kert 59272d715a feat(rec): OppsPricer — reconcile OPPS APC rates vs Addendum B
Adds the second pricer to the reconciliation engine (rec was open/closed
with only PfsPricer). OppsPricer validates that our OPPS conversion
factor reproduces CMS's published Addendum B national unadjusted rate:

    ground truth = opps.addendum_b.payment_rate  (published, rate > 0)
    calculated   = relative_weight × RULES[year].conversion_factor
                   (APC-priced rows, weight > 0)

Rows with a weight but no published rate (packaged, SI N) surface as
calculated_only; a published rate with no weight (non-APC method) as
ground_truth_only — mirroring how PfsPricer treats carrier-priced codes.
Wage-index adjustment is intentionally out of scope: Addendum B is the
national unadjusted rate, so the check is weight × CF only.

Also:
- stack rec opps CLI subcommand (mirrors rec pfs).
- Pricer-aware "no years available" hint (was hardcoded to PFS tables).

100% coverage on the new module, CLI paths, and registry.

Note: running this against loaded Addendum B data surfaces a systematic
CF drift in opps.rules for CY2021-CY2026 (stored CFs differ from the
empirical payment_rate/weight, which matches the real published CMS
values). Tracked for a follow-up fix — the pricer is doing its job.
2026-07-08 10:38:48 -04:00

125 lines
4.5 KiB
Python

"""Deep exercising tests for cli/rec.py."""
from __future__ import annotations
from unittest.mock import MagicMock, patch
from typer.testing import CliRunner
from cli.rec import app
runner = CliRunner()
class TestListPricers:
@patch(
"rec.pricers.PRICERS",
{
"pfs": MagicMock(
description="PFS", join_keys=["hcpcs"], compare_cols=["fee"]
)
},
)
def test_lists(self):
result = runner.invoke(app, ["list"])
assert result.exit_code == 0
assert "pfs" in result.output
@patch("rec.pricers.PRICERS", {})
def test_empty(self):
result = runner.invoke(app, ["list"])
assert result.exit_code == 0
class TestReconcilePfs:
@patch("rec.pricers.PRICERS")
@patch("conf.connect.duckdb")
@patch("rec.engine.reconcile")
@patch("rec.report.as_markdown", return_value="# Report")
def test_single_year(self, mc_md, mc_reconcile, mc_duck, mc_pricers):
pricer = MagicMock()
mc_pricers.__contains__ = MagicMock(return_value=True)
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
mc_reconcile.return_value = MagicMock()
result = runner.invoke(app, ["pfs", "--year", "2025"])
assert result.exit_code == 0
@patch("rec.pricers.PRICERS")
@patch("conf.connect.duckdb")
@patch("rec.engine.reconcile_all_years")
@patch("rec.report.as_markdown", return_value="# All years")
def test_all_years(self, mc_md, mc_all, mc_duck, mc_pricers):
pricer = MagicMock()
mc_pricers.__contains__ = MagicMock(return_value=True)
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
mc_all.return_value = {2024: MagicMock(), 2025: MagicMock()}
result = runner.invoke(app, ["pfs"])
assert result.exit_code == 0
@patch("rec.pricers.PRICERS")
@patch("conf.connect.duckdb")
@patch("rec.engine.reconcile_all_years", return_value={})
def test_no_years(self, mc_all, mc_duck, mc_pricers):
pricer = MagicMock()
mc_pricers.__contains__ = MagicMock(return_value=True)
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
result = runner.invoke(app, ["pfs"])
assert result.exit_code == 1
@patch("rec.pricers.PRICERS")
@patch("conf.connect.duckdb")
@patch("rec.engine.reconcile")
@patch("rec.report.as_json", return_value='{"year": 2025}')
def test_json_format(self, mc_json, mc_reconcile, mc_duck, mc_pricers):
pricer = MagicMock()
mc_pricers.__contains__ = MagicMock(return_value=True)
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
mc_reconcile.return_value = MagicMock()
result = runner.invoke(app, ["pfs", "--year", "2025", "--format", "json"])
assert result.exit_code == 0
@patch("rec.pricers.PRICERS")
@patch("conf.connect.duckdb")
@patch("rec.engine.reconcile")
@patch("rec.report.as_markdown", return_value="# Report")
def test_write_to_file(self, mc_md, mc_reconcile, mc_duck, mc_pricers, tmp_path):
pricer = MagicMock()
mc_pricers.__contains__ = MagicMock(return_value=True)
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
mc_reconcile.return_value = MagicMock()
out = str(tmp_path / "report.md")
result = runner.invoke(app, ["pfs", "--year", "2025", "-o", out])
assert result.exit_code == 0
class TestReconcileOpps:
@patch("rec.pricers.PRICERS")
@patch("conf.connect.duckdb")
@patch("rec.engine.reconcile")
@patch("rec.report.as_markdown", return_value="# OPPS Report")
def test_single_year(self, mc_md, mc_reconcile, mc_duck, mc_pricers):
pricer = MagicMock()
mc_pricers.__contains__ = MagicMock(return_value=True)
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
mc_reconcile.return_value = MagicMock()
result = runner.invoke(app, ["opps", "--year", "2026"])
assert result.exit_code == 0
@patch("rec.pricers.PRICERS")
@patch("conf.connect.duckdb")
@patch("rec.engine.reconcile_all_years", return_value={})
def test_no_years_hints_addendum_b(self, mc_all, mc_duck, mc_pricers):
pricer = MagicMock()
mc_pricers.__contains__ = MagicMock(return_value=True)
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
result = runner.invoke(app, ["opps"])
assert result.exit_code == 1
assert "opps.addendum_b" in result.output