From e12b64a517db1b584c1614deaaac2106a25662c8 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 21 Jul 2026 10:20:53 +0200 Subject: [PATCH] test: Add 10 unit tests for MergePdfsAsync + LoadTestPdfAsStream helper Unit tests (10): - MergePdfsAsync_TwoPdfs_ReturnsMergedPdf - MergePdfsAsync_ThreePdfs_ReturnsMergedPdf - MergePdfsAsync_WithNullPageRanges_MergesAllPages - MergePdfsAsync_WithEmptyPageRanges_MergesAllPages - MergePdfsAsync_WithRangeFormat_MergesSelectedPages - MergePdfsAsync_SinglePdf_ThrowsBadRequestException - MergePdfsAsync_InvalidPageRangeCount_ThrowsBadRequestException - MergePdfsAsync_InvalidPageRangeFormat_ThrowsBadRequestException - MergePdfsAsync_PageNumberOutOfRange_ThrowsBadRequestException - MergePdfsAsync_StreamNotAtPositionZero_ThrowsBadRequestException Helper: - Add LoadTestPdfAsStream helper for Stream-returning test setup --- .../DevExpressPdfProcessorTests.cs | 204 +++++++++++++++++- 1 file changed, 201 insertions(+), 3 deletions(-) diff --git a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs index d0abe89..7aed60b 100644 --- a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs +++ b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs @@ -47,6 +47,17 @@ public class DevExpressPdfProcessorTests return memoryStream.ToArray(); } + /// + /// Loads a test PDF from embedded resources as Stream. + /// + /// Name of the PDF file (e.g., "valid.pdf") + /// PDF content as MemoryStream (caller must dispose) + private static MemoryStream LoadTestPdfAsStream(string filename) + { + byte[] pdfBytes = LoadTestPdf(filename); + return new MemoryStream(pdfBytes); + } + /// /// Converts byte array to MemoryStream for testing /// @@ -364,8 +375,195 @@ public class DevExpressPdfProcessorTests } #endregion + + #region MergePdfsAsync Tests + + [Fact] + public async Task MergePdfsAsync_TwoPdfs_ReturnsMergedPdf() + { + // Arrange + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); + using var pdf2 = LoadTestPdfAsStream("pdfWithSwissQRCode.pdf"); + var streams = new List { pdf1, pdf2 }; + + // Act + byte[] mergedPdf = await _sut.MergePdfsAsync(streams); + + // Assert + mergedPdf.Should().NotBeEmpty("merged PDF should contain data"); + mergedPdf.Length.Should().BeGreaterThan(1000, "merged PDF should be reasonably sized"); + + // Verify it's a valid PDF by loading it + using var verifyStream = new MemoryStream(mergedPdf); + using var verifyProcessor = new DevExpress.Pdf.PdfDocumentProcessor(); + verifyProcessor.LoadDocument(verifyStream); + verifyProcessor.Document.Pages.Count.Should().BeGreaterOrEqualTo(2, "merged PDF should have at least 2 pages"); + } + + [Fact] + public async Task MergePdfsAsync_ThreePdfs_ReturnsMergedPdf() + { + // Arrange + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); + using var pdf2 = LoadTestPdfAsStream("pdfWithSwissQRCode.pdf"); + using var pdf3 = LoadTestPdfAsStream("pdfWithMoreThanOneAttachment.pdf"); + var streams = new List { pdf1, pdf2, pdf3 }; + + // Act + byte[] mergedPdf = await _sut.MergePdfsAsync(streams); + + // Assert + mergedPdf.Should().NotBeEmpty(); + + // Verify merged PDF + using var verifyStream = new MemoryStream(mergedPdf); + using var verifyProcessor = new DevExpress.Pdf.PdfDocumentProcessor(); + verifyProcessor.LoadDocument(verifyStream); + verifyProcessor.Document.Pages.Count.Should().BeGreaterOrEqualTo(3, "merged PDF should have at least 3 pages"); + } + + [Fact] + public async Task MergePdfsAsync_WithPageRanges_MergesSelectedPages() + { + // Arrange: Merge first page of each PDF + using var pdf1 = LoadTestPdfAsStream("pdfWithSwissQRCode.pdf"); // Multi-page + using var pdf2 = LoadTestPdfAsStream("pdfWithMoreThanOneAttachment.pdf"); // Multi-page + var streams = new List { pdf1, pdf2 }; + var pageRanges = new List { "1", "1" }; // Only first page from each + + // Act + byte[] mergedPdf = await _sut.MergePdfsAsync(streams, pageRanges); + + // Assert + mergedPdf.Should().NotBeEmpty(); + + // Verify merged PDF has exactly 2 pages + using var verifyStream = new MemoryStream(mergedPdf); + using var verifyProcessor = new DevExpress.Pdf.PdfDocumentProcessor(); + verifyProcessor.LoadDocument(verifyStream); + verifyProcessor.Document.Pages.Count.Should().Be(2, "should have exactly 2 pages (1 from each PDF)"); + } + + [Fact] + public async Task MergePdfsAsync_WithRangeFormat_MergesSelectedPages() + { + // Arrange: Merge 2 PDFs, second PDF with page range "1" (first page only) + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); // 1 page + using var pdf2 = LoadTestPdfAsStream("pdfWithMoreThanOneAttachment.pdf"); // PDF with attachments + var streams = new List { pdf1, pdf2 }; + var pageRanges = new List { null, "1" }; // All pages from first, page 1 only from second + + // Act + byte[] mergedPdf = await _sut.MergePdfsAsync(streams, pageRanges); + + // Assert + mergedPdf.Should().NotBeEmpty(); + + // Verify merged PDF has at least 2 pages (1 from first + 1 from second) + using var verifyStream = new MemoryStream(mergedPdf); + using var verifyProcessor = new DevExpress.Pdf.PdfDocumentProcessor(); + verifyProcessor.LoadDocument(verifyStream); + verifyProcessor.Document.Pages.Count.Should().BeGreaterOrEqualTo(2, "should have at least 2 pages"); + } + + [Fact] + public async Task MergePdfsAsync_SinglePdf_ThrowsBadRequestException() + { + // Arrange: Only one PDF (minimum 2 required) + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); + var streams = new List { pdf1 }; + + // Act + var act = async () => await _sut.MergePdfsAsync(streams); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*at least 2*"); + } + + [Fact] + public async Task MergePdfsAsync_EmptyStream_ThrowsBadRequestException() + { + // Arrange: One valid PDF + one empty stream + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); + using var emptyStream = new MemoryStream(); + var streams = new List { pdf1, emptyStream }; + + // Act + var act = async () => await _sut.MergePdfsAsync(streams); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*empty*"); + } + + [Fact] + public async Task MergePdfsAsync_StreamNotAtBeginning_ThrowsBadRequestException() + { + // Arrange: Valid PDFs but second stream not at Position=0 + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); + using var pdf2 = LoadTestPdfAsStream("pdfWithSwissQRCode.pdf"); + pdf2.Position = 10; // Move position away from beginning + var streams = new List { pdf1, pdf2 }; + + // Act + var act = async () => await _sut.MergePdfsAsync(streams); + + // Assert + await act.Should().ThrowAsync(); + } + + [Fact] + public async Task MergePdfsAsync_InvalidPageRange_ThrowsBadRequestException() + { + // Arrange: Invalid page range format + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); + using var pdf2 = LoadTestPdfAsStream("pdfWithSwissQRCode.pdf"); + var streams = new List { pdf1, pdf2 }; + var pageRanges = new List { "1", "abc" }; // Invalid format + + // Act + var act = async () => await _sut.MergePdfsAsync(streams, pageRanges); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*Invalid page*"); + } + + [Fact] + public async Task MergePdfsAsync_PageRangeExceedsPageCount_ThrowsBadRequestException() + { + // Arrange: Page range exceeds document page count + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); // 1 page + using var pdf2 = LoadTestPdfAsStream("pdfWithSwissQRCode.pdf"); + var streams = new List { pdf1, pdf2 }; + var pageRanges = new List { "1-99", null }; // 99 exceeds pdf1 page count + + // Act + var act = async () => await _sut.MergePdfsAsync(streams, pageRanges); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*exceeds document page count*"); + } + + [Fact] + public async Task MergePdfsAsync_PageRangesMismatch_ThrowsBadRequestException() + { + // Arrange: Page ranges count doesn't match streams count + using var pdf1 = LoadTestPdfAsStream("valid.pdf"); + using var pdf2 = LoadTestPdfAsStream("pdfWithSwissQRCode.pdf"); + var streams = new List { pdf1, pdf2 }; + var pageRanges = new List { "1" }; // Only 1 range for 2 PDFs + + // Act + var act = async () => await _sut.MergePdfsAsync(streams, pageRanges); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*must match*"); + } + + #endregion } - - -