"""Lesemodus-Endpoints: Baustein-Karten (nicht faellig-gefiltert), Lernstand, fertig.""" import db import main from conftest import topic_anlegen def _setup(topic): b = db.insert("bausteine", topic=topic, ziel_id=1, titel="B", ord=0, status="neu") a = db.insert("atome", topic=topic, titel="A", typ="begriff", definition="d", status="neu", baustein_id=b, ord=0) db.insert("artefakte", atom_id=a, typ="flashcard", status="verifiziert", inhalt=db.j({"frage": "F1", "antwort": "A1"})) db.insert("artefakte", atom_id=a, typ="flashcard", status="kandidat", # unverifiziert inhalt=db.j({"frage": "F2", "antwort": "A2"})) db.insert("artefakte", atom_id=a, typ="beispiel", status="verifiziert", # kein Flashcard inhalt=db.j({"form": "text", "text": "bsp"})) return b, a def test_baustein_karten_nur_verifizierte_flashcards(): topic = topic_anlegen("lm1") b, _ = _setup(topic) karten = main.baustein_karten(topic, b) assert len(karten) == 1 # nur die verifizierte Flashcard assert karten[0]["inhalt"]["frage"] == "F1" assert karten[0]["box"] == 1 # Default ohne Leitner-Eintrag def _aussage(topic, atom_id, paar, wahr, text): return db.insert("artefakte", atom_id=atom_id, typ="aussage", status="verifiziert", inhalt=db.j({"text": text, "wahr": wahr, "paar": paar, "erklaerung": "die wahre Fassung"})) def test_pruefung_panels_anti_cheat_und_paar_regel(): topic = topic_anlegen("pf1") b, a = _setup(topic) for p in range(4): # 4 Paare = 8 Aussagen → mind. 1 volles Panel möglich _aussage(topic, a, f"{a}-{p}", True, f"wahr {p}") _aussage(topic, a, f"{a}-{p}", False, f"falsch {p}") panels = main.pruefung_holen(topic, b) assert panels and all(len(p["panel"]) == 4 for p in panels) for p in panels: for x in p["panel"]: assert set(x) == {"id", "text"} # kein wahr/erklaerung (Anti-Cheat) paare = [db.uj(db.one("SELECT inhalt FROM artefakte WHERE id=?", (x["id"],)) ["inhalt"], {}).get("paar") for x in p["panel"]] assert len(set(paare)) == 4 # kein Paar-Partner im selben Panel def test_pruefung_scoring_exakte_teilmenge(): topic = topic_anlegen("pf2") b, a = _setup(topic) ids_wahr = [_aussage(topic, a, f"{a}-{p}", True, f"w{p}") for p in range(2)] ids_falsch = [_aussage(topic, a, f"{a}-{p+2}", False, f"f{p}") for p in range(2)] ids = ids_wahr + ids_falsch r = main.pruefung_antwort(topic, main.PruefungAntwort(ids=ids, angekreuzt=ids_wahr)) assert r["richtig"] and r["xp"] == 1 assert all(set(x) == {"id", "wahr", "erklaerung"} for x in r["aufloesung"]) # eine falsche angekreuzt → −1, Boden 0 r = main.pruefung_antwort(topic, main.PruefungAntwort( ids=ids, angekreuzt=ids_wahr + ids_falsch[:1])) assert not r["richtig"] and r["xp"] == 0 # Schwelle → fertig + lernstand-Status for _ in range(10): r = main.pruefung_antwort(topic, main.PruefungAntwort(ids=ids, angekreuzt=ids_wahr)) assert r["fertig"] stand = [s for s in main.lernstand_holen(topic) if s["baustein_id"] == b][0] assert stand["status"] == "fertig" def test_check_migration_erlaubt_aussage(): import sqlite3 con = sqlite3.connect(":memory:") con.execute("CREATE TABLE artefakte(id INTEGER PRIMARY KEY, atom_id INTEGER NOT NULL," " typ TEXT NOT NULL CHECK(typ IN ('flashcard','beispiel'))," " inhalt TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'kandidat')") con.execute("INSERT INTO artefakte(atom_id, typ, inhalt) VALUES(1,'flashcard','{}')") db._init_schema(con) # muss den CHECK erweitern und Daten erhalten con.execute("INSERT INTO artefakte(atom_id, typ, inhalt) VALUES(1,'aussage','{}')") assert con.execute("SELECT COUNT(*) FROM artefakte").fetchone()[0] == 2 def test_lernstand_und_fertig_idempotent(): topic = topic_anlegen("lm2") b, _ = _setup(topic) assert main.lernstand_holen(topic) == [] main.baustein_fertig(topic, b) assert main.lernstand_holen(topic) == [{"baustein_id": b, "status": "fertig", "xp": 0}] main.baustein_fertig(topic, b) # zweimal → kein Duplikat assert len(main.lernstand_holen(topic)) == 1