diff options
23 files changed, 328 insertions, 251 deletions
diff --git a/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java b/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java index 606383f..4117922 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java @@ -73,9 +73,9 @@ public sealed interface Aenderungsbefehl { * @param vorher {@code true} bei „Vor …“, {@code false} bei „Nach …“. * @param bezeichnung die Bezeichnung des neuen Elements (z.B. „28a“, „5a“); {@code null}, wenn * der Befehl keine nennt (z.B. „folgender Satz“). - * @param anker bei „Vor den Wörtern „Aus dem Bereich Verkehr:“ wird folgender Absatz 5 - * eingefügt“ der Wortanker, der die Position innerhalb von {@code stelle} bestimmt; - * {@code null}, wenn die Position wie üblich aus der Struktur folgt. + * @param anker bei „Vor den Wörtern „Aus dem Bereich Verkehr:“ wird folgender Absatz 5 eingefügt“ + * der Wortanker, der die Position innerhalb von {@code stelle} bestimmt; {@code null}, wenn + * die Position wie üblich aus der Struktur folgt. */ record StrukturEinfuegung( Stelle stelle, diff --git a/src/main/java/eu/mulk/aendggner/aenderung/Stelle.java b/src/main/java/eu/mulk/aendggner/aenderung/Stelle.java index 1c63a5f..69e6837 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/Stelle.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/Stelle.java @@ -29,8 +29,8 @@ public record Stelle(List<Komponente> komponenten) { Absatzbezeichnung {} /** - * „§ 5“, „§ 28a“, im bayerischen Landesrecht „Art. 5“ — die Normnummer ohne Sigel, dazu das - * Sigel selbst („§“ oder „Art.“). + * „§ 5“, „§ 28a“, im bayerischen Landesrecht „Art. 5“ — die Normnummer ohne Sigel, dazu das Sigel + * selbst („§“ oder „Art.“). */ public record Paragraph(String nummer, String sigel) implements Komponente { public Paragraph(String nummer) { diff --git a/src/main/java/eu/mulk/aendggner/aenderung/parse/ZitatExtraktor.java b/src/main/java/eu/mulk/aendggner/aenderung/parse/ZitatExtraktor.java index d4df176..4b9d511 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/parse/ZitatExtraktor.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/ZitatExtraktor.java @@ -170,8 +170,8 @@ public final class ZitatExtraktor { Pattern.compile("^(?:\\d+[a-z]?\\.|[a-z]{1,3}\\))[ \\t]"); /** - * Wahr, wenn das öffnende Anführungszeichen an Position {@code i} ein Fortführungszeichen ist: - * Es steht am Zeilenanfang innerhalb eines offenen Zitats und ihm folgt unmittelbar ein + * Wahr, wenn das öffnende Anführungszeichen an Position {@code i} ein Fortführungszeichen ist: Es + * steht am Zeilenanfang innerhalb eines offenen Zitats und ihm folgt unmittelbar ein * Aufzählungsmarker. */ private static boolean istFortfuehrungszeichen(String text, int i) { @@ -191,7 +191,8 @@ public final class ZitatExtraktor { * Stammgesetze zitieren ihre Normköpfe als „Art. N“, nicht als „Artikel N“ — zitierter Inhalt * läuft hier also nicht versehentlich auf. */ - private static final Pattern ARTIKEL_GRENZE = Pattern.compile("^Artikel[ \\t]+\\d+[a-z]?[ \\t]*$"); + private static final Pattern ARTIKEL_GRENZE = + Pattern.compile("^Artikel[ \\t]+\\d+[a-z]?[ \\t]*$"); /** Wahr, wenn die bei {@code von} beginnende Zeile eine Artikel-Überschrift ist. */ private static boolean beginntArtikelUeberschrift(String text, int von) { diff --git a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java index d8e710c..b8540c5 100644 --- a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java +++ b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java @@ -2,14 +2,14 @@ package eu.mulk.aendggner.anwendung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Anfuegung; -import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Ebene; 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.FussnotenAufhebung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.GliederungsUeberschriften; -import eu.mulk.aendggner.aenderung.Aenderungsbefehl.SatznummerierungStreichung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Neufassung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Sammelbefehl; +import eu.mulk.aendggner.aenderung.Aenderungsbefehl.SatznummerierungStreichung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Streichung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturEinfuegung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturErsetzung; @@ -298,7 +298,8 @@ public final class BefehlAnwender { private static List<StrukturErsetzung> ersetzungen(Aenderungsbefehl befehl) { return switch (befehl) { case StrukturErsetzung e -> List.of(e); - case Sammelbefehl s -> s.teilbefehle().stream().flatMap(t -> ersetzungen(t).stream()).toList(); + case Sammelbefehl s -> + s.teilbefehle().stream().flatMap(t -> ersetzungen(t).stream()).toList(); default -> List.of(); }; } @@ -374,8 +375,7 @@ public final class BefehlAnwender { // Führende Eigenbezeichnung („Abschnitt 2 …“ oder „2. Abschnitt …“) aus dem Zitat entfernen. var label = Pattern.compile("^(\\d+[a-z]?\\.\\s+\\S+|\\S+\\s+\\d+[a-z]?)\\s+").matcher(titel); if (label.find() - && kanonischeBezeichnung(label.group(1)) - .equals(kanonischeBezeichnung(alt.bezeichnung()))) { + && kanonischeBezeichnung(label.group(1)).equals(kanonischeBezeichnung(alt.bezeichnung()))) { titel = titel.substring(label.end()).strip(); } else if (titel.startsWith(alt.bezeichnung())) { titel = titel.substring(alt.bezeichnung().length()).strip(); @@ -395,7 +395,9 @@ public final class BefehlAnwender { return angewandt(befehl, alt.bezeichnung()); } - /** „Der bisherige Abschnitt 2 wird zu Abschnitt 3.“ — Bezeichnung der Gliederungseinheit umsetzen. */ + /** + * „Der bisherige Abschnitt 2 wird zu Abschnitt 3.“ — Bezeichnung der Gliederungseinheit umsetzen. + */ private static AngewandteAenderung wendeGliederungUmnummerierungAn( List<Gliederung> gliederungen, Umnummerierung befehl) { int idx = findeGliederung(gliederungen, befehl.stelle().gliederungsPfad()); @@ -451,12 +453,12 @@ public final class BefehlAnwender { if (idx < 0) { return manuell( befehl, - "Gliederungseinheit nicht gefunden: " - + pfad.get(pfad.size() - 1).bezeichnung()); + "Gliederungseinheit nicht gefunden: " + pfad.get(pfad.size() - 1).bezeichnung()); } indizes.add(idx); } - var alte = indizes.stream().map(gliederungen::get).collect(java.util.stream.Collectors.toSet()); + var alte = + indizes.stream().map(gliederungen::get).collect(java.util.stream.Collectors.toSet()); int einfuegePos = java.util.Collections.min(indizes); indizes.sort(java.util.Comparator.reverseOrder()); for (int idx : indizes) { @@ -479,7 +481,9 @@ public final class BefehlAnwender { } var anker = normen.get(aufloesung.normIndex()); int gliederungsPos = - anker.gliederung() != null ? gliederungen.indexOf(anker.gliederung()) + 1 : gliederungen.size(); + anker.gliederung() != null + ? gliederungen.indexOf(anker.gliederung()) + 1 + : gliederungen.size(); if (gliederungsPos == 0) { gliederungsPos = gliederungen.size(); } @@ -513,7 +517,8 @@ public final class BefehlAnwender { gefunden = -1; for (int i = 0; i < gliederungen.size(); i++) { var g = gliederungen.get(i); - if (kanonischeBezeichnung(g.bezeichnung()).equals(kanonischeBezeichnung(einheit.bezeichnung())) + if (kanonischeBezeichnung(g.bezeichnung()) + .equals(kanonischeBezeichnung(einheit.bezeichnung())) && (g.kennzahl() == null || g.kennzahl().startsWith(praefix))) { gefunden = i; break; @@ -542,34 +547,39 @@ public final class BefehlAnwender { normen, befehl, ohneFussnoten( - text -> { - if (befehl.amEnde()) { - var gestutzt = text.stripTrailing(); - if (!gestutzt.endsWith(befehl.alt())) { - return TextErgebnis.fehler("Der Text endet nicht mit „" + befehl.alt() + "“."); - } - var rumpf = gestutzt.substring(0, gestutzt.length() - befehl.alt().length()); - // Tritt an die Stelle des Satzzeichens ein Klammerzusatz („Der Punkt am Ende wird - // durch die Angabe „(Gesellschaftsdialog).“ ersetzt“), gehört davor ein Leerzeichen — - // so setzt es auch die amtliche Nachfassung. - var fuge = - befehl.neu().startsWith("(") - && !rumpf.isEmpty() - && Character.isLetterOrDigit(rumpf.charAt(rumpf.length() - 1)) - ? " " - : ""; - return TextErgebnis.ok(rumpf + fuge + befehl.neu()); - } - int anzahl = zaehleVorkommen(text, befehl.alt()); - if (anzahl == 0) { - return TextErgebnis.fehler("„" + befehl.alt() + "“ kommt im Zieltext nicht vor."); - } - if (anzahl > 1 && !befehl.jeweils()) { - return TextErgebnis.fehler( - "„" + befehl.alt() + "“ kommt " + anzahl + "-mal vor (ohne „jeweils“ mehrdeutig)."); - } - return TextErgebnis.ok(text.replace(befehl.alt(), befehl.neu())); - })); + text -> { + if (befehl.amEnde()) { + var gestutzt = text.stripTrailing(); + if (!gestutzt.endsWith(befehl.alt())) { + return TextErgebnis.fehler("Der Text endet nicht mit „" + befehl.alt() + "“."); + } + var rumpf = gestutzt.substring(0, gestutzt.length() - befehl.alt().length()); + // Tritt an die Stelle des Satzzeichens ein Klammerzusatz („Der Punkt am Ende wird + // durch die Angabe „(Gesellschaftsdialog).“ ersetzt“), gehört davor ein Leerzeichen + // — + // so setzt es auch die amtliche Nachfassung. + var fuge = + befehl.neu().startsWith("(") + && !rumpf.isEmpty() + && Character.isLetterOrDigit(rumpf.charAt(rumpf.length() - 1)) + ? " " + : ""; + return TextErgebnis.ok(rumpf + fuge + befehl.neu()); + } + int anzahl = zaehleVorkommen(text, befehl.alt()); + if (anzahl == 0) { + return TextErgebnis.fehler("„" + befehl.alt() + "“ kommt im Zieltext nicht vor."); + } + if (anzahl > 1 && !befehl.jeweils()) { + return TextErgebnis.fehler( + "„" + + befehl.alt() + + "“ kommt " + + anzahl + + "-mal vor (ohne „jeweils“ mehrdeutig)."); + } + return TextErgebnis.ok(text.replace(befehl.alt(), befehl.neu())); + })); } private static AngewandteAenderung wendeStreichungAn(List<Norm> normen, Streichung befehl) { @@ -577,19 +587,21 @@ public final class BefehlAnwender { normen, befehl, ohneFussnoten( - text -> { - int anzahl = zaehleVorkommen(text, befehl.woerter()); - if (anzahl == 0) { - return TextErgebnis.fehler("„" + befehl.woerter() + "“ kommt im Zieltext nicht vor."); - } - if (anzahl > 1) { - return TextErgebnis.fehler("„" + befehl.woerter() + "“ kommt " + anzahl + "-mal vor."); - } - return TextErgebnis.ok( - text.replace(befehl.woerter(), "") - .replaceAll(" +", " ") - .replaceAll(" ([,;.])", "$1")); - })); + text -> { + int anzahl = zaehleVorkommen(text, befehl.woerter()); + if (anzahl == 0) { + return TextErgebnis.fehler( + "„" + befehl.woerter() + "“ kommt im Zieltext nicht vor."); + } + if (anzahl > 1) { + return TextErgebnis.fehler( + "„" + befehl.woerter() + "“ kommt " + anzahl + "-mal vor."); + } + return TextErgebnis.ok( + text.replace(befehl.woerter(), "") + .replaceAll(" +", " ") + .replaceAll(" ([,;.])", "$1")); + })); } private static AngewandteAenderung wendeWoerterEinfuegungAn( @@ -598,50 +610,57 @@ public final class BefehlAnwender { normen, befehl, ohneFussnoten( - text -> - switch (befehl.anker()) { - case WortAnker.NachWoertern nach -> { - var pruefung = eindeutigeFundstelle(text, nach.woerter()); - if (pruefung.fehler() != null) { - yield TextErgebnis.fehler(pruefung.fehler()); - } - int ende = pruefung.index() + nach.woerter().length(); - yield TextErgebnis.ok( - text.substring(0, ende) + fuge(befehl.woerter()) + befehl.woerter() - + text.substring(ende)); - } - case WortAnker.VorWoertern vor -> { - var pruefung = eindeutigeFundstelle(text, vor.woerter()); - if (pruefung.fehler() != null) { - yield TextErgebnis.fehler(pruefung.fehler()); - } - yield TextErgebnis.ok( - text.substring(0, pruefung.index()) - + befehl.woerter() - + " " - + text.substring(pruefung.index())); - } - case WortAnker.VorKommaAmEnde ignoriert -> { - var gestutzt = text.stripTrailing(); - if (!gestutzt.endsWith(",")) { - yield TextErgebnis.fehler("Der Zieltext endet nicht mit einem Komma."); - } - yield TextErgebnis.ok( - gestutzt.substring(0, gestutzt.length() - 1) + " " + befehl.woerter() + ","); - } - case WortAnker.AmEnde ignoriert -> { - var gestutzt = text.stripTrailing(); - if (gestutzt.endsWith(".") || gestutzt.endsWith(",") || gestutzt.endsWith(";")) { - var satzzeichen = gestutzt.charAt(gestutzt.length() - 1); - yield TextErgebnis.ok( - gestutzt.substring(0, gestutzt.length() - 1) - + " " - + befehl.woerter() - + satzzeichen); - } - yield TextErgebnis.ok(gestutzt + " " + befehl.woerter()); - } - })); + text -> + switch (befehl.anker()) { + case WortAnker.NachWoertern nach -> { + var pruefung = eindeutigeFundstelle(text, nach.woerter()); + if (pruefung.fehler() != null) { + yield TextErgebnis.fehler(pruefung.fehler()); + } + int ende = pruefung.index() + nach.woerter().length(); + yield TextErgebnis.ok( + text.substring(0, ende) + + fuge(befehl.woerter()) + + befehl.woerter() + + text.substring(ende)); + } + case WortAnker.VorWoertern vor -> { + var pruefung = eindeutigeFundstelle(text, vor.woerter()); + if (pruefung.fehler() != null) { + yield TextErgebnis.fehler(pruefung.fehler()); + } + yield TextErgebnis.ok( + text.substring(0, pruefung.index()) + + befehl.woerter() + + " " + + text.substring(pruefung.index())); + } + case WortAnker.VorKommaAmEnde ignoriert -> { + var gestutzt = text.stripTrailing(); + if (!gestutzt.endsWith(",")) { + yield TextErgebnis.fehler("Der Zieltext endet nicht mit einem Komma."); + } + yield TextErgebnis.ok( + gestutzt.substring(0, gestutzt.length() - 1) + + " " + + befehl.woerter() + + ","); + } + case WortAnker.AmEnde ignoriert -> { + var gestutzt = text.stripTrailing(); + if (gestutzt.endsWith(".") + || gestutzt.endsWith(",") + || gestutzt.endsWith(";")) { + var satzzeichen = gestutzt.charAt(gestutzt.length() - 1); + yield TextErgebnis.ok( + gestutzt.substring(0, gestutzt.length() - 1) + + " " + + befehl.woerter() + + satzzeichen); + } + yield TextErgebnis.ok(gestutzt + " " + befehl.woerter()); + } + })); } // --- Strukturoperationen ------------------------------------------------------------------- @@ -876,7 +895,8 @@ public final class BefehlAnwender { var text = absatz.text(); var einrueckung = einrueckungVon(text, von); var ersatz = rueckeZitatEin(normalisiereZitatText(befehl.text()), einrueckung); - absaetze.set(f1.absatzIndex(), absatz.mitText(text.substring(0, von) + ersatz + text.substring(bis))); + absaetze.set( + f1.absatzIndex(), absatz.mitText(text.substring(0, von) + ersatz + text.substring(bis))); normen.set(f1.normIndex(), norm.mitAbsaetzen(absaetze)); return angewandt(befehl, norm.enbez()); } @@ -911,8 +931,7 @@ public final class BefehlAnwender { yield angewandt(befehl, neue.stream().map(Norm::enbez).toList()); } - var sigelNeu = - befehl.stelle().paragraph().map(Stelle.Paragraph::sigel).orElse("§"); + var sigelNeu = befehl.stelle().paragraph().map(Stelle.Paragraph::sigel).orElse("§"); var enbezNeu = sigelNeu + " " + befehl.bezeichnung(); if (StellenAufloeser.normIndex(gesetzAus(normen), enbezNeu) >= 0) { yield manuell(befehl, enbezNeu + " existiert bereits im Stammgesetz."); @@ -1016,7 +1035,10 @@ public final class BefehlAnwender { normalisiereZitatText(befehl.text()), einrueckungVon(text, zeilenAnfang)); return TextErgebnis.ok( befehl.vorher() - ? text.substring(0, zeilenAnfang) + block + "\n" + text.substring(zeilenAnfang) + ? text.substring(0, zeilenAnfang) + + block + + "\n" + + text.substring(zeilenAnfang) : text.substring(0, zeilenEnde) + "\n" + block + text.substring(zeilenEnde)); })); } @@ -1176,8 +1198,10 @@ public final class BefehlAnwender { var absaetze = new ArrayList<>(norm.absaetze()); int quelleIdx = fundstelle.absatzIndex(); var neueNummer = neuAbsatz.get().nummer(); - // Ein leerer Platzhalter-Absatz mit der Zielnummer (weggefallen/gegenstandslos) wird durch die - // Umnummerierung überschrieben (analog zur Norm-Umnummerierung auf eine weggefallene Zielnorm). + // Ein leerer Platzhalter-Absatz mit der Zielnummer (weggefallen/gegenstandslos) wird durch + // die + // Umnummerierung überschrieben (analog zur Norm-Umnummerierung auf eine weggefallene + // Zielnorm). for (int i = absaetze.size() - 1; i >= 0; i--) { if (i != quelleIdx && neueNummer.equals(absaetze.get(i).nummer()) @@ -1208,8 +1232,11 @@ public final class BefehlAnwender { .matcher(text.substring(bereich.von(), bereich.bis())); if (!marke.find()) { return TextErgebnis.fehler( - "„" + alteMarke + "“ steht nicht am Anfang von " - + befehl.stelle().anzeigeText() + "."); + "„" + + alteMarke + + "“ steht nicht am Anfang von " + + befehl.stelle().anzeigeText() + + "."); } var umbenannt = text.substring(0, bereich.von()) @@ -1235,9 +1262,11 @@ public final class BefehlAnwender { var absaetze = new ArrayList<>(norm.absaetze()); var absatz = absaetze.get(fundstelle.absatzIndex()); var text = absatz.text(); - var marker = Superskript.LAUF.matcher(text).region(fundstelle.bereich().von(), fundstelle.bereich().bis()); - if (marker.lookingAt() - && Superskript.istSatzanfang(text, marker.start(), marker.end())) { + var marker = + Superskript.LAUF + .matcher(text) + .region(fundstelle.bereich().von(), fundstelle.bereich().bis()); + if (marker.lookingAt() && Superskript.istSatzanfang(text, marker.start(), marker.end())) { var neuerText = text.substring(0, marker.start()) + Superskript.zuSuperskript(neuSatz.nummer()) @@ -1279,7 +1308,9 @@ public final class BefehlAnwender { */ private static String entferneWeggefallenenPlatzhalter(String text, String marke) { return text.replaceFirst( - "(?m)^[ \\t]*" + Pattern.quote(marke) + "[ \\t]+\\((?:weggefallen|gegenstandslos|aufgehoben)\\)\\n?", + "(?m)^[ \\t]*" + + Pattern.quote(marke) + + "[ \\t]+\\((?:weggefallen|gegenstandslos|aufgehoben)\\)\\n?", ""); } @@ -1310,8 +1341,7 @@ public final class BefehlAnwender { // Steht genau ein unnummerierter Absatz zwischen nummerierten (bayerische Folge „Dem Wortlaut // werden … Abs. 1 bis 4 vorangestellt“ → „Der bisherige Wortlaut wird Abs. 5“), erhält nur // dieser die Nummer. Sind alle Absätze unnummeriert, wird der Gesamtwortlaut zu einem Absatz. - var unnummerierte = - norm.absaetze().stream().filter(a -> a.nummer() == null).toList(); + var unnummerierte = norm.absaetze().stream().filter(a -> a.nummer() == null).toList(); if (unnummerierte.size() == 1 && norm.absaetze().size() > 1) { var absaetze = new ArrayList<>(norm.absaetze()); int idx = absaetze.indexOf(unnummerierte.get(0)); @@ -1427,11 +1457,7 @@ public final class BefehlAnwender { if (!fehlend.isEmpty()) { return manuell( befehl, - "Fußnote " - + String.join(", ", fehlend) - + " kommt in " - + norm.enbez() - + " nicht vor."); + "Fußnote " + String.join(", ", fehlend) + " kommt in " + norm.enbez() + " nicht vor."); } normen.set(aufloesung.normIndex(), norm.mitAbsaetzen(absaetze)); return angewandt(befehl, norm.enbez()); @@ -1475,7 +1501,11 @@ public final class BefehlAnwender { betroffene.addAll(ergebnis.betroffeneEnbez()); if (ergebnis.status() != Status.ANGEWANDT) { meldungen[index] = - "Teil " + (index + 1) + " (" + teil.stelle().anzeigeText() + "): " + "Teil " + + (index + 1) + + " (" + + teil.stelle().anzeigeText() + + "): " + ergebnis.begruendung(); } } @@ -1742,7 +1772,8 @@ public final class BefehlAnwender { /** * Zerlegt einen Zitatblock mehrerer Paragraphen an den §-Überschriften (nicht an Querverweisen) - * und parst jeden Abschnitt zu einer {@link Norm}. Die Gliederung wird von der Vorlage übernommen. + * und parst jeden Abschnitt zu einer {@link Norm}. Die Gliederung wird von der Vorlage + * übernommen. */ private static List<Norm> parseNormenBlock(String block, @Nullable Gliederung gliederung) { var normen = new ArrayList<Norm>(); @@ -1868,10 +1899,10 @@ public final class BefehlAnwender { } /** - * Rückt die kanonischen Zitatzeilen auf die Ziel-Einrückung um: Aufzählungszeilen (und die - * erste Zeile) auf {@code einrueckung}, Fortsetzungszeilen — etwa der Definitionstext unter - * einer Kurzüberschrift — zwei Zeichen tiefer, damit sie Kindzeilen der Einheit bleiben - * (dieselbe Form, die der ContentFlattener aus dem Stammgesetz-XML erzeugt). + * Rückt die kanonischen Zitatzeilen auf die Ziel-Einrückung um: Aufzählungszeilen (und die erste + * Zeile) auf {@code einrueckung}, Fortsetzungszeilen — etwa der Definitionstext unter einer + * Kurzüberschrift — zwei Zeichen tiefer, damit sie Kindzeilen der Einheit bleiben (dieselbe Form, + * die der ContentFlattener aus dem Stammgesetz-XML erzeugt). */ private static String rueckeZitatEin(String zitat, String einrueckung) { var sb = new StringBuilder(); diff --git a/src/main/java/eu/mulk/aendggner/anwendung/InhaltsuebersichtAnwender.java b/src/main/java/eu/mulk/aendggner/anwendung/InhaltsuebersichtAnwender.java index e9f84b6..acd42d7 100644 --- a/src/main/java/eu/mulk/aendggner/anwendung/InhaltsuebersichtAnwender.java +++ b/src/main/java/eu/mulk/aendggner/anwendung/InhaltsuebersichtAnwender.java @@ -74,12 +74,13 @@ final class InhaltsuebersichtAnwender { /** Die adressierte Angabe: die §-/Gliederungs-Komponenten hinter der Inhaltsübersichts-Marke. */ private static List<Stelle.Komponente> zielKette(Stelle stelle) { return stelle.komponenten().stream() - .filter( - k -> k instanceof Stelle.Paragraph || k instanceof Stelle.Gliederungseinheit) + .filter(k -> k instanceof Stelle.Paragraph || k instanceof Stelle.Gliederungseinheit) .toList(); } - /** Ersetzt die Zeilen von {@code von} bis {@code bis} durch die Angaben des Zitats (oder nichts). */ + /** + * Ersetzt die Zeilen von {@code von} bis {@code bis} durch die Angaben des Zitats (oder nichts). + */ private static AngewandteAenderung ersetzeZeilen( List<Norm> normen, Aenderungsbefehl befehl, @@ -139,8 +140,7 @@ final class InhaltsuebersichtAnwender { // --- Zeilenmodell ---------------------------------------------------------------------------- - private record Zeilenfund( - int absatzIndex, int vonZeile, int bisZeile, @Nullable String fehler) { + private record Zeilenfund(int absatzIndex, int vonZeile, int bisZeile, @Nullable String fehler) { static Zeilenfund fehlgeschlagen(String begruendung) { return new Zeilenfund(-1, -1, -1, begruendung); } @@ -148,8 +148,8 @@ final class InhaltsuebersichtAnwender { /** * Findet die (norm-weit eindeutige) Zeile der adressierten Angabe. Die Kette wird verschachtelt - * aufgelöst: „Teil 2 Abschnitt 4“ sucht die Abschnitt-Zeile erst hinter der Teil-2-Zeile (und - * vor dem nächsten Teil), sodass gleichnamige Abschnitte anderer Teile nicht stören. + * aufgelöst: „Teil 2 Abschnitt 4“ sucht die Abschnitt-Zeile erst hinter der Teil-2-Zeile (und vor + * dem nächsten Teil), sodass gleichnamige Abschnitte anderer Teile nicht stören. */ private static Zeilenfund findeZeile(Norm norm, List<Stelle.Komponente> kette) { var ziel = kette.get(kette.size() - 1); diff --git a/src/main/java/eu/mulk/aendggner/anwendung/SatzTeiler.java b/src/main/java/eu/mulk/aendggner/anwendung/SatzTeiler.java index b457cf2..3360bc6 100644 --- a/src/main/java/eu/mulk/aendggner/anwendung/SatzTeiler.java +++ b/src/main/java/eu/mulk/aendggner/anwendung/SatzTeiler.java @@ -11,8 +11,8 @@ import org.jspecify.annotations.Nullable; * Zerlegt einen Absatztext in Sätze im Rechtssinne, mit einer Stoppliste für juristische * Abkürzungen und Datumsangaben („Abs.“, „31. März 2021“). * - * <p>Trägt der Text amtliche Satznummern als Unicode-Superskripte (bayerisches Landesrecht, - * „¹Die freilebende Tierwelt …“), wird exakt an diesen geteilt statt heuristisch. + * <p>Trägt der Text amtliche Satznummern als Unicode-Superskripte (bayerisches Landesrecht, „¹Die + * freilebende Tierwelt …“), wird exakt an diesen geteilt statt heuristisch. */ public final class SatzTeiler { @@ -182,8 +182,8 @@ public final class SatzTeiler { /** * Punkt einer Aufzählungsmarke am Zeilenanfang („… folgende Aufgaben ⏎ 1. Erlaß von Satzungen * …“). Er beendet keinen Satz: die Glieder einer Aufzählung gehören zum tragenden Satz. Die - * Beschränkung auf den Zeilenanfang unterscheidet die Marke von einer Zahl am Satzende („… beträgt - * 30. Die Frist …“). + * Beschränkung auf den Zeilenanfang unterscheidet die Marke von einer Zahl am Satzende („… + * beträgt 30. Die Frist …“). */ private static boolean istAufzaehlungsMarke(String text, int punktPosition) { var wort = wortVor(text, punktPosition); diff --git a/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java b/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java index dd8409e..ff77279 100644 --- a/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java +++ b/src/main/java/eu/mulk/aendggner/anwendung/StellenAufloeser.java @@ -164,7 +164,9 @@ final class StellenAufloeser { } bereich = zeilenBlock( - text, labelRegex, bereich != null ? bereich : new SatzTeiler.SatzBereich(0, text.length())); + text, + labelRegex, + bereich != null ? bereich : new SatzTeiler.SatzBereich(0, text.length())); if (bereich == null) { return null; } diff --git a/src/main/java/eu/mulk/aendggner/gesetz/Gliederung.java b/src/main/java/eu/mulk/aendggner/gesetz/Gliederung.java index 7a09093..00106d2 100644 --- a/src/main/java/eu/mulk/aendggner/gesetz/Gliederung.java +++ b/src/main/java/eu/mulk/aendggner/gesetz/Gliederung.java @@ -6,8 +6,8 @@ import org.jspecify.annotations.Nullable; * Eine Gliederungseinheit (z.B. „Teil 2 — Anforderungen an zu errichtende Gebäude“ oder „2. * Abschnitt — Koordinierung und Früherkennung“). * - * @param kennzahl die hierarchie-kodierende Gliederungskennzahl aus dem gii-XML (z.B. {@code 020020} - * für Abschnitt 2 in Teil 2); {@code null} bei anderweitig konstruierten Einheiten. + * @param kennzahl die hierarchie-kodierende Gliederungskennzahl aus dem gii-XML (z.B. {@code + * 020020} für Abschnitt 2 in Teil 2); {@code null} bei anderweitig konstruierten Einheiten. * @param bezeichnung die relative Bezeichnung („Teil 2“, „Abschnitt 2“). * @param titel die Überschrift der Einheit ({@code null} bei titellosen Einheiten). */ diff --git a/src/main/java/eu/mulk/aendggner/gesetz/Superskript.java b/src/main/java/eu/mulk/aendggner/gesetz/Superskript.java index 733c1f7..4ba8304 100644 --- a/src/main/java/eu/mulk/aendggner/gesetz/Superskript.java +++ b/src/main/java/eu/mulk/aendggner/gesetz/Superskript.java @@ -46,9 +46,9 @@ public final class Superskript { } /** - * Wahr, wenn {@code text} mindestens eine amtliche Satznummer am Satzanfang trägt. Dient dazu, die - * Schreibweise eines Stammgesetzes zu erkennen (Landesrecht mit amtlicher Satzzählung behält seine - * Superskripte, Bundesrecht ohne solche verwirft sie). + * Wahr, wenn {@code text} mindestens eine amtliche Satznummer am Satzanfang trägt. Dient dazu, + * die Schreibweise eines Stammgesetzes zu erkennen (Landesrecht mit amtlicher Satzzählung behält + * seine Superskripte, Bundesrecht ohne solche verwirft sie). */ public static boolean traegtSatznummern(String text) { var m = LAUF.matcher(text); diff --git a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtLoader.java b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtLoader.java index ecb10f8..c64ca21 100644 --- a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtLoader.java +++ b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtLoader.java @@ -6,17 +6,17 @@ import eu.mulk.aendggner.aenderung.parse.TextBereiniger; import eu.mulk.aendggner.gesetz.Gesetz; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.text.Normalizer; import java.nio.file.Files; import java.nio.file.Path; +import java.text.Normalizer; import org.apache.tika.Tika; import org.jboss.logging.Logger; /** * Liest ein Stammgesetz des Landesrechts aus der konsolidierten Fassung — als PDF oder als * kanonischer Klartext. Deckt bayerisches Landesrecht (Gliederung in {@code Art.}, amtliche - * Satznummern) ebenso ab wie die {@code §}-gegliederten Gesetze der übrigen Länder; das Sigel - * folgt je Norm aus dem Text (siehe {@link LandesRechtTextParser}). + * Satznummern) ebenso ab wie die {@code §}-gegliederten Gesetze der übrigen Länder; das Sigel folgt + * je Norm aus dem Text (siehe {@link LandesRechtTextParser}). * * <p>PDFs durchlaufen dieselbe Aufbereitung wie Änderungsgesetze (Fontgrößen-Filter mit * Superskript-Erhalt, Textbereinigung); der bereinigte Lineartext ist zugleich das dokumentierte @@ -56,7 +56,7 @@ public final class LandesRechtLoader { /** * Stellt einen vom Zeilen-Reflow an das Satzende der Vornorm geklebten Normkopf („… verlangen. - * Art. 17 Jagderlaubnis“) wieder auf eine eigene Zeile. Das doppelte Leerzeichen zwischen + * Art. 17 Jagderlaubnis“) wieder auf eine eigene Zeile. Das doppelte Leerzeichen zwischen * Norm-Nummer und Titel unterscheidet den Normkopf von gewöhnlichen Querverweisen. */ private static String nachSatzendeGetrennteNormkoepfe(String text) { diff --git a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java index 6c58c49..a256243 100644 --- a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java +++ b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java @@ -57,20 +57,22 @@ final class LandesRechtTextParser { // nachgestelltem Schlüsselwort („I. Abschnitt“, Muster GLIEDERUNG). Der Titel steht — nach der // kanonischen Aufbereitung — mit doppeltem Leerzeichen auf derselben Zeile. private static final Pattern GLIEDERUNG_ARABISCH = - Pattern.compile("^(Buch|Teil|Kapitel|Abschnitt|Unterabschnitt|Titel) (\\d+[a-z]?)\\s+(\\S.*)$"); + Pattern.compile( + "^(Buch|Teil|Kapitel|Abschnitt|Unterabschnitt|Titel) (\\d+[a-z]?)\\s+(\\S.*)$"); // Römische Gliederung ohne Schlüsselwort („I. Rechtsform und Aufgaben“, NRW). Sie ist nur an der // Stellung erkennbar, deshalb gilt dieselbe Absicherung wie für UNTER_GLIEDERUNG: kurzer, // großgeschriebener, satzzeichenfreier Titel und ein Normkopf oder eine weitere Überschrift als // nächste nicht-leere Zeile. - private static final Pattern GLIEDERUNG_ROEMISCH = Pattern.compile("^([IVXLCDM]+)\\.\\s+(\\S.*)$"); + private static final Pattern GLIEDERUNG_ROEMISCH = + Pattern.compile("^([IVXLCDM]+)\\.\\s+(\\S.*)$"); private static final Pattern UNTER_GLIEDERUNG = Pattern.compile("^(\\d+[a-z]?)\\.\\s+(\\S.*)$"); /** * Die Inhaltsübersicht ist eine Norm ohne Sigel; Angabe-Befehle adressieren sie unter genau - * diesem Namen (siehe {@code InhaltsuebersichtAnwender}). Ihre Zeilen tragen das - * Übersichtsformat „§ N | Titel“. + * diesem Namen (siehe {@code InhaltsuebersichtAnwender}). Ihre Zeilen tragen das Übersichtsformat + * „§ N | Titel“. */ private static final String INHALTSUEBERSICHT = "Inhaltsübersicht"; @@ -81,12 +83,14 @@ final class LandesRechtTextParser { Pattern.compile( "^(§|Art\\.)\\s+(\\d+[a-z]?)\\s+" // Querverweis-Schlüsselwörter nur als ganzes Wort ausschließen: „§ 4 Satz 2“ ist ein - // Verweis, „§ 4 Satzungen“ dagegen ein Normtitel. Der Schutz „(?![a-zäöüß])“ verhindert, + // Verweis, „§ 4 Satzungen“ dagegen ein Normtitel. Der Schutz „(?![a-zäöüß])“ + // verhindert, // dass „Satz“ auch „Satzungen“, „Nummer“ auch „Nummerierung“ trifft. + "(?!(?:Absatz|Abs\\.|Satz|Sätze|Nummer|Nr\\.|Buchstabe|Buchst\\." + "|und|bis|oder|sowie|des|der|dieses)(?![a-zäöüß]))" // Der Titel endet nicht auf einen Punkt: ein Normkopf trägt eine Überschrift, keinen - // ganzen Satz. So wird ein am Zeilenanfang stehender Querverweis-Satz („§ 7 GAPInVeKoSG + // ganzen Satz. So wird ein am Zeilenanfang stehender Querverweis-Satz („§ 7 + // GAPInVeKoSG // findet entsprechend Anwendung.“) nicht fälschlich als Normkopf „§ 7“ gelesen. + "((?:\\p{Lu}|\\().*[^.])\\s*$"); @@ -210,8 +214,7 @@ final class LandesRechtTextParser { gliederungsZaehler++; elternKennzahl = String.format("%03d", gliederungsZaehler); aktuelleGliederung = - new Gliederung( - elternKennzahl, roemisch.group(1) + ".", roemisch.group(2).strip()); + new Gliederung(elternKennzahl, roemisch.group(1) + ".", roemisch.group(2).strip()); gliederungen.add(aktuelleGliederung); } else { var kennzahl = @@ -278,8 +281,8 @@ final class LandesRechtTextParser { } /** - * Ein Normkopf eröffnet nur dann eine neue Norm, wenn seine Nummer hinter der letzten liegt — - * das fängt Querverweise ab, die die Negativliste nicht ausschließt. + * Ein Normkopf eröffnet nur dann eine neue Norm, wenn seine Nummer hinter der letzten liegt — das + * fängt Querverweise ab, die die Negativliste nicht ausschließt. */ private static boolean istNeuerNormKopf(String nummer, int letzteNormNummer) { return numerisch(nummer) >= letzteNormNummer; @@ -315,10 +318,7 @@ final class LandesRechtTextParser { } private static Norm baueNorm( - String enbez, - @Nullable String titel, - @Nullable Gliederung gliederung, - List<String> zeilen) { + String enbez, @Nullable String titel, @Nullable Gliederung gliederung, List<String> zeilen) { boolean weggefallen = titel != null && WEGGEFALLEN_TITEL.matcher(titel).matches(); var absaetze = new ArrayList<Absatz>(); diff --git a/src/main/java/eu/mulk/aendggner/synopse/SynopseBuilder.java b/src/main/java/eu/mulk/aendggner/synopse/SynopseBuilder.java index 1568aa9..ce4f1a1 100644 --- a/src/main/java/eu/mulk/aendggner/synopse/SynopseBuilder.java +++ b/src/main/java/eu/mulk/aendggner/synopse/SynopseBuilder.java @@ -50,13 +50,13 @@ public final class SynopseBuilder { var manuell = anwendung.protokoll().stream().filter(a -> a.status() == Status.MANUELL_PRUEFEN).toList(); - return new Synopse(alt, neu, eintraege, gliederungsAenderungen(alt, neu), manuell, parseWarnungen); + return new Synopse( + alt, neu, eintraege, gliederungsAenderungen(alt, neu), manuell, parseWarnungen); } /** - * Paart die Gliederungseinheiten nach Kennzahl und sammelt die mit geänderter Überschrift. - * Neu eingefügte Einheiten (ohne Kennzahl und ohne Alt-Pendant) erscheinen mit {@code alt == - * null}. + * Paart die Gliederungseinheiten nach Kennzahl und sammelt die mit geänderter Überschrift. Neu + * eingefügte Einheiten (ohne Kennzahl und ohne Alt-Pendant) erscheinen mit {@code alt == null}. */ private static List<Synopse.GliederungsAenderung> gliederungsAenderungen(Gesetz alt, Gesetz neu) { var aenderungen = new ArrayList<Synopse.GliederungsAenderung>(); diff --git a/src/main/java/eu/mulk/aendggner/web/Multipart.java b/src/main/java/eu/mulk/aendggner/web/Multipart.java index 3e5a059..745443b 100644 --- a/src/main/java/eu/mulk/aendggner/web/Multipart.java +++ b/src/main/java/eu/mulk/aendggner/web/Multipart.java @@ -17,7 +17,8 @@ final class Multipart { private static final Pattern BOUNDARY_PATTERN = Pattern.compile("boundary=\"?([^\";]+)\"?"); private static final Pattern NAME_PATTERN = Pattern.compile("name=\"([^\"]*)\""); private static final Pattern FILENAME_PATTERN = Pattern.compile("filename=\"([^\"]*)\""); - private static final byte[] HEADER_BODY_SEPARATOR = "\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1); + private static final byte[] HEADER_BODY_SEPARATOR = + "\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1); private Multipart() {} @@ -33,7 +34,9 @@ final class Multipart { var delimiter = ("--" + boundary).getBytes(StandardCharsets.ISO_8859_1); var positions = new ArrayList<Integer>(); - for (int i = indexOf(body, delimiter, 0); i >= 0; i = indexOf(body, delimiter, i + delimiter.length)) { + for (int i = indexOf(body, delimiter, 0); + i >= 0; + i = indexOf(body, delimiter, i + delimiter.length)) { positions.add(i); } diff --git a/src/main/java/eu/mulk/aendggner/web/StaticHandler.java b/src/main/java/eu/mulk/aendggner/web/StaticHandler.java index 8cdf6e5..24a6e41 100644 --- a/src/main/java/eu/mulk/aendggner/web/StaticHandler.java +++ b/src/main/java/eu/mulk/aendggner/web/StaticHandler.java @@ -7,7 +7,10 @@ import java.io.InputStream; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; -/** Liefert eine einzelne, beim Start einmal geladene statische Ressource aus (Formular, Impressum, CSS, …). */ +/** + * Liefert eine einzelne, beim Start einmal geladene statische Ressource aus (Formular, Impressum, + * CSS, …). + */ final class StaticHandler implements HttpHandler { private final byte[] content; @@ -48,7 +51,8 @@ final class StaticHandler implements HttpHandler { } } - private static void sendText(HttpExchange exchange, int status, String message) throws IOException { + private static void sendText(HttpExchange exchange, int status, String message) + throws IOException { var body = message.getBytes(StandardCharsets.UTF_8); exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8"); exchange.sendResponseHeaders(status, body.length); diff --git a/src/main/java/eu/mulk/aendggner/web/UploadHandler.java b/src/main/java/eu/mulk/aendggner/web/UploadHandler.java index 8765ac3..efcb512 100644 --- a/src/main/java/eu/mulk/aendggner/web/UploadHandler.java +++ b/src/main/java/eu/mulk/aendggner/web/UploadHandler.java @@ -21,19 +21,20 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** - * {@code POST /synopse} — nimmt Stammgesetz- und Änderungsgesetz-Datei(en) per - * {@code multipart/form-data} entgegen, ruft {@link Pipeline#erzeugeSynopse} auf und liefert das - * erzeugte HTML zurück. + * {@code POST /synopse} — nimmt Stammgesetz- und Änderungsgesetz-Datei(en) per {@code + * multipart/form-data} entgegen, ruft {@link Pipeline#erzeugeSynopse} auf und liefert das erzeugte + * HTML zurück. * - * <p>Hochgeladene Dateien landen ausschließlich als temporäre Dateien für die Dauer der Anfrage - * und werden danach in jedem Fall gelöscht — es wird nichts dauerhaft gespeichert. Die eigentliche + * <p>Hochgeladene Dateien landen ausschließlich als temporäre Dateien für die Dauer der Anfrage und + * werden danach in jedem Fall gelöscht — es wird nichts dauerhaft gespeichert. Die eigentliche * Verarbeitung läuft auf einem auf die Kernzahl begrenzten Thread-Pool mit fester Warteschlange; * bei Überlast wird sofort mit {@code 503} abgelehnt, statt unbegrenzt Arbeit anzunehmen. */ final class UploadHandler implements HttpHandler { private static final long MAX_PART_BYTES = 15L * 1024 * 1024; // 15 MB je Datei - private static final long MAX_BODY_BYTES = 40L * 1024 * 1024; // Sicherheitsnetz für die gesamte Anfrage + private static final long MAX_BODY_BYTES = + 40L * 1024 * 1024; // Sicherheitsnetz für die gesamte Anfrage private static final long TIMEOUT_SECONDS = 30; private final ExecutorService pipelinePool; @@ -77,7 +78,8 @@ final class UploadHandler implements HttpHandler { try { Files.deleteIfExists(path); } catch (IOException ignored) { - // Aufräumen ist best effort; ein verwaistes Temp-File blockiert die Antwort nicht. + // Aufräumen ist best effort; ein verwaistes Temp-File blockiert die Antwort + // nicht. } }); } catch (IOException ignored) { @@ -169,7 +171,8 @@ final class UploadHandler implements HttpHandler { var future = pipelinePool.submit(job); ergebnis = future.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); } catch (RejectedExecutionException e) { - sendText(exchange, 503, "Der Dienst ist gerade ausgelastet. Bitte in Kürze erneut versuchen."); + sendText( + exchange, 503, "Der Dienst ist gerade ausgelastet. Bitte in Kürze erneut versuchen."); return; } catch (TimeoutException e) { sendText(exchange, 504, "Die Verarbeitung hat zu lange gedauert und wurde abgebrochen."); @@ -215,7 +218,8 @@ final class UploadHandler implements HttpHandler { return filename.replaceAll("[^A-Za-z0-9._-]", "_"); } - private static void sendText(HttpExchange exchange, int status, String message) throws IOException { + private static void sendText(HttpExchange exchange, int status, String message) + throws IOException { var body = message.getBytes(StandardCharsets.UTF_8); exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8"); exchange.sendResponseHeaders(status, body.length); diff --git a/src/main/java/eu/mulk/aendggner/web/WebMain.java b/src/main/java/eu/mulk/aendggner/web/WebMain.java index 9d71558..815f0db 100644 --- a/src/main/java/eu/mulk/aendggner/web/WebMain.java +++ b/src/main/java/eu/mulk/aendggner/web/WebMain.java @@ -34,7 +34,8 @@ public final class WebMain { "/datenschutz", new StaticHandler("/eu/mulk/aendggner/web/datenschutz.html", "text/html; charset=utf-8")); server.createContext( - "/style.css", new StaticHandler("/eu/mulk/aendggner/web/style.css", "text/css; charset=utf-8")); + "/style.css", + new StaticHandler("/eu/mulk/aendggner/web/style.css", "text/css; charset=utf-8")); server.createContext("/synopse", new UploadHandler()); server.start(); diff --git a/src/test/java/eu/mulk/aendggner/aenderung/parse/AenderungsgesetzParserTest.java b/src/test/java/eu/mulk/aendggner/aenderung/parse/AenderungsgesetzParserTest.java index 2dc53bb..79e257e 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/AenderungsgesetzParserTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/AenderungsgesetzParserTest.java @@ -93,8 +93,7 @@ class AenderungsgesetzParserTest { @Test void eingebettetesRahmenzielSetztKontext() { var bayUig = - new Gesetz( - "BayUIG", "Bayerisches Umweltinformationsgesetz", null, List.of(), List.of()); + new Gesetz("BayUIG", "Bayerisches Umweltinformationsgesetz", null, List.of(), List.of()); var text = """ § 3 @@ -113,8 +112,7 @@ class AenderungsgesetzParserTest { // aus der Zitierkette der Änderungshistorie. assertThat(ergebnis.befehle()) .allSatisfy( - befehl -> - assertThat(befehl.stelle().anzeigeText()).startsWith("Art. 7 Absatz 2")); + befehl -> assertThat(befehl.stelle().anzeigeText()).startsWith("Art. 7 Absatz 2")); } @Test 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 46c5ad6..cbf790b 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java @@ -225,8 +225,7 @@ class BefehlErkennerTest { // 17/2026): Die Position der neuen Einheit bestimmt ein Wortanker, das Ziel erbt der Befehl aus // dem Rahmen („Nummer 23“ der Anlage). var kontext = - new Stelle( - List.of(new Stelle.Gliederungseinheit("Anlage", ""), new Stelle.NummerNr("23"))); + new Stelle(List.of(new Stelle.Gliederungseinheit("Anlage", ""), new Stelle.NummerNr("23"))); var befehl = erkenne( "Vor den Wörtern „Aus dem Bereich Verkehr:“ wird folgender Absatz 5 eingefügt:" @@ -239,8 +238,7 @@ class BefehlErkennerTest { assertThat(einfuegung.vorher()).isTrue(); assertThat(einfuegung.ebene()).isEqualTo(Ebene.ABSATZ); assertThat(einfuegung.bezeichnung()).isEqualTo("5"); - assertThat(einfuegung.anker()) - .isEqualTo(new WortAnker.VorWoertern("Aus dem Bereich Verkehr:")); + assertThat(einfuegung.anker()).isEqualTo(new WortAnker.VorWoertern("Aus dem Bereich Verkehr:")); assertThat(einfuegung.text()).startsWith("(5) die Identifizierung"); } @@ -486,9 +484,11 @@ class BefehlErkennerTest { assertThat(befehl).containsInstanceOf(Sammelbefehl.class); var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); assertThat(teile).hasSize(2).allMatch(t -> t instanceof Streichung); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("§ 3 Absatz 1 Satz 2", "§ 3 Absatz 4"); - assertThat(((Streichung) teile.get(0)).woerter()).isEqualTo("in Bezug auf § 2 Abs. 1 Nr. 1 bis 4"); + assertThat(((Streichung) teile.get(0)).woerter()) + .isEqualTo("in Bezug auf § 2 Abs. 1 Nr. 1 bis 4"); } @Test @@ -502,7 +502,8 @@ class BefehlErkennerTest { assertThat(befehl).containsInstanceOf(Sammelbefehl.class); var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); assertThat(teile).hasSize(2).allMatch(t -> t instanceof Ersetzung); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("§ 20 Absatz 1 Satz 1", "§ 20 Absatz 2 Satz 2"); assertThat(((Ersetzung) teile.get(0)).neu()).isEqualTo("Lebensalters"); } @@ -518,7 +519,8 @@ class BefehlErkennerTest { assertThat(befehl).containsInstanceOf(Sammelbefehl.class); var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); assertThat(teile).hasSize(2).allMatch(t -> t instanceof WoerterEinfuegung); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("§ 30 Absatz 2 Satz 1", "§ 30 Absatz 3"); } @@ -533,9 +535,11 @@ class BefehlErkennerTest { var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); assertThat(teile).hasSize(3).allMatch(t -> t instanceof Umnummerierung); // Absteigend, damit die Anwendung keine Labels kollidieren lässt: 4→5, 3→4, 2→3. - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("§ 5 Absatz 4", "§ 5 Absatz 3", "§ 5 Absatz 2"); - assertThat(teile).extracting(t -> ((Umnummerierung) t).neu().anzeigeText()) + assertThat(teile) + .extracting(t -> ((Umnummerierung) t).neu().anzeigeText()) .containsExactly("§ 5 Absatz 5", "§ 5 Absatz 4", "§ 5 Absatz 3"); } @@ -563,7 +567,8 @@ class BefehlErkennerTest { Stelle.LEER); var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); assertThat(teile).hasSize(2).allMatch(t -> t instanceof Ersetzung); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("Absatz 1 Satz 1", "Absatz 1 Satz 2"); } @@ -614,19 +619,23 @@ class BefehlErkennerTest { @Test void bereichsAufhebungWirdSammelbefehl() { var teile = - ((Sammelbefehl) erkenne("Die Nummern 1 bis 3 werden aufgehoben.", Stelle.LEER).orElseThrow()) + ((Sammelbefehl) + erkenne("Die Nummern 1 bis 3 werden aufgehoben.", Stelle.LEER).orElseThrow()) .teilbefehle(); assertThat(teile).hasSize(3).allMatch(t -> t instanceof Aufhebung); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("Nummer 1", "Nummer 2", "Nummer 3"); } @Test void koordinierteAufhebungWirdSammelbefehl() { var teile = - ((Sammelbefehl) erkenne("Die Absätze 4 und 5 werden aufgehoben.", Stelle.LEER).orElseThrow()) + ((Sammelbefehl) + erkenne("Die Absätze 4 und 5 werden aufgehoben.", Stelle.LEER).orElseThrow()) .teilbefehle(); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("Absatz 4", "Absatz 5"); } @@ -639,9 +648,11 @@ class BefehlErkennerTest { .teilbefehle(); assertThat(teile).hasSize(3).allMatch(t -> t instanceof Umnummerierung); // Absteigend: 6→10, 5→9, 4→8. - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("Nummer 6", "Nummer 5", "Nummer 4"); - assertThat(teile).extracting(t -> ((Umnummerierung) t).neu().anzeigeText()) + assertThat(teile) + .extracting(t -> ((Umnummerierung) t).neu().anzeigeText()) .containsExactly("Nummer 10", "Nummer 9", "Nummer 8"); } @@ -656,7 +667,8 @@ class BefehlErkennerTest { .orElseThrow()) .teilbefehle(); assertThat(teile).hasSize(3).allMatch(t -> t instanceof Neufassung); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("§ 52", "§ 53", "§ 54"); } @@ -704,7 +716,9 @@ class BefehlErkennerTest { new Stelle(List.of(new Stelle.Paragraph("64")))); var b = befehl.orElseThrow(); assertThat(b).isInstanceOf(Aufhebung.class); - assertThat(b.stelle().absatzbezeichnung()).get().extracting(Stelle.Absatzbezeichnung::nummer) + assertThat(b.stelle().absatzbezeichnung()) + .get() + .extracting(Stelle.Absatzbezeichnung::nummer) .isEqualTo("2"); } @@ -737,7 +751,8 @@ class BefehlErkennerTest { ((Sammelbefehl) erkenne("Die §§ 34 bis 39 werden gestrichen.", Stelle.LEER).orElseThrow()) .teilbefehle(); assertThat(teile).hasSize(6).allMatch(t -> t instanceof Aufhebung); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("§ 34", "§ 35", "§ 36", "§ 37", "§ 38", "§ 39"); } @@ -774,7 +789,8 @@ class BefehlErkennerTest { .orElseThrow()) .teilbefehle(); assertThat(teile).hasSize(4).allMatch(t -> t instanceof Umnummerierung); - assertThat(teile).extracting(t -> t.stelle().anzeigeText()) + assertThat(teile) + .extracting(t -> t.stelle().anzeigeText()) .containsExactly("§ 108 Absatz 7", "§ 108 Absatz 6", "§ 108 Absatz 5", "§ 108 Absatz 4"); } @@ -806,11 +822,13 @@ class BefehlErkennerTest { @Test void koordinierteParagraphUmnummerierung() { var teile = - ((Sammelbefehl) erkenne("Die §§ 46 und 47 werden zu den §§ 34 und 35.", Stelle.LEER).orElseThrow()) + ((Sammelbefehl) + erkenne("Die §§ 46 und 47 werden zu den §§ 34 und 35.", Stelle.LEER).orElseThrow()) .teilbefehle(); assertThat(teile).hasSize(2).allMatch(t -> t instanceof Umnummerierung); assertThat(teile).extracting(t -> t.stelle().anzeigeText()).containsExactly("§ 46", "§ 47"); - assertThat(teile).extracting(t -> ((Umnummerierung) t).neu().anzeigeText()) + assertThat(teile) + .extracting(t -> ((Umnummerierung) t).neu().anzeigeText()) .containsExactly("§ 34", "§ 35"); } @@ -884,6 +902,7 @@ 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 @@ -920,7 +939,8 @@ class BefehlErkennerTest { kontext); assertThat(befehl).containsInstanceOf(Neufassung.class); - assertThat(befehl.orElseThrow().stelle().anzeigeText()).isEqualTo("Inhaltsübersicht Abschnitt 2"); + assertThat(befehl.orElseThrow().stelle().anzeigeText()) + .isEqualTo("Inhaltsübersicht Abschnitt 2"); } @Test @@ -1300,7 +1320,8 @@ class BefehlErkennerTest { @Test void erkenntSatzzeichenErsetzungOhneStelle() { var befehl = - erkenne("Der Punkt am Ende wird durch die Angabe „(Gesellschaftsdialog).“ ersetzt.", + erkenne( + "Der Punkt am Ende wird durch die Angabe „(Gesellschaftsdialog).“ ersetzt.", PARAGRAPH_5); assertThat(befehl).containsInstanceOf(Ersetzung.class); 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 d5b960a..e32489a 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java @@ -23,22 +23,23 @@ class StellenParserTest { void parstMehrfachMitGemeinsamemPraefix() { // Zweites Segment erbt „§ 3“, ersetzt aber ab „Absatz“. var stellen = StellenParser.parseMehrfach("§ 3 Absatz 1 Satz 2 und Absatz 4"); - assertThat(stellen).extracting(Stelle::anzeigeText) + assertThat(stellen) + .extracting(Stelle::anzeigeText) .containsExactly("§ 3 Absatz 1 Satz 2", "§ 3 Absatz 4"); } @Test void parstMehrfachMitSatzTiefe() { var stellen = StellenParser.parseMehrfach("§ 20 Absatz 1 Satz 1 und Absatz 2 Satz 2"); - assertThat(stellen).extracting(Stelle::anzeigeText) + assertThat(stellen) + .extracting(Stelle::anzeigeText) .containsExactly("§ 20 Absatz 1 Satz 1", "§ 20 Absatz 2 Satz 2"); } @Test void parstMehrfachMitKomma() { var stellen = StellenParser.parseMehrfach("§ 1, § 2 und § 3"); - assertThat(stellen).extracting(Stelle::anzeigeText) - .containsExactly("§ 1", "§ 2", "§ 3"); + assertThat(stellen).extracting(Stelle::anzeigeText).containsExactly("§ 1", "§ 2", "§ 3"); } @Test @@ -57,14 +58,16 @@ class StellenParserTest { void bloßeNummerErbtKomponentenart() { // „Absatz 1 und 5“: das „5“ erbt die Komponentenart „Absatz“ der letzten Komponente. var stellen = StellenParser.parseMehrfach("§ 7 Absatz 1 und 5"); - assertThat(stellen).extracting(Stelle::anzeigeText) + assertThat(stellen) + .extracting(Stelle::anzeigeText) .containsExactly("§ 7 Absatz 1", "§ 7 Absatz 5"); } @Test void bloßeNummerNachSatz() { var stellen = StellenParser.parseMehrfach("Absatz 1 Satz 1 und 2"); - assertThat(stellen).extracting(Stelle::anzeigeText) + assertThat(stellen) + .extracting(Stelle::anzeigeText) .containsExactly("Absatz 1 Satz 1", "Absatz 1 Satz 2"); } @@ -94,10 +97,12 @@ class StellenParserTest { void parstBayerischenBereichMitAbkuerzung() { // „In den Abs. 4 und 5“ und Bereiche wie „Art. 4 bis 6“ mit erhaltenem Sigel. var stellen = StellenParser.parseMehrfach("Art. 4 Abs. 3, Art. 5 Abs. 2 und Art. 11 Abs. 6"); - assertThat(stellen).extracting(Stelle::anzeigeText) + assertThat(stellen) + .extracting(Stelle::anzeigeText) .containsExactly("Art. 4 Absatz 3", "Art. 5 Absatz 2", "Art. 11 Absatz 6"); var bereich = StellenParser.parseMehrfach("Abs. 1 bis 3"); - assertThat(bereich).extracting(Stelle::anzeigeText) + assertThat(bereich) + .extracting(Stelle::anzeigeText) .containsExactly("Absatz 1", "Absatz 2", "Absatz 3"); } @@ -127,7 +132,8 @@ class StellenParserTest { @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()) + assertThat( + StellenParser.parse("Absatz 1 in der Angabe vor Nummer 1").orElseThrow().anzeigeText()) .isEqualTo("Absatz 1"); } } 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 1591a74..4d78639 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/TextBereinigerTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/TextBereinigerTest.java @@ -21,7 +21,8 @@ class TextBereinigerTest { @Test void setztZerlegteUmlauteKanonischZusammen() { - // Das GV.-NRW.-Heft 7/2026 kodiert einen Teil seiner Umlaute zerlegt; für die Befehlsmuster wäre + // Das GV.-NRW.-Heft 7/2026 kodiert einen Teil seiner Umlaute zerlegt; für die Befehlsmuster + // wäre // „angefügt“ dann ein anderes Wort und dutzende Befehle könnten nie matchen. // Der Umlaut steht hier bewusst zerlegt (u + U+0308), wie im Heft. var roh = "Dem § 128 wird folgender Absatz 3 angefu\u0308gt:"; @@ -203,7 +204,8 @@ class TextBereinigerTest { + "Nächste eigene Zeile. \uE000"; assertThat(TextBereiniger.bereinige(roh)) - .isEqualTo("Erste Zeile des Absatzes wird fortgesetzt und endet hier.\nNächste eigene Zeile."); + .isEqualTo( + "Erste Zeile des Absatzes wird fortgesetzt und endet hier.\nNächste eigene Zeile."); } @Test @@ -217,7 +219,8 @@ class TextBereinigerTest { + "Dieses Gesetz tritt am Tag nach der Verkündung in Kraft. \uE000"; assertThat(TextBereiniger.bereinige(roh)) - .isEqualTo("Artikel 2\nInkrafttreten\nDieses Gesetz tritt am Tag nach der Verkündung in Kraft."); + .isEqualTo( + "Artikel 2\nInkrafttreten\nDieses Gesetz tritt am Tag nach der Verkündung in Kraft."); } @Test diff --git a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java index e9ecbcd..c12f118 100644 --- a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java +++ b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java @@ -260,8 +260,9 @@ class BefehlAnwenderTest { assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); assertThat(absatzText(ergebnis.neu(), "§ 1", 1)) - .contains(" 1. das Einlesen von Gesetzen,\n 1a. die Prüfung von Zitaten,\n 2. die" - + " Anwendung von Befehlen und"); + .contains( + " 1. das Einlesen von Gesetzen,\n 1a. die Prüfung von Zitaten,\n 2. die" + + " Anwendung von Befehlen und"); } @Test @@ -515,7 +516,8 @@ class BefehlAnwenderTest { // Ein Befehl → genau ein Protokolleintrag, aber beide Teiledits wirken. assertThat(ergebnis.protokoll()).hasSize(1); assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); - assertThat(ergebnis.protokoll().get(0).betroffeneEnbez()).containsExactlyInAnyOrder("§ 1", "§ 2"); + assertThat(ergebnis.protokoll().get(0).betroffeneEnbez()) + .containsExactlyInAnyOrder("§ 1", "§ 2"); assertThat(absatzText(ergebnis.neu(), "§ 1", 0)) .isEqualTo("Zweck dieses Gesetzes ist die Prüfung."); assertThat(absatzText(ergebnis.neu(), "§ 2", 0)).startsWith("Prüfung ist die Prüfung"); @@ -550,7 +552,8 @@ class BefehlAnwenderTest { @Test void nummeriertParagraphUm() { var befehl = - new Umnummerierung(stelle(new Stelle.Paragraph("3")), stelle(new Stelle.Paragraph("4")), PROV); + new Umnummerierung( + stelle(new Stelle.Paragraph("3")), stelle(new Stelle.Paragraph("4")), PROV); var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(befehl)); @@ -580,7 +583,8 @@ class BefehlAnwenderTest { @Test void meldetKonfliktBeiParagraphUmnummerierung() { var befehl = - new Umnummerierung(stelle(new Stelle.Paragraph("3")), stelle(new Stelle.Paragraph("1")), PROV); + new Umnummerierung( + stelle(new Stelle.Paragraph("3")), stelle(new Stelle.Paragraph("1")), PROV); var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(befehl)); @@ -712,20 +716,26 @@ class BefehlAnwenderTest { var teile = List.<eu.mulk.aendggner.aenderung.Aenderungsbefehl>of( new Aufhebung( - stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("1")), + stelle( + new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("1")), PROV), new Aufhebung( - stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("2")), + stelle( + new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("2")), PROV), new Aufhebung( - stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("3")), + stelle( + new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("3")), PROV)); var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(new Sammelbefehl(teile))); assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); var text = absatzText(ergebnis.neu(), "§ 1", 1); - assertThat(text).contains("1. (weggefallen)").contains("2. (weggefallen)").contains("3. (weggefallen)"); + assertThat(text) + .contains("1. (weggefallen)") + .contains("2. (weggefallen)") + .contains("3. (weggefallen)"); } // --- Anhang/Anlage als Norm-Ziel ----------------------------------------------------------- @@ -737,12 +747,7 @@ class BefehlAnwenderTest { null, null, List.of( - new Norm( - "§ 1", - "Zweck", - null, - List.of(new Absatz("1", "Es gilt der Anhang.")), - false), + new Norm("§ 1", "Zweck", null, List.of(new Absatz("1", "Es gilt der Anhang.")), false), new Norm( "Anhang", "(zu § 1)", @@ -1057,8 +1062,7 @@ class BefehlAnwenderTest { @Test void ersetztGesetzesUeberschrift() { var befehl = - new Neufassung( - stelle(new Stelle.Ueberschrift()), "Gesetz zur gründlichen Erprobung", PROV); + new Neufassung(stelle(new Stelle.Ueberschrift()), "Gesetz zur gründlichen Erprobung", PROV); var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(befehl)); @@ -1126,10 +1130,8 @@ class BefehlAnwenderTest { void nummeriertAufzaehlungsNummerImTextUm() { var befehl = new Umnummerierung( - stelle( - new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("2")), - stelle( - new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("4")), + stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("2")), + stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("2"), new Stelle.NummerNr("4")), PROV); var ergebnis = BefehlAnwender.anwenden(gesetz(), List.of(befehl)); @@ -1163,10 +1165,8 @@ class BefehlAnwenderTest { List.of()); var befehl = new Umnummerierung( - stelle( - new Stelle.Paragraph("1"), new Stelle.AbsatzNr("1"), new Stelle.NummerNr("2")), - stelle( - new Stelle.Paragraph("1"), new Stelle.AbsatzNr("1"), new Stelle.NummerNr("1")), + stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("1"), new Stelle.NummerNr("2")), + stelle(new Stelle.Paragraph("1"), new Stelle.AbsatzNr("1"), new Stelle.NummerNr("1")), PROV); var ergebnis = BefehlAnwender.anwenden(mitLuecke, List.of(befehl)); diff --git a/src/test/java/eu/mulk/aendggner/anwendung/SatzTeilerTest.java b/src/test/java/eu/mulk/aendggner/anwendung/SatzTeilerTest.java index c0da1f3..47acc3b 100644 --- a/src/test/java/eu/mulk/aendggner/anwendung/SatzTeilerTest.java +++ b/src/test/java/eu/mulk/aendggner/anwendung/SatzTeilerTest.java @@ -115,7 +115,8 @@ class SatzTeilerTest { SatzTeiler.teileTexte( "Die Angebote können zusammengefasst werden. § 27 Absatz 2 bleibt unberührt."); - assertThat(saetze).containsExactly( - "Die Angebote können zusammengefasst werden.", "§ 27 Absatz 2 bleibt unberührt."); + assertThat(saetze) + .containsExactly( + "Die Angebote können zusammengefasst werden.", "§ 27 Absatz 2 bleibt unberührt."); } } diff --git a/src/test/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParserTest.java b/src/test/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParserTest.java index 77249f6..897a440 100644 --- a/src/test/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParserTest.java +++ b/src/test/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParserTest.java @@ -159,7 +159,9 @@ class LandesRechtTextParserTest { // Unnummerierter Einzelabsatz und weggefallene Norm wie im bayerischen Fall. assertThat(gesetz.norm("§ 2").orElseThrow().absaetze().get(0).nummer()).isNull(); assertThat(gesetz.norm("§ 3").orElseThrow().weggefallen()).isTrue(); - assertThat(gesetz.gliederungen()).extracting(Gliederung::anzeigeText).containsExactly("I. Teil — Grundlagen der Gemeindeverfassung"); + assertThat(gesetz.gliederungen()) + .extracting(Gliederung::anzeigeText) + .containsExactly("I. Teil — Grundlagen der Gemeindeverfassung"); } @Test |
