From 2febdfd49776c473377ec08c0d4920ede38a242a Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sun, 23 Aug 2026 21:17:36 +0200 Subject: Der Rest sagt fortan, welcher Art er ist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eine Synopse mit fünfzig liegengebliebenen Befehlen war bisher eine unsortierte Liste von achtundsechzig verschiedenen Sätzen. Wer sie las, erfuhr über jeden einzelnen Befehl das Genaue und über das Ganze nichts — namentlich nicht, ob eine Vorlage am Werkzeug scheitert, am Wortlaut des Änderungsgesetzes oder am falschen Stand des Stammgesetzes. Neben den ausformulierten Grund tritt deshalb seine Art. Vergeben wird sie dort, wo der Grund entsteht: Die Stellenauflösung, die Textoperation und die Zeilensuche in der Inhaltsübersicht führen sie mit ihrem Wortlaut, weil allein die erzeugende Stelle sie kennt. Der Wortlaut bleibt unberührt und maßgeblich — der Grundsatz der Nichtverwerfung verlangt die genaue Auskunft im Einzelfall; gebündelt wird nur, was ohne Ordnung eine bloße Liste wäre. Den größten Ertrag trägt die Auszählung sofort: Von den fünfzig Resten des Gebäudeenergiegesetzes gegen den heutigen Stamm sind einundvierzig von einer einzigen Art, nämlich „Zieltext nicht vorhanden“ — die Handschrift eines Stammgesetzes, das jünger ist als das Änderungsgesetz. Diese Lage rügt das Werkzeug nunmehr eigens. Dazu liest es die Standangabe der Quelle, und zwar nicht die Standzeile allein: Das gii-XML führt daneben Hinweise der Form „Änderung durch Art. 1 G v. 18.11.2020 … textlich nachgewiesen“, die bezeugen, dass der Wortlaut die Änderung längst trägt, während die Standzeile noch die vorige nennt. Genau daran scheiterten im Infektionsschutzgesetz siebenundzwanzig Befehle, ohne dass jemand den Grund benennen konnte. Verglichen wird das späteste genannte Datum mit der Fassung, die der Einleitungssatz fortschreibt; ist der Stamm der jüngere, ergeht die Rüge einmal je Dokument. Fehlt eine Angabe, schweigt die Prüfung. Zwei Anwendungslücken sind daneben geschlossen: Das ankerlose Anfügen ganzer Paragraphen wird angewandt statt gemeldet, und die Zurückweisung des Einfügeankers „am Ende“ ist als bewusst gezogene Grenze kenntlich gemacht — die Verbindung kommt im gesamten Prüfbestand kein einziges Mal vor, und Vorschriften auf Verdacht werden nicht geschrieben. Geprüft mit „mvnw verify“: 332 Prüfungen, kein Fehlschlag; keine gepinnte Zahl hat sich geändert. REUSE 168/168. Co-Authored-By: Claude Opus 5 Change-Id: I042c4389034f728c4b66f8161dc15e05938185ba --- src/test/java/eu/mulk/aendggner/EndToEndTest.java | 10 +++++++ .../aendggner/anwendung/BefehlAnwenderTest.java | 31 ++++++++++++++++++++++ .../mulk/aendggner/synopse/HtmlRendererTest.java | 2 ++ 3 files changed, 43 insertions(+) (limited to 'src/test') diff --git a/src/test/java/eu/mulk/aendggner/EndToEndTest.java b/src/test/java/eu/mulk/aendggner/EndToEndTest.java index 66b7f00..97bcffb 100644 --- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java +++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java @@ -66,6 +66,13 @@ class EndToEndTest { // Das Original-BGBl enthält ein überzähliges Anführungszeichen (Artikel 3) — muss als // Warnung gemeldet werden, nicht als Abbruch. assertThat(parseErgebnis.warnungen()).isNotEmpty(); + // Und der Leser erfährt, woran die Reste liegen: Das XML trägt die Änderung dieses + // Gesetzes bereits als „textlich nachgewiesen“ und ist damit jünger als das Gesetz selbst. + assertThat(parseErgebnis.warnungen()) + .anyMatch(w -> w.contains("Das Stammgesetz ist jünger als das Änderungsgesetz")) + // Die Rüge ergeht einmal, obwohl zwei Artikel dasselbe Stammgesetz betreffen. + .filteredOn(w -> w.contains("ist jünger als")) + .hasSize(1); // 4. Anwenden: wirft nicht; jeder Befehl erhält einen Protokolleintrag. Auch hier ist das XML // jünger als das Änderungsgesetz — die Sollzahlen stehen in ifsgGegenZeitrichtigenStamm(). @@ -102,6 +109,9 @@ class EndToEndTest { assertThat(parseErgebnis.artikel()).containsExactly("1", "2"); assertThat(parseErgebnis.befehle()).hasSize(75); + // Gegen den zeitrichtigen Stamm ergeht keine Altersrüge; gegen den heutigen schon (siehe + // gesamtePipelineAufIfSgBeispiel). + assertThat(parseErgebnis.warnungen()).noneMatch(w -> w.contains("ist jünger als")); var anwendung = BefehlAnwender.anwenden(gesetz, parseErgebnis.befehle()); var manuellPfade = diff --git a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java index 8b60017..1650d1b 100644 --- a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java +++ b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java @@ -341,6 +341,37 @@ class BefehlAnwenderTest { assertThat(norm.absaetze().get(1).nummer()).isEqualTo("2"); } + @Test + void haengtGanzeParagraphenAnsGesetzAn() { + var befehl = + new Anfuegung( + Stelle.LEER, + Ebene.PARAGRAPH, + null, + "§ 4\nÜbergang\nWer zuvor erprobt hat, erprobt weiter.\n\n" + + "§ 5\nSchluss\nDiese Vorschrift gilt zuletzt.", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(ergebnis.neu().normen().stream().map(Norm::enbez)) + .containsExactly("§ 1", "§ 2", "§ 3", "§ 4", "§ 5"); + assertThat(ergebnis.neu().norm("§ 4").orElseThrow().titel()).isEqualTo("Übergang"); + } + + @Test + void haengtNichtAnUndBegruendetEsWennDasZitatKeinenNormkopfTraegt() { + var befehl = + new Anfuegung(Stelle.LEER, Ebene.PARAGRAPH, null, "Wer zuvor erprobt hat, …", PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.MANUELL_PRUEFEN); + assertThat(ergebnis.protokoll().get(0).grund()).isEqualTo(Grund.ZITAT_UNBRAUCHBAR); + assertThat(ergebnis.neu().normen()).hasSize(3); + } + @Test void hebtParagraphenAuf() { var befehl = new Aufhebung(stelle(new Stelle.Paragraph("2")), PROV); diff --git a/src/test/java/eu/mulk/aendggner/synopse/HtmlRendererTest.java b/src/test/java/eu/mulk/aendggner/synopse/HtmlRendererTest.java index b80fc88..6d8c840 100644 --- a/src/test/java/eu/mulk/aendggner/synopse/HtmlRendererTest.java +++ b/src/test/java/eu/mulk/aendggner/synopse/HtmlRendererTest.java @@ -72,6 +72,8 @@ class HtmlRendererTest { assertThat(html).contains("Manuell prüfen"); assertThat(html).contains("Die Nummern 1 bis 3 werden aufgehoben."); + // Nach Art des Grundes gebündelt, mit vorangestellter Häufigkeit. + assertThat(html).contains("Befehl nicht erkannt").contains("1"); } @Test -- cgit v1.2.1