Files
stack/tests/bib/test_ui.py
kert 5261032a9b
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 tests for 100% line coverage across all packages
Cover remaining uncovered lines in bcda (client, store, log, pipe/cclf,
flatten), bib (sync, spider, translate, ingest, item, store, format, ui),
cms (express wrappers, log edge cases), api (base, gitea, rustfs,
woodpecker, zotero), bls (table import), and pfs (pragma on race guard).

37,687 statements, 0 missed — 11,061 tests passing.
2026-02-28 22:03:23 -05:00

216 lines
6.6 KiB
Python

"""Tests for bib.ui — marimo widgets for bibliography."""
from __future__ import annotations
import sys
from unittest.mock import MagicMock
from bib.item import Rule
from bib.store import Store
def _install_mock_marimo() -> MagicMock:
"""Install a mock marimo module into sys.modules."""
mo = MagicMock()
# mo.Html returns an object with the html stored
class MockHtml:
def __init__(self, html: str) -> None:
self.text = html
mo.Html = MockHtml
mo.ui.text.return_value = MagicMock(value="")
mo.ui.table.return_value = MagicMock()
mo.accordion.return_value = MagicMock()
mo.md.return_value = MagicMock()
mo.tabs.return_value = MagicMock()
mo.vstack.return_value = MagicMock()
sys.modules["marimo"] = mo
return mo
def _remove_mock_marimo() -> None:
"""Remove mock marimo from sys.modules."""
sys.modules.pop("marimo", None)
# Also remove cached ui submodule imports
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
# ── ui.__init__ ─────────────────────────────────────────────────────
class TestUiInit:
def test_imports(self) -> None:
_install_mock_marimo()
try:
# Force reimport
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
import bib.ui
assert hasattr(bib.ui, "library_browser")
assert hasattr(bib.ui, "cite")
assert hasattr(bib.ui, "bibliography")
finally:
_remove_mock_marimo()
# ── library_browser ─────────────────────────────────────────────────
class TestLibraryBrowser:
def test_returns_widget(self) -> None:
_install_mock_marimo()
try:
# Force reimport
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
from bib.ui.browser import library_browser
s = Store(":memory:")
s.create(Rule(title="Test Rule"), tags=["module:pfs"])
s.ensure_collections({"Rules": {}})
result = library_browser(s)
assert result is not None
s.close()
finally:
_remove_mock_marimo()
def test_with_collection_filter(self) -> None:
_install_mock_marimo()
try:
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
from bib.ui.browser import library_browser
s = Store(":memory:")
coll_map = s.ensure_collections({"Rules": {}})
s.create(
Rule(title="R1"),
collection=coll_map["Rules"],
)
result = library_browser(s, collection=coll_map["Rules"])
assert result is not None
s.close()
finally:
_remove_mock_marimo()
def test_with_search_value(self) -> None:
"""Line 72: search.value is non-empty."""
_install_mock_marimo()
try:
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
# Set search mock to return non-empty value
mo = sys.modules["marimo"]
search_mock = MagicMock()
search_mock.value = "test query"
mo.ui.text.return_value = search_mock
from bib.ui.browser import library_browser
s = Store(":memory:")
s.create(Rule(title="Test Rule"))
result = library_browser(s)
assert result is not None
s.close()
finally:
_remove_mock_marimo()
def test_empty_store(self) -> None:
_install_mock_marimo()
try:
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
from bib.ui.browser import library_browser
s = Store(":memory:")
result = library_browser(s)
assert result is not None
s.close()
finally:
_remove_mock_marimo()
# ── cite ────────────────────────────────────────────────────────────
class TestCite:
def test_returns_html(self) -> None:
_install_mock_marimo()
try:
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
from bib.ui.cite import cite
s = Store(":memory:")
key = s.create(Rule(title="Test Rule", date_published="2025-01-01"))
result = cite(s, key)
assert result is not None
assert hasattr(result, "text")
assert "bib-cite" in result.text
s.close()
finally:
_remove_mock_marimo()
# ── bibliography ────────────────────────────────────────────────────
class TestBibliography:
def test_returns_html(self) -> None:
_install_mock_marimo()
try:
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
from bib.ui.cite import bibliography
s = Store(":memory:")
k1 = s.create(Rule(title="Rule A", date_published="2025-01-01"))
k2 = s.create(Rule(title="Rule B", date_published="2025-06-01"))
result = bibliography(s, [k1, k2])
assert result is not None
assert hasattr(result, "text")
assert "bib-bibliography" in result.text
assert "<ol>" in result.text
s.close()
finally:
_remove_mock_marimo()
def test_empty_keys(self) -> None:
_install_mock_marimo()
try:
for key in list(sys.modules):
if key.startswith("bib.ui"):
sys.modules.pop(key, None)
from bib.ui.cite import bibliography
s = Store(":memory:")
result = bibliography(s, [])
assert result is not None
s.close()
finally:
_remove_mock_marimo()