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 "&lt;script&gt;" in html    assert "<blockquote>said <code>y</code></blockquote>" in html    assert 'href="http://e.x/a?b=1&amp;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