# -*- coding: utf-8 -*- """Tests fuer lib/scl_context.py - TroDocument -> Render-Kontext. Die komplette Ausgabe sichern die Golden-Files (test_scl_skeleton_golden.py); hier stehen die Ableitungen einzeln, auf die sich Templates (Schritt 3) und Namensregeln (Schritt 4) aus doc/SCL_Templates.md verlassen. """ from pathlib import Path import pytest from model import Analysis, DerivedTro, TroDocument from scl_context import SclName, build_context, flow_order from scl_skeleton import load_document FIXTURES = Path(__file__).resolve().parent / "fixtures" / "scl" def _tro(tro_id: str, type_name: str, **extra) -> DerivedTro: data = dict( tro_id=tro_id, type_name=type_name, label=f"Label {tro_id}", hosts=["0001"], separators=["0040"], scanners=[], reason="Test", ) data.update(extra) return DerivedTro(**data) @pytest.fixture def kontext(): """SYS1 -> TRO01 (1 Weiche) -> TRO02 -> SYS2 und TRO01 -> TRO03 (Vario).""" analysis = Analysis(tros=[ _tro("TRO01", "1Sep1Swi", predecessors=["SYS1"], successors=["TRO02", "TRO03"]), _tro("TRO02", "1Sep", separators=["0041"], predecessors=["TRO01"], successors=["SYS2"]), _tro("TRO03", "Vario", separators=[], predecessors=["TRO01"]), ]) document = TroDocument.from_analysis(analysis, source="test.csv") return build_context(document, "test_tro.json", created="2026-01-01 00:00") def _by_id(context, tro_id): return next(t for t in context.tros if t.id == tro_id) def test_reihenfolge_und_startgrund(kontext): assert [t.id for t in kontext.tros] == ["TRO01", "TRO02", "TRO03"] assert kontext.start_reason == "Materialeingang ueber SYS1" assert kontext.created == "2026-01-01 00:00" def test_nummernteil_wie_geschrieben(): """{nr} fuer die Namensregeln: fuehrende Nullen bleiben stehen.""" analysis = Analysis(tros=[_tro("TRO07", "1Sep"), _tro("TRO107", "1Sep"), _tro("XY", "1Sep")]) ctx = build_context(TroDocument.from_analysis(analysis, source="t"), "t") assert {t.id: t.nr for t in ctx.tros} == {"TRO07": "07", "TRO107": "107", "XY": ""} def test_staubereiche_nummerierung(kontext): """Eingaenge ab 1, Ausgaenge ab 2 - wie in den Referenz-Aufrufstellen.""" tro = _by_id(kontext, "TRO01") assert [(j.n, j.neighbour) for j in tro.jam_entries] == [ (1, "SYS1 (Station, kein TRO)")] assert [(j.n, j.neighbour) for j in tro.jam_exits] == [(2, "TRO02"), (3, "TRO03")] def test_eine_weiche_bedient_alle_abgaenge(kontext): tro = _by_id(kontext, "TRO01") assert len(tro.switches) == 1 weiche = tro.switches[0] assert weiche.to1_destinations == 2 assert weiche.direction_target == "#TRO01.nInDirection" assert [(e.via, e.targets) for e in tro.switch_exits] == [ ("TRO02", ["SYS2", "TRO02"]), ("TRO03", ["TRO03"])] def test_mehrere_weichen_keine_geratene_aufteilung(): """2Sep2Swi (mubea): nTo1Destinations bleibt offen, Richtung je Weiche.""" ctx = build_context(load_document(FIXTURES / "mubea_tro.json"), "mubea_tro.json") tro = next(t for t in ctx.tros if t.type == "2Sep2Swi") assert [w.to1_destinations for w in tro.switches] == [None, None] assert [w.direction_target for w in tro.switches] == [ f"#{tro.id}.nInDirection1", f"#{tro.id}.nInDirection2"] def test_separatoren_aus_dem_layout(kontext): """Mehr Separatoren laut Typ als im Layout -> '?' statt Fehler.""" assert [s.layout for s in _by_id(kontext, "TRO01").separators] == ["0040"] assert [s.layout for s in _by_id(kontext, "TRO03").separators] == ["?"] def test_vario_nur_beim_vario_typ(kontext): vario = _by_id(kontext, "TRO03") assert vario.has_vario assert list(vario.vario_sensors) == [ "stSenCarrInPos", "stSenFinger", "stSenLastPos", "stSenJam"] assert _by_id(kontext, "TRO02").vario_sensors == {} def test_heute_sind_alle_namen_offen(kontext): """Bis zu den Namensregeln (Schritt 4) ist jeder Name ein TODO-Platzhalter.""" namen: list[SclName] = [] for tro in kontext.tros: namen += [tro.main_tro, tro.safety, tro.motor_protection, tro.vario_motor, tro.machine_state, tro.priority_udt, tro.prio_dir2, tro.carousel_run] namen += [j.sensor for j in tro.jam_exits] assert all(j.sensor is None for j in tro.jam_entries) namen += [n for s in tro.separators for n in (s.no, s.sensor, s.stopper)] namen += [n for w in tro.switches for n in (w.no, w.valve, w.jam_db)] namen += [j.db for j in tro.jam_entries + tro.jam_exits] namen += list(tro.vario_sensors.values()) assert namen and all(n.todo for n in namen) def test_flow_order_kreislauf_ohne_eingang(): analysis = Analysis(tros=[ _tro("TRO02", "1Sep", predecessors=["TRO01"], successors=["TRO01"]), _tro("TRO01", "1Sep", predecessors=["TRO02"], successors=["TRO02"]), ]) geordnet, grund = flow_order(analysis.tros) assert [t.tro_id for t in geordnet] == ["TRO01", "TRO02"] assert grund.startswith("Kreislauf ohne Eingang")