"""Tests for the wikilink + red-link model (SHARD-WP-0010 T1).""" from shard_wiki.adapters import FolderAdapter from shard_wiki.union import ResolutionKind, UnionGraph from shard_wiki.views import extract_links, resolve_links def _shard(tmp_path, name, files): root = tmp_path / name for rel, text in files.items(): p = root / rel p.parent.mkdir(parents=True, exist_ok=True) p.write_text(text, encoding="utf-8") return FolderAdapter(name, root) def test_extracts_plain_and_labelled_links(): links = extract_links("See [[Home]] and [[Index|the index]].") assert [(link.target, link.label, link.text) for link in links] == [ ("Home", None, "Home"), ("Index", "the index", "the index"), ] def test_links_carry_body_offsets_in_document_order(): body = "a [[One]] b [[Two]]" links = extract_links(body) assert [link.target for link in links] == ["One", "Two"] s, e = links[0].span assert body[s:e] == "[[One]]" def test_code_regions_are_not_scanned(): body = "real [[Home]]\n```\n[[NotALink]]\n```\ninline `[[AlsoNot]]` done" targets = [link.target for link in extract_links(body)] assert targets == ["Home"] def test_camelcase_off_by_default_then_opt_in(): body = "FrontPage links to [[Home]]" assert [link.target for link in extract_links(body)] == ["Home"] # CamelCase ignored on = extract_links(body, camelcase=True) assert {link.target for link in on} == {"FrontPage", "Home"} assert next(link for link in on if link.target == "FrontPage").auto is True def test_camelcase_does_not_double_count_inside_explicit_link(): # [[FrontPage]] is one explicit link, not also a CamelCase auto-link. links = extract_links("[[FrontPage]]", camelcase=True) assert len(links) == 1 assert links[0].auto is False def test_resolve_links_distinguishes_link_from_red_link(tmp_path): u = UnionGraph("space") u.attach(_shard(tmp_path, "shardA", {"Home.md": "home"})) resolved = resolve_links(u, "[[Home]] and [[Ghost]]") by_target = {r.link.target: r for r in resolved} assert by_target["Home"].resolution.kind is ResolutionKind.SINGLE assert by_target["Home"].is_red_link is False assert by_target["Ghost"].is_red_link is True # unresolved → createable red-link def test_resolve_links_surfaces_chorus(tmp_path): u = UnionGraph("space") u.attach(_shard(tmp_path, "shardA", {"Home.md": "A"})) u.attach(_shard(tmp_path, "shardB", {"Home.md": "B"})) (resolved,) = resolve_links(u, "[[Home]]") assert resolved.resolution.kind is ResolutionKind.CHORUS