Files
horror/backend/tests/test_gaestebuch.py
2026-09-29 00:54:58 +02:00

157 lines
6.0 KiB
Python

"""Das Buch der Abende: Wertungen als Momentaufnahme, Kommentare als
Diskussion — verschachtelt, so tief man will."""
def abend(client, film, movie_id=1):
"""Host trägt einen Film ein, gibt die watched_id zurück."""
return client.post("/api/watched", json={"movie_id": film(movie_id)}).json()["id"]
def wertung(client, watched_id, stars=4):
client.post(f"/api/watched/{watched_id}/rating", json={"stars": stars})
return next(f for f in client.get("/api/watched").json() if f["id"] == watched_id)
def film_von(client, watched_id):
return next(f for f in client.get("/api/watched").json() if f["id"] == watched_id)
def kommentar(client, watched_id, text, parent_id=None):
antwort = client.post(
f"/api/watched/{watched_id}/notes", json={"text": text, "parent_id": parent_id}
)
assert antwort.status_code == 200, antwort.text
return antwort.json()["id"]
def test_laufende_nummer_zaehlt_vom_ersten_abend(client, film):
erster = abend(client, film, 1)
client.patch(f"/api/watched/{erster}", json={"watched_at": "2026-01-01"})
zweiter = abend(client, film, 2)
client.patch(f"/api/watched/{zweiter}", json={"watched_at": "2026-01-08"})
liste = client.get("/api/watched").json()
# Jüngster zuerst, trägt aber die höchste Nummer
assert [(f["id"], f["nummer"]) for f in liste] == [(zweiter, 2), (erster, 1)]
def test_katalogdaten_haengen_am_abend(client):
from app import db
with db.connect() as conn:
db.upsert(conn, {"id": 5, "title": "Alien", "backdrop_path": "/b.jpg",
"images": ["/s1.jpg"], "runtime": 117, "genres": ["Horror"]})
watched_id = client.post("/api/watched", json={"movie_id": 5}).json()["id"]
f = film_von(client, watched_id)
assert f["backdrop_path"] == "/b.jpg"
assert f["images"] == ["/s1.jpg"]
assert f["runtime"] == 117
assert f["genres"] == ["Horror"]
def test_kommentare_bilden_einen_baum(client, client2, film):
watched_id = abend(client, film)
oben = kommentar(client, watched_id, "War super.")
antwort = kommentar(client2, watched_id, "Fand ich nicht.", oben)
tiefer = kommentar(client, watched_id, "Doch!", antwort)
noch_einer = kommentar(client2, watched_id, "Anderes Thema.")
notes = film_von(client, watched_id)["notes"]
assert [n["text"] for n in notes] == ["War super.", "Anderes Thema."]
assert notes[0]["replies"][0]["text"] == "Fand ich nicht."
assert notes[0]["replies"][0]["name"] == "Ben"
assert notes[0]["replies"][0]["mine"] is False
assert notes[0]["replies"][0]["replies"][0]["text"] == "Doch!"
assert notes[0]["replies"][0]["replies"][0]["mine"] is True
assert notes[1]["replies"] == []
assert (oben, antwort, tiefer, noch_einer) == tuple(sorted((oben, antwort, tiefer, noch_einer)))
def test_zehn_ebenen_tief(client, film):
watched_id = abend(client, film)
vater = None
for stufe in range(10):
vater = kommentar(client, watched_id, f"Stufe {stufe}", vater)
knoten = film_von(client, watched_id)["notes"][0]
tiefe = 0
while knoten["replies"]:
knoten = knoten["replies"][0]
tiefe += 1
assert tiefe == 9
assert knoten["text"] == "Stufe 9"
def test_leerer_text_oder_fremder_vater_werden_abgelehnt(client, film):
watched_id = abend(client, film, 1)
anderer = abend(client, film, 2)
dort = kommentar(client, anderer, "woanders")
assert client.post(f"/api/watched/{watched_id}/notes", json={"text": " "}).status_code == 400
# Der Vater gehört zu einem anderen Abend
assert client.post(
f"/api/watched/{watched_id}/notes", json={"text": "x", "parent_id": dort}
).status_code == 400
assert client.post(
f"/api/watched/{watched_id}/notes", json={"text": "x", "parent_id": 9999}
).status_code == 400
def test_wertungen_und_kommentare_sind_unabhaengig(client, film):
watched_id = abend(client, film)
wertung(client, watched_id, 5)
kommentar(client, watched_id, "Diskussion.")
f = film_von(client, watched_id)
assert f["average"] == 5.0 and f["mine"] == 5
# Die Namen an den Wertungen sieht nur der Host
assert f["ratings"] == []
assert [n["text"] for n in f["notes"]] == ["Diskussion."]
def test_eigenen_kommentar_loeschen_fremden_nicht(client, client2, film):
watched_id = abend(client, film)
meiner = kommentar(client, watched_id, "meiner")
assert client2.delete(f"/api/watched-notes/{meiner}").status_code == 404
assert client.delete(f"/api/watched-notes/{meiner}").json()["removed"] == 1
assert film_von(client, watched_id)["notes"] == []
def test_loeschen_nimmt_den_ganzen_ast_mit(client, client2, film):
"""Eine Antwort ohne ihren Anlass ergäbe keinen Sinn."""
watched_id = abend(client, film)
oben = kommentar(client, watched_id, "a")
mitte = kommentar(client2, watched_id, "b", oben)
unten = kommentar(client, watched_id, "c", mitte)
daneben = kommentar(client2, watched_id, "d")
assert client.delete(f"/api/watched-notes/{oben}").json()["removed"] == 3
notes = film_von(client, watched_id)["notes"]
assert [n["id"] for n in notes] == [daneben]
def test_host_loescht_jeden_kommentar(client, zuschauer, hostmodus, film):
watched_id = abend(client, film)
note_id = kommentar(client, watched_id, "x")
hostmodus(zuschauer)
assert zuschauer.delete(f"/api/watched-notes/{note_id}").json()["removed"] == 1
def test_film_loeschen_raeumt_alles(client, client2, film):
from app import db
watched_id = abend(client, film)
wertung(client, watched_id, 5)
oben = kommentar(client2, watched_id, "frei")
kommentar(client, watched_id, "antwort", oben)
client.delete(f"/api/watched/{watched_id}")
with db.connect() as conn:
for tabelle in ("ratings", "watched_notes"):
assert conn.execute(f"SELECT COUNT(*) FROM {tabelle}").fetchone()[0] == 0, tabelle
def test_zuschauer_darf_nicht_schreiben(zuschauer, client, film):
watched_id = abend(client, film)
assert zuschauer.post(f"/api/watched/{watched_id}/notes", json={"text": "x"}).status_code == 403