"""Unit tests for doc/category detection, section parsing, and example loading.
All network access (`_fetch_doc`) is mocked; these tests are hermetic.
"""
from __future__ import annotations
from felderize import docs
# ---------------------------------------------------------------------------
# _detect_sql_functions / _detect_categories
# ---------------------------------------------------------------------------
def test_detect_sql_functions_uppercases_and_dedupes():
funcs = docs._detect_sql_functions("SELECT upper(a), Upper(b), LEN(c) FROM t")
assert funcs == {"UPPER", "LEN"}
def test_detect_sql_functions_none():
assert docs._detect_sql_functions("SELECT a FROM t") == set()
def test_detect_categories_always_includes_baseline():
matched = docs._detect_categories("SELECT 1", categories={})
assert matched == docs._ALWAYS_INCLUDED
def test_detect_categories_matches_pattern():
cats = {"string": [r"\bUPPER\b"], "array": [r"\bEXPLODE\b"]}
matched = docs._detect_categories("SELECT UPPER(x) FROM t", categories=cats)
assert "string" in matched
assert "array" not in matched
def test_detect_categories_skips_empty_pattern_lists():
matched = docs._detect_categories("SELECT 1", categories={"string": []})
assert "string" not in matched
# ---------------------------------------------------------------------------
# _parse_doc_sections
# ---------------------------------------------------------------------------
def test_parse_doc_sections_splits_preamble_and_anchors():
content = (
"intro text\n"
'## UPPER\n\nupper docs\n'
'## LOWER\n\nlower docs\n'
)
preamble, sections, anchors = docs._parse_doc_sections(content)
assert preamble.strip() == "intro text"
assert set(anchors) == {"upper", "lower"}
assert anchors["upper"] == "## UPPER"
assert "upper docs" in sections["## UPPER"]
assert "lower docs" in sections["## LOWER"]
def test_parse_doc_sections_no_headings_is_all_preamble():
preamble, sections, anchors = docs._parse_doc_sections("just text\nmore text")
assert "just text" in preamble
assert sections == {} and anchors == {}
# ---------------------------------------------------------------------------
# _load_relevant_sections (mocking the parsed-section cache)
# ---------------------------------------------------------------------------
def _fake_sections(monkeypatch, preamble, sections, anchors):
monkeypatch.setattr(
docs, "_get_doc_sections", lambda fn: (preamble, sections, anchors)
)
def test_load_relevant_sections_plain_file_returns_preamble(monkeypatch):
_fake_sections(monkeypatch, "plain body", {}, {})
assert docs._load_relevant_sections("x.md", set()) == "plain body"
def test_load_relevant_sections_filters_to_matching_anchor(monkeypatch):
sections = {"## UPPER": "## UPPER\nupper\n", "## LOWER": "## LOWER\nlower\n"}
anchors = {"upper": "## UPPER", "lower": "## LOWER"}
_fake_sections(monkeypatch, "", sections, anchors)
out = docs._load_relevant_sections("string.md", {"upper"})
assert "upper" in out
assert "lower" not in out
def test_load_relevant_sections_no_match_returns_everything(monkeypatch):
sections = {"## UPPER": "## UPPER\nupper\n", "## LOWER": "## LOWER\nlower\n"}
anchors = {"upper": "## UPPER"}
_fake_sections(monkeypatch, "pre", sections, anchors)
out = docs._load_relevant_sections("string.md", {"missing"})
assert "upper" in out and "lower" in out and "pre" in out
# ---------------------------------------------------------------------------
# _build_categories_from_index (mocking _fetch_doc)
# ---------------------------------------------------------------------------
def test_build_categories_from_index_parses_funcs_and_anchors(monkeypatch):
index = "* `UPPER` [string](string.md#upper)\n* `ABS` [integer](integer.md#abs)\n"
monkeypatch.setattr(docs, "_fetch_doc", lambda fn: index)
categories, func_anchors = docs._build_categories_from_index()
assert r"\bUPPER\b" in categories["string"]
assert ("string.md", "upper") in func_anchors["UPPER"]
assert ("integer.md", "abs") in func_anchors["ABS"]
def test_build_categories_from_index_empty_on_fetch_failure(monkeypatch):
monkeypatch.setattr(docs, "_fetch_doc", lambda fn: "")
categories, func_anchors = docs._build_categories_from_index()
assert func_anchors == {}
assert all(v == [] for v in categories.values())
# ---------------------------------------------------------------------------
# load_docs (end to end, fully mocked)
# ---------------------------------------------------------------------------
def test_load_docs_selects_relevant_category(monkeypatch):
categories = {"string": [r"\bUPPER\b"]}
func_anchors = {"UPPER": [("string.md", "upper")]}
monkeypatch.setattr(
docs, "_get_categories_and_anchors", lambda: (categories, func_anchors)
)
sections = {"## UPPER": "## UPPER\nupper docs\n"}
monkeypatch.setattr(
docs, "_get_doc_sections", lambda fn: ("", sections, {"upper": "## UPPER"})
)
out = docs.load_docs("SELECT UPPER(x) FROM t")
assert "### string" in out
assert "upper docs" in out
# ---------------------------------------------------------------------------
# Example loading: _load_example_file / _load_examples_from_dir / load_examples
# ---------------------------------------------------------------------------
def test_load_example_file_matches_category(tmp_path):
f = tmp_path / "ex.md"
f.write_text("---\ncategories: [string]\n---\nSTRING EXAMPLE")
assert docs._load_example_file(f, {"string"}) == "STRING EXAMPLE"
def test_load_example_file_non_matching_returns_none(tmp_path):
f = tmp_path / "ex.md"
f.write_text("---\ncategories: [array]\n---\nARRAY EXAMPLE")
assert docs._load_example_file(f, {"string"}) is None
def test_load_example_file_no_categories_always_matches(tmp_path):
f = tmp_path / "ex.md"
f.write_text("---\n---\nALWAYS EXAMPLE")
assert docs._load_example_file(f, {"string"}) == "ALWAYS EXAMPLE"
def test_load_example_file_no_frontmatter_is_none(tmp_path):
f = tmp_path / "ex.md"
f.write_text("no frontmatter")
assert docs._load_example_file(f, {"string"}) is None
def test_load_examples_combines_dir_and_files(tmp_path, monkeypatch):
monkeypatch.setattr(docs, "_detect_categories", lambda sql: {"datetime"})
d = tmp_path / "exdir"
d.mkdir()
(d / "a.md").write_text("---\ncategories: [datetime]\n---\nDIR EXAMPLE")
(d / "skip.md").write_text("---\ncategories: [array]\n---\nSKIP")
standalone = tmp_path / "b.md"
standalone.write_text("---\ncategories: [datetime]\n---\nFILE EXAMPLE")
out = docs.load_examples(
"SELECT now()", extra_examples_dirs=[d], extra_examples_files=[standalone]
)
assert "DIR EXAMPLE" in out and "FILE EXAMPLE" in out
assert "SKIP" not in out
def test_load_examples_from_dir_missing_dir(tmp_path):
assert docs._load_examples_from_dir(tmp_path / "nope", {"string"}) == []