update
This commit is contained in:
@@ -177,7 +177,7 @@ def test_det_auftraege_blockquote_und_artefakt():
|
||||
ziel = db.insert("lernziele", topic=topic, text="Kann X", status="aktiv")
|
||||
b_id = db.insert("bausteine", topic=topic, ziel_id=ziel, titel="B", ord=0, status="neu")
|
||||
a = db.insert("atome", topic=topic, titel="A", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b_id, braucht=db.j([]))
|
||||
status="neu", baustein_id=b_id)
|
||||
lang = (f"<!-- atom: {a} | A -->\n" + "Fließtext. " * 45
|
||||
+ "\n> wörtliches Rohzitat aus der Quelle\nEs gilt u 6= v."
|
||||
+ "\n\nDas Blank-Symbol $[. ist speziell und liegt in $[ \\in \\Gamma$.")
|
||||
@@ -197,7 +197,7 @@ def test_det_auftraege_neue_checks():
|
||||
ziel = db.insert("lernziele", topic=topic, text="Kann X", status="aktiv")
|
||||
b_id = db.insert("bausteine", topic=topic, ziel_id=ziel, titel="B", ord=0, status="neu")
|
||||
a = db.insert("atome", topic=topic, titel="A", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b_id, braucht=db.j([]))
|
||||
status="neu", baustein_id=b_id)
|
||||
wand = "Wort " * 130
|
||||
lang = (f"<!-- atom: {a} | A -->\n<!-- atom: 99999 | Fremd -->\n"
|
||||
"Der Beweis folgt aus Satz 6.25, dazu später mehr.\n\n"
|
||||
@@ -231,7 +231,7 @@ async def test_fix_fehlschlag_behaelt_auftraege(monkeypatch):
|
||||
ziel = db.insert("lernziele", topic=topic, text="Kann X", status="aktiv")
|
||||
b_id = db.insert("bausteine", topic=topic, ziel_id=ziel, titel="B", ord=0, status="neu")
|
||||
db.insert("atome", topic=topic, titel="A", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b_id, braucht=db.j([]))
|
||||
status="neu", baustein_id=b_id)
|
||||
db.insert("sections", baustein_id=b_id, stage="fix", text_lang="alt", text_kompakt="")
|
||||
au = db.insert("auftraege", baustein_id=b_id, art="falsch", detail="y")
|
||||
# Fix liefert Text OHNE Marker → Marker-Invariante bricht → Fehlschlag-Pfad
|
||||
@@ -256,9 +256,9 @@ def test_marker_titel_erzeugen_keine_auftraege():
|
||||
ziel = db.insert("lernziele", topic=topic, text="Kann X", status="aktiv")
|
||||
b_id = db.insert("bausteine", topic=topic, ziel_id=ziel, titel="B", ord=0, status="neu")
|
||||
a1 = db.insert("atome", topic=topic, titel="Folge a_n", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b_id, braucht=db.j([]))
|
||||
status="neu", baustein_id=b_id)
|
||||
a2 = db.insert("atome", topic=topic, titel="A*-Suche", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b_id, braucht=db.j([]))
|
||||
status="neu", baustein_id=b_id)
|
||||
lang = (f"<!-- atom: {a1} | Folge a_n -->\n<!-- atom: {a2} | A*-Suche -->\n"
|
||||
+ "Sauberer Fließtext ohne Formeln. " * 12)
|
||||
joined = " ".join(guide._det_auftraege(topic, {"id": b_id, "ord": 0}, lang, ""))
|
||||
@@ -293,7 +293,7 @@ async def test_auftrag_offen_in_messen():
|
||||
ziel = db.insert("lernziele", topic=topic, text="Kann X", status="aktiv")
|
||||
b_id = db.insert("bausteine", topic=topic, ziel_id=ziel, titel="B", ord=0, status="neu")
|
||||
a = db.insert("atome", topic=topic, titel="A", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b_id, braucht=db.j([]))
|
||||
status="neu", baustein_id=b_id)
|
||||
lang = f"<!-- atom: {a} | A -->\n" + "Wort " * 60
|
||||
db.insert("sections", baustein_id=b_id, stage="done", text_lang=lang, text_kompakt="- p")
|
||||
db.insert("auftraege", baustein_id=b_id, art="luecke", detail="Atom-Inhalt fehlt")
|
||||
@@ -320,7 +320,7 @@ async def test_reparieren_bewegt_false_bei_identischem_text(monkeypatch):
|
||||
ziel = db.insert("lernziele", topic=topic, text="Kann X", status="aktiv")
|
||||
b_id = db.insert("bausteine", topic=topic, ziel_id=ziel, titel="B", ord=0, status="neu")
|
||||
a = db.insert("atome", topic=topic, titel="A", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b_id, braucht=db.j([]))
|
||||
status="neu", baustein_id=b_id)
|
||||
lang = f"<!-- atom: {a} | A -->\n" + ("Wort " * 60).strip() # ohne Trailing-Space
|
||||
db.insert("sections", baustein_id=b_id, stage="fix", text_lang=lang,
|
||||
text_kompakt="- p")
|
||||
@@ -413,7 +413,7 @@ async def test_fix_cap_friert_section_ein(monkeypatch):
|
||||
ziel = db.insert("lernziele", topic=topic, text="Kann X", status="aktiv")
|
||||
b = db.insert("bausteine", topic=topic, ziel_id=ziel, titel="B", ord=0, status="neu")
|
||||
a = db.insert("atome", topic=topic, titel="A", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b, braucht=db.j([]))
|
||||
status="neu", baustein_id=b)
|
||||
lang = f"<!-- atom: {a} | A -->\n" + "Wort " * 60
|
||||
db.insert("sections", baustein_id=b, stage="fix", text_lang=lang, text_kompakt="- p",
|
||||
fix_versuche=guide.FIX_MAX_VERSUCHE) # schon am Cap
|
||||
@@ -433,7 +433,7 @@ async def test_marker_platzieren_deterministisch():
|
||||
topic = topic_anlegen("platz")
|
||||
b = db.insert("bausteine", topic=topic, ziel_id=1, titel="B", ord=0, status="neu")
|
||||
a = db.insert("atome", topic=topic, titel="X", typ="begriff", definition="d",
|
||||
status="neu", baustein_id=b, ord=0, braucht=db.j([]))
|
||||
status="neu", baustein_id=b, ord=0)
|
||||
art = db.insert("artefakte", atom_id=a, typ="beispiel", status="verifiziert",
|
||||
inhalt=db.j({"form": "tabelle", "tabelle": "| A | B |\n|---|---|\n| 1 | 2 |"}))
|
||||
lang = f"#### X\n<!-- atom: {a} | X -->\nErklärung von X.\n\nWeiterer Absatz zum Thema."
|
||||
@@ -444,3 +444,90 @@ async def test_marker_platzieren_deterministisch():
|
||||
# idempotent: zweiter Lauf dupliziert nicht
|
||||
assert guide._marker_platzieren(db.one("SELECT * FROM bausteine WHERE id=?", (b,)),
|
||||
out).count("<!-- beispiel:") == 1
|
||||
|
||||
|
||||
def test_finde_zitat_latex_gerendert():
|
||||
"""tex-Quellen: das Modell zitiert die gerenderte Lesart (k ∈ ℕ), die Quelle
|
||||
trägt Markup ($k \\in \\mathbb{N}$) — die Faltung macht beide gleich."""
|
||||
text = ("Für das \\textsc{VertexCover} Problem ist neben einem Graphen $G$ eine"
|
||||
" Zahl $k \\in \\mathbb{N}_{\\geq 0}$ gegeben und es wird gefragt, ob ein"
|
||||
" Vertex Cover mit Größe höchstens $k$ in $G$ existiert.")
|
||||
zitat = ("Für das VertexCover Problem ist neben einem Graphen G eine Zahl k ∈ ℕ"
|
||||
" gegeben und es wird gefragt, ob ein Vertex Cover mit Größe höchstens k"
|
||||
" in G existiert.")
|
||||
span = textkit.finde_zitat(text, zitat)
|
||||
assert span is not None and text[span[0]:span[1]].startswith("Für das")
|
||||
# griechische Befehle ↔ Unicode-Buchstaben
|
||||
text2 = ("Ein Wort $w \\in \\Sigma^*$ über dem Alphabet $\\Sigma$ ist eine"
|
||||
" endliche Folge von Zeichen aus dem Alphabet.")
|
||||
zitat2 = ("Ein Wort w ∈ Σ* über dem Alphabet Σ ist eine endliche Folge von"
|
||||
" Zeichen aus dem Alphabet.")
|
||||
assert textkit.finde_zitat(text2, zitat2) is not None
|
||||
# LaTeX-Zitat gegen LaTeX-Quelle bleibt symmetrisch matchbar
|
||||
assert textkit.finde_zitat(text, "Zahl $k \\in \\mathbb{N}_{\\geq 0}$ gegeben und"
|
||||
" es wird gefragt, ob ein Vertex Cover") is not None
|
||||
|
||||
|
||||
def test_finde_zitat_kurz_nur_bei_eindeutigkeit():
|
||||
"""Kurze Zitate (gefaltet 10–19 Zeichen) matchen nur bei GENAU EINEM
|
||||
Vorkommen — Eindeutigkeit direkt geprüft statt Proxy-Länge."""
|
||||
text = ("Vorher steht Text. Definiere $\\alpha_{\\text{Anfang}} = z_{00} \\wedge"
|
||||
" s_{00}$ als Startbelegung. Nachher steht mehr.")
|
||||
zitat = "α_Anfang = z_00 ∧ s_00" # gerendert, gefaltet 13 Zeichen
|
||||
span = textkit.finde_zitat(text, zitat)
|
||||
assert span is not None and "alpha" in text[span[0]:span[1]]
|
||||
# zweites Vorkommen → mehrdeutig → None
|
||||
assert textkit.finde_zitat(
|
||||
text + " Wieder $\\alpha_{\\text{Anfang}} = z_{00} \\wedge s_{00}$.", zitat) is None
|
||||
# unter 10 gefalteten Zeichen: nie
|
||||
assert textkit.finde_zitat("Es gilt x=y hier.", "x = y") is None
|
||||
|
||||
|
||||
def test_jsonx_repariert_zeilenumbruch_in_string():
|
||||
# rohes mehrzeiliges Zitat (Markup-Zitat-Regel) → Kontrollzeichen-Reparatur
|
||||
assert jsonx.parse('[{"zitat": "\\\\item Zeile eins\nZeile zwei"}]') == [
|
||||
{"zitat": "\\item Zeile eins\nZeile zwei"}]
|
||||
assert jsonx.parse('{"a": "x\n\ny\tz"}') == {"a": "x\n\ny\tz"}
|
||||
# intaktes JSON bleibt unverändert
|
||||
assert jsonx.parse('{"a": "x\\nb"}') == {"a": "x\nb"}
|
||||
|
||||
|
||||
def test_finde_zitat_ueber_listenstart():
|
||||
"""\\begin{itemize} darf kein „itemize"-Residuum in der Faltung lassen."""
|
||||
text = ("Ein Algorithmus löst das Problem, wenn für alle $x \\in U$ gilt:\n"
|
||||
"\\begin{itemize}\n\\item $x \\in L$ impliziert $A(x) = 1$,\n"
|
||||
"\\item $x \\notin L$ impliziert $A(x) = 0$.\n\\end{itemize}")
|
||||
zitat = ("Ein Algorithmus löst das Problem, wenn für alle x ∈ U gilt: x ∈ L"
|
||||
" impliziert A(x) = 1, x ∉ L impliziert A(x) = 0.")
|
||||
assert textkit.finde_zitat(text, zitat) is not None
|
||||
|
||||
|
||||
def test_finde_zitat_wortalignment_verbalisierung():
|
||||
"""Stufe 5: Modell verbalisiert Mathe (\\cdot → „mal", \\sqrt → sqrt()) —
|
||||
auf Wort-Ebene wenige Edits → Treffer trotz Zeichen-Chaos."""
|
||||
text = ("Angenommen es gäbe einen Algorithmus, der VertexCover in "
|
||||
"$2^{o(|V'|)} \\cdot |I|^{O(1)}$ löst. Durch die Kombination der "
|
||||
"Reduktionen entsteht ein Widerspruch zur ETH und damit die Aussage.")
|
||||
zitat = ("Angenommen es gäbe einen Algorithmus, der VertexCover in "
|
||||
"2^{o(|V'|)} mal |I|^{O(1)} löst. Durch die Kombination der "
|
||||
"Reduktionen entsteht ein Widerspruch zur ETH und damit die Aussage.")
|
||||
span = textkit.finde_zitat(text, zitat)
|
||||
assert span is not None and text[span[0]:span[1]].startswith("Angenommen")
|
||||
|
||||
|
||||
def test_finde_zitat_wortalignment_paraphrase_bleibt_draussen():
|
||||
"""Echte Umformulierung: Wörter selbst anders → Wort-Distanz über Schranke."""
|
||||
text = ("Dann wird geprüft, ob $|X| \\leq k$ gilt und es wird abgelehnt, "
|
||||
"falls es nicht gilt. Danach wird ein Graph konstruiert, in dem alle "
|
||||
"Knoten entfernt wurden und die Suche neu beginnt.")
|
||||
zitat = ("Prüfe, ob |X| ≤ k, sonst ablehnen. Konstruiere den Graphen ohne "
|
||||
"diese Knoten und starte die Suche von vorn im Verfahren.")
|
||||
assert textkit.finde_zitat(text, zitat) is None
|
||||
|
||||
|
||||
def test_finde_zitat_wortalignment_negations_guard():
|
||||
text = ("Die Sprache ist in diesem Modell regulär und wird von einem "
|
||||
"endlichen Automaten mit wenigen Zuständen ohne Keller akzeptiert.")
|
||||
zitat = ("Die Sprache ist in diesem Modell nicht regulär und wird von einem "
|
||||
"endlichen Automaten mit wenigen Zuständen ohne Keller akzeptiert.")
|
||||
assert textkit.finde_zitat(text, zitat) is None
|
||||
|
||||
Reference in New Issue
Block a user