166 lines
5.8 KiB
Python
166 lines
5.8 KiB
Python
"""Das Gedächtnis der Stilprüfung: was gilt weiter, was wird neu gefragt.
|
|
|
|
Die Prüfung fragt ein Modell. Dieselbe Frage kippt bei Grenzfällen auch bei
|
|
Temperatur 0 — vorher meldete Runde 1 einen Befund, Runde 2 keinen, Runde 3 wieder
|
|
einen. Hier steht, unter welchen Bedingungen ein Urteil stehen bleibt.
|
|
"""
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
import agents
|
|
import features
|
|
import ledger
|
|
import projekte
|
|
|
|
|
|
@pytest.fixture
|
|
def projekt(datenordner):
|
|
projekte.anlegen("Test")
|
|
return "Test"
|
|
|
|
|
|
def karte(projekt, titel, *funktionen):
|
|
"""funktionen sind (name, regel) oder (name, regel, [testschritte])."""
|
|
text = f"<!-- titel -->\n{titel}\n"
|
|
for eintrag in funktionen:
|
|
name, regel, schritte = (*eintrag, [])[:3]
|
|
text += f"<!-- funktion -->\n{name}\n<!-- regeln -->\n- {regel}\n"
|
|
if schritte:
|
|
text += "<!-- testen -->\n" + "".join(f"- {s}\n" for s in schritte)
|
|
return features.anlegen(projekt, text)
|
|
|
|
|
|
class Zaehler:
|
|
"""Ersetzt das Modell und zählt mit, wie oft überhaupt gefragt wurde."""
|
|
|
|
def __init__(self, antwort):
|
|
self.antwort = antwort
|
|
self.rufe = 0
|
|
|
|
async def __call__(self, system, nachricht, temperatur=0.0):
|
|
self.rufe += 1
|
|
wert = self.antwort
|
|
return wert(nachricht, self.rufe) if callable(wert) else wert
|
|
|
|
|
|
# ---------------------------------------------------------------- Datei
|
|
|
|
def test_leeres_gedaechtnis_hat_alle_faecher(projekt):
|
|
stand = ledger.lade(projekt)
|
|
assert set(stand) == set(ledger.FAECHER)
|
|
assert all(v == {} for v in stand.values())
|
|
|
|
|
|
def test_kaputte_datei_wird_wie_leer_behandelt(projekt):
|
|
(projekte.wurzel(projekt) / ledger.DATEI).write_text("{kein json")
|
|
assert ledger.lade(projekt)["belege"] == {}
|
|
|
|
|
|
def test_gemerktes_ueberlebt_den_lauf(projekt):
|
|
stand = ledger.lade(projekt)
|
|
stand["belege"][ledger.schluessel("a", "Tun")] = {"abdruck": "x", "datei": "a.py",
|
|
"beleg": "def tun():"}
|
|
ledger.sichere(projekt, stand)
|
|
assert ledger.lade(projekt)["belege"] == stand["belege"]
|
|
|
|
|
|
def test_schluessel_bleibt_zerlegbar(projekt):
|
|
"""Titel dürfen alles enthalten — auch das, was als Trennzeichen taugen würde."""
|
|
fies = 'Klick auf "x", dann | und \\ und ["a","b"]'
|
|
assert ledger.teile(ledger.schluessel("karte", fies)) == ["karte", fies]
|
|
|
|
|
|
def test_gedaechtnis_ist_kein_feature(projekt):
|
|
karte(projekt, "Eins")
|
|
ledger.sichere(projekt, ledger.lade(projekt))
|
|
assert [f["sektionen"]["titel"] for f in features.liste(projekt)] == ["Eins"]
|
|
|
|
|
|
# ---------------------------------------------------------------- Vision
|
|
|
|
VISION = "<!-- titel -->\nVision\n<!-- art -->\nvision\n<!-- ziel -->\nSo soll es werden\n"
|
|
|
|
|
|
def test_vision_ist_eine_eigene_kartenart(projekt):
|
|
f = features.anlegen(projekt, VISION)
|
|
assert f["sektionen"]["art"] == "vision"
|
|
assert f["sektionen"]["ziel"] == "So soll es werden"
|
|
|
|
|
|
def test_unbekannte_art_bleibt_kern(projekt):
|
|
f = features.anlegen(projekt, "<!-- titel -->\nX\n<!-- art -->\nwichtig\n")
|
|
assert f["sektionen"]["art"] == "kern"
|
|
|
|
|
|
def test_keine_pruefung_fasst_die_vision_an(projekt):
|
|
"""Die Vision ist die Vorlage, nicht der Prüfling."""
|
|
karte(projekt, "Eins", ("Etwas starten", "Knopf"))
|
|
features.anlegen(projekt, VISION)
|
|
assert len(features.liste(projekt)) == 2
|
|
titel = [f["sektionen"]["titel"] for f in features.pruefbar(projekt)]
|
|
assert titel == ["Eins"]
|
|
|
|
|
|
# ---------------------------------------------------------------- Prüfung 1
|
|
|
|
async def test_stilurteil_wird_gemerkt_und_nicht_neu_gefragt(projekt, monkeypatch):
|
|
"""176 Anfragen je Lauf brachten den Anbieter zum Drosseln. Unveränderter
|
|
Ausschnitt bei unverändertem Katalog heißt: das Urteil von vorhin gilt."""
|
|
import pruefung
|
|
|
|
karte(projekt, "Eins", ("Etwas starten", "Knopf"))
|
|
modell = Zaehler('{"felder": {}}')
|
|
monkeypatch.setattr(agents, "frage", modell)
|
|
|
|
liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt)
|
|
for a in liste:
|
|
assert await arbeite(a, None) == []
|
|
abschluss()
|
|
erste = modell.rufe
|
|
assert erste >= len(pruefung.TEMPERATUREN)
|
|
|
|
liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt)
|
|
for a in liste:
|
|
assert await arbeite(a, None) == []
|
|
assert modell.rufe == erste # keine einzige neue Anfrage
|
|
|
|
|
|
async def test_geaenderter_text_wird_neu_gefragt(projekt, monkeypatch):
|
|
import pruefung
|
|
|
|
karte(projekt, "Eins", ("Etwas starten", "Knopf"))
|
|
modell = Zaehler('{"felder": {}}')
|
|
monkeypatch.setattr(agents, "frage", modell)
|
|
|
|
liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt)
|
|
for a in liste:
|
|
await arbeite(a, None)
|
|
abschluss()
|
|
vorher = modell.rufe
|
|
|
|
datei = projekte.wurzel(projekt) / f"{features.liste(projekt)[0]['id']}.md"
|
|
datei.write_text(datei.read_text().replace("- Knopf", "- Ganz anderer Text"))
|
|
liste, arbeite, _ = await pruefung._stil_aufgaben(projekt)
|
|
for a in liste:
|
|
await arbeite(a, None)
|
|
assert modell.rufe > vorher
|
|
|
|
|
|
async def test_gemessener_verstoss_kommt_nie_aus_dem_gedaechtnis(projekt, monkeypatch):
|
|
"""Sonst bliebe eine neu hinzugekommene Messregel an alten Karten wirkungslos."""
|
|
import pruefung
|
|
|
|
karte(projekt, "Eins", ("Etwas starten", "Auch Passwort prüfen."))
|
|
modell = Zaehler('{"felder": {"regeln": {"neu": "- Passwort prüfen",'
|
|
' "grund": "Füllwort", "regel": "x"}}}')
|
|
monkeypatch.setattr(agents, "frage", modell)
|
|
|
|
for lauf in range(2):
|
|
liste, arbeite, abschluss = await pruefung._stil_aufgaben(projekt)
|
|
gefunden = [p for a in liste for p in await arbeite(a, None)]
|
|
abschluss()
|
|
assert [p["vorschlag"] for p in gefunden] == ["Passwort prüfen"], lauf
|
|
assert modell.rufe > len(pruefung.TEMPERATUREN) # zweimal wirklich gefragt
|