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
This commit is contained in:
2026-07-21 10:20:53 +02:00
parent 3598c5f9c6
commit e12b64a517

View File

@@ -47,6 +47,17 @@ public class DevExpressPdfProcessorTests
return memoryStream.ToArray();
}
/// <summary>
/// Loads a test PDF from embedded resources as Stream.
/// </summary>
/// <param name="filename">Name of the PDF file (e.g., "valid.pdf")</param>
/// <returns>PDF content as MemoryStream (caller must dispose)</returns>
private static MemoryStream LoadTestPdfAsStream(string filename)
{
byte[] pdfBytes = LoadTestPdf(filename);
return new MemoryStream(pdfBytes);
}
/// <summary>
/// Converts byte array to MemoryStream for testing
/// </summary>
@@ -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<Stream> { 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<Stream> { 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<Stream> { pdf1, pdf2 };
var pageRanges = new List<string?> { "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<Stream> { pdf1, pdf2 };
var pageRanges = new List<string?> { 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<Stream> { pdf1 };
// Act
var act = async () => await _sut.MergePdfsAsync(streams);
// Assert
await act.Should().ThrowAsync<BadRequestException>()
.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<Stream> { pdf1, emptyStream };
// Act
var act = async () => await _sut.MergePdfsAsync(streams);
// Assert
await act.Should().ThrowAsync<BadRequestException>()
.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<Stream> { pdf1, pdf2 };
// Act
var act = async () => await _sut.MergePdfsAsync(streams);
// Assert
await act.Should().ThrowAsync<BadRequestException>();
}
[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<Stream> { pdf1, pdf2 };
var pageRanges = new List<string?> { "1", "abc" }; // Invalid format
// Act
var act = async () => await _sut.MergePdfsAsync(streams, pageRanges);
// Assert
await act.Should().ThrowAsync<BadRequestException>()
.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<Stream> { pdf1, pdf2 };
var pageRanges = new List<string?> { "1-99", null }; // 99 exceeds pdf1 page count
// Act
var act = async () => await _sut.MergePdfsAsync(streams, pageRanges);
// Assert
await act.Should().ThrowAsync<BadRequestException>()
.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<Stream> { pdf1, pdf2 };
var pageRanges = new List<string?> { "1" }; // Only 1 range for 2 PDFs
// Act
var act = async () => await _sut.MergePdfsAsync(streams, pageRanges);
// Assert
await act.Should().ThrowAsync<BadRequestException>()
.WithMessage("*must match*");
}
#endregion
}