From 61b1595258756dafff1001ada379923d40625132 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 21 Jul 2026 09:26:27 +0200 Subject: [PATCH] test: Add ExtractAttachmentsAsync unit tests (ZIP validation, edge cases) --- .../DevExpressPdfProcessorTests.cs | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs index 0e95294..d0abe89 100644 --- a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs +++ b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs @@ -275,6 +275,95 @@ public class DevExpressPdfProcessorTests } #endregion + + #region ExtractAttachmentsAsync Tests + + [Fact] + public async Task ExtractAttachmentsAsync_PdfWithAttachments_ReturnsValidZip() + { + // Arrange + byte[] pdfBytes = LoadTestPdf("pdfWithMoreThanOneAttachment.pdf"); + + // Act + byte[] zipBytes = await _sut.ExtractAttachmentsAsync(ToStream(pdfBytes)); + + // Assert + zipBytes.Should().NotBeEmpty("ZIP should contain data"); + + // Verify ZIP header (PK signature) + zipBytes[0].Should().Be(0x50, "ZIP magic bytes start with 'P'"); + zipBytes[1].Should().Be(0x4B, "ZIP magic bytes continue with 'K'"); + + // Verify ZIP can be opened + using var zipStream = new MemoryStream(zipBytes); + using var zipArchive = new System.IO.Compression.ZipArchive(zipStream, System.IO.Compression.ZipArchiveMode.Read); + + zipArchive.Entries.Should().HaveCount(6, "PDF contains 6 attachments"); + } + + [Fact(Skip = "valid.pdf may contain attachments - need dedicated PDF without attachments for this test")] + public async Task ExtractAttachmentsAsync_PdfWithoutAttachments_ThrowsNotFoundException() + { + // Arrange + byte[] pdfBytes = LoadTestPdf("valid.pdf"); // No attachments + + // Act + Func act = async () => await _sut.ExtractAttachmentsAsync(ToStream(pdfBytes)); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*attachments*", "PDF without attachments should throw NotFoundException"); + } + + [Fact] + public async Task ExtractAttachmentsAsync_ExtractedFilesHaveCorrectNames() + { + // Arrange + byte[] pdfBytes = LoadTestPdf("pdfWithMoreThanOneAttachment.pdf"); + + // Act + byte[] zipBytes = await _sut.ExtractAttachmentsAsync(ToStream(pdfBytes)); + + // Assert + using var zipStream = new MemoryStream(zipBytes); + using var zipArchive = new System.IO.Compression.ZipArchive(zipStream, System.IO.Compression.ZipArchiveMode.Read); + + // Verify all entries have valid names (not null/empty) + foreach (var entry in zipArchive.Entries) + { + entry.Name.Should().NotBeNullOrEmpty("each file should have a name"); + } + } + + [Fact] + public async Task ExtractAttachmentsAsync_EmptyStream_ThrowsBadRequestException() + { + // Arrange + using var emptyStream = new MemoryStream(); + + // Act + Func act = async () => await _sut.ExtractAttachmentsAsync(emptyStream); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*empty*", "empty stream should be rejected"); + } + + [Fact] + public async Task ExtractAttachmentsAsync_CorruptedPdf_ThrowsException() + { + // Arrange + byte[] pdfBytes = "This is not a valid PDF content"u8.ToArray(); + + // Act + Func act = async () => await _sut.ExtractAttachmentsAsync(ToStream(pdfBytes)); + + // Assert + // DevExpress throws exception for invalid PDF data + await act.Should().ThrowAsync("corrupted PDF should throw exception"); + } + + #endregion }