diff options
Diffstat (limited to 'src/test')
3 files changed, 616 insertions, 5 deletions
diff --git a/src/test/java/eu/mulk/aendggner/EndToEndTest.java b/src/test/java/eu/mulk/aendggner/EndToEndTest.java index 483f06a..d4b0b17 100644 --- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java +++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java @@ -89,9 +89,12 @@ class EndToEndTest { assertThat(parseErgebnis.befehle().size()).isGreaterThanOrEqualTo(10); var typisiert = parseErgebnis.befehle().stream().filter(b -> !(b instanceof UnbekannterBefehl)).count(); - assertThat(typisiert).isGreaterThan(parseErgebnis.befehle().size() / 2); + assertThat(typisiert).isEqualTo(parseErgebnis.befehle().size()); + // Referenzfall des Ausbaus: alle Befehle (auch die Anhang-Änderungen) werden angewandt. var anwendung = BefehlAnwender.anwenden(gesetz, parseErgebnis.befehle()); + assertThat(anwendung.anzahlManuell()).isZero(); + assertThat(anwendung.anzahlAngewandt()).isEqualTo(parseErgebnis.befehle().size()); var synopse = SynopseBuilder.baue(gesetz, anwendung, parseErgebnis.warnungen(), false); assertThat(HtmlRenderer.rendere(synopse, "E2E-Test")).contains("Neue Fassung"); } diff --git a/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java b/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java index bbee916..f8cfe82 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java @@ -11,6 +11,7 @@ import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Neufassung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Sammelbefehl; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Streichung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturEinfuegung; +import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturErsetzung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Umnummerierung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WoerterEinfuegung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortAnker; @@ -222,8 +223,12 @@ class BefehlErkennerTest { + " „§ 28a Besondere Schutzmaßnahmen“.", Stelle.LEER); - assertThat(befehl).containsInstanceOf(WoerterEinfuegung.class); - assertThat(befehl.orElseThrow().stelle().betrifftInhaltsuebersicht()).isTrue(); + assertThat(befehl).containsInstanceOf(StrukturEinfuegung.class); + var einfuegung = (StrukturEinfuegung) befehl.orElseThrow(); + assertThat(einfuegung.stelle().betrifftInhaltsuebersicht()).isTrue(); + assertThat(einfuegung.stelle().anzeigeText()).isEqualTo("Inhaltsübersicht § 28"); + assertThat(einfuegung.vorher()).isFalse(); + assertThat(einfuegung.text()).isEqualTo("§ 28a Besondere Schutzmaßnahmen"); } @Test @@ -344,8 +349,11 @@ class BefehlErkennerTest { "Nach der Angabe zu § 9 wird folgende Angabe eingefügt: „§ 9a" + " Länderregelung“.", kontext); - assertThat(befehl).containsInstanceOf(WoerterEinfuegung.class); - assertThat(befehl.orElseThrow().stelle().betrifftInhaltsuebersicht()).isTrue(); + assertThat(befehl).containsInstanceOf(StrukturEinfuegung.class); + var einfuegung = (StrukturEinfuegung) befehl.orElseThrow(); + assertThat(einfuegung.stelle().betrifftInhaltsuebersicht()).isTrue(); + assertThat(einfuegung.stelle().anzeigeText()).isEqualTo("Inhaltsübersicht § 9"); + assertThat(einfuegung.text()).isEqualTo("§ 9a Länderregelung"); } @Test @@ -757,4 +765,265 @@ class BefehlErkennerTest { assertThat(teile).extracting(t -> ((Ersetzung) t).alt()).containsExactly("a", "c"); assertThat(teile).extracting(t -> ((Ersetzung) t).neu()).containsExactly("b", "d"); } + // --- Welle-4-Formen -------------------------------------------------------------------------- + + @Test + void erkenntAngabenBereichsErsetzungInDerInhaltsuebersicht() { + var kontext = new Stelle(List.of(new Stelle.Inhaltsuebersicht())); + var befehl = + erkenne( + "Die Angaben zu den §§ 34 bis § 45 werden durch die folgenden Angaben ersetzt:" + + " „§ 34 (weggefallen) § 35 (weggefallen)“.", + kontext); + + assertThat(befehl).containsInstanceOf(StrukturErsetzung.class); + var ersetzung = (StrukturErsetzung) befehl.orElseThrow(); + assertThat(ersetzung.stelle().anzeigeText()).isEqualTo("Inhaltsübersicht § 34"); + assertThat(ersetzung.bisStelle().anzeigeText()).isEqualTo("Inhaltsübersicht § 45"); + } + + @Test + void erkenntAngabeStreichungInDerInhaltsuebersicht() { + var befehl = + erkenne("In der Inhaltsübersicht wird die Angabe zu § 5a gestrichen.", Stelle.LEER); + + assertThat(befehl).containsInstanceOf(Aufhebung.class); + assertThat(befehl.orElseThrow().stelle().anzeigeText()).isEqualTo("Inhaltsübersicht § 5a"); + } + + @Test + void erkenntAngabeMitOrdinalerGliederung() { + var kontext = new Stelle(List.of(new Stelle.Inhaltsuebersicht())); + var befehl = + erkenne( + "Die Angabe zum zweiten Abschnitt wird wie folgt gefasst: „2. Abschnitt" + + " Koordinierung und epidemische Lage von nationaler Tragweite“.", + kontext); + + assertThat(befehl).containsInstanceOf(Neufassung.class); + assertThat(befehl.orElseThrow().stelle().anzeigeText()).isEqualTo("Inhaltsübersicht Abschnitt 2"); + } + + @Test + void erkenntVoranstellung() { + var befehl = + erkenne( + "Der Nummer 1 wird folgende Nummer 1 vorangestellt: „1. eine Umwälzpumpe nach § 64" + + " Absatz 2 auszutauschen ist,“.", + new Stelle(List.of(new Stelle.Paragraph("64")))); + + assertThat(befehl).containsInstanceOf(StrukturEinfuegung.class); + var einfuegung = (StrukturEinfuegung) befehl.orElseThrow(); + assertThat(einfuegung.vorher()).isTrue(); + assertThat(einfuegung.ebene()).isEqualTo(Ebene.NUMMER); + assertThat(einfuegung.stelle().anzeigeText()).isEqualTo("§ 64 Nummer 1"); + } + + @Test + void erkenntVoranstellungOhneAnker() { + var befehl = + erkenne( + "Folgende Nummer 1 wird vorangestellt: „1. einer vollziehbaren Anordnung nach § 5" + + " Absatz 2 Nummer 1 oder 2 zuwiderhandelt,“.", + Stelle.LEER); + + assertThat(befehl).containsInstanceOf(StrukturEinfuegung.class); + assertThat(((StrukturEinfuegung) befehl.orElseThrow()).vorher()).isTrue(); + } + + @Test + void erkenntNummernBereichsErsetzungMitKardinalitaetswechsel() { + var befehl = + erkenne( + "Satz 1 Nummer 3 bis 6 wird durch die folgenden Nummern 3 und 4 ersetzt: 3. „ bei" + + " Wärmeverteilungs- und Warmwasserleitungen die Wärmeabgabe begrenzt ist und" + + " 4. die Anforderungen eingehalten werden.“.", + new Stelle(List.of(new Stelle.Paragraph("61")))); + + assertThat(befehl).containsInstanceOf(StrukturErsetzung.class); + var ersetzung = (StrukturErsetzung) befehl.orElseThrow(); + assertThat(ersetzung.ebene()).isEqualTo(Ebene.NUMMER); + assertThat(ersetzung.stelle().anzeigeText()).isEqualTo("§ 61 Satz 1 Nummer 3"); + assertThat(ersetzung.bisStelle().anzeigeText()).isEqualTo("§ 61 Satz 1 Nummer 6"); + assertThat(ersetzung.text()).startsWith("3. "); + } + + @Test + void erkenntKommaMehrfachErsetzung() { + var befehl = + erkenne( + "In Satz 1 wird die Angabe „2025“ durch die Angabe „2030“, die Angabe „§ 50 Absatz 1" + + " in Verbindung mit § 48“ durch die Angabe „§ 38 Absatz 1 in Verbindung mit" + + " § 36“ und die Angabe „§ 50 Absatz 1“ durch die Angabe „§ 38 Absatz 1“" + + " ersetzt.", + new Stelle(List.of(new Stelle.Paragraph("109")))); + + assertThat(befehl).containsInstanceOf(Sammelbefehl.class); + var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); + assertThat(teile).hasSize(3).allMatch(t -> t instanceof Ersetzung); + assertThat(((Ersetzung) teile.get(0)).alt()).isEqualTo("2025"); + assertThat(((Ersetzung) teile.get(0)).neu()).isEqualTo("2030"); + } + + @Test + void erkenntMehrfachEinfuegepaare() { + var befehl = + erkenne( + "In Nummer 24 werden nach den Wörtern „einer Rechtsverordnung nach“ die Wörter" + + " „§ 5 Absatz 2 Nummer 4,“ und nach der Angabe „§ 23 Absatz 8 Satz 1“ ein" + + " Komma und die Angabe „§ 32 Satz 1“ eingefügt.", + new Stelle(List.of(new Stelle.Paragraph("73")))); + + assertThat(befehl).containsInstanceOf(Sammelbefehl.class); + var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); + assertThat(teile).hasSize(2).allMatch(t -> t instanceof WoerterEinfuegung); + assertThat(((WoerterEinfuegung) teile.get(1)).woerter()).isEqualTo(", § 32 Satz 1"); + } + + @Test + void erkenntKommaUndWoerterVorDemPunktAmEnde() { + var befehl = + erkenne( + "In Absatz 3 Satz 1 wird vor dem Punkt am Ende ein Komma und werden die Wörter" + + " „oder wenn der Nachweis erfolgt ist“ eingefügt.", + new Stelle(List.of(new Stelle.Paragraph("8")))); + + assertThat(befehl).containsInstanceOf(Ersetzung.class); + var ersetzung = (Ersetzung) befehl.orElseThrow(); + assertThat(ersetzung.alt()).isEqualTo("."); + assertThat(ersetzung.neu()).isEqualTo(", oder wenn der Nachweis erfolgt ist."); + assertThat(ersetzung.amEnde()).isTrue(); + } + + @Test + void erkenntKoordinierteUmnummerierung() { + var befehl = + erkenne( + "Die bisherigen Absätze 6 und 7 werden die Absätze 1 und 2.", + new Stelle(List.of(new Stelle.Paragraph("5")))); + + assertThat(befehl).containsInstanceOf(Sammelbefehl.class); + var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); + assertThat(teile).hasSize(2).allMatch(t -> t instanceof Umnummerierung); + // Absteigend: 7 → 2 zuerst, damit die Labels nicht kollidieren. + assertThat(teile.get(0).stelle().anzeigeText()).isEqualTo("§ 5 Absatz 7"); + } + + @Test + void erkenntVerbundMitUmnummerierungUndRueckbezug() { + var befehl = + erkenne( + "Die bisherige Nummer 1 wird Nummer 2 und in ihr werden die Wörter „§ 72 Absatz 1" + + " bis 3,“ durch die Wörter „Ablauf der Übergangsfristen,“ ersetzt.", + new Stelle(List.of(new Stelle.Paragraph("96")))); + + assertThat(befehl).containsInstanceOf(Sammelbefehl.class); + var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); + assertThat(teile).hasSize(2); + assertThat(teile.get(0)).isInstanceOf(Umnummerierung.class); + assertThat(teile.get(1)).isInstanceOf(Ersetzung.class); + assertThat(teile.get(1).stelle().anzeigeText()).isEqualTo("§ 96 Nummer 2"); + } + + @Test + void erkenntVerbundMitUmnummerierungUndNeufassung() { + var befehl = + erkenne( + "Die bisherige Nummer 3 wird Nummer 4 und wird wie folgt gefasst: 4. „ die" + + " Abrechnungen und Bestätigungen nach § 96 Absatz 5 vorliegen.“", + new Stelle(List.of(new Stelle.Paragraph("96")))); + + assertThat(befehl).containsInstanceOf(Sammelbefehl.class); + var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); + assertThat(teile.get(0)).isInstanceOf(Umnummerierung.class); + assertThat(teile.get(1)).isInstanceOf(Neufassung.class); + assertThat(((Neufassung) teile.get(1)).neuerText()).startsWith("4. "); + } + + @Test + void erkenntParagraphAnfuegungNachAnker() { + var befehl = + erkenne( + "Nach § 114 wird folgender § 115 angefügt: „§ 115 Übergangsvorschriften für" + + " Geldbußen Text.“", + Stelle.LEER); + + assertThat(befehl).containsInstanceOf(StrukturEinfuegung.class); + var einfuegung = (StrukturEinfuegung) befehl.orElseThrow(); + assertThat(einfuegung.ebene()).isEqualTo(Ebene.PARAGRAPH); + assertThat(einfuegung.bezeichnung()).isEqualTo("115"); + } + + @Test + void erkenntAnkerloseAbsatzEinfuegung() { + var befehl = + erkenne( + "Folgender Absatz 2 wird eingefügt: „(2) In einem Wohngebäude gilt dies nicht.“", + new Stelle(List.of(new Stelle.Paragraph("72")))); + + assertThat(befehl).containsInstanceOf(StrukturEinfuegung.class); + var einfuegung = (StrukturEinfuegung) befehl.orElseThrow(); + assertThat(einfuegung.vorher()).isFalse(); + assertThat(einfuegung.stelle().anzeigeText()).isEqualTo("§ 72 Absatz 1"); + } + + @Test + void erkenntNummernBlockAnfuegung() { + var befehl = + erkenne( + "Die folgenden Nummern 9 bis 11 werden angefügt: 9. „ Durchführung hydraulischer" + + " Abgleiche, 10. Einbau von Messausstattungen, 11. Sonstiges.“", + new Stelle(List.of(new Stelle.Paragraph("60")))); + + assertThat(befehl).containsInstanceOf(Anfuegung.class); + var anfuegung = (Anfuegung) befehl.orElseThrow(); + assertThat(anfuegung.ebene()).isEqualTo(Ebene.NUMMER); + assertThat(anfuegung.text()).startsWith("9. "); + } + + @Test + void erkenntPunktErsetzungDurchFolgendeWoerter() { + var befehl = + erkenne( + "In Absatz 1 Satz 2 wird der Punkt am Ende durch folgende Wörter ersetzt: „, das" + + " heißt, wenn die Investitionen unangemessen sind.“", + new Stelle(List.of(new Stelle.Paragraph("102")))); + + assertThat(befehl).containsInstanceOf(Ersetzung.class); + var ersetzung = (Ersetzung) befehl.orElseThrow(); + assertThat(ersetzung.alt()).isEqualTo("."); + assertThat(ersetzung.amEnde()).isTrue(); + } + + @Test + void erkenntWortVoranstellungImVerbund() { + var befehl = + erkenne( + "In Buchstabe a werden die Wörter „des § 10“ durch die Wörter „der §§ 71 bis 71h“" + + " ersetzt, wird dem Wort „Anforderungen“ das Wort „dortigen“ vorangestellt und" + + " werden die Wörter „nach den §§ 35 bis 41“ gestrichen.", + new Stelle(List.of(new Stelle.Paragraph("105")))); + + assertThat(befehl).containsInstanceOf(Sammelbefehl.class); + var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); + assertThat(teile).hasSize(3); + assertThat(teile.get(1)).isInstanceOf(WoerterEinfuegung.class); + assertThat(((WoerterEinfuegung) teile.get(1)).woerter()).isEqualTo("dortigen"); + assertThat(teile.get(2)).isInstanceOf(Streichung.class); + } + + @Test + void erkenntErsetzungMitPositionsanker() { + var befehl = + erkenne( + "In Nummer 2 werden nach den Wörtern „jeweils auch in Verbindung mit“ die Wörter" + + " „einer Rechtsverordnung nach § 14,“ durch die Wörter „§ 14 Absatz 8,“" + + " ersetzt.", + new Stelle(List.of(new Stelle.Paragraph("73")))); + + assertThat(befehl).containsInstanceOf(Ersetzung.class); + var ersetzung = (Ersetzung) befehl.orElseThrow(); + assertThat(ersetzung.alt()).isEqualTo("einer Rechtsverordnung nach § 14,"); + assertThat(ersetzung.neu()).isEqualTo("§ 14 Absatz 8,"); + } } diff --git a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java index 9b9c18d..aa658dd 100644 --- a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java +++ b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java @@ -6,6 +6,7 @@ import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Anfuegung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Aufhebung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Ebene; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Ersetzung; +import eu.mulk.aendggner.aenderung.Aenderungsbefehl.GliederungsUeberschriften; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Neufassung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Sammelbefehl; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Streichung; @@ -642,6 +643,344 @@ class BefehlAnwenderTest { assertThat(text).contains("1. (weggefallen)").contains("2. (weggefallen)").contains("3. (weggefallen)"); } + // --- Anhang/Anlage als Norm-Ziel ----------------------------------------------------------- + + /** Ein Gesetz mit Anhang-Norm nach dem Muster des UWG (mehrere Absätze, Nummern mit Kindern). */ + private static Gesetz gesetzMitAnhang() { + return new Gesetz( + "TestG", + null, + null, + List.of( + new Norm( + "§ 1", + "Zweck", + null, + List.of(new Absatz("1", "Es gilt der Anhang.")), + false), + new Norm( + "Anhang", + "(zu § 1)", + null, + List.of( + new Absatz(null, "Folgende Handlungen sind stets unzulässig:"), + new Absatz( + null, + " 1. die erste Handlung;\n" + + " 2. die zweite Handlung,\n" + + " a) wenn sie morgens geschieht, oder\n" + + " b) wenn sie abends geschieht;\n" + + " 3. die dritte Handlung;"), + new Absatz( + null, + " 31. die aggressive Handlung,\n" + + " a) wenn sie laut geschieht, oder\n" + + " b) wenn sie leise gemacht wird.\n" + + " 32. die letzte Handlung;")), + false))); + } + + private static Stelle anhangStelle(Stelle.Komponente... feinere) { + var komponenten = new java.util.ArrayList<Stelle.Komponente>(); + komponenten.add(new Stelle.Gliederungseinheit("Anhang", "")); + komponenten.addAll(List.of(feinere)); + return new Stelle(komponenten); + } + + @Test + void fuegtNummerImAnhangNachNummerMitKindernEin() { + // „Nach Nummer 2 wird die folgende Nummer 2a eingefügt“ — Nummer 2 hat Buchstaben a)/b); + // die neue Nummer muss hinter deren Block landen, nicht zwischen Nummer und Buchstaben. + var befehl = + new StrukturEinfuegung( + anhangStelle(new Stelle.NummerNr("2")), + false, + Ebene.NUMMER, + "2a", + "2a. die eingeschobene Handlung;", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitAnhang(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "Anhang", 1)) + .isEqualTo( + " 1. die erste Handlung;\n" + + " 2. die zweite Handlung,\n" + + " a) wenn sie morgens geschieht, oder\n" + + " b) wenn sie abends geschieht;\n" + + " 2a. die eingeschobene Handlung;\n" + + " 3. die dritte Handlung;"); + } + + @Test + void fuegtNummernBlockImAnhangEin() { + // Mehrere Einheiten in einem Einfügeblock bleiben eigene Zeilen. + var befehl = + new StrukturEinfuegung( + anhangStelle(new Stelle.NummerNr("3")), + false, + Ebene.NUMMER, + null, + "3a. die vierte Handlung;\n3b. die fünfte Handlung;", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitAnhang(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "Anhang", 1)) + .endsWith( + " 3. die dritte Handlung;\n" + + " 3a. die vierte Handlung;\n" + + " 3b. die fünfte Handlung;"); + } + + @Test + void loestNummerBuchstabeKetteImAnhangAuf() { + // „b)“ existiert in Nummer 2 und Nummer 31 — die Kette „Nummer 31 Buchstabe b“ ist trotzdem + // eindeutig, weil der Buchstabe im Block der Nummer 31 gesucht wird. + var befehl = + new Ersetzung( + anhangStelle(new Stelle.NummerNr("31"), new Stelle.BuchstabeNr("b")), + "gemacht wird.", + "gemacht wird;", + false, + false, + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitAnhang(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "Anhang", 2)) + .contains("wenn sie leise gemacht wird;") + .contains(" 32. die letzte Handlung;"); + // Nummer 2 Buchstabe b bleibt unangetastet. + assertThat(absatzText(ergebnis.neu(), "Anhang", 1)).contains("wenn sie abends geschieht;"); + } + + @Test + void streichtWoerterInDerUeberschriftEinerNorm() { + var befehl = + new Streichung( + stelle(new Stelle.Paragraph("3"), new Stelle.Ueberschrift()), + "Schlussvorschriften", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(ergebnis.neu().norm("§ 3").orElseThrow().titel()).isEmpty(); + } + + @Test + void meldetMehrdeutigeNummerOhneAbsatzangabeImAnhang() { + // Gäbe es dieselbe Nummer in mehreren Absätzen, bliebe der Befehl manuell. + var gesetz = + new Gesetz( + "TestG", + null, + null, + List.of( + new Norm( + "Anhang", + null, + null, + List.of( + new Absatz(null, " 1. erstens;"), + new Absatz(null, " 1. nochmal erstens;")), + false))); + var befehl = + new Ersetzung( + anhangStelle(new Stelle.NummerNr("1")), "erstens", "zuerst", false, false, PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetz, List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.MANUELL_PRUEFEN); + assertThat(ergebnis.protokoll().get(0).begruendung()).contains("nicht eindeutig"); + } + + // --- Inhaltsübersicht ------------------------------------------------------------------------ + + private static Gesetz gesetzMitInhaltsuebersicht() { + return new Gesetz( + "TestG", + null, + null, + List.of( + new Norm( + "Inhaltsübersicht", + null, + null, + List.of( + new Absatz( + null, + "Teil 1 | Allgemeines\n" + + "§ 1 | Zweck\n" + + "§ 2 | Begriffe\n" + + "Teil 2 | Verfahren\n" + + "Abschnitt 1 | Grundsätze\n" + + "§ 3 | Ablauf\n" + + "§ 4 | Fristen\n" + + "§ 5 | Schluss")), + false), + new Norm("§ 1", "Zweck", null, List.of(new Absatz(null, "Text.")), false))); + } + + private static Stelle iuStelle(Stelle.Komponente... feinere) { + var komponenten = new java.util.ArrayList<Stelle.Komponente>(); + komponenten.add(new Stelle.Inhaltsuebersicht()); + komponenten.addAll(List.of(feinere)); + return new Stelle(komponenten); + } + + @Test + void fasstAngabeInDerInhaltsuebersichtNeu() { + var befehl = + new Neufassung(iuStelle(new Stelle.Paragraph("2")), "§ 2 Begriffsbestimmungen", PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitInhaltsuebersicht(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "Inhaltsübersicht", 0)) + .contains("§ 2 | Begriffsbestimmungen") + .doesNotContain("§ 2 | Begriffe\n"); + } + + @Test + void fuegtAngabeInDerInhaltsuebersichtEin() { + var befehl = + new StrukturEinfuegung( + iuStelle(new Stelle.Paragraph("2")), + false, + Ebene.PARAGRAPH, + null, + "§ 2a Anwendungsbereich", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitInhaltsuebersicht(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "Inhaltsübersicht", 0)) + .contains("§ 2 | Begriffe\n§ 2a | Anwendungsbereich\nTeil 2 | Verfahren"); + } + + @Test + void ersetztAngabenBereichInDerInhaltsuebersicht() { + // „Die Angaben zu den §§ 3 bis 4 werden durch die folgenden Angaben ersetzt: …“ + var befehl = + new StrukturErsetzung( + iuStelle(new Stelle.Paragraph("3")), + iuStelle(new Stelle.Paragraph("4")), + Ebene.PARAGRAPH, + "§ 3 (weggefallen) § 4 (weggefallen)", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitInhaltsuebersicht(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "Inhaltsübersicht", 0)) + .contains("§ 3 | (weggefallen)\n§ 4 | (weggefallen)") + .doesNotContain("Ablauf"); + } + + @Test + void streichtAngabeUndLoestGliederungsKetteAuf() { + // „Die Angabe zu Teil 2 Abschnitt 1 wird gestrichen.“ — Kette grenzt das Fenster ein. + var befehl = + new Aufhebung( + iuStelle( + new Stelle.Gliederungseinheit("Teil", "2"), + new Stelle.Gliederungseinheit("Abschnitt", "1")), + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitInhaltsuebersicht(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(absatzText(ergebnis.neu(), "Inhaltsübersicht", 0)) + .doesNotContain("Abschnitt 1 | Grundsätze") + .contains("Teil 2 | Verfahren\n§ 3 | Ablauf"); + } + + // --- Gliederungs-Überschriften --------------------------------------------------------------- + + private static Gesetz gesetzMitGliederungen() { + var teil1 = new Gliederung("010", "Teil 1", "Allgemeines"); + var teil2 = new Gliederung("020", "Teil 2", "Anforderungen"); + return new Gesetz( + "TestG", + null, + null, + List.of( + new Norm("§ 1", "Zweck", teil1, List.of(new Absatz(null, "Eins.")), false), + new Norm("§ 2", "Begriffe", teil1, List.of(new Absatz(null, "Zwei.")), false), + new Norm("§ 3", "Pflichten", teil2, List.of(new Absatz(null, "Drei.")), false), + new Norm("§ 4", "Nachweise", teil2, List.of(new Absatz(null, "Vier.")), false)), + List.of(teil1, teil2)); + } + + @Test + void fuegtGliederungsUeberschriftenEin() { + // „Nach § 2 werden die folgenden Überschriften zu Teil 3 und zu Teil 3 Abschnitt 1 + // eingefügt: „Teil 3 Modernisierung Abschnitt 1 Grundpflichten“.“ + var befehl = + new GliederungsUeberschriften( + stelle(new Stelle.Paragraph("2")), + List.of( + new Stelle.Gliederungseinheit("Teil", "3"), + new Stelle.Gliederungseinheit("Abschnitt", "1")), + List.of(), + "Teil 3 Modernisierung Abschnitt 1 Grundpflichten", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitGliederungen(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(ergebnis.neu().gliederungen()) + .extracting(Gliederung::bezeichnung) + .containsExactly("Teil 1", "Teil 3", "Abschnitt 1", "Teil 2"); + var abschnitt1 = ergebnis.neu().gliederungen().get(2); + assertThat(abschnitt1.titel()).isEqualTo("Grundpflichten"); + // §§ 3 und 4 (der zusammenhängende Block nach dem Anker) hängen jetzt unter Abschnitt 1. + assertThat(ergebnis.neu().norm("§ 3").orElseThrow().gliederung()).isEqualTo(abschnitt1); + assertThat(ergebnis.neu().norm("§ 4").orElseThrow().gliederung()).isEqualTo(abschnitt1); + assertThat(ergebnis.neu().norm("§ 2").orElseThrow().gliederung().bezeichnung()) + .isEqualTo("Teil 1"); + } + + @Test + void ersetztGliederungsUeberschriften() { + // „Die bisherigen Überschriften zu Teil 2 werden durch die folgende Überschrift zu + // Abschnitt 2 ersetzt: „Abschnitt 2 Neue Anforderungen“.“ + var befehl = + new GliederungsUeberschriften( + Stelle.LEER, + List.of(new Stelle.Gliederungseinheit("Abschnitt", "2")), + List.of(List.of(new Stelle.Gliederungseinheit("Teil", "2"))), + "Abschnitt 2 Neue Anforderungen", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetzMitGliederungen(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(ergebnis.neu().gliederungen()) + .extracting(Gliederung::bezeichnung) + .containsExactly("Teil 1", "Abschnitt 2"); + assertThat(ergebnis.neu().norm("§ 3").orElseThrow().gliederung().titel()) + .isEqualTo("Neue Anforderungen"); + } + + @Test + void ersetztGesetzesUeberschrift() { + var befehl = + new Neufassung( + stelle(new Stelle.Ueberschrift()), "Gesetz zur gründlichen Erprobung", PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(befehl)); + + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(ergebnis.neu().langue()).isEqualTo("Gesetz zur gründlichen Erprobung"); + } + private static String absatzText(Gesetz gesetz, String enbez, int index) { return gesetz.norm(enbez).orElseThrow().absaetze().get(index).text(); } |
