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