diff --git a/pdf-umbenenner-application/src/main/java/de/gecheckt/pdf/umbenenner/application/service/TargetFilenameBuildingService.java b/pdf-umbenenner-application/src/main/java/de/gecheckt/pdf/umbenenner/application/service/TargetFilenameBuildingService.java index de41c2a..09d35ca 100644 --- a/pdf-umbenenner-application/src/main/java/de/gecheckt/pdf/umbenenner/application/service/TargetFilenameBuildingService.java +++ b/pdf-umbenenner-application/src/main/java/de/gecheckt/pdf/umbenenner/application/service/TargetFilenameBuildingService.java @@ -93,7 +93,7 @@ public final class TargetFilenameBuildingService { *
  • Validated title must be non-null and non-blank.
  • *
  • Validated title must not exceed the configured maximum length * (before Windows cleaning).
  • - *
  • After Windows-character cleaning, title must contain only letters, digits, and spaces.
  • + *
  • After Windows-character cleaning, title must contain only letters, digits, spaces, and hyphens.
  • * * If any rule is violated, the state is treated as an * {@link InconsistentProposalState}. @@ -148,11 +148,11 @@ public final class TargetFilenameBuildingService { + title + "'"); } - // After cleaning, verify that only letters, digits, and spaces remain + // After cleaning, verify that only letters, digits, spaces, and hyphens remain if (!isAllowedTitleCharacters(cleanedTitle)) { return new InconsistentProposalState( "After Windows-compatibility cleaning, title contains disallowed characters " - + "(only letters, digits, and spaces are permitted): '" + + "(only letters, digits, spaces, and hyphens are permitted): '" + cleanedTitle + "'"); } @@ -166,13 +166,13 @@ public final class TargetFilenameBuildingService { // ------------------------------------------------------------------------- /** - * Returns {@code true} if every character in the title is a letter, a digit, or a space. + * Returns {@code true} if every character in the title is a letter, a digit, space, or hyphen. * Unicode letters (including German Umlauts and ß) are permitted. */ private static boolean isAllowedTitleCharacters(String title) { for (int i = 0; i < title.length(); i++) { char c = title.charAt(i); - if (!Character.isLetter(c) && !Character.isDigit(c) && c != ' ') { + if (!Character.isLetter(c) && !Character.isDigit(c) && c != ' ' && c != '-') { return false; } } diff --git a/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/service/DocumentProcessingCoordinatorTest.java b/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/service/DocumentProcessingCoordinatorTest.java index 3d1beaa..0f7897b 100644 --- a/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/service/DocumentProcessingCoordinatorTest.java +++ b/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/service/DocumentProcessingCoordinatorTest.java @@ -978,14 +978,14 @@ class DocumentProcessingCoordinatorTest { DocumentRecord existingRecord = buildRecord(ProcessingStatus.PROPOSAL_READY, FailureCounters.zero()); recordRepo.setLookupResult(new DocumentKnownProcessable(existingRecord)); - // Hyphen is a disallowed character in the fachliche Titelregel + // Exclamation mark is a disallowed character in the fachliche Titelregel ProcessingAttempt badProposal = new ProcessingAttempt( fingerprint, context.runId(), 1, Instant.now(), Instant.now(), ProcessingStatus.PROPOSAL_READY, null, null, false, null, "model", "prompt", 1, 100, "{}", "reason", LocalDate.of(2026, 1, 15), DateSource.AI_PROVIDED, - "Rechnung-2026", null); + "Rechnung!", null); attemptRepo.savedAttempts.add(badProposal); boolean result = processor.processDeferredOutcome(candidate, fingerprint, context, attemptStart, c -> null); diff --git a/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/service/TargetFilenameBuildingServiceTest.java b/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/service/TargetFilenameBuildingServiceTest.java index 405f7aa..8fa2d85 100644 --- a/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/service/TargetFilenameBuildingServiceTest.java +++ b/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/service/TargetFilenameBuildingServiceTest.java @@ -212,15 +212,15 @@ class TargetFilenameBuildingServiceTest { // ------------------------------------------------------------------------- @Test - void buildBaseFilename_titleWithHyphen_returnsInconsistentProposalState() { - // Hyphens are not letters, digits, or spaces — disallowed by fachliche Titelregel + void buildBaseFilename_titleWithHyphen_succeeds() { + // Hyphens are allowed per fachliche Titelregel ProcessingAttempt attempt = proposalAttempt(LocalDate.of(2026, 1, 1), "Rechnung-2026"); BaseFilenameResult result = TargetFilenameBuildingService.buildBaseFilename(attempt, TEST_MAX_TITLE_LENGTH); - assertThat(result).isInstanceOf(InconsistentProposalState.class); - assertThat(((InconsistentProposalState) result).reason()) - .contains("disallowed characters"); + assertThat(result).isInstanceOf(BaseFilenameReady.class); + assertThat(((BaseFilenameReady) result).baseFilename()) + .isEqualTo("2026-01-01 - Rechnung-2026.pdf"); } @Test