git / moonbite-network / tests/test_forum.py · raw
"""Community forum: categories, sorting, search, safe body rendering, and thein-place migration for boards created before categories existed."""import sqlite3import pytestimport 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"] == 3def 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"] == 0def test_render_body_escapes_and_formats(): html = str(forum.render_body("<script>x</script>\n\n> said `y`\nhttp://e.x/a?b=1&c=2.")) assert "<script>" not in html and "<script>" in html assert "<blockquote>said <code>y</code></blockquote>" in html assert 'href="http://e.x/a?b=1&c=2"' in html and "</a>." in html assert "<a" not in str(forum.render_body("javascript:alert(1)"))def test_old_board_gains_category_column(): conn = sqlite3.connect(forum._DB_PATH) conn.execute("CREATE TABLE threads (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, " "author TEXT NOT NULL, body TEXT NOT NULL, created_at INTEGER NOT NULL, " "bumped_at INTEGER NOT NULL, reply_count INTEGER NOT NULL DEFAULT 0)") conn.execute("INSERT INTO threads (title, author, body, created_at, bumped_at) VALUES ('old', 'x', 'b', 1, 1)") conn.commit() conn.close() t = forum.list_threads()["threads"][0] assert t["title"] == "old" and t["category"] == "general"def test_votes_toggle_and_dedupe_by_browser_or_network(): t = forum.create_thread("v", "x", "body") assert forum.vote("t", t["id"], "browserA", "net1", 1) == {"score": 1, "mine": 1} # same browser flips its vote rather than adding one assert forum.vote("t", t["id"], "browserA", "net1", -1)["score"] == -1 # cleared cookies on the same network: still one vote assert forum.vote("t", t["id"], "browserB", "net1", 1)["score"] == 1 # a different browser on a different network counts separately assert forum.vote("t", t["id"], "browserC", "net2", 1)["score"] == 2 assert forum.vote("t", t["id"], "browserC", "net2", 0)["score"] == 1 assert forum.my_votes("browserB", "nope", "t", [t["id"]]) == {t["id"]: 1} with pytest.raises(ValueError): forum.vote("t", t["id"], "a", "b", 5) with pytest.raises(ValueError): forum.vote("r", 999, "a", "b", 1)def test_nested_replies_build_a_tree_sorted_by_score(): t = forum.create_thread("tree", "op", "body") a = forum.add_reply(t["id"], "a", "first") b = forum.add_reply(t["id"], "b", "second") a1 = forum.add_reply(t["id"], "c", "under a", parent_id=a["id"]) forum.vote("r", b["id"], "v", "n", 1) thread = forum.get_thread(t["id"]) assert [c["id"] for c in thread["comments"]] == [b["id"], a["id"]] # best first assert thread["comments"][1]["children"][0]["id"] == a1["id"] assert thread["comments"][1]["children"][0]["depth"] == 1 assert forum.get_thread(t["id"], sort="old")["comments"][0]["id"] == a["id"] other = forum.create_thread("other", "op", "body") with pytest.raises(ValueError): forum.add_reply(other["id"], "x", "wrong thread", parent_id=a["id"])def test_reply_depth_is_capped(): t = forum.create_thread("deep", "op", "body") parent = None for i in range(forum.MAX_DEPTH + 3): parent = forum.add_reply(t["id"], "x", f"level {i}", parent_id=parent and parent["id"]) def deepest(nodes): return max([n["depth"] for n in nodes] + [deepest(n["children"]) for n in nodes if n["children"]]) assert deepest(forum.get_thread(t["id"])["comments"]) == forum.MAX_DEPTH