"""Community forum: categories, sorting, search, safe body rendering, and the
in-place migration for boards created before categories existed."""
import sqlite3
import pytest
import forum
@pytest.fixture(autouse=True)
def board(tmp_path, monkeypatch):
monkeypatch.setattr(forum, "_DB_PATH", str(tmp_path / "forum.db"))
def test_categories_filter_and_validate():
forum.create_thread("a", "x", "body", "mining")
forum.create_thread("b", "x", "body", "wallets")
assert [t["title"] for t in forum.list_threads(category="mining")["threads"]] == ["a"]
assert forum.stats()["per_category"]["wallets"] == 1
with pytest.raises(ValueError):
forum.create_thread("c", "x", "body", "not-a-category")
def test_sorts_and_unanswered():
quiet = forum.create_thread("quiet", "x", "body")
busy = forum.create_thread("busy", "x", "body")
forum.add_reply(busy["id"], "y", "one")
forum.add_reply(busy["id"], "z", "two")
assert forum.list_threads(sort="top")["threads"][0]["id"] == busy["id"]
forum.vote("t", busy["id"], "v", "n", 1)
unanswered = forum.list_threads(sort="unanswered")
assert [t["id"] for t in unanswered["threads"]] == [quiet["id"]]
top = forum.list_threads(sort="top")["threads"][0]
assert top["last_author"] == "z" and top["voice_count"] == 3
def test_search_treats_wildcards_literally():
forum.create_thread("100% uptime", "x", "body")
forum.create_thread("plain", "x", "body")
assert forum.list_threads(q="100%")["total"] == 1
assert forum.list_threads(q="%")["total"] == 1
assert forum.list_threads(q="_")["total"] == 0
def test_render_body_escapes_and_formats():
html = str(forum.render_body("\n\n> said `y`\nhttp://e.x/a?b=1&c=2."))
assert "