From 7cdb676dee34fbb98fbf2a7d0e035ad0ee739283 Mon Sep 17 00:00:00 2001 From: Pat201290 Date: Sun, 5 Apr 2026 15:21:15 +0200 Subject: [PATCH] Anpassung an DQFL Specification V 1.1 --- pom.xml | 12 +- src.zip | Bin 0 -> 26878 bytes .../de/dogfire/dqfl/model/DqflCategory.java | 31 +++- .../de/dogfire/dqfl/parser/DqflParser.java | 8 +- .../dogfire/dqfl/validator/DqflValidator.java | 61 ++++---- src/test/java/de/dogfire/dqfl/DqflTest.java | 143 +++++++++++++++++- 6 files changed, 201 insertions(+), 54 deletions(-) create mode 100644 src.zip diff --git a/pom.xml b/pom.xml index 17e0f6c..fee8220 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ - + 4.0.0 de.dogfire.dqfl @@ -32,18 +32,18 @@ gitea - https://dein-gitea-server/api/packages/pat201290/maven + https://gitea.dogfire.de/api/packages/pat201290/maven gitea - https://dein-gitea-server/api/packages/pat201290/maven + https://gitea.dogfire.de/api/packages/pat201290/maven gitea - https://dein-gitea-server/api/packages/pat201290/maven + https://gitea.dogfire.de/api/packages/pat201290/maven diff --git a/src.zip b/src.zip new file mode 100644 index 0000000000000000000000000000000000000000..33df3c2309bd974662e655c75f75a7c63eeaa481 GIT binary patch literal 26878 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 VR&TtyGYN=3h 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 X)&c#M&{~m&MF#p+fF|`66Y%MO7w1Pm literal 0 HcmV?d00001 diff --git a/src/main/java/de/dogfire/dqfl/model/DqflCategory.java b/src/main/java/de/dogfire/dqfl/model/DqflCategory.java index e77cdf0..d47ac5d 100644 --- a/src/main/java/de/dogfire/dqfl/model/DqflCategory.java +++ b/src/main/java/de/dogfire/dqfl/model/DqflCategory.java @@ -1,4 +1,3 @@ - package de.dogfire.dqfl.model; import java.util.ArrayList; @@ -14,18 +13,20 @@ public final class DqflCategory private final String alias; private final String title; private final String usePool; + private final String useCategory; private final LayoutType layout; private final GridSize size; private final List phases; private DqflCategory(final Builder builder) { - this.alias = Objects.requireNonNull(builder.alias, "alias must not be null"); - this.title = builder.title; - this.usePool = builder.usePool; - this.layout = builder.layout; - this.size = builder.size; - this.phases = Collections.unmodifiableList(new ArrayList<>(builder.phases)); + this.alias = Objects.requireNonNull(builder.alias, "alias must not be null"); + this.title = builder.title; + this.usePool = builder.usePool; + this.useCategory = builder.useCategory; + this.layout = builder.layout; + this.size = builder.size; + this.phases = Collections.unmodifiableList(new ArrayList<>(builder.phases)); } public String getAlias() @@ -44,6 +45,12 @@ public final class DqflCategory return this.usePool; } + /** Kann null sein — USE_CATEGORY ist optional (V1_1). */ + public String getUseCategory() + { + return this.useCategory; + } + public LayoutType getLayout() { return this.layout; @@ -66,6 +73,7 @@ public final class DqflCategory return "CATEGORY " + this.alias + " [title=" + this.title + ", pool=" + this.usePool + + ", category=" + this.useCategory + ", phases=" + this.phases.size() + "]"; } @@ -83,6 +91,7 @@ public final class DqflCategory private final String alias; private String title; private String usePool; + private String useCategory; private LayoutType layout; private GridSize size; private final List phases = new ArrayList<>(); @@ -104,6 +113,12 @@ public final class DqflCategory return this; } + public Builder useCategory(final String useCategory) + { + this.useCategory = useCategory; + return this; + } + public Builder layout(final LayoutType layout) { this.layout = layout; @@ -127,4 +142,4 @@ public final class DqflCategory return new DqflCategory(this); } } -} +} \ No newline at end of file diff --git a/src/main/java/de/dogfire/dqfl/parser/DqflParser.java b/src/main/java/de/dogfire/dqfl/parser/DqflParser.java index 5a147a3..753644d 100644 --- a/src/main/java/de/dogfire/dqfl/parser/DqflParser.java +++ b/src/main/java/de/dogfire/dqfl/parser/DqflParser.java @@ -10,7 +10,7 @@ import de.dogfire.dqfl.error.DqflParseException; import de.dogfire.dqfl.model.*; /** - * Parser für DQFL V1 Dokumente. + * Parser für DQFL V1/V1_1 Dokumente. * Liest ein einrückungssensitives Textformat und erzeugt einen {@link DqflDocument} AST. */ public final class DqflParser @@ -330,6 +330,10 @@ public final class DqflParser catBuilder.usePool(child.value); this.cursor++; } + case "USE_CATEGORY" -> { + catBuilder.useCategory(this.unquote(child.value)); + this.cursor++; + } case "LAYOUT" -> { final LayoutType lt = LayoutType.parse(child.value); if(lt == null) @@ -670,4 +674,4 @@ public final class DqflParser + this.keyword + (this.value != null ? " " + this.value : ""); } } -} +} \ No newline at end of file diff --git a/src/main/java/de/dogfire/dqfl/validator/DqflValidator.java b/src/main/java/de/dogfire/dqfl/validator/DqflValidator.java index 63e283f..e47b968 100644 --- a/src/main/java/de/dogfire/dqfl/validator/DqflValidator.java +++ b/src/main/java/de/dogfire/dqfl/validator/DqflValidator.java @@ -1,4 +1,3 @@ - package de.dogfire.dqfl.validator; import java.util.ArrayList; @@ -12,8 +11,8 @@ import de.dogfire.dqfl.error.DqflValidationResult; import de.dogfire.dqfl.model.*; /** - * Validator für DQFL V1 Dokumente. - * Prüft alle Fachregeln aus Kapitel 10 der Spezifikation. + * Validator für DQFL V1/V1_1 Dokumente. + * Prüft alle Fachregeln aus der Spezifikation. */ public final class DqflValidator { @@ -40,25 +39,18 @@ public final class DqflValidator errors.add(DqflError.error("FLOW is required")); } - // 3. SOURCE-Aliase müssen eindeutig sein (bereits durch Map im Parser sichergestellt, - // aber wir prüfen trotzdem ob Sources vorhanden sind wenn Pools sie referenzieren) - - // 4. POOL-Validierung + // 3. POOL-Validierung this.validatePools(document, errors); - // 5. ROUND-Validierung + // 4. ROUND-Validierung this.validateRounds(document, errors); - // 6. Alias-Eindeutigkeit über Objektarten + // 5. Alias-Eindeutigkeit über Objektarten this.validateAliasUniqueness(document, errors); return new DqflValidationResult(errors); } - // ================================================================ - // Pool-Validierung - // ================================================================ - private void validatePools(final DqflDocument document, final List errors) { for(final DqflPool pool : document.getPools().values()) @@ -82,10 +74,6 @@ public final class DqflValidator } } - // ================================================================ - // Round-Validierung - // ================================================================ - private void validateRounds(final DqflDocument document, final List errors) { if(document.getRounds().isEmpty()) @@ -119,10 +107,6 @@ public final class DqflValidator } } - // ================================================================ - // Category-Validierung - // ================================================================ - private void validateCategory( final DqflCategory category, final DqflDocument document, @@ -153,6 +137,26 @@ public final class DqflValidator } } + // USE_CATEGORY Validierung (V1_1) + if(category.getUseCategory() != null) + { + // USE_CATEGORY ohne USE_POOL ist ein Syntaxfehler + if(category.getUsePool() == null || category.getUsePool().isBlank()) + { + errors.add(DqflError.error( + "CATEGORY '" + category.getAlias() + + "' has USE_CATEGORY without USE_POOL")); + } + + // Wert darf nicht leer sein + if(category.getUseCategory().isBlank()) + { + errors.add(DqflError.error( + "CATEGORY '" + category.getAlias() + + "' USE_CATEGORY must not be empty")); + } + } + // SIZE nur gültig wenn LAYOUT vorhanden if(category.getSize() != null && category.getLayout() == null) { @@ -182,10 +186,6 @@ public final class DqflValidator } } - // ================================================================ - // Phase-Validierung - // ================================================================ - private void validatePhase( final DqflPhase phase, final String categoryAlias, @@ -236,19 +236,10 @@ public final class DqflValidator } } - // ================================================================ - // Alias-Eindeutigkeit (über Objektarten) - // ================================================================ - private void validateAliasUniqueness( final DqflDocument document, final List errors) { - // SOURCE-Aliase eindeutig (Map-Struktur prüft bereits implizit, - // aber bei Duplikaten im Dokument wurde der erste überschrieben) - // POOL-Aliase eindeutig (gleiche Map-Logik) - - // Wir prüfen explizit ob Pool-Aliase und Source-Aliase kollidieren (optional, sauber) final Set sourceAliases = document.getSources().keySet(); final Set poolAliases = document.getPools().keySet(); @@ -262,4 +253,4 @@ public final class DqflValidator } } } -} +} \ No newline at end of file diff --git a/src/test/java/de/dogfire/dqfl/DqflTest.java b/src/test/java/de/dogfire/dqfl/DqflTest.java index b2662ae..a01e8a7 100644 --- a/src/test/java/de/dogfire/dqfl/DqflTest.java +++ b/src/test/java/de/dogfire/dqfl/DqflTest.java @@ -1,4 +1,3 @@ - package de.dogfire.dqfl; import static org.junit.jupiter.api.Assertions.*; @@ -14,7 +13,7 @@ import de.dogfire.dqfl.error.DqflValidationResult; import de.dogfire.dqfl.model.*; /** - * Tests für die DQFL V1 Library: Parser + Validator. + * Tests für die DQFL V1/V1_1 Library: Parser + Validator. */ class DqflTest { @@ -75,6 +74,7 @@ class DqflTest assertEquals("C1", c1.getAlias()); assertEquals("Geschichte", c1.getTitle()); assertEquals("HISTORY", c1.getUsePool()); + assertNull(c1.getUseCategory()); assertEquals(LayoutType.GRID_2D, c1.getLayout()); assertEquals(new GridSize(6, 6), c1.getSize()); assertEquals(2, c1.getPhases().size()); @@ -322,6 +322,143 @@ class DqflTest } } + // ================================================================ + // V1_1 USE_CATEGORY Tests + // ================================================================ + + @Nested + @DisplayName("V1_1 USE_CATEGORY") + class UseCategoryTests + { + @Test + @DisplayName("Parst USE_CATEGORY korrekt") + void parseUseCategory() throws Exception + { + final String input = """ + DQFL_VERSION V1_1 + FLOW "Test" + SOURCE SRC1 + TYPE REST + CONNECTION CONN1 + POOL GEO + SOURCE SRC1 + REMOTE_ID "ZX82LM550000009321" + ROUND R1 + CATEGORY C1 + USE_POOL GEO + USE_CATEGORY "Hauptstädte" + LAYOUT GRID_2D + SIZE 4x4 + PHASE NORMAL + QUESTION_SET NORMAL + CYCLES 2 + TURNS_PER_CYCLE 4 + TURN_ORDER ROTATING_START + PICK_MODE FREE_UNANSWERED + TEAM_MODE SOLO + SCORING SOLO_PLUS1_NO_PENALTY + """; + + final DqflDocument doc = Dqfl.parseAndValidate(input); + final DqflCategory c1 = doc.getRounds().get(0).getCategories().get(0); + + assertEquals("V1_1", doc.getDqflVersion()); + assertEquals("GEO", c1.getUsePool()); + assertEquals("Hauptstädte", c1.getUseCategory()); + } + + @Test + @DisplayName("USE_CATEGORY ohne USE_POOL wird als Fehler erkannt") + void useCategoryWithoutUsePool() throws Exception + { + final String input = """ + DQFL_VERSION V1_1 + FLOW "Test" + SOURCE SRC1 + TYPE REST + CONNECTION CONN1 + POOL P1 + SOURCE SRC1 + REMOTE_ID "AB12CD340000004711" + ROUND R1 + CATEGORY C1 + USE_CATEGORY "Test" + PHASE NORMAL + TEAM_MODE SOLO + SCORING SOLO_PLUS1_NO_PENALTY + """; + + final DqflDocument doc = Dqfl.parse(input); + final DqflValidationResult result = Dqfl.validate(doc); + + assertFalse(result.isValid()); + assertTrue(result.getErrorsOnly().stream() + .anyMatch(e -> e.getMessage().contains("USE_CATEGORY without USE_POOL"))); + } + + @Test + @DisplayName("Category ohne USE_CATEGORY bleibt null (V1 Abwärtskompatibilität)") + void noCategoryFilterReturnsNull() throws Exception + { + final DqflDocument doc = loadReferenceDocument(); + final DqflCategory c1 = doc.getRounds().get(0).getCategories().get(0); + + assertNull(c1.getUseCategory()); + } + + @Test + @DisplayName("V1_1 Dokument mit und ohne USE_CATEGORY gemischt") + void mixedCategoriesWithAndWithout() throws Exception + { + final String input = """ + DQFL_VERSION V1_1 + FLOW "Mixed Test" + SOURCE SRC1 + TYPE REST + CONNECTION CONN1 + POOL HISTORY + SOURCE SRC1 + REMOTE_ID "AB12CD340000004711" + POOL GEO + SOURCE SRC1 + REMOTE_ID "ZX82LM550000009321" + ROUND R1 + CATEGORY C1 + USE_POOL HISTORY + LAYOUT GRID_2D + SIZE 6x6 + PHASE NORMAL + QUESTION_SET NORMAL + CYCLES 3 + TURNS_PER_CYCLE 4 + TURN_ORDER ROTATING_START + PICK_MODE FREE_UNANSWERED + TEAM_MODE SOLO + SCORING SOLO_PLUS1_NO_PENALTY + CATEGORY C2 + USE_POOL GEO + USE_CATEGORY "Hauptstädte" + LAYOUT GRID_2D + SIZE 4x4 + PHASE NORMAL + QUESTION_SET NORMAL + CYCLES 2 + TURNS_PER_CYCLE 4 + TURN_ORDER ROTATING_START + PICK_MODE FREE_UNANSWERED + TEAM_MODE SOLO + SCORING SOLO_PLUS1_NO_PENALTY + """; + + final DqflDocument doc = Dqfl.parseAndValidate(input); + final var categories = doc.getAllCategoriesFlat(); + + assertEquals(2, categories.size()); + assertNull(categories.get(0).getUseCategory()); + assertEquals("Hauptstädte", categories.get(1).getUseCategory()); + } + } + // ================================================================ // GridSize Tests // ================================================================ @@ -408,4 +545,4 @@ class DqflTest return new String(is.readAllBytes()); } } -} +} \ No newline at end of file