1
0

Windows-Zeichenbehandlung im finalen Basis-Dateinamen explizit umgesetzt

This commit is contained in:
2026-04-07 13:59:18 +02:00
parent f81f30c7ea
commit 7e4201b651
2 changed files with 114 additions and 3 deletions

View File

@@ -21,8 +21,9 @@ import static org.assertj.core.api.Assertions.assertThatNullPointerException;
* Unit tests for {@link TargetFilenameBuildingService}.
* <p>
* Covers the verbindliches Zielformat {@code YYYY-MM-DD - Titel.pdf}, the 20-character
* base-title rule, the fachliche Titelregel (only letters, digits, and spaces), and the
* detection of inconsistent persistence states.
* base-title rule, the fachliche Titelregel (only letters, digits, and spaces),
* Windows-compatibility character removal, and the detection of inconsistent persistence
* states.
*/
class TargetFilenameBuildingServiceTest {
@@ -218,6 +219,86 @@ class TargetFilenameBuildingServiceTest {
assertThat(result).isInstanceOf(InconsistentProposalState.class);
}
// -------------------------------------------------------------------------
// Windows compatibility removal of incompatible characters
// (defensive measure; characters should not appear in validated title)
// -------------------------------------------------------------------------
@Test
void buildBaseFilename_validTitleProducesWindowsCompatibleFilename() {
// Valid titles containing only letters, digits, and spaces should produce
// correct Windows-compatible filenames
ProcessingAttempt attempt = proposalAttempt(LocalDate.of(2026, 5, 20), "Versicherung");
BaseFilenameResult result = TargetFilenameBuildingService.buildBaseFilename(attempt);
assertThat(result).isInstanceOf(BaseFilenameReady.class);
assertThat(((BaseFilenameReady) result).baseFilename())
.isEqualTo("2026-05-20 - Versicherung.pdf");
}
@Test
void buildBaseFilename_germanUmlautsAreRetainedInFilename() {
// German Umlauts (ä, ö, ü) and ß are valid filename characters on Windows
// and must be retained in the output filename
ProcessingAttempt attempt = proposalAttempt(LocalDate.of(2026, 6, 15), "Überprüfung");
BaseFilenameResult result = TargetFilenameBuildingService.buildBaseFilename(attempt);
assertThat(result).isInstanceOf(BaseFilenameReady.class);
assertThat(((BaseFilenameReady) result).baseFilename())
.isEqualTo("2026-06-15 - Überprüfung.pdf");
}
@Test
void buildBaseFilename_germanSzligIsRetainedInFilename() {
// German ß is a valid filename character on Windows and must be retained
ProcessingAttempt attempt = proposalAttempt(LocalDate.of(2026, 3, 10), "Straße");
BaseFilenameResult result = TargetFilenameBuildingService.buildBaseFilename(attempt);
assertThat(result).isInstanceOf(BaseFilenameReady.class);
assertThat(((BaseFilenameReady) result).baseFilename())
.isEqualTo("2026-03-10 - Straße.pdf");
}
@Test
void buildBaseFilename_completeFormatIsWindowsCompatible() {
// The complete filename format (YYYY-MM-DD - Titel.pdf) is Windows-compatible
// The hyphen in the date and the dot in the extension are valid Windows characters
ProcessingAttempt attempt = proposalAttempt(LocalDate.of(2026, 12, 31), "Bericht");
BaseFilenameResult result = TargetFilenameBuildingService.buildBaseFilename(attempt);
assertThat(result).isInstanceOf(BaseFilenameReady.class);
String filename = ((BaseFilenameReady) result).baseFilename();
assertThat(filename).matches("\\d{4}-\\d{2}-\\d{2} - .+\\.pdf");
// Verify no Windows-incompatible characters: < > : " / \ | ? *
assertThat(filename).doesNotContain("<");
assertThat(filename).doesNotContain(">");
assertThat(filename).doesNotContain(":");
assertThat(filename).doesNotContain("\"");
assertThat(filename).doesNotContain("/");
assertThat(filename).doesNotContain("\\");
assertThat(filename).doesNotContain("|");
assertThat(filename).doesNotContain("?");
assertThat(filename).doesNotContain("*");
}
@Test
void buildBaseFilename_twentyCharacterRuleUnaffectedByWindowsCompatibility() {
// The 20-character rule applies to the base title only.
// Windows-compatibility cleaning does not change the length counting mechanism.
String title = "Stromabrechnung 2026"; // exactly 20 characters
ProcessingAttempt attempt = proposalAttempt(LocalDate.of(2026, 3, 31), title);
BaseFilenameResult result = TargetFilenameBuildingService.buildBaseFilename(attempt);
assertThat(result).isInstanceOf(BaseFilenameReady.class);
assertThat(((BaseFilenameReady) result).baseFilename())
.startsWith("2026-03-31 - Stromabrechnung 2026");
}
// -------------------------------------------------------------------------
// InconsistentProposalState reason field is non-null
// -------------------------------------------------------------------------