diff --git a/backend/src/test/java/org/raddatz/familienarchiv/service/ThumbnailServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/ThumbnailServiceTest.java index 90b0e8c8..a2074891 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/service/ThumbnailServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/ThumbnailServiceTest.java @@ -167,6 +167,38 @@ class ThumbnailServiceTest { verify(documentRepository, never()).save(any()); } + @Test + void generate_returnsFailed_whenImageBytesAreCorrupt() throws IOException { + // Truncated JPEG header — ImageIO returns null rather than throwing. + // Without the corrupt-image guard this would later NPE inside the aspect / + // dimension computation in scaleToWidth. + Document doc = makeDoc("image/jpeg", "documents/corrupt.jpg"); + byte[] truncated = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE0}; + when(fileService.downloadFileStream(anyString())) + .thenReturn(new ByteArrayInputStream(truncated)); + + ThumbnailService.Outcome outcome = thumbnailService.generate(doc); + + assertThat(outcome).isEqualTo(ThumbnailService.Outcome.FAILED); + verifyNoInteractions(s3Client); + verify(documentRepository, never()).save(any()); + } + + @Test + void generate_returnsFailed_whenPdfBytesAreCorrupt() throws IOException { + // "PDF" header but no body — PDFBox throws IOException while loading. + Document doc = makeDoc("application/pdf", "documents/corrupt.pdf"); + byte[] fakePdf = "%PDF-1.4\n".getBytes(); + when(fileService.downloadFileStream(anyString())) + .thenReturn(new ByteArrayInputStream(fakePdf)); + + ThumbnailService.Outcome outcome = thumbnailService.generate(doc); + + assertThat(outcome).isEqualTo(ThumbnailService.Outcome.FAILED); + verifyNoInteractions(s3Client); + verify(documentRepository, never()).save(any()); + } + @Test void generate_returnsFailed_whenPersistThrows_butUploadSucceeded() throws IOException { // Covers the "orphan thumbnail" edge case: S3 upload succeeded but the