diff options
| author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2026-07-26 08:53:10 +0200 |
|---|---|---|
| committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2026-07-26 08:53:10 +0200 |
| commit | 81777013dfa582053489efea874e84379f1f0805 (patch) | |
| tree | 83f227c65b91152d4a8aaca67d418da04d601e9e /src/test/java | |
| parent | c86a73a6e1da7dd28076054936458b850eda2947 (diff) | |
Support unnumbered named Anlagen; strip control characters
Investigating "Anlagen as amendment target" corrected the diagnosis from
yesterday: Anlagen are supported. In gii-XML they are norms of their own
("Anlage 8", "Anhang"), Stelle.anlagenEnbez() resolves them, and the GEG
sample applies annex-targeted commands — only two of its fifty manual
entries touch annexes, both for content reasons.
What actually failed in Berlin was narrower, and is fixed:
* A law with a single annex names it after the provision it belongs to
("Die Anlage zu § 2 Absatz 4 Satz 1"). StellenParser demanded a
number after "Anlage" and rejected the phrase, so the article's frame
command went unrecognised and its items lost their context. The
annex now carries the designation "Anlage", like "Anhang". The naming
suffix is skipped deliberately: read along, the "§ 2" inside it would
become the target and the wrong norm would be amended.
* C0 control characters are now stripped. Berlin's enumeration indent
carries a U+0007 that sits invisibly in front of the command and made
its start-of-line anchor miss.
* Command verbs torn apart by a stray space in the official typesetting
("ein gefügt" for "eingefügt") are rejoined, restricted to sequences
that are not valid German word order.
Three of Article 1's four commands are now recognised. The fourth places
the new unit by a word anchor ("Vor den Wörtern … wird folgender Absatz 5
eingefügt"), which StrukturEinfuegung cannot express; that and the
inability of the plain-text stem format to carry an Anlage at all are
recorded in Landesrecht-Beispiele.adoc.
231 tests green; all pinned figures unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ic5804bf343dd5d8ce435c07b8f882ca0372890d2
Diffstat (limited to 'src/test/java')
3 files changed, 46 insertions, 0 deletions
diff --git a/src/test/java/eu/mulk/aendggner/EndToEndTest.java b/src/test/java/eu/mulk/aendggner/EndToEndTest.java index 19a7c8c..b3bea08 100644 --- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java +++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java @@ -597,5 +597,27 @@ class EndToEndTest { assertThat(ergebnis.befehle()) .extracting(b -> b.stelle().anzeigeText()) .containsExactly("§ 2 Satz 1 Nummer 2", "§ 2 Satz 1 Nummer 2"); + + // Artikel 1 ändert die unnummerierte, nach ihrer Vorschrift benannte Anlage („Die Anlage zu + // § 2 Absatz 4 Satz 1 wird wie folgt geändert“). Der Zusatz benennt die Anlage nur — er darf + // nicht als Ziel „§ 2“ gelesen werden; die Punkte erben „Anlage“ als Kontext. + var asog = + new Gesetz( + "ASOG Bln", "Allgemeines Sicherheits- und Ordnungsgesetz", null, List.of()); + var artikel1 = new AenderungsgesetzParser().parse(text, asog, null); + assertThat(artikel1.artikel()).containsExactly("1"); + assertThat(artikel1.befehle()) + .extracting(b -> b.stelle().anzeigeText()) + .containsExactly( + "§ 67 Absatz 2", + "Anlage Nummer 6 Absatz 2", + "Anlage Nummer 23 Absatz 4a", + "Anlage Nummer 23"); + // Bekannte Grenze: „Vor den Wörtern „…“ wird folgender Absatz 5 eingefügt“ — eine + // Struktureinfügung, deren Position ein Wortanker statt einer Stelle bestimmt. + assertThat(artikel1.befehle().stream().filter(b -> b instanceof UnbekannterBefehl).toList()) + .singleElement() + .extracting(b -> b.provenienz().gliederungsPfad()) + .isEqualTo("2. b) bb)"); } } diff --git a/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java b/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java index f15b98f..d5b960a 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java @@ -110,6 +110,21 @@ class StellenParserTest { } @Test + void parstUnnummerierteBenannteAnlage() { + // Ein Gesetz mit einer einzigen Anlage benennt sie nach der Vorschrift, zu der sie gehört. + // Der Zusatz identifiziert die Anlage und ist nicht selbst Ziel — sonst würde das darin + // genannte „§ 2“ als Ziel gelesen und die falsche Norm geändert. + var anlage = StellenParser.parse("Die Anlage zu § 2 Absatz 4 Satz 1").orElseThrow(); + assertThat(anlage.anzeigeText()).isEqualTo("Anlage"); + assertThat(anlage.anlagenEnbez()).contains("Anlage"); + assertThat(anlage.paragraph()).isEmpty(); + + // Nummerierte Anlagen bleiben unverändert. + assertThat(StellenParser.parse("Anlage 8 Nummer 1 Buchstabe b").orElseThrow().anzeigeText()) + .isEqualTo("Anlage 8 Nummer 1 Buchstabe b"); + } + + @Test void ignoriertChapeauZusatz() { // „in der Angabe vor Nummer 1“ ist ein verfeinernder Zusatz ohne eigene Komponente. assertThat(StellenParser.parse("Absatz 1 in der Angabe vor Nummer 1").orElseThrow().anzeigeText()) diff --git a/src/test/java/eu/mulk/aendggner/aenderung/parse/TextBereinigerTest.java b/src/test/java/eu/mulk/aendggner/aenderung/parse/TextBereinigerTest.java index 5ed8b93..5b7e850 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/TextBereinigerTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/TextBereinigerTest.java @@ -224,6 +224,15 @@ class TextBereinigerTest { } @Test + void entferntSteuerzeichenUndRepariertZerrisseneBefehlsvokabeln() { + // Im GVBl. für Berlin trägt der Einzug der Aufzählungsglieder ein U+0007; es steht unsichtbar + // vor dem Befehl und ließ dessen Zeilenanfangs-Anker ins Leere greifen. Im selben Heft ist + // „eingefügt“ als „ein ge-“ + „fügt“ gesetzt — ein Leerzeichen mitten in der Befehlsvokabel. + assertThat(TextBereiniger.bereinige("a)\t Nach Nummer 6 wird folgender Absatz ein ge-\nfügt:")) + .isEqualTo("a)\t Nach Nummer 6 wird folgender Absatz eingefügt:"); + } + + @Test void schneidetDenBerlinerSeitenkopfAusDemFliesstext() { // Im GVBl. für Berlin steht der laufende Seitenkopf nicht auf einer eigenen Zeile, sondern // klebt samt Seitenzahl mitten im Text der folgenden Spalte. |
