From 64be11f7add2d01e8af3fc7370832f225e668a27 Mon Sep 17 00:00:00 2001 From: OlgunR Date: Fri, 19 Jun 2026 14:38:12 +0200 Subject: [PATCH] Add tests for DevExpressPdfProcessor and roadmap updates Updated ROADMAP.md to reflect progress on the TDD process for DevExpressPdfProcessor, including the creation of unit tests (6 tests in the Red Phase). Updated progress to 4/7 mini-steps completed and outlined the next step (Green Phase). Added `DevExpressPdfProcessorTests.cs` with unit tests to validate PDF files and extract metadata. Tests cover valid PDFs, null/empty inputs, corrupted PDFs, and file size calculations. Used `FluentAssertions` for assertions. Cleaned up `DocumentOperator.Tests.csproj` by removing an unused folder reference. No functional changes to the project structure. --- DocumentOperator.API/ROADMAP.md | 6 +- .../DocumentOperator.Tests.csproj | 6 +- .../DevExpressPdfProcessorTests.cs | 146 ++++++++++++++++++ 3 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs diff --git a/DocumentOperator.API/ROADMAP.md b/DocumentOperator.API/ROADMAP.md index 400d3e8..847476e 100644 --- a/DocumentOperator.API/ROADMAP.md +++ b/DocumentOperator.API/ROADMAP.md @@ -1321,11 +1321,12 @@ public async Task POST_ValidatePdf_InvalidPdf_Returns400() { } - ? Step 3.2.1 - ProcessDocument Ordner gelöscht (Application Layer cleanup) - ? Step 3.2.2 - Test-Ordnerstruktur erstellt (Unit/Infrastructure/Services/PdfProcessing) - ? Step 3.2.3 - Test-PDF Datei hinzugefügt (valid.pdf als Embedded Resource) + - ? Step 3.2.4 - DevExpressPdfProcessorTests.cs erstellt (TDD Red Phase - 6 Tests) ### ?? In Progress - **Phase 3, Step 3.2:** DevExpressPdfProcessor (TDD) - - **NEXT:** Step 3.2.4 - DevExpressPdfProcessorTests.cs erstellen (TDD Red Phase) - - **Progress:** 3/7 Mini-Steps abgeschlossen + - **NEXT:** Step 3.2.5 - DevExpressPdfProcessor.cs implementieren (TDD Green Phase) + - **Progress:** 4/7 Mini-Steps abgeschlossen ### ? Pending - **Phase 3:** Infrastructure Layer @@ -1484,6 +1485,7 @@ public async Task POST_ValidatePdf_InvalidPdf_Returns400() { } | 17.01.2025 | Application | ? Step 3.2.1 - ProcessDocument Ordner gelöscht (Cleanup) | | 17.01.2025 | Tests | ? Step 3.2.2 - Test-Ordnerstruktur erstellt, UnitTest1.cs gelöscht | | 17.01.2025 | Tests | ? Step 3.2.3 - Test-PDF (valid.pdf) als Embedded Resource hinzugefügt | +| 17.01.2025 | Tests | ? Step 3.2.4 - DevExpressPdfProcessorTests.cs erstellt (TDD Red - 6 Tests) | --- diff --git a/DocumentOperator.Tests/DocumentOperator.Tests.csproj b/DocumentOperator.Tests/DocumentOperator.Tests.csproj index 5a024dd..41ec07f 100644 --- a/DocumentOperator.Tests/DocumentOperator.Tests.csproj +++ b/DocumentOperator.Tests/DocumentOperator.Tests.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -39,8 +39,4 @@ - - - - diff --git a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs new file mode 100644 index 0000000..c74046a --- /dev/null +++ b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs @@ -0,0 +1,146 @@ +using System.Reflection; +using DocumentOperator.Application.Common.Interfaces; +using DocumentOperator.Domain.Common.Exceptions; +using DocumentOperator.Domain.Models.ValueObjects; +using DocumentOperator.Infrastructure.Services.PdfProcessing; +using FluentAssertions; + +namespace DocumentOperator.Tests.Unit.Infrastructure.Services.PdfProcessing; + +/// +/// Unit tests for DevExpressPdfProcessor. +/// Tests PDF validation and metadata extraction. +/// +public class DevExpressPdfProcessorTests +{ + private readonly IPdfProcessor _sut; // SUT = System Under Test + + public DevExpressPdfProcessorTests() + { + // Arrange: Create instance (wird später implementiert) + _sut = new DevExpressPdfProcessor(); + } + + #region Helper Methods + + /// + /// Loads a test PDF from embedded resources. + /// + /// Name of the PDF file (e.g., "valid.pdf") + /// PDF content as byte array + private static byte[] LoadTestPdf(string filename) + { + var assembly = Assembly.GetExecutingAssembly(); + var resourceName = $"DocumentOperator.Tests.TestData.Pdfs.{filename}"; + + using var stream = assembly.GetManifestResourceStream(resourceName); + + if (stream == null) + { + throw new FileNotFoundException( + $"Embedded resource '{resourceName}' not found. " + + $"Available resources: {string.Join(", ", assembly.GetManifestResourceNames())}"); + } + + using var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + return memoryStream.ToArray(); + } + + #endregion + + #region ValidateAsync Tests + + [Fact] + public async Task ValidateAsync_ValidPdf_ReturnsPdfMetadata() + { + // Arrange + byte[] pdfBytes = LoadTestPdf("valid.pdf"); + + // Act + var metadata = await _sut.ValidateAsync(pdfBytes); + + // Assert + metadata.Should().NotBeNull("a valid PDF should return metadata"); + metadata.PageCount.Should().BeGreaterThan(0, "PDF must have at least one page"); + metadata.FileSizeBytes.Should().Be(pdfBytes.Length, "file size should match input"); + metadata.PdfVersion.Should().NotBeNullOrEmpty("PDF version should be detected"); + } + + [Fact] + public async Task ValidateAsync_ValidPdf_ReturnsCorrectPageCount() + { + // Arrange + byte[] pdfBytes = LoadTestPdf("valid.pdf"); + + // Act + var metadata = await _sut.ValidateAsync(pdfBytes); + + // Assert + // Deine valid.pdf hat wahrscheinlich 1-5 Seiten - passe an! + metadata.PageCount.Should().BeInRange(1, 100, "test PDF should have reasonable page count"); + } + + [Fact] + public async Task ValidateAsync_NullBytes_ThrowsPdfProcessingException() + { + // Arrange + byte[]? pdfBytes = null; + + // Act + Func act = async () => await _sut.ValidateAsync(pdfBytes!); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*null*", "null input should be rejected"); + } + + [Fact] + public async Task ValidateAsync_EmptyBytes_ThrowsPdfProcessingException() + { + // Arrange + byte[] pdfBytes = Array.Empty(); + + // Act + Func act = async () => await _sut.ValidateAsync(pdfBytes); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*empty*", "empty input should be rejected"); + } + + [Fact] + public async Task ValidateAsync_CorruptedPdf_ThrowsPdfProcessingException() + { + // Arrange + byte[] pdfBytes = "This is not a valid PDF content"u8.ToArray(); + + // Act + Func act = async () => await _sut.ValidateAsync(pdfBytes); + + // Assert + await act.Should().ThrowAsync() + .WithMessage("*invalid*", "corrupted PDF should throw exception"); + } + + #endregion + + #region Metadata Tests + + [Fact] + public async Task ValidateAsync_ValidPdf_FileSizeMBCalculatedCorrectly() + { + // Arrange + byte[] pdfBytes = LoadTestPdf("valid.pdf"); + + // Act + var metadata = await _sut.ValidateAsync(pdfBytes); + + // Assert + double expectedSizeMB = pdfBytes.Length / 1024.0 / 1024.0; + metadata.FileSizeMB.Should().BeApproximately(expectedSizeMB, 0.01, + "FileSizeMB should be calculated correctly from bytes"); + } + + #endregion +} \ No newline at end of file