lllin000_PaperForge/tests/unit/schema/test_field_registry.py
Research Assistant b1fdbc30eb feat: P0 fixes (ref sort, caption insert) + P1 figure containment render hygiene
P0:
- Fix 2: _ref_number_sort_key handles [N] bracket format (ocr_render.py:481)
- Fix 4: remove figure_caption from _INSERT_CANDIDATE_ROLES (ocr_document.py:3846)
- Fix 5: filter demoted body_paragraph from figure legends (ocr_figures.py:2950)

P1:
- figure containment render-hygiene pass after table inventory writeback
- 6 helpers: _cluster_bboxes_by_proximity, _is_contained,
  _highly_overlaps_any_matched_region, _figure_region_bbox,
  _matched_asset_keys, tag_figure_contained_text
- Wire call site in postprocess_ocr_result() (ocr.py:1891)

Infra:
- Sync workspace fulltext after rebuild (asset_index.py)
- Fix UnboundLocalError on index-refresh (sync_service.py)
- Add missing frontmatter fields to field registry (field_registry.yaml)
- 283 + 19 = 302 tests passing
2026-06-27 22:56:22 +08:00

92 lines
3.3 KiB
Python

from __future__ import annotations
from pathlib import Path
from paperforge.schema import (
get_field_info,
get_owner_fields,
load_field_registry,
)
HERE = Path(__file__).resolve().parent
REGISTRY_PATH = HERE.parent.parent.parent / "paperforge" / "schema" / "field_registry.yaml"
class TestLoadFieldRegistry:
def test_valid_path_returns_non_empty(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
assert isinstance(reg, dict)
assert len(reg) > 0
def test_nonexistent_path_returns_empty(self) -> None:
reg = load_field_registry(Path("/nonexistent/path.yaml"))
assert reg == {}
def test_default_path_works(self) -> None:
reg = load_field_registry()
assert isinstance(reg, dict)
assert len(reg) > 0
class TestRegistryOwners:
def test_has_all_three_owners(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
assert "frontmatter" in reg
assert "index_entry" in reg
assert "ocr_meta" in reg
assert len(reg) == 3
class TestFrontmatterFields:
def test_has_required_fields(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
fm = get_owner_fields(reg, "frontmatter")
required = {"zotero_key", "domain", "title", "has_pdf"}
for field in required:
assert field in fm, f"Missing required frontmatter field: {field}"
assert fm[field]["required"] is True, f"{field} should be required"
def test_all_expected_fields_present(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
fm = get_owner_fields(reg, "frontmatter")
expected = {
"zotero_key", "citation_key", "domain", "title", "year", "doi",
"collection_path", "collection_tags", "has_pdf", "pdf_path", "supplementary",
"fulltext_md_path", "recommend_analyze", "analyze",
"do_ocr", "ocr_status", "ocr_redo", "deep_reading_status", "path_error",
"aliases", "tags", "journal", "first_author", "pmid",
"impact_factor", "abstract", "keywords", "ocr_time",
}
assert set(fm.keys()) == expected
class TestGetOwnerFields:
def test_returns_correct_owner(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
fm = get_owner_fields(reg, "frontmatter")
assert "zotero_key" in fm
assert fm["zotero_key"]["type"] == "str"
def test_unknown_owner_returns_empty(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
assert get_owner_fields(reg, "nonexistent") == {}
class TestGetFieldInfo:
def test_known_field_returns_metadata(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
info = get_field_info(reg, "frontmatter", "zotero_key")
assert info is not None
assert info["type"] == "str"
assert info["required"] is True
assert info["public"] is True
def test_unknown_field_returns_none(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
info = get_field_info(reg, "frontmatter", "nonexistent_field")
assert info is None
def test_unknown_owner_field_returns_none(self) -> None:
reg = load_field_registry(REGISTRY_PATH)
info = get_field_info(reg, "nonexistent", "zotero_key")
assert info is None