Files
planer2/backend/tests/test_planung.py
2026-07-29 15:19:41 +02:00

202 lines
6.7 KiB
Python

"""Die Planung: eine Arbeitskopie, die den Projektstand nicht anfasst.
Geprüft wird die eine Zusage — solange die Planung läuft, bleibt die Übersicht,
was sie war. Und dass sie einen Neustart übersteht, weil sie auf der Platte liegt.
"""
import features
import parser
import planung
import projekte
import pytest
def karte(projekt: str, titel: str, *funktionen: str) -> str:
roh = f"<!-- titel -->\n{titel}\n" + "".join(
f"{'-' * 40}\n<!-- funktion -->\n{f}\n<!-- regeln -->\n- Etwas gilt\n"
for f in funktionen)
return features.anlegen(projekt, roh)["id"]
def titel(projekt: str) -> list:
return sorted(f["sektionen"]["titel"] for f in features.liste(projekt))
@pytest.fixture
def projekt(datenordner):
projekte.anlegen("P")
karte("P", "Galerie", "Bild wählen")
karte("P", "Shop", "Karte kaufen")
return "P"
def test_ohne_planung_arbeitet_alles_im_projektordner(projekt):
assert not planung.laeuft(projekt)
assert projekte.wurzel(projekt) == projekte.stand(projekt)
assert planung.aenderungen(projekt) == {}
def test_planung_leitet_das_schreiben_um(projekt):
planung.starte(projekt)
assert projekte.wurzel(projekt) != projekte.stand(projekt)
karte(projekt, "Neu", "Etwas tun")
# Die Karte steht in der Kopie …
assert "Neu" in titel(projekt)
# … und nicht im Projektstand
assert not (projekte.stand(projekt) / "neu.md").exists()
def test_zweite_planung_wird_abgelehnt(projekt):
planung.starte(projekt)
with pytest.raises(ValueError):
planung.starte(projekt)
def test_planung_ueberlebt_einen_neustart(projekt):
planung.starte(projekt)
karte(projekt, "Neu", "Etwas tun")
# Nichts im Speicher — der nächste Prozess sieht nur die Platte
assert planung.laeuft(projekt)
assert "Neu" in planung.aenderungen(projekt)
def test_abbruch_laesst_den_projektstand_unberuehrt(projekt):
vorher = titel(projekt)
planung.starte(projekt)
karte(projekt, "Neu", "Etwas tun")
planung.brich_ab(projekt)
assert not planung.laeuft(projekt)
assert titel(projekt) == vorher
def test_umsetzen_macht_die_kopie_zum_stand(projekt):
planung.starte(projekt)
karte(projekt, "Neu", "Etwas tun")
planung.setze_um(projekt)
assert not planung.laeuft(projekt)
assert "Neu" in titel(projekt)
assert not (projekte.stand(projekt) / projekte.PLANUNG).exists()
def test_umsetzen_ohne_planung_ist_ein_fehler(projekt):
with pytest.raises(ValueError):
planung.setze_um(projekt)
# ---------------------------------------------------------------- Änderungen
def test_neue_karte_ist_neu(projekt):
planung.starte(projekt)
karte(projekt, "Neu", "Etwas tun")
a = planung.aenderungen(projekt)
assert a["Neu"]["art"] == "neu"
assert a["Neu"]["funktionen"] == {"Etwas tun": "neu"}
assert "Galerie" not in a
def test_entfernte_karte_ist_weg(projekt):
planung.starte(projekt)
features.loeschen(projekt, "shop")
a = planung.aenderungen(projekt)
assert a["Shop"]["art"] == "weg"
assert a["Shop"]["funktionen"] == {"Karte kaufen": "weg"}
def test_neue_funktion_wird_markiert(projekt):
planung.starte(projekt)
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie")
features.speichern(projekt, f["id"],
f["roh"] + f"{'-' * 40}\n<!-- funktion -->\nBild löschen\n")
a = planung.aenderungen(projekt)
assert a["Galerie"]["art"] == "geaendert"
assert a["Galerie"]["funktionen"] == {"Bild löschen": "neu"}
def test_geaenderte_regel_wird_markiert(projekt):
planung.starte(projekt)
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie")
features.speichern(projekt, f["id"], f["roh"].replace("Etwas gilt", "Anderes gilt"))
assert planung.aenderungen(projekt)["Galerie"]["funktionen"] == {
"Bild wählen": "geaendert"}
def test_umbenannte_karte_ist_neu_und_weg(projekt):
"""Verglichen wird über den Titel. Eine Umbenennung ist zwei Änderungen."""
planung.starte(projekt)
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Shop")
features.speichern(projekt, f["id"], f["roh"].replace("Shop", "Laden", 1))
a = planung.aenderungen(projekt)
assert a["Shop"]["art"] == "weg" and a["Laden"]["art"] == "neu"
def test_gleicher_inhalt_ist_keine_aenderung(projekt):
planung.starte(projekt)
f = features.liste(projekt)[0]
features.speichern(projekt, f["id"], f["roh"])
assert planung.aenderungen(projekt) == {}
# ---------------------------------------------------------------- Zurücksetzen
def test_zuruecksetzen_loescht_eine_neue_karte(projekt):
planung.starte(projekt)
karte(projekt, "Neu", "Etwas tun")
planung.zuruecksetzen(projekt, "Neu")
assert planung.aenderungen(projekt) == {}
assert "Neu" not in titel(projekt)
def test_zuruecksetzen_holt_eine_geloeschte_karte_zurueck(projekt):
planung.starte(projekt)
features.loeschen(projekt, "shop")
planung.zuruecksetzen(projekt, "Shop")
assert planung.aenderungen(projekt) == {}
assert "Shop" in titel(projekt)
def test_zuruecksetzen_stellt_den_alten_inhalt_her(projekt):
planung.starte(projekt)
f = next(x for x in features.liste(projekt) if x["sektionen"]["titel"] == "Galerie")
features.speichern(projekt, f["id"], f["roh"].replace("Etwas gilt", "Anderes gilt"))
planung.zuruecksetzen(projekt, "Galerie")
assert planung.aenderungen(projekt) == {}
def test_zuruecksetzen_laesst_die_uebrigen_stehen(projekt):
planung.starte(projekt)
karte(projekt, "Eins", "A tun")
karte(projekt, "Zwei", "B tun")
planung.zuruecksetzen(projekt, "Eins")
assert set(planung.aenderungen(projekt)) == {"Zwei"}
def test_zuruecksetzen_ohne_planung_ist_ein_fehler(projekt):
with pytest.raises(ValueError):
planung.zuruecksetzen(projekt, "Galerie")
def test_unbekannte_karte_zuruecksetzen_meldet_es(projekt):
planung.starte(projekt)
with pytest.raises(FileNotFoundError):
planung.zuruecksetzen(projekt, "Gibt es nicht")
# ---------------------------------------------------------------- Nachbarschaft
def test_die_kopie_ist_kein_eigenes_projekt(projekt):
planung.starte(projekt)
assert [p["name"] for p in projekte.liste()] == ["P"]
def test_gespraech_und_gedaechtnis_wandern_mit(projekt):
"""Was während des Planens beurteilt wurde, gilt für den geplanten Stand."""
(projekte.stand(projekt) / ".pruefung.json").write_text('{"stil": {}}')
planung.starte(projekt)
assert (projekte.wurzel(projekt) / ".pruefung.json").is_file()
def test_die_kopie_kopiert_sich_nicht_selbst(projekt):
planung.starte(projekt)
assert not (projekte.wurzel(projekt) / projekte.PLANUNG).exists()