Files
stack/tests/rec/test_base.py
kert dbf71a6594 test: 99.93% coverage — Zotero 9 schema fix + 400+ new tests
Fix Zotero table models for Zotero 9:
- Remove stale Annotations/Highlights/Transaction* models
- Add ItemAnnotations, RetractedItems, DeletedCollections,
  DeletedSearches, DbDebug1
- Fix ItemAttachments, Libraries, Users column mismatches

New test files covering all major modules:
- cli/{bib,prisma,rec,zot,mail,run} deep exercising tests
- mail/{droplet,postmark,resend,cloudflare} lifecycle tests
- bib/{iom,oig,pincite,sync,regulations_gov,email_ingest,format,store}
- prisma/{vpn,fetch,export,llm,screen,eligibility,extract,project,ingest,flow}
- aco/lake/{unity,quality,deploy} + api/aco coverage gaps
- zot/{ops,db,extract,duck} + rec/{report,engine,base,pricers}
- pfs/{pipe,rules,eq,files}

Add pytest-xdist for parallel test execution.

Tracks #353
2026-04-18 10:06:47 -04:00

181 lines
4.9 KiB
Python

"""Tests for rec.base — Pricer protocol and Reconciliation dataclass."""
from __future__ import annotations
import polars as pl
from rec.base import Pricer, Reconciliation
class TestPricerProtocol:
def test_fake_pricer_conforms(self, fake_pricer) -> None:
assert isinstance(fake_pricer, Pricer)
def test_pfs_pricer_conforms(self) -> None:
from rec.pricers.pfs import PfsPricer
assert isinstance(PfsPricer(), Pricer)
def test_non_conforming_object_rejected(self) -> None:
class NotAPricer:
pass
assert not isinstance(NotAPricer(), Pricer)
def test_missing_method_rejected(self) -> None:
class Incomplete:
system = "x"
description = "x"
join_keys: list[str] = []
compare_cols: list[str] = []
def ground_truth(self, con, year):
return None
# missing calculated and years_available
assert not isinstance(Incomplete(), Pricer)
class TestReconciliation:
def test_scalar_fields(self) -> None:
r = Reconciliation(
system="x",
year=2025,
ground_truth_rows=100,
calculated_rows=100,
matched_rows=99,
ground_truth_only=1,
calculated_only=1,
exact_matches=95,
near_matches=98,
deltas=pl.DataFrame(),
)
assert r.system == "x"
assert r.year == 2025
assert r.matched_rows == 99
assert r.tolerance_cents == 0
def test_pct_exact(self) -> None:
r = Reconciliation(
system="x",
year=2025,
ground_truth_rows=100,
calculated_rows=100,
matched_rows=100,
ground_truth_only=0,
calculated_only=0,
exact_matches=75,
near_matches=100,
deltas=pl.DataFrame(),
)
assert r.pct_exact == 75.0
def test_pct_exact_empty(self) -> None:
r = Reconciliation(
system="x",
year=2025,
ground_truth_rows=0,
calculated_rows=0,
matched_rows=0,
ground_truth_only=0,
calculated_only=0,
exact_matches=0,
near_matches=0,
deltas=pl.DataFrame(),
)
assert r.pct_exact == 0.0
def test_is_perfect_true(self) -> None:
r = Reconciliation(
system="x",
year=2025,
ground_truth_rows=10,
calculated_rows=10,
matched_rows=10,
ground_truth_only=0,
calculated_only=0,
exact_matches=10,
near_matches=10,
deltas=pl.DataFrame(),
)
assert r.is_perfect is True
def test_is_perfect_false_on_unmatched(self) -> None:
r = Reconciliation(
system="x",
year=2025,
ground_truth_rows=10,
calculated_rows=10,
matched_rows=10,
ground_truth_only=0,
calculated_only=0,
exact_matches=9, # one row off
near_matches=10,
deltas=pl.DataFrame(),
)
assert r.is_perfect is False
def test_frozen(self) -> None:
import dataclasses
r = Reconciliation(
system="x",
year=2025,
ground_truth_rows=0,
calculated_rows=0,
matched_rows=0,
ground_truth_only=0,
calculated_only=0,
exact_matches=0,
near_matches=0,
deltas=pl.DataFrame(),
)
import pytest
with pytest.raises(dataclasses.FrozenInstanceError):
r.year = 2026 # type: ignore[misc]
# ── Gap coverage — missed lines ────────────────────────────────
class TestConvenienceFormatters:
"""Lines 140, 142, 146, 148: summary_md and to_json delegates."""
def test_summary_md(self) -> None:
r = Reconciliation(
system="x",
year=2025,
ground_truth_rows=10,
calculated_rows=10,
matched_rows=10,
ground_truth_only=0,
calculated_only=0,
exact_matches=10,
near_matches=10,
deltas=pl.DataFrame(),
)
md = r.summary_md()
assert "# Reconciliation" in md
assert "CY2025" in md
def test_to_json(self) -> None:
import json
r = Reconciliation(
system="x",
year=2025,
ground_truth_rows=5,
calculated_rows=5,
matched_rows=5,
ground_truth_only=0,
calculated_only=0,
exact_matches=5,
near_matches=5,
deltas=pl.DataFrame(),
)
payload = json.loads(r.to_json())
assert payload["system"] == "x"
assert payload["year"] == 2025